activerecord-jdbc-adapter 1.3.0.beta2 → 1.3.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +14 -8
- data/.travis.yml +40 -31
- data/.yardopts +4 -0
- data/Appraisals +2 -5
- data/CONTRIBUTING.md +46 -0
- data/Gemfile +21 -4
- data/Gemfile.lock +42 -17
- data/{History.txt → History.md} +142 -75
- data/README.md +102 -104
- data/RUNNING_TESTS.md +76 -0
- data/Rakefile.jdbc +20 -0
- data/activerecord-jdbc-adapter.gemspec +35 -18
- data/gemfiles/rails23.gemfile +4 -3
- data/gemfiles/rails23.gemfile.lock +9 -6
- data/gemfiles/rails30.gemfile +4 -3
- data/gemfiles/rails30.gemfile.lock +9 -6
- data/gemfiles/rails31.gemfile +4 -3
- data/gemfiles/rails31.gemfile.lock +9 -6
- data/gemfiles/rails32.gemfile +4 -3
- data/gemfiles/rails32.gemfile.lock +17 -14
- data/gemfiles/rails40.gemfile +5 -5
- data/gemfiles/rails40.gemfile.lock +17 -69
- data/lib/active_record/connection_adapters/firebird_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +1 -0
- data/lib/arel/visitors/compat.rb +22 -3
- data/lib/arel/visitors/db2.rb +8 -4
- data/lib/arel/visitors/derby.rb +14 -13
- data/lib/arel/visitors/firebird.rb +5 -4
- data/lib/arel/visitors/hsqldb.rb +11 -9
- data/lib/arel/visitors/sql_server.rb +89 -61
- data/lib/arjdbc.rb +1 -1
- data/lib/arjdbc/db2/adapter.rb +181 -212
- data/lib/arjdbc/db2/as400.rb +31 -18
- data/lib/arjdbc/db2/column.rb +167 -0
- data/lib/arjdbc/db2/connection_methods.rb +2 -0
- data/lib/arjdbc/derby/adapter.rb +206 -107
- data/lib/arjdbc/derby/connection_methods.rb +4 -9
- data/lib/arjdbc/firebird.rb +1 -0
- data/lib/arjdbc/firebird/adapter.rb +202 -64
- data/lib/arjdbc/firebird/connection_methods.rb +20 -0
- data/lib/arjdbc/h2/adapter.rb +56 -36
- data/lib/arjdbc/hsqldb/adapter.rb +99 -68
- data/lib/arjdbc/jdbc/adapter.rb +474 -265
- data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
- data/lib/arjdbc/jdbc/adapter_require.rb +8 -7
- data/lib/arjdbc/jdbc/arel_support.rb +132 -0
- data/lib/arjdbc/jdbc/base_ext.rb +8 -7
- data/lib/arjdbc/jdbc/callbacks.rb +16 -10
- data/lib/arjdbc/jdbc/column.rb +25 -3
- data/lib/arjdbc/jdbc/connection.rb +28 -55
- data/lib/arjdbc/jdbc/extension.rb +14 -14
- data/lib/arjdbc/jdbc/java.rb +6 -3
- data/lib/arjdbc/jdbc/jdbc.rake +1 -1
- data/lib/arjdbc/jdbc/quoted_primary_key.rb +2 -2
- data/lib/arjdbc/jdbc/rake_tasks.rb +1 -1
- data/lib/arjdbc/jdbc/type_converter.rb +5 -2
- data/lib/arjdbc/mssql/adapter.rb +160 -280
- data/lib/arjdbc/mssql/column.rb +182 -0
- data/lib/arjdbc/mssql/connection_methods.rb +37 -4
- data/lib/arjdbc/mssql/explain_support.rb +13 -21
- data/lib/arjdbc/mssql/limit_helpers.rb +79 -42
- data/lib/arjdbc/mssql/lock_methods.rb +77 -0
- data/lib/arjdbc/mssql/utils.rb +11 -11
- data/lib/arjdbc/mysql/adapter.rb +165 -247
- data/lib/arjdbc/mysql/column.rb +123 -0
- data/lib/arjdbc/mysql/connection_methods.rb +3 -6
- data/lib/arjdbc/oracle/adapter.rb +282 -288
- data/lib/arjdbc/oracle/column.rb +122 -0
- data/lib/arjdbc/oracle/connection_methods.rb +3 -0
- data/lib/arjdbc/postgresql/adapter.rb +336 -574
- data/lib/arjdbc/postgresql/column.rb +458 -0
- data/lib/arjdbc/postgresql/connection_methods.rb +1 -2
- data/lib/arjdbc/postgresql/schema_creation.rb +38 -0
- data/lib/arjdbc/sqlite3/adapter.rb +189 -145
- data/lib/arjdbc/sqlite3/explain_support.rb +1 -1
- data/lib/arjdbc/tasks/oracle/enhanced_structure_dump.rb +8 -8
- data/lib/arjdbc/util/quoted_cache.rb +60 -0
- data/lib/arjdbc/util/table_copier.rb +110 -0
- data/lib/arjdbc/version.rb +6 -7
- data/pom.xml +56 -2
- data/rakelib/02-test.rake +72 -83
- data/rakelib/db.rake +29 -17
- data/src/java/arjdbc/ArJdbcModule.java +21 -18
- data/src/java/arjdbc/db2/DB2RubyJdbcConnection.java +84 -12
- data/src/java/arjdbc/derby/DerbyModule.java +140 -143
- data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +58 -7
- data/src/java/arjdbc/h2/H2Module.java +43 -0
- data/src/java/arjdbc/informix/InformixRubyJdbcConnection.java +7 -6
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +1223 -648
- data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +24 -23
- data/src/java/arjdbc/mysql/MySQLModule.java +33 -32
- data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +147 -30
- data/src/java/arjdbc/oracle/OracleModule.java +13 -13
- data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +114 -6
- data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +166 -36
- data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +101 -19
- data/src/java/arjdbc/util/QuotingUtils.java +19 -19
- metadata +240 -394
- data/bench/bench_attributes.rb +0 -13
- data/bench/bench_attributes_new.rb +0 -14
- data/bench/bench_create.rb +0 -12
- data/bench/bench_find_all.rb +0 -12
- data/bench/bench_find_all_mt.rb +0 -25
- data/bench/bench_model.rb +0 -85
- data/bench/bench_new.rb +0 -12
- data/bench/bench_new_valid.rb +0 -12
- data/bench/bench_valid.rb +0 -13
- data/lib/arel/engines/sql/compilers/db2_compiler.rb +0 -9
- data/lib/arel/engines/sql/compilers/derby_compiler.rb +0 -6
- data/lib/arel/engines/sql/compilers/h2_compiler.rb +0 -6
- data/lib/arel/engines/sql/compilers/hsqldb_compiler.rb +0 -15
- data/lib/arel/engines/sql/compilers/jdbc_compiler.rb +0 -6
- data/lib/arel/engines/sql/compilers/mssql_compiler.rb +0 -46
- data/lib/arjdbc/jdbc/missing_functionality_helper.rb +0 -98
- data/lib/arjdbc/mssql/lock_helpers.rb +0 -76
- data/lib/arjdbc/mssql/tsql_methods.rb +0 -58
- data/lib/arjdbc/postgresql/column_cast.rb +0 -134
- data/test/activerecord/connections/native_jdbc_mysql/connection.rb +0 -25
- data/test/activerecord/jall.sh +0 -7
- data/test/activerecord/jtest.sh +0 -3
- data/test/assets/flowers.jpg +0 -0
- data/test/binary.rb +0 -67
- data/test/db/db2.rb +0 -43
- data/test/db/db2/binary_test.rb +0 -6
- data/test/db/db2/has_many_through_test.rb +0 -6
- data/test/db/db2/rake_test.rb +0 -82
- data/test/db/db2/rake_test_data.sql +0 -35
- data/test/db/db2/reset_column_information_test.rb +0 -5
- data/test/db/db2/serialize_test.rb +0 -6
- data/test/db/db2/simple_test.rb +0 -81
- data/test/db/db2/test_helper.rb +0 -6
- data/test/db/db2/unit_test.rb +0 -73
- data/test/db/derby.rb +0 -12
- data/test/db/derby/binary_test.rb +0 -6
- data/test/db/derby/migration_test.rb +0 -74
- data/test/db/derby/rake_test.rb +0 -96
- data/test/db/derby/reset_column_information_test.rb +0 -6
- data/test/db/derby/row_locking_test.rb +0 -20
- data/test/db/derby/schema_dump_test.rb +0 -5
- data/test/db/derby/serialize_test.rb +0 -6
- data/test/db/derby/simple_test.rb +0 -173
- data/test/db/derby/test_helper.rb +0 -6
- data/test/db/derby/unit_test.rb +0 -32
- data/test/db/derby/xml_column_test.rb +0 -17
- data/test/db/h2.rb +0 -11
- data/test/db/h2/binary_test.rb +0 -6
- data/test/db/h2/change_column_test.rb +0 -68
- data/test/db/h2/identity_column_test.rb +0 -35
- data/test/db/h2/offset_test.rb +0 -49
- data/test/db/h2/rake_test.rb +0 -98
- data/test/db/h2/schema_dump_test.rb +0 -29
- data/test/db/h2/serialize_test.rb +0 -6
- data/test/db/h2/simple_test.rb +0 -56
- data/test/db/hsqldb.rb +0 -11
- data/test/db/hsqldb/binary_test.rb +0 -6
- data/test/db/hsqldb/rake_test.rb +0 -101
- data/test/db/hsqldb/schema_dump_test.rb +0 -19
- data/test/db/hsqldb/serialize_test.rb +0 -6
- data/test/db/hsqldb/simple_test.rb +0 -17
- data/test/db/informix.rb +0 -13
- data/test/db/jdbc.rb +0 -16
- data/test/db/jdbc_derby.rb +0 -14
- data/test/db/jdbc_h2.rb +0 -17
- data/test/db/jdbc_mysql.rb +0 -13
- data/test/db/jdbc_postgres.rb +0 -23
- data/test/db/jndi_config.rb +0 -32
- data/test/db/jndi_pooled_config.rb +0 -32
- data/test/db/mssql.rb +0 -11
- data/test/db/mssql/binary_test.rb +0 -6
- data/test/db/mssql/exec_proc_test.rb +0 -46
- data/test/db/mssql/identity_insert_test.rb +0 -18
- data/test/db/mssql/ignore_system_views_test.rb +0 -40
- data/test/db/mssql/limit_offset_test.rb +0 -190
- data/test/db/mssql/multibyte_test.rb +0 -16
- data/test/db/mssql/multiple_connections_test.rb +0 -71
- data/test/db/mssql/rake_test.rb +0 -143
- data/test/db/mssql/reset_column_information_test.rb +0 -6
- data/test/db/mssql/row_locking_test.rb +0 -7
- data/test/db/mssql/serialize_test.rb +0 -6
- data/test/db/mssql/simple_test.rb +0 -140
- data/test/db/mssql/transaction_test.rb +0 -6
- data/test/db/mssql/types_test.rb +0 -205
- data/test/db/mssql/unit_test.rb +0 -249
- data/test/db/mysql.rb +0 -4
- data/test/db/mysql/_rails_test_mysql.32.out +0 -6585
- data/test/db/mysql/binary_test.rb +0 -6
- data/test/db/mysql/connection_test.rb +0 -51
- data/test/db/mysql/index_length_test.rb +0 -58
- data/test/db/mysql/multibyte_test.rb +0 -10
- data/test/db/mysql/nonstandard_primary_key_test.rb +0 -39
- data/test/db/mysql/rake_test.rb +0 -97
- data/test/db/mysql/reset_column_information_test.rb +0 -6
- data/test/db/mysql/schema_dump_test.rb +0 -228
- data/test/db/mysql/serialize_test.rb +0 -6
- data/test/db/mysql/simple_test.rb +0 -187
- data/test/db/mysql/statement_escaping_test.rb +0 -46
- data/test/db/mysql/transaction_test.rb +0 -6
- data/test/db/mysql/types_test.rb +0 -30
- data/test/db/mysql/unit_test.rb +0 -93
- data/test/db/mysql_config.rb +0 -7
- data/test/db/oracle.rb +0 -27
- data/test/db/oracle/binary_test.rb +0 -6
- data/test/db/oracle/limit_test.rb +0 -24
- data/test/db/oracle/multibyte_test.rb +0 -22
- data/test/db/oracle/rake_test.rb +0 -100
- data/test/db/oracle/reset_column_information_test.rb +0 -6
- data/test/db/oracle/serialize_test.rb +0 -6
- data/test/db/oracle/simple_test.rb +0 -140
- data/test/db/oracle/specific_test.rb +0 -180
- data/test/db/oracle/transaction_test.rb +0 -31
- data/test/db/oracle/unit_test.rb +0 -31
- data/test/db/postgres.rb +0 -11
- data/test/db/postgres/_rails_test_postgres.32.out +0 -6405
- data/test/db/postgres/a_custom_primary_key_test.rb +0 -50
- data/test/db/postgres/active_schema_unit_test.rb +0 -68
- data/test/db/postgres/array_type_test.rb +0 -101
- data/test/db/postgres/binary_test.rb +0 -6
- data/test/db/postgres/connection_test.rb +0 -63
- data/test/db/postgres/data_types_test.rb +0 -703
- data/test/db/postgres/hstore_test.rb +0 -200
- data/test/db/postgres/information_schema_leak_test.rb +0 -30
- data/test/db/postgres/json_test.rb +0 -86
- data/test/db/postgres/ltree_test.rb +0 -51
- data/test/db/postgres/mixed_case_test.rb +0 -29
- data/test/db/postgres/native_types_test.rb +0 -124
- data/test/db/postgres/rake_test.rb +0 -117
- data/test/db/postgres/reserved_test.rb +0 -22
- data/test/db/postgres/reset_column_information_test.rb +0 -6
- data/test/db/postgres/row_locking_test.rb +0 -21
- data/test/db/postgres/schema_dump_test.rb +0 -95
- data/test/db/postgres/schema_test.rb +0 -115
- data/test/db/postgres/simple_test.rb +0 -260
- data/test/db/postgres/table_alias_length_test.rb +0 -16
- data/test/db/postgres/transaction_test.rb +0 -6
- data/test/db/postgres/unit_test.rb +0 -31
- data/test/db/postgres_config.rb +0 -10
- data/test/db/sqlite3.rb +0 -6
- data/test/db/sqlite3/_rails_test_sqlite3.32.out +0 -6274
- data/test/db/sqlite3/has_many_though_test.rb +0 -6
- data/test/db/sqlite3/rake_test.rb +0 -71
- data/test/db/sqlite3/reset_column_information_test.rb +0 -6
- data/test/db/sqlite3/schema_dump_test.rb +0 -6
- data/test/db/sqlite3/serialize_test.rb +0 -6
- data/test/db/sqlite3/simple_test.rb +0 -268
- data/test/db/sqlite3/transaction_test.rb +0 -32
- data/test/db/sqlite3/type_conversion_test.rb +0 -104
- data/test/has_many_through.rb +0 -61
- data/test/informix_simple_test.rb +0 -48
- data/test/jdbc/db2.rb +0 -36
- data/test/jdbc/oracle.rb +0 -34
- data/test/jdbc_column_test.rb +0 -23
- data/test/jdbc_common.rb +0 -16
- data/test/jdbc_connection_test.rb +0 -196
- data/test/jndi_callbacks_test.rb +0 -33
- data/test/jndi_test.rb +0 -55
- data/test/manualTestDatabase.rb +0 -191
- data/test/models/add_not_null_column_to_table.rb +0 -9
- data/test/models/auto_id.rb +0 -15
- data/test/models/binary.rb +0 -18
- data/test/models/custom_pk_name.rb +0 -15
- data/test/models/data_types.rb +0 -40
- data/test/models/entry.rb +0 -41
- data/test/models/mixed_case.rb +0 -22
- data/test/models/reserved_word.rb +0 -15
- data/test/models/rights_and_roles.rb +0 -57
- data/test/models/string_id.rb +0 -17
- data/test/models/thing.rb +0 -17
- data/test/models/topic.rb +0 -32
- data/test/models/validates_uniqueness_of_string.rb +0 -19
- data/test/rails/mysql.rb +0 -13
- data/test/rails/sqlite3/version.rb +0 -6
- data/test/rails_stub.rb +0 -31
- data/test/rake_test_support.rb +0 -298
- data/test/row_locking.rb +0 -102
- data/test/schema_dump.rb +0 -182
- data/test/serialize.rb +0 -275
- data/test/shared_helper.rb +0 -35
- data/test/simple.rb +0 -1317
- data/test/sybase_jtds_simple_test.rb +0 -28
- data/test/sybase_reset_column_information_test.rb +0 -6
- data/test/test_helper.rb +0 -304
- data/test/transaction.rb +0 -109
@@ -0,0 +1,122 @@
|
|
1
|
+
module ArJdbc
|
2
|
+
module Oracle
|
3
|
+
|
4
|
+
# @see ActiveRecord::ConnectionAdapters::JdbcColumn#column_types
|
5
|
+
def self.column_selector
|
6
|
+
[ /oracle/i, lambda { |config, column| column.extend(Column) } ]
|
7
|
+
end
|
8
|
+
|
9
|
+
# @see ActiveRecord::ConnectionAdapters::JdbcColumn
|
10
|
+
module Column
|
11
|
+
|
12
|
+
def self.included(base)
|
13
|
+
# NOTE: assumes a standalone OracleColumn class
|
14
|
+
class << base; include Cast; end
|
15
|
+
end
|
16
|
+
|
17
|
+
def primary=(value)
|
18
|
+
super
|
19
|
+
@type = :integer if value && @sql_type =~ /^NUMBER$/i
|
20
|
+
end
|
21
|
+
|
22
|
+
def type_cast(value)
|
23
|
+
return nil if value.nil?
|
24
|
+
case type
|
25
|
+
when :datetime then self.class.string_to_time(value)
|
26
|
+
when :timestamp then self.class.string_to_time(value)
|
27
|
+
when :boolean then self.class.value_to_boolean(value)
|
28
|
+
else
|
29
|
+
super
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def type_cast_code(var_name)
|
34
|
+
case type
|
35
|
+
when :datetime then "#{self.class.name}.string_to_time(#{var_name})"
|
36
|
+
when :timestamp then "#{self.class.name}.string_to_time(#{var_name})"
|
37
|
+
when :boolean then "#{self.class.name}.value_to_boolean(#{var_name})"
|
38
|
+
else
|
39
|
+
super
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def extract_limit(sql_type)
|
46
|
+
case sql_type
|
47
|
+
when /^(clob|date)/i then nil
|
48
|
+
when /^xml/i then @sql_type = 'XMLTYPE'; nil
|
49
|
+
else super
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def simplified_type(field_type)
|
54
|
+
case field_type
|
55
|
+
when /char/i then :string
|
56
|
+
when /float|double/i then :float
|
57
|
+
when /int/i then :integer
|
58
|
+
when /^number\(1\)$/i then Oracle.emulate_booleans ? :boolean : :integer
|
59
|
+
when /^num|dec|real/i then extract_scale(field_type) == 0 ? :integer : :decimal
|
60
|
+
# Oracle TIMESTAMP stores the date and time to up to 9 digits of sub-second precision
|
61
|
+
when /TIMESTAMP/i then :timestamp
|
62
|
+
# Oracle DATE stores the date and time to the second
|
63
|
+
when /DATE|TIME/i then :datetime
|
64
|
+
when /CLOB/i then :text
|
65
|
+
when /BLOB/i then :binary
|
66
|
+
when /XML/i then :xml
|
67
|
+
else
|
68
|
+
super
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Post process default value from JDBC into a Rails-friendly format (columns{-internal})
|
73
|
+
def default_value(value)
|
74
|
+
return nil unless value
|
75
|
+
value = value.strip # Not sure why we need this for Oracle?
|
76
|
+
upcase = value.upcase
|
77
|
+
|
78
|
+
return nil if upcase == "NULL"
|
79
|
+
# SYSDATE default should be treated like a NULL value
|
80
|
+
return nil if upcase == "SYSDATE"
|
81
|
+
# jdbc returns column default strings with actual single quotes around the value.
|
82
|
+
return $1 if value =~ /^'(.*)'$/
|
83
|
+
|
84
|
+
value
|
85
|
+
end
|
86
|
+
|
87
|
+
module Cast
|
88
|
+
|
89
|
+
# Convert a value to a boolean.
|
90
|
+
def value_to_boolean(value)
|
91
|
+
# NOTE: Oracle JDBC meta-data gets us DECIMAL for NUMBER(1) values
|
92
|
+
# thus we're likely to get a column back as BigDecimal (e.g. 1.0)
|
93
|
+
if value.is_a?(String)
|
94
|
+
value.blank? ? nil : value == '1'
|
95
|
+
elsif value.is_a?(Numeric)
|
96
|
+
value.to_i == 1 # <BigDecimal:7b5bfe,'0.1E1',1(4)>
|
97
|
+
else
|
98
|
+
!! value
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# @override
|
103
|
+
def string_to_time(string)
|
104
|
+
return string unless string.is_a?(String)
|
105
|
+
return nil if string.empty?
|
106
|
+
return Time.now if string.index('CURRENT') == 0 # TODO seems very wrong
|
107
|
+
|
108
|
+
super(string)
|
109
|
+
end
|
110
|
+
|
111
|
+
# @private
|
112
|
+
def guess_date_or_time(value)
|
113
|
+
return value if value.is_a? Date
|
114
|
+
( value && value.hour == 0 && value.min == 0 && value.sec == 0 ) ?
|
115
|
+
Date.new(value.year, value.month, value.day) : value
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -1,4 +1,7 @@
|
|
1
1
|
ArJdbc::ConnectionMethods.module_eval do
|
2
|
+
# Unless a connection URL (`url: jdbc:oracle:...`) is specified we'll use the
|
3
|
+
# *thin* method to connect to the Oracle DB.
|
4
|
+
# @note Oracle's JDBC driver should be on the class-path.
|
2
5
|
def oracle_connection(config)
|
3
6
|
config[:port] ||= 1521
|
4
7
|
config[:url] ||= "jdbc:oracle:thin:@#{config[:host]}:#{config[:port]}:#{config[:database]}"
|
@@ -1,29 +1,75 @@
|
|
1
1
|
ArJdbc.load_java_part :PostgreSQL
|
2
2
|
|
3
3
|
require 'ipaddr'
|
4
|
-
require 'arjdbc/postgresql/column_cast'
|
5
|
-
require 'arjdbc/postgresql/explain_support'
|
6
4
|
|
7
5
|
module ArJdbc
|
6
|
+
# Strives to provide Rails built-in PostgreSQL adapter (API) compatibility.
|
8
7
|
module PostgreSQL
|
9
|
-
|
10
|
-
AR4_COMPAT = ::ActiveRecord::VERSION::MAJOR > 3 unless const_defined?(:AR4_COMPAT) # :nodoc:
|
11
8
|
|
12
|
-
|
13
|
-
|
14
|
-
|
9
|
+
# @private
|
10
|
+
AR4_COMPAT = ::ActiveRecord::VERSION::MAJOR > 3 unless const_defined?(:AR4_COMPAT)
|
11
|
+
|
12
|
+
require 'arjdbc/postgresql/column'
|
13
|
+
require 'arjdbc/postgresql/explain_support'
|
15
14
|
|
15
|
+
# @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_connection_class
|
16
16
|
def self.jdbc_connection_class
|
17
17
|
::ActiveRecord::ConnectionAdapters::PostgreSQLJdbcConnection
|
18
18
|
end
|
19
19
|
|
20
|
+
# @private
|
21
|
+
def init_connection(jdbc_connection)
|
22
|
+
meta = jdbc_connection.meta_data
|
23
|
+
if meta.driver_version.index('JDBC3') # e.g. 'PostgreSQL 9.2 JDBC4 (build 1002)'
|
24
|
+
config[:connection_alive_sql] ||= 'SELECT 1'
|
25
|
+
else
|
26
|
+
# NOTE: since the loaded Java driver class can't change :
|
27
|
+
PostgreSQL.send(:remove_method, :init_connection) rescue nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.arel_visitor_type(config = nil)
|
32
|
+
::Arel::Visitors::PostgreSQL
|
33
|
+
end
|
34
|
+
|
35
|
+
# @see ActiveRecord::ConnectionAdapters::JdbcAdapter#bind_substitution
|
36
|
+
# @private
|
37
|
+
class BindSubstitution < ::Arel::Visitors::PostgreSQL
|
38
|
+
include ::Arel::Visitors::BindVisitor
|
39
|
+
end if defined? ::Arel::Visitors::BindVisitor
|
40
|
+
|
41
|
+
ADAPTER_NAME = 'PostgreSQL'.freeze
|
42
|
+
|
43
|
+
def adapter_name
|
44
|
+
ADAPTER_NAME
|
45
|
+
end
|
46
|
+
|
47
|
+
def postgresql_version
|
48
|
+
@postgresql_version ||=
|
49
|
+
begin
|
50
|
+
value = select_value('SELECT version()')
|
51
|
+
if value =~ /PostgreSQL (\d+)\.(\d+)\.(\d+)/
|
52
|
+
($1.to_i * 10000) + ($2.to_i * 100) + $3.to_i
|
53
|
+
else
|
54
|
+
0
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def use_insert_returning?
|
60
|
+
if ( @use_insert_returning ||= nil ).nil?
|
61
|
+
@use_insert_returning = supports_insert_with_returning?
|
62
|
+
end
|
63
|
+
@use_insert_returning
|
64
|
+
end
|
65
|
+
|
20
66
|
def set_client_encoding(encoding)
|
21
67
|
ActiveRecord::Base.logger.warn "client_encoding is set by the driver and should not be altered, ('#{encoding}' ignored)"
|
22
68
|
ActiveRecord::Base.logger.debug "Set the 'allowEncodingChanges' driver property (e.g. using config[:properties]) if you need to override the client encoding when doing a copy."
|
23
69
|
end
|
24
70
|
|
25
71
|
# Configures the encoding, verbosity, schema search path, and time zone of the connection.
|
26
|
-
# This is called
|
72
|
+
# This is called on `connection.connect` and should not be called manually.
|
27
73
|
def configure_connection
|
28
74
|
#if encoding = config[:encoding]
|
29
75
|
# The client_encoding setting is set by the driver and should not be altered.
|
@@ -42,8 +88,8 @@ module ArJdbc
|
|
42
88
|
# (SET TIME ZONE does not use an equals sign like other SET variables)
|
43
89
|
if ActiveRecord::Base.default_timezone == :utc
|
44
90
|
execute("SET time zone 'UTC'", 'SCHEMA')
|
45
|
-
elsif
|
46
|
-
execute("SET time zone '#{
|
91
|
+
elsif tz = local_tz
|
92
|
+
execute("SET time zone '#{tz}'", 'SCHEMA')
|
47
93
|
end # if defined? ActiveRecord::Base.default_timezone
|
48
94
|
|
49
95
|
# SET statements from :variables config hash
|
@@ -58,334 +104,9 @@ module ArJdbc
|
|
58
104
|
end
|
59
105
|
end
|
60
106
|
|
61
|
-
#
|
62
|
-
|
63
|
-
|
64
|
-
def adapter_name # :nodoc:
|
65
|
-
ADAPTER_NAME
|
66
|
-
end
|
67
|
-
|
68
|
-
def self.arel2_visitors(config)
|
69
|
-
{
|
70
|
-
'postgresql' => ::Arel::Visitors::PostgreSQL,
|
71
|
-
'jdbcpostgresql' => ::Arel::Visitors::PostgreSQL,
|
72
|
-
'pg' => ::Arel::Visitors::PostgreSQL
|
73
|
-
}
|
74
|
-
end
|
75
|
-
|
76
|
-
def new_visitor(config = nil)
|
77
|
-
visitor = ::Arel::Visitors::PostgreSQL
|
78
|
-
( prepared_statements? ? visitor : bind_substitution(visitor) ).new(self)
|
79
|
-
end if defined? ::Arel::Visitors::PostgreSQL
|
80
|
-
|
81
|
-
# @see #bind_substitution
|
82
|
-
class BindSubstitution < Arel::Visitors::PostgreSQL # :nodoc:
|
83
|
-
include Arel::Visitors::BindVisitor
|
84
|
-
end if defined? Arel::Visitors::BindVisitor
|
107
|
+
# @private
|
108
|
+
ActiveRecordError = ::ActiveRecord::ActiveRecordError
|
85
109
|
|
86
|
-
def postgresql_version
|
87
|
-
@postgresql_version ||=
|
88
|
-
begin
|
89
|
-
value = select_value('SELECT version()')
|
90
|
-
if value =~ /PostgreSQL (\d+)\.(\d+)\.(\d+)/
|
91
|
-
($1.to_i * 10000) + ($2.to_i * 100) + $3.to_i
|
92
|
-
else
|
93
|
-
0
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
def use_insert_returning?
|
99
|
-
if ( @use_insert_returning ||= nil ).nil?
|
100
|
-
@use_insert_returning = supports_insert_with_returning?
|
101
|
-
end
|
102
|
-
@use_insert_returning
|
103
|
-
end
|
104
|
-
|
105
|
-
# column behavior based on postgresql_adapter in rails
|
106
|
-
module Column
|
107
|
-
|
108
|
-
def self.included(base)
|
109
|
-
class << base
|
110
|
-
include ArJdbc::PostgreSQL::Column::Cast
|
111
|
-
# include ArJdbc::PostgreSQL::Column::ArrayParser
|
112
|
-
attr_accessor :money_precision
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
attr_accessor :array
|
117
|
-
def array?; array; end # in case we remove the array reader
|
118
|
-
|
119
|
-
# Extracts the value from a PostgreSQL column default definition.
|
120
|
-
#
|
121
|
-
# @override JdbcColumn#default_value
|
122
|
-
# NOTE: based on `self.extract_value_from_default(default)` code
|
123
|
-
def default_value(default)
|
124
|
-
# This is a performance optimization for Ruby 1.9.2 in development.
|
125
|
-
# If the value is nil, we return nil straight away without checking
|
126
|
-
# the regular expressions. If we check each regular expression,
|
127
|
-
# Regexp#=== will call NilClass#to_str, which will trigger
|
128
|
-
# method_missing (defined by whiny nil in ActiveSupport) which
|
129
|
-
# makes this method very very slow.
|
130
|
-
return default unless default
|
131
|
-
|
132
|
-
case default
|
133
|
-
when /\A'(.*)'::(num|date|tstz|ts|int4|int8)range\z/m
|
134
|
-
$1
|
135
|
-
# Numeric types
|
136
|
-
when /\A\(?(-?\d+(\.\d*)?\)?)\z/
|
137
|
-
$1
|
138
|
-
# Character types
|
139
|
-
when /\A\(?'(.*)'::.*\b(?:character varying|bpchar|text)\z/m
|
140
|
-
$1
|
141
|
-
# Binary data types
|
142
|
-
when /\A'(.*)'::bytea\z/m
|
143
|
-
$1
|
144
|
-
# Date/time types
|
145
|
-
when /\A'(.+)'::(?:time(?:stamp)? with(?:out)? time zone|date)\z/
|
146
|
-
$1
|
147
|
-
when /\A'(.*)'::interval\z/
|
148
|
-
$1
|
149
|
-
# Boolean type
|
150
|
-
when 'true'
|
151
|
-
true
|
152
|
-
when 'false'
|
153
|
-
false
|
154
|
-
# Geometric types
|
155
|
-
when /\A'(.*)'::(?:point|line|lseg|box|"?path"?|polygon|circle)\z/
|
156
|
-
$1
|
157
|
-
# Network address types
|
158
|
-
when /\A'(.*)'::(?:cidr|inet|macaddr)\z/
|
159
|
-
$1
|
160
|
-
# Bit string types
|
161
|
-
when /\AB'(.*)'::"?bit(?: varying)?"?\z/
|
162
|
-
$1
|
163
|
-
# XML type
|
164
|
-
when /\A'(.*)'::xml\z/m
|
165
|
-
$1
|
166
|
-
# Arrays
|
167
|
-
when /\A'(.*)'::"?\D+"?\[\]\z/
|
168
|
-
$1
|
169
|
-
# Hstore
|
170
|
-
when /\A'(.*)'::hstore\z/
|
171
|
-
$1
|
172
|
-
# JSON
|
173
|
-
when /\A'(.*)'::json\z/
|
174
|
-
$1
|
175
|
-
# Object identifier types
|
176
|
-
when /\A-?\d+\z/
|
177
|
-
$1
|
178
|
-
else
|
179
|
-
# Anything else is blank, some user type, or some function
|
180
|
-
# and we can't know the value of that, so return nil.
|
181
|
-
nil
|
182
|
-
end
|
183
|
-
end
|
184
|
-
|
185
|
-
# Casts value (which is a String) to an appropriate instance.
|
186
|
-
def type_cast(value)
|
187
|
-
return if value.nil?
|
188
|
-
return super if encoded? # respond_to?(:encoded?) only since AR-3.2
|
189
|
-
|
190
|
-
# NOTE: we do not use OID::Type
|
191
|
-
# @oid_type.type_cast value
|
192
|
-
|
193
|
-
return value if array? # handled on the connection (JDBC) side
|
194
|
-
|
195
|
-
case type
|
196
|
-
when :hstore then self.class.string_to_hstore value
|
197
|
-
when :json then self.class.string_to_json value
|
198
|
-
when :cidr, :inet then self.class.string_to_cidr value
|
199
|
-
when :macaddr then value
|
200
|
-
when :tsvector then value
|
201
|
-
when :datetime, :timestamp then self.class.string_to_time value
|
202
|
-
else
|
203
|
-
case sql_type
|
204
|
-
when 'money'
|
205
|
-
# Because money output is formatted according to the locale, there
|
206
|
-
# are two cases to consider (note the decimal separators) :
|
207
|
-
# (1) $12,345,678.12
|
208
|
-
# (2) $12.345.678,12
|
209
|
-
case value
|
210
|
-
when /^-?\D+[\d,]+\.\d{2}$/ # (1)
|
211
|
-
value.gsub!(/[^-\d.]/, '')
|
212
|
-
when /^-?\D+[\d.]+,\d{2}$/ # (2)
|
213
|
-
value.gsub!(/[^-\d,]/, '')
|
214
|
-
value.sub!(/,/, '.')
|
215
|
-
end
|
216
|
-
self.class.value_to_decimal value
|
217
|
-
when /^point/
|
218
|
-
if value.is_a?(String)
|
219
|
-
self.class.string_to_point value
|
220
|
-
else
|
221
|
-
value
|
222
|
-
end
|
223
|
-
when /(.*?)range$/
|
224
|
-
return if value.nil? || value == 'empty'
|
225
|
-
return value if value.is_a?(::Range)
|
226
|
-
|
227
|
-
extracted = extract_bounds(value)
|
228
|
-
|
229
|
-
case $1 # subtype
|
230
|
-
when 'date' # :date
|
231
|
-
from = self.class.value_to_date(extracted[:from])
|
232
|
-
from -= 1.day if extracted[:exclude_start]
|
233
|
-
to = self.class.value_to_date(extracted[:to])
|
234
|
-
when 'num' # :decimal
|
235
|
-
from = BigDecimal.new(extracted[:from].to_s)
|
236
|
-
# FIXME: add exclude start for ::Range, same for timestamp ranges
|
237
|
-
to = BigDecimal.new(extracted[:to].to_s)
|
238
|
-
when 'ts', 'tstz' # :time
|
239
|
-
from = self.class.string_to_time(extracted[:from])
|
240
|
-
to = self.class.string_to_time(extracted[:to])
|
241
|
-
when 'int4', 'int8' # :integer
|
242
|
-
from = to_integer(extracted[:from]) rescue value ? 1 : 0
|
243
|
-
from -= 1 if extracted[:exclude_start]
|
244
|
-
to = to_integer(extracted[:to]) rescue value ? 1 : 0
|
245
|
-
else
|
246
|
-
return value
|
247
|
-
end
|
248
|
-
|
249
|
-
::Range.new(from, to, extracted[:exclude_end])
|
250
|
-
else super
|
251
|
-
end
|
252
|
-
end
|
253
|
-
end if AR4_COMPAT
|
254
|
-
|
255
|
-
private
|
256
|
-
|
257
|
-
def extract_limit(sql_type)
|
258
|
-
case sql_type
|
259
|
-
when /^bigint/i; 8
|
260
|
-
when /^smallint/i; 2
|
261
|
-
when /^timestamp/i; nil
|
262
|
-
else super
|
263
|
-
end
|
264
|
-
end
|
265
|
-
|
266
|
-
# Extracts the scale from PostgreSQL-specific data types.
|
267
|
-
def extract_scale(sql_type)
|
268
|
-
# Money type has a fixed scale of 2.
|
269
|
-
sql_type =~ /^money/ ? 2 : super
|
270
|
-
end
|
271
|
-
|
272
|
-
# Extracts the precision from PostgreSQL-specific data types.
|
273
|
-
def extract_precision(sql_type)
|
274
|
-
if sql_type == 'money'
|
275
|
-
self.class.money_precision
|
276
|
-
elsif sql_type =~ /timestamp/i
|
277
|
-
$1.to_i if sql_type =~ /\((\d+)\)/
|
278
|
-
else
|
279
|
-
super
|
280
|
-
end
|
281
|
-
end
|
282
|
-
|
283
|
-
# Maps PostgreSQL-specific data types to logical Rails types.
|
284
|
-
def simplified_type(field_type)
|
285
|
-
case field_type
|
286
|
-
# Numeric and monetary types
|
287
|
-
when /^(?:real|double precision)$/ then :float
|
288
|
-
# Monetary types
|
289
|
-
when 'money' then :decimal
|
290
|
-
# Character types
|
291
|
-
when /^(?:character varying|bpchar)(?:\(\d+\))?$/ then :string
|
292
|
-
# Binary data types
|
293
|
-
when 'bytea' then :binary
|
294
|
-
# Date/time types
|
295
|
-
when /^timestamp with(?:out)? time zone$/ then :datetime
|
296
|
-
when 'interval' then :string
|
297
|
-
# Geometric types
|
298
|
-
when /^(?:point|line|lseg|box|"?path"?|polygon|circle)$/ then :string
|
299
|
-
# Network address types
|
300
|
-
when /^(?:cidr|inet|macaddr)$/ then :string
|
301
|
-
# Bit strings
|
302
|
-
when /^bit(?: varying)?(?:\(\d+\))?$/ then :string
|
303
|
-
# XML type
|
304
|
-
when 'xml' then :xml
|
305
|
-
# tsvector type
|
306
|
-
when 'tsvector' then :tsvector
|
307
|
-
# Arrays
|
308
|
-
when /^\D+\[\]$/ then :string
|
309
|
-
# Object identifier types
|
310
|
-
when 'oid' then :integer
|
311
|
-
# UUID type
|
312
|
-
when 'uuid' then :string
|
313
|
-
# Small and big integer types
|
314
|
-
when /^(?:small|big)int$/ then :integer
|
315
|
-
# Pass through all types that are not specific to PostgreSQL.
|
316
|
-
else
|
317
|
-
super
|
318
|
-
end
|
319
|
-
end
|
320
|
-
|
321
|
-
def simplified_type(field_type) # :nodoc:
|
322
|
-
case field_type
|
323
|
-
# Numeric and monetary types
|
324
|
-
when /^(?:real|double precision)$/ then :float
|
325
|
-
# Monetary types
|
326
|
-
when 'money' then :decimal
|
327
|
-
when 'hstore' then :hstore
|
328
|
-
when 'ltree' then :ltree
|
329
|
-
# Network address types
|
330
|
-
when 'inet' then :inet
|
331
|
-
when 'cidr' then :cidr
|
332
|
-
when 'macaddr' then :macaddr
|
333
|
-
# Character types
|
334
|
-
when /^(?:character varying|bpchar)(?:\(\d+\))?$/ then :string
|
335
|
-
# Binary data types
|
336
|
-
when 'bytea' then :binary
|
337
|
-
# Date/time types
|
338
|
-
when /^timestamp with(?:out)? time zone$/ then :datetime
|
339
|
-
when /^interval(?:|\(\d+\))$/ then :string
|
340
|
-
# Geometric types
|
341
|
-
when /^(?:point|line|lseg|box|"?path"?|polygon|circle)$/ then :string
|
342
|
-
# Bit strings
|
343
|
-
when /^bit(?: varying)?(?:\(\d+\))?$/ then :string
|
344
|
-
# XML type
|
345
|
-
when 'xml' then :xml
|
346
|
-
# tsvector type
|
347
|
-
when 'tsvector' then :tsvector
|
348
|
-
# Arrays
|
349
|
-
when /^\D+\[\]$/ then :string
|
350
|
-
# Object identifier types
|
351
|
-
when 'oid' then :integer
|
352
|
-
# UUID type
|
353
|
-
when 'uuid' then :uuid
|
354
|
-
# JSON type
|
355
|
-
when 'json' then :json
|
356
|
-
# Small and big integer types
|
357
|
-
when /^(?:small|big)int$/ then :integer
|
358
|
-
when /(num|date|tstz|ts|int4|int8)range$/
|
359
|
-
field_type.to_sym
|
360
|
-
# Pass through all types that are not specific to PostgreSQL.
|
361
|
-
else
|
362
|
-
super
|
363
|
-
end
|
364
|
-
end if AR4_COMPAT
|
365
|
-
|
366
|
-
# OID Type::Range helpers :
|
367
|
-
|
368
|
-
def extract_bounds(value)
|
369
|
-
f, t = value[1..-2].split(',')
|
370
|
-
{
|
371
|
-
:from => (value[1] == ',' || f == '-infinity') ? infinity(:negative => true) : f,
|
372
|
-
:to => (value[-2] == ',' || t == 'infinity') ? infinity : t,
|
373
|
-
:exclude_start => (value[0] == '('), :exclude_end => (value[-1] == ')')
|
374
|
-
}
|
375
|
-
end if AR4_COMPAT
|
376
|
-
|
377
|
-
def infinity(options = {})
|
378
|
-
::Float::INFINITY * (options[:negative] ? -1 : 1)
|
379
|
-
end if AR4_COMPAT
|
380
|
-
|
381
|
-
def to_integer(value)
|
382
|
-
(value.respond_to?(:infinite?) && value.infinite?) ? value : value.to_i
|
383
|
-
end if AR4_COMPAT
|
384
|
-
|
385
|
-
end # Column
|
386
|
-
|
387
|
-
ActiveRecordError = ::ActiveRecord::ActiveRecordError # :nodoc:
|
388
|
-
|
389
110
|
# Maps logical Rails types to PostgreSQL-specific data types.
|
390
111
|
def type_to_sql(type, limit = nil, precision = nil, scale = nil)
|
391
112
|
case type.to_sym
|
@@ -432,9 +153,15 @@ module ArJdbc
|
|
432
153
|
return super(value, column) unless 'bytea' == column.sql_type
|
433
154
|
value # { :value => value, :format => 1 }
|
434
155
|
when Array
|
435
|
-
|
436
|
-
|
437
|
-
|
156
|
+
case column.sql_type
|
157
|
+
when 'point'
|
158
|
+
column_class = ::ActiveRecord::ConnectionAdapters::PostgreSQLColumn
|
159
|
+
column_class.point_to_string(value)
|
160
|
+
else
|
161
|
+
return super(value, column) unless column.array?
|
162
|
+
column_class = ::ActiveRecord::ConnectionAdapters::PostgreSQLColumn
|
163
|
+
column_class.array_to_string(value, column, self)
|
164
|
+
end
|
438
165
|
when NilClass
|
439
166
|
if column.array? && array_member
|
440
167
|
'NULL'
|
@@ -457,18 +184,23 @@ module ArJdbc
|
|
457
184
|
return super unless column.sql_type == 'inet' || column.sql_type == 'cidr'
|
458
185
|
column_class = ::ActiveRecord::ConnectionAdapters::PostgreSQLColumn
|
459
186
|
column_class.cidr_to_string(value)
|
187
|
+
when Range
|
188
|
+
return super(value, column) unless /range$/ =~ column.sql_type
|
189
|
+
column_class = ::ActiveRecord::ConnectionAdapters::PostgreSQLColumn
|
190
|
+
column_class.range_to_string(value)
|
460
191
|
else
|
461
192
|
super(value, column)
|
462
193
|
end
|
463
194
|
end if AR4_COMPAT
|
464
|
-
|
195
|
+
|
465
196
|
NATIVE_DATABASE_TYPES = {
|
466
197
|
:primary_key => "serial primary key",
|
467
198
|
:string => { :name => "character varying", :limit => 255 },
|
468
199
|
:text => { :name => "text" },
|
469
200
|
:integer => { :name => "integer" },
|
470
201
|
:float => { :name => "float" },
|
471
|
-
:
|
202
|
+
:numeric => { :name => "numeric" },
|
203
|
+
:decimal => { :name => "decimal" }, # :limit => 1000
|
472
204
|
:datetime => { :name => "timestamp" },
|
473
205
|
:timestamp => { :name => "timestamp" },
|
474
206
|
:time => { :name => "time" },
|
@@ -476,8 +208,14 @@ module ArJdbc
|
|
476
208
|
:binary => { :name => "bytea" },
|
477
209
|
:boolean => { :name => "boolean" },
|
478
210
|
:xml => { :name => "xml" },
|
211
|
+
# AR-JDBC added :
|
212
|
+
#:timestamptz => { :name => "timestamptz" },
|
213
|
+
#:timetz => { :name => "timetz" },
|
214
|
+
:money => { :name=>"money" },
|
215
|
+
:char => { :name => "char" },
|
216
|
+
:serial => { :name => "serial" }, # auto-inc integer, bigserial, smallserial
|
479
217
|
}
|
480
|
-
|
218
|
+
|
481
219
|
NATIVE_DATABASE_TYPES.update({
|
482
220
|
:tsvector => { :name => "tsvector" },
|
483
221
|
:hstore => { :name => "hstore" },
|
@@ -495,41 +233,35 @@ module ArJdbc
|
|
495
233
|
:int4range => { :name => "int4range" },
|
496
234
|
:int8range => { :name => "int8range" },
|
497
235
|
}) if AR4_COMPAT
|
498
|
-
|
236
|
+
|
499
237
|
def native_database_types
|
500
238
|
NATIVE_DATABASE_TYPES
|
501
239
|
end
|
502
|
-
|
503
|
-
# Adds `:array` option to the default set provided by the AbstractAdapter
|
240
|
+
|
241
|
+
# Adds `:array` option to the default set provided by the `AbstractAdapter`.
|
504
242
|
def prepare_column_options(column, types)
|
505
243
|
spec = super
|
506
244
|
spec[:array] = 'true' if column.respond_to?(:array) && column.array
|
507
245
|
spec
|
508
246
|
end if AR4_COMPAT
|
509
247
|
|
510
|
-
# Adds `:array` as a valid migration key
|
248
|
+
# Adds `:array` as a valid migration key.
|
511
249
|
def migration_keys
|
512
250
|
super + [:array]
|
513
251
|
end if AR4_COMPAT
|
514
|
-
|
515
|
-
def add_column_options!(sql, options)
|
516
|
-
if options[:array] || options[:column].try(:array)
|
517
|
-
sql << '[]'
|
518
|
-
end
|
519
252
|
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
253
|
+
if ActiveRecord::VERSION::MAJOR > 3
|
254
|
+
|
255
|
+
require 'arjdbc/postgresql/schema_creation'
|
256
|
+
def schema_creation; SchemaCreation.new(self); end
|
257
|
+
|
258
|
+
end
|
259
|
+
|
528
260
|
# Enable standard-conforming strings if available.
|
529
|
-
def set_standard_conforming_strings
|
261
|
+
def set_standard_conforming_strings
|
530
262
|
self.standard_conforming_strings=(true)
|
531
263
|
end
|
532
|
-
|
264
|
+
|
533
265
|
# Enable standard-conforming strings if available.
|
534
266
|
def standard_conforming_strings=(enable)
|
535
267
|
client_min_messages = self.client_min_messages
|
@@ -545,7 +277,7 @@ module ArJdbc
|
|
545
277
|
end
|
546
278
|
end
|
547
279
|
|
548
|
-
def standard_conforming_strings?
|
280
|
+
def standard_conforming_strings?
|
549
281
|
if @standard_conforming_strings.nil?
|
550
282
|
client_min_messages = self.client_min_messages
|
551
283
|
begin
|
@@ -562,38 +294,38 @@ module ArJdbc
|
|
562
294
|
end
|
563
295
|
|
564
296
|
# Does PostgreSQL support migrations?
|
565
|
-
def supports_migrations?
|
297
|
+
def supports_migrations?
|
566
298
|
true
|
567
299
|
end
|
568
300
|
|
569
301
|
# Does PostgreSQL support finding primary key on non-Active Record tables?
|
570
|
-
def supports_primary_key?
|
302
|
+
def supports_primary_key?
|
571
303
|
true
|
572
304
|
end
|
573
|
-
|
305
|
+
|
574
306
|
# Does PostgreSQL support standard conforming strings?
|
575
|
-
def supports_standard_conforming_strings?
|
307
|
+
def supports_standard_conforming_strings?
|
576
308
|
standard_conforming_strings?
|
577
309
|
@standard_conforming_strings != :unsupported
|
578
310
|
end
|
579
311
|
|
580
|
-
def supports_hex_escaped_bytea?
|
312
|
+
def supports_hex_escaped_bytea?
|
581
313
|
postgresql_version >= 90000
|
582
314
|
end
|
583
315
|
|
584
|
-
def supports_insert_with_returning?
|
316
|
+
def supports_insert_with_returning?
|
585
317
|
postgresql_version >= 80200
|
586
318
|
end
|
587
319
|
|
588
|
-
def supports_ddl_transactions?
|
320
|
+
def supports_ddl_transactions?
|
589
321
|
true
|
590
322
|
end
|
591
323
|
|
592
|
-
def supports_transaction_isolation?
|
324
|
+
def supports_transaction_isolation?
|
593
325
|
true
|
594
326
|
end
|
595
|
-
|
596
|
-
def supports_index_sort_order?
|
327
|
+
|
328
|
+
def supports_index_sort_order?
|
597
329
|
true
|
598
330
|
end
|
599
331
|
|
@@ -601,39 +333,41 @@ module ArJdbc
|
|
601
333
|
true
|
602
334
|
end if AR4_COMPAT
|
603
335
|
|
604
|
-
# Range
|
605
|
-
def supports_ranges?
|
336
|
+
# Range data-types weren't introduced until PostgreSQL 9.2.
|
337
|
+
def supports_ranges?
|
606
338
|
postgresql_version >= 90200
|
607
339
|
end if AR4_COMPAT
|
608
|
-
|
609
|
-
def supports_savepoints? # :nodoc:
|
610
|
-
true
|
611
|
-
end
|
612
|
-
|
340
|
+
|
613
341
|
def supports_transaction_isolation?(level = nil)
|
614
342
|
true
|
615
343
|
end
|
616
344
|
|
617
|
-
|
618
|
-
|
345
|
+
# NOTE: handled by JdbcAdapter we override only to have save-point in logs :
|
346
|
+
|
347
|
+
# @override
|
348
|
+
def supports_savepoints?
|
349
|
+
true
|
619
350
|
end
|
620
351
|
|
621
|
-
|
622
|
-
|
352
|
+
# @override
|
353
|
+
def create_savepoint(name = current_savepoint_name(true))
|
354
|
+
log("SAVEPOINT #{name}", 'Savepoint') { super }
|
623
355
|
end
|
624
356
|
|
625
|
-
|
626
|
-
|
357
|
+
# @override
|
358
|
+
def rollback_to_savepoint(name = current_savepoint_name)
|
359
|
+
log("ROLLBACK TO SAVEPOINT #{name}", 'Savepoint') { super }
|
627
360
|
end
|
628
361
|
|
629
|
-
|
630
|
-
|
362
|
+
# @override
|
363
|
+
def release_savepoint(name = current_savepoint_name)
|
364
|
+
log("RELEASE SAVEPOINT #{name}", 'Savepoint') { super }
|
631
365
|
end
|
632
|
-
|
633
|
-
def supports_extensions?
|
366
|
+
|
367
|
+
def supports_extensions?
|
634
368
|
postgresql_version >= 90200
|
635
369
|
end # NOTE: only since AR-4.0 but should not hurt on other versions
|
636
|
-
|
370
|
+
|
637
371
|
def enable_extension(name)
|
638
372
|
execute("CREATE EXTENSION IF NOT EXISTS \"#{name}\"")
|
639
373
|
end
|
@@ -657,18 +391,22 @@ module ArJdbc
|
|
657
391
|
[]
|
658
392
|
end
|
659
393
|
end
|
660
|
-
|
661
|
-
|
394
|
+
|
395
|
+
def index_algorithms
|
396
|
+
{ :concurrently => 'CONCURRENTLY' }
|
397
|
+
end
|
398
|
+
|
399
|
+
# Set the authorized user for this session.
|
662
400
|
def session_auth=(user)
|
663
401
|
execute "SET SESSION AUTHORIZATION #{user}"
|
664
402
|
end
|
665
|
-
|
403
|
+
|
666
404
|
# Returns the configured supported identifier length supported by PostgreSQL,
|
667
405
|
# or report the default of 63 on PostgreSQL 7.x.
|
668
406
|
def table_alias_length
|
669
407
|
@table_alias_length ||= (
|
670
|
-
postgresql_version >= 80000 ?
|
671
|
-
select_one('SHOW max_identifier_length')['max_identifier_length'].to_i :
|
408
|
+
postgresql_version >= 80000 ?
|
409
|
+
select_one('SHOW max_identifier_length')['max_identifier_length'].to_i :
|
672
410
|
63
|
673
411
|
)
|
674
412
|
end
|
@@ -678,8 +416,8 @@ module ArJdbc
|
|
678
416
|
default_seq || "#{table_name}_#{pk || default_pk || 'id'}_seq"
|
679
417
|
end
|
680
418
|
|
681
|
-
# Resets sequence to the max value of the table's
|
682
|
-
def reset_pk_sequence!(table, pk = nil, sequence = nil)
|
419
|
+
# Resets sequence to the max value of the table's primary key if present.
|
420
|
+
def reset_pk_sequence!(table, pk = nil, sequence = nil)
|
683
421
|
if ! pk || ! sequence
|
684
422
|
default_pk, default_sequence = pk_and_sequence_for(table)
|
685
423
|
pk ||= default_pk; sequence ||= default_sequence
|
@@ -694,15 +432,13 @@ module ArJdbc
|
|
694
432
|
end
|
695
433
|
|
696
434
|
# Find a table's primary key and sequence.
|
697
|
-
def pk_and_sequence_for(table)
|
698
|
-
#
|
699
|
-
# given table's primary key.
|
435
|
+
def pk_and_sequence_for(table)
|
436
|
+
# try looking for a seq with a dependency on the table's primary key :
|
700
437
|
result = select(<<-end_sql, 'PK and Serial Sequence')[0]
|
701
438
|
SELECT attr.attname, seq.relname
|
702
439
|
FROM pg_class seq,
|
703
440
|
pg_attribute attr,
|
704
441
|
pg_depend dep,
|
705
|
-
pg_namespace name,
|
706
442
|
pg_constraint cons
|
707
443
|
WHERE seq.oid = dep.objid
|
708
444
|
AND seq.relkind = 'S'
|
@@ -715,16 +451,15 @@ module ArJdbc
|
|
715
451
|
end_sql
|
716
452
|
|
717
453
|
if result.nil? || result.empty?
|
718
|
-
#
|
719
|
-
# Support the 7.x and 8.0 nextval('foo'::text) as well as
|
720
|
-
# the 8.1+ nextval('foo'::regclass).
|
454
|
+
# if that fails, try parsing the primary key's default value :
|
721
455
|
result = select(<<-end_sql, 'PK and Custom Sequence')[0]
|
722
456
|
SELECT attr.attname,
|
723
457
|
CASE
|
724
|
-
WHEN
|
725
|
-
|
726
|
-
|
727
|
-
|
458
|
+
WHEN pg_get_expr(def.adbin, def.adrelid) !~* 'nextval' THEN NULL
|
459
|
+
WHEN split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2) ~ '.' THEN
|
460
|
+
substr(split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2),
|
461
|
+
strpos(split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2), '.')+1)
|
462
|
+
ELSE split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2)
|
728
463
|
END as relname
|
729
464
|
FROM pg_class t
|
730
465
|
JOIN pg_attribute attr ON (t.oid = attrelid)
|
@@ -732,7 +467,7 @@ module ArJdbc
|
|
732
467
|
JOIN pg_constraint cons ON (conrelid = adrelid AND adnum = conkey[1])
|
733
468
|
WHERE t.oid = '#{quote_table_name(table)}'::regclass
|
734
469
|
AND cons.contype = 'p'
|
735
|
-
AND def.
|
470
|
+
AND pg_get_expr(def.adbin, def.adrelid) ~* 'nextval|uuid_generate'
|
736
471
|
end_sql
|
737
472
|
end
|
738
473
|
|
@@ -740,7 +475,21 @@ module ArJdbc
|
|
740
475
|
rescue
|
741
476
|
nil
|
742
477
|
end
|
743
|
-
|
478
|
+
|
479
|
+
def primary_key(table)
|
480
|
+
result = select(<<-end_sql, 'SCHEMA').first
|
481
|
+
SELECT attr.attname
|
482
|
+
FROM pg_attribute attr
|
483
|
+
INNER JOIN pg_constraint cons ON attr.attrelid = cons.conrelid AND attr.attnum = cons.conkey[1]
|
484
|
+
WHERE cons.contype = 'p'
|
485
|
+
AND cons.conrelid = '#{quote_table_name(table)}'::regclass
|
486
|
+
end_sql
|
487
|
+
|
488
|
+
result && result['attname']
|
489
|
+
# pk_and_sequence = pk_and_sequence_for(table)
|
490
|
+
# pk_and_sequence && pk_and_sequence.first
|
491
|
+
end
|
492
|
+
|
744
493
|
def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
|
745
494
|
unless pk
|
746
495
|
# Extract the table from the insert sql. Yuck.
|
@@ -767,52 +516,66 @@ module ArJdbc
|
|
767
516
|
id_value
|
768
517
|
end
|
769
518
|
end
|
770
|
-
|
771
|
-
#
|
519
|
+
|
520
|
+
# @override
|
772
521
|
def sql_for_insert(sql, pk, id_value, sequence_name, binds)
|
773
522
|
unless pk
|
523
|
+
# Extract the table from the insert sql. Yuck.
|
774
524
|
table_ref = extract_table_ref_from_insert_sql(sql)
|
775
525
|
pk = primary_key(table_ref) if table_ref
|
776
526
|
end
|
777
527
|
|
778
|
-
|
528
|
+
if pk && use_insert_returning?
|
529
|
+
sql = "#{sql} RETURNING #{quote_column_name(pk)}"
|
530
|
+
end
|
779
531
|
|
780
532
|
[ sql, binds ]
|
781
533
|
end
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
534
|
+
|
535
|
+
# @override due RETURNING clause
|
536
|
+
def exec_insert(sql, name, binds, pk = nil, sequence_name = nil)
|
537
|
+
# NOTE: 3.2 does not pass the PK on #insert (passed only into #sql_for_insert) :
|
538
|
+
# sql, binds = sql_for_insert(to_sql(arel, binds), pk, id_value, sequence_name, binds)
|
539
|
+
# 3.2 :
|
540
|
+
# value = exec_insert(sql, name, binds)
|
541
|
+
# 4.x :
|
542
|
+
# value = exec_insert(sql, name, binds, pk, sequence_name)
|
543
|
+
if use_insert_returning? && ( pk || (sql.is_a?(String) && sql =~ /RETURNING "?\S+"?$/) )
|
544
|
+
exec_query(sql, name, binds) # due RETURNING clause returns a result set
|
545
|
+
else
|
546
|
+
result = super
|
547
|
+
if pk
|
548
|
+
unless sequence_name
|
549
|
+
table_ref = extract_table_ref_from_insert_sql(sql)
|
550
|
+
sequence_name = default_sequence_name(table_ref, pk)
|
551
|
+
return result unless sequence_name
|
552
|
+
end
|
553
|
+
last_insert_id_result(sequence_name)
|
554
|
+
else
|
555
|
+
result
|
556
|
+
end
|
557
|
+
end
|
795
558
|
end
|
796
|
-
|
559
|
+
|
797
560
|
# Returns an array of schema names.
|
798
561
|
def schema_names
|
799
562
|
select_values(
|
800
563
|
"SELECT nspname FROM pg_namespace" <<
|
801
564
|
" WHERE nspname !~ '^pg_.*' AND nspname NOT IN ('information_schema')" <<
|
802
|
-
" ORDER by nspname;",
|
565
|
+
" ORDER by nspname;",
|
803
566
|
'SCHEMA')
|
804
567
|
end
|
805
|
-
|
568
|
+
|
806
569
|
# Returns true if schema exists.
|
807
570
|
def schema_exists?(name)
|
808
571
|
select_value("SELECT COUNT(*) FROM pg_namespace WHERE nspname = '#{name}'", 'SCHEMA').to_i > 0
|
809
572
|
end
|
810
|
-
|
573
|
+
|
811
574
|
# Returns the current schema name.
|
812
575
|
def current_schema
|
813
576
|
select_value('SELECT current_schema', 'SCHEMA')
|
814
577
|
end
|
815
|
-
|
578
|
+
|
816
579
|
# current database name
|
817
580
|
def current_database
|
818
581
|
select_value('SELECT current_database()', 'SCHEMA')
|
@@ -821,21 +584,21 @@ module ArJdbc
|
|
821
584
|
# Returns the current database encoding format.
|
822
585
|
def encoding
|
823
586
|
select_value(
|
824
|
-
"SELECT pg_encoding_to_char(pg_database.encoding)" <<
|
825
|
-
" FROM pg_database" <<
|
826
|
-
" WHERE pg_database.datname LIKE '#{current_database}'",
|
587
|
+
"SELECT pg_encoding_to_char(pg_database.encoding)" <<
|
588
|
+
" FROM pg_database" <<
|
589
|
+
" WHERE pg_database.datname LIKE '#{current_database}'",
|
827
590
|
'SCHEMA')
|
828
591
|
end
|
829
592
|
|
830
593
|
# Returns the current database collation.
|
831
594
|
def collation
|
832
595
|
select_value(
|
833
|
-
"SELECT pg_database.datcollate" <<
|
834
|
-
" FROM pg_database" <<
|
596
|
+
"SELECT pg_database.datcollate" <<
|
597
|
+
" FROM pg_database" <<
|
835
598
|
" WHERE pg_database.datname LIKE '#{current_database}'",
|
836
599
|
'SCHEMA')
|
837
600
|
end
|
838
|
-
|
601
|
+
|
839
602
|
# Returns the current database ctype.
|
840
603
|
def ctype
|
841
604
|
select_value(
|
@@ -847,7 +610,7 @@ module ArJdbc
|
|
847
610
|
def schema_search_path
|
848
611
|
@schema_search_path ||= select_value('SHOW search_path', 'SCHEMA')
|
849
612
|
end
|
850
|
-
|
613
|
+
|
851
614
|
# Sets the schema search path to a string of comma-separated schema names.
|
852
615
|
# Names beginning with $ have to be quoted (e.g. $user => '$user').
|
853
616
|
# See: http://www.postgresql.org/docs/current/static/ddl-schemas.html
|
@@ -860,25 +623,26 @@ module ArJdbc
|
|
860
623
|
end
|
861
624
|
end
|
862
625
|
|
863
|
-
#
|
626
|
+
# Take an id from the result of an INSERT query.
|
627
|
+
# @return [Integer, NilClass]
|
864
628
|
def last_inserted_id(result)
|
865
|
-
if result.
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
629
|
+
return nil if result.nil?
|
630
|
+
return result if result.is_a? Integer
|
631
|
+
# <ActiveRecord::Result @hash_rows=nil, @columns=["id"], @rows=[[3]]>
|
632
|
+
# but it will work with [{ 'id' => 1 }] Hash wrapped results as well
|
633
|
+
result.first.first[1] # .first = { "id"=>1 } .first = [ "id", 1 ]
|
870
634
|
end
|
871
635
|
|
872
636
|
def last_insert_id(table, sequence_name = nil)
|
873
637
|
sequence_name = table if sequence_name.nil? # AR-4.0 1 argument
|
874
638
|
Integer(select_value("SELECT currval('#{sequence_name}')", 'SQL'))
|
875
639
|
end
|
876
|
-
|
640
|
+
|
877
641
|
def recreate_database(name, options = {})
|
878
642
|
drop_database(name)
|
879
643
|
create_database(name, options)
|
880
644
|
end
|
881
|
-
|
645
|
+
|
882
646
|
# Create a new PostgreSQL database. Options include <tt>:owner</tt>, <tt>:template</tt>,
|
883
647
|
# <tt>:encoding</tt>, <tt>:collation</tt>, <tt>:ctype</tt>,
|
884
648
|
# <tt>:tablespace</tt>, and <tt>:connection_limit</tt> (note that MySQL uses
|
@@ -936,6 +700,7 @@ module ArJdbc
|
|
936
700
|
select('SELECT nspname FROM pg_namespace').map { |row| row["nspname"] }
|
937
701
|
end
|
938
702
|
|
703
|
+
# @deprecated no longer used - handled with (AR built-in) Rake tasks
|
939
704
|
def structure_dump
|
940
705
|
database = @config[:database]
|
941
706
|
if database.nil?
|
@@ -977,35 +742,42 @@ module ArJdbc
|
|
977
742
|
def multi_column_index_limit
|
978
743
|
defined?(@multi_column_index_limit) && @multi_column_index_limit || 32
|
979
744
|
end
|
980
|
-
|
745
|
+
|
981
746
|
# Sets the maximum number columns postgres has, default 32
|
982
747
|
def multi_column_index_limit=(limit)
|
983
748
|
@multi_column_index_limit = limit
|
984
749
|
end
|
985
|
-
|
986
|
-
# SELECT DISTINCT clause for a given set of columns and a given
|
750
|
+
|
751
|
+
# Returns a SELECT DISTINCT clause for a given set of columns and a given
|
752
|
+
# ORDER BY clause.
|
987
753
|
#
|
988
|
-
# PostgreSQL requires the ORDER BY columns in the select list for distinct
|
989
|
-
# requires that the ORDER BY include the distinct column.
|
754
|
+
# PostgreSQL requires the ORDER BY columns in the select list for distinct
|
755
|
+
# queries, and requires that the ORDER BY include the distinct column.
|
990
756
|
#
|
991
|
-
#
|
992
|
-
|
993
|
-
|
757
|
+
# distinct("posts.id", ["posts.created_at desc"])
|
758
|
+
# # => "DISTINCT posts.id, posts.created_at AS alias_0"
|
759
|
+
def distinct(columns, orders)
|
760
|
+
if orders.is_a?(String)
|
761
|
+
orders = orders.split(','); orders.each(&:strip!)
|
762
|
+
end
|
763
|
+
|
764
|
+
order_columns = orders.map do |column|
|
765
|
+
column = column.to_sql unless column.is_a?(String) # handle AREL node
|
766
|
+
column.gsub(/\s+(ASC|DESC)\s*(NULLS\s+(FIRST|LAST)\s*)?/i, '') # remove ASC/DESC
|
767
|
+
end.reject(&:blank?)
|
994
768
|
|
995
|
-
|
996
|
-
# any ASC/DESC modifiers
|
997
|
-
order_columns = orders.collect { |s| s.gsub(/\s+(ASC|DESC)\s*/i, '') }.
|
998
|
-
reject(&:blank?)
|
999
|
-
order_columns = order_columns.
|
1000
|
-
zip((0...order_columns.size).to_a).map { |s,i| "#{s} AS alias_#{i}" }
|
769
|
+
return "DISTINCT #{columns}" if order_columns.empty?
|
1001
770
|
|
1002
|
-
"
|
771
|
+
i = -1; order_columns.map! { |c| "#{c} AS alias_#{i += 1}" }
|
772
|
+
|
773
|
+
"DISTINCT #{columns}, #{order_columns.join(', ')}"
|
1003
774
|
end
|
1004
775
|
|
1005
776
|
# ORDER BY clause for the passed order option.
|
1006
777
|
#
|
1007
|
-
# PostgreSQL does not allow arbitrary ordering when using DISTINCT ON,
|
1008
|
-
# by wrapping the
|
778
|
+
# PostgreSQL does not allow arbitrary ordering when using DISTINCT ON,
|
779
|
+
# so we work around this by wrapping the SQL as a sub-select and ordering
|
780
|
+
# in that query.
|
1009
781
|
def add_order_by_for_association_limiting!(sql, options)
|
1010
782
|
return sql if options[:order].blank?
|
1011
783
|
|
@@ -1016,9 +788,11 @@ module ArJdbc
|
|
1016
788
|
sql.replace "SELECT * FROM (#{sql}) AS id_list ORDER BY #{order}"
|
1017
789
|
end
|
1018
790
|
|
1019
|
-
|
791
|
+
# @return [String]
|
792
|
+
# @override
|
793
|
+
def quote(value, column = nil)
|
1020
794
|
return super unless column
|
1021
|
-
|
795
|
+
|
1022
796
|
case value
|
1023
797
|
when Float
|
1024
798
|
if value.infinite? && ( column.type == :datetime || column.type == :timestamp )
|
@@ -1037,22 +811,13 @@ module ArJdbc
|
|
1037
811
|
return "E'#{escape_bytea(value)}'::bytea" if column.type == :binary
|
1038
812
|
return "xml '#{quote_string(value)}'" if column.type == :xml
|
1039
813
|
if column.respond_to?(:sql_type) && column.sql_type[0, 3] == 'bit'
|
1040
|
-
|
1041
|
-
# NOTE: as reported with #60 this is not quite "right" :
|
1042
|
-
# "0103" will be treated as hexadecimal string
|
1043
|
-
# "0102" will be treated as hexadecimal string
|
1044
|
-
# "0101" will be treated as binary string
|
1045
|
-
# "0100" will be treated as binary string
|
1046
|
-
# ... but is kept due Rails compatibility
|
1047
|
-
when /^[01]*$/ then "B'#{value}'" # Bit-string notation
|
1048
|
-
when /^[0-9A-F]*$/i then "X'#{value}'" # Hexadecimal notation
|
1049
|
-
end
|
814
|
+
quote_bit(value)
|
1050
815
|
else super
|
1051
816
|
end
|
1052
817
|
when Array
|
1053
818
|
if AR4_COMPAT && column.array? # will be always falsy in AR < 4.0
|
1054
819
|
column_class = ::ActiveRecord::ConnectionAdapters::PostgreSQLColumn
|
1055
|
-
"'#{column_class.array_to_string(value, column, self)}'"
|
820
|
+
"'#{column_class.array_to_string(value, column, self).gsub(/'/, "''")}'"
|
1056
821
|
else super
|
1057
822
|
end
|
1058
823
|
when Hash
|
@@ -1081,8 +846,9 @@ module ArJdbc
|
|
1081
846
|
end
|
1082
847
|
end
|
1083
848
|
|
1084
|
-
# Quotes a string, escaping any ' (single quote) and \ (backslash)
|
1085
|
-
#
|
849
|
+
# Quotes a string, escaping any ' (single quote) and \ (backslash) chars.
|
850
|
+
# @return [String]
|
851
|
+
# @override
|
1086
852
|
def quote_string(string)
|
1087
853
|
quoted = string.gsub("'", "''")
|
1088
854
|
unless standard_conforming_strings?
|
@@ -1091,6 +857,24 @@ module ArJdbc
|
|
1091
857
|
quoted
|
1092
858
|
end
|
1093
859
|
|
860
|
+
# @return [String]
|
861
|
+
def quote_bit(value)
|
862
|
+
case value
|
863
|
+
# NOTE: as reported with #60 this is not quite "right" :
|
864
|
+
# "0103" will be treated as hexadecimal string
|
865
|
+
# "0102" will be treated as hexadecimal string
|
866
|
+
# "0101" will be treated as binary string
|
867
|
+
# "0100" will be treated as binary string
|
868
|
+
# ... but is kept due Rails compatibility
|
869
|
+
when /^[01]*$/ then "B'#{value}'" # Bit-string notation
|
870
|
+
when /^[0-9A-F]*$/i then "X'#{value}'" # Hexadecimal notation
|
871
|
+
end
|
872
|
+
end
|
873
|
+
|
874
|
+
def quote_bit(value)
|
875
|
+
"B'#{value}'"
|
876
|
+
end if PostgreSQL::AR4_COMPAT
|
877
|
+
|
1094
878
|
def escape_bytea(string)
|
1095
879
|
if string
|
1096
880
|
if supports_hex_escaped_bytea?
|
@@ -1102,10 +886,11 @@ module ArJdbc
|
|
1102
886
|
end
|
1103
887
|
end
|
1104
888
|
end
|
1105
|
-
|
889
|
+
|
890
|
+
# @override
|
1106
891
|
def quote_table_name(name)
|
1107
892
|
schema, name_part = extract_pg_identifier_from_name(name.to_s)
|
1108
|
-
|
893
|
+
|
1109
894
|
unless name_part
|
1110
895
|
quote_column_name(schema)
|
1111
896
|
else
|
@@ -1114,30 +899,34 @@ module ArJdbc
|
|
1114
899
|
end
|
1115
900
|
end
|
1116
901
|
|
902
|
+
# @override
|
1117
903
|
def quote_table_name_for_assignment(table, attr)
|
1118
904
|
quote_column_name(attr)
|
1119
905
|
end if ::ActiveRecord::VERSION::MAJOR > 3
|
1120
906
|
|
907
|
+
# @override
|
1121
908
|
def quote_column_name(name)
|
1122
909
|
%("#{name.to_s.gsub("\"", "\"\"")}")
|
1123
910
|
end
|
1124
|
-
|
1125
|
-
# Quote date/time values for use in SQL input.
|
1126
|
-
# Includes microseconds if the value is a Time responding to usec
|
1127
|
-
|
911
|
+
|
912
|
+
# Quote date/time values for use in SQL input.
|
913
|
+
# Includes microseconds if the value is a Time responding to `usec`.
|
914
|
+
# @override
|
915
|
+
def quoted_date(value)
|
1128
916
|
result = super
|
1129
917
|
if value.acts_like?(:time) && value.respond_to?(:usec)
|
1130
|
-
"#{result}.#{sprintf("%06d", value.usec)}"
|
918
|
+
result = "#{result}.#{sprintf("%06d", value.usec)}"
|
1131
919
|
end
|
1132
920
|
result = "#{result.sub(/^-/, '')} BC" if value.year < 0
|
1133
921
|
result
|
1134
|
-
end
|
1135
|
-
|
1136
|
-
|
922
|
+
end if ::ActiveRecord::VERSION::MAJOR >= 3
|
923
|
+
|
924
|
+
# @override
|
925
|
+
def supports_disable_referential_integrity?
|
1137
926
|
true
|
1138
927
|
end
|
1139
928
|
|
1140
|
-
def disable_referential_integrity
|
929
|
+
def disable_referential_integrity
|
1141
930
|
if supports_disable_referential_integrity?
|
1142
931
|
begin
|
1143
932
|
execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} DISABLE TRIGGER ALL" }.join(";"))
|
@@ -1165,15 +954,18 @@ module ArJdbc
|
|
1165
954
|
end
|
1166
955
|
rename_table_indexes(table_name, new_name) if respond_to?(:rename_table_indexes) # AR-4.0 SchemaStatements
|
1167
956
|
end
|
1168
|
-
|
957
|
+
|
1169
958
|
# Adds a new column to the named table.
|
1170
959
|
# See TableDefinition#column for details of the options you can use.
|
1171
960
|
def add_column(table_name, column_name, type, options = {})
|
1172
961
|
default = options[:default]
|
1173
962
|
notnull = options[:null] == false
|
1174
963
|
|
964
|
+
sql_type = type_to_sql(type, options[:limit], options[:precision], options[:scale])
|
965
|
+
sql_type << "[]" if options[:array]
|
966
|
+
|
1175
967
|
# Add the column.
|
1176
|
-
execute("ALTER TABLE #{quote_table_name(table_name)} ADD COLUMN #{quote_column_name(column_name)} #{
|
968
|
+
execute("ALTER TABLE #{quote_table_name(table_name)} ADD COLUMN #{quote_column_name(column_name)} #{sql_type}")
|
1177
969
|
|
1178
970
|
change_column_default(table_name, column_name, default) if options_include_default?(options)
|
1179
971
|
change_column_null(table_name, column_name, false, default) if notnull
|
@@ -1183,8 +975,11 @@ module ArJdbc
|
|
1183
975
|
def change_column(table_name, column_name, type, options = {})
|
1184
976
|
quoted_table_name = quote_table_name(table_name)
|
1185
977
|
|
978
|
+
sql_type = type_to_sql(type, options[:limit], options[:precision], options[:scale])
|
979
|
+
sql_type << "[]" if options[:array]
|
980
|
+
|
1186
981
|
begin
|
1187
|
-
execute "ALTER TABLE #{quoted_table_name} ALTER COLUMN #{quote_column_name(column_name)} TYPE #{
|
982
|
+
execute "ALTER TABLE #{quoted_table_name} ALTER COLUMN #{quote_column_name(column_name)} TYPE #{sql_type}"
|
1188
983
|
rescue ActiveRecord::StatementInvalid => e
|
1189
984
|
raise e if postgresql_version > 80000
|
1190
985
|
# This is PostgreSQL 7.x, so we have to use a more arcane way of doing it.
|
@@ -1192,7 +987,7 @@ module ArJdbc
|
|
1192
987
|
begin_db_transaction
|
1193
988
|
tmp_column_name = "#{column_name}_ar_tmp"
|
1194
989
|
add_column(table_name, tmp_column_name, type, options)
|
1195
|
-
execute "UPDATE #{quoted_table_name} SET #{quote_column_name(tmp_column_name)} = CAST(#{quote_column_name(column_name)} AS #{
|
990
|
+
execute "UPDATE #{quoted_table_name} SET #{quote_column_name(tmp_column_name)} = CAST(#{quote_column_name(column_name)} AS #{sql_type})"
|
1196
991
|
remove_column(table_name, column_name)
|
1197
992
|
rename_column(table_name, tmp_column_name, column_name)
|
1198
993
|
commit_db_transaction
|
@@ -1217,17 +1012,17 @@ module ArJdbc
|
|
1217
1012
|
execute("ALTER TABLE #{quote_table_name(table_name)} ALTER #{quote_column_name(column_name)} #{null ? 'DROP' : 'SET'} NOT NULL")
|
1218
1013
|
end
|
1219
1014
|
|
1220
|
-
def rename_column(table_name, column_name, new_column_name)
|
1015
|
+
def rename_column(table_name, column_name, new_column_name)
|
1221
1016
|
execute "ALTER TABLE #{quote_table_name(table_name)} RENAME COLUMN #{quote_column_name(column_name)} TO #{quote_column_name(new_column_name)}"
|
1222
1017
|
rename_column_indexes(table_name, column_name, new_column_name) if respond_to?(:rename_column_indexes) # AR-4.0 SchemaStatements
|
1223
1018
|
end
|
1224
1019
|
|
1225
|
-
def add_index(table_name, column_name, options = {})
|
1020
|
+
def add_index(table_name, column_name, options = {})
|
1226
1021
|
index_name, index_type, index_columns, index_options, index_algorithm, index_using = add_index_options(table_name, column_name, options)
|
1227
1022
|
execute "CREATE #{index_type} INDEX #{index_algorithm} #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} #{index_using} (#{index_columns})#{index_options}"
|
1228
1023
|
end if AR4_COMPAT
|
1229
1024
|
|
1230
|
-
def remove_index!(table_name, index_name)
|
1025
|
+
def remove_index!(table_name, index_name)
|
1231
1026
|
execute "DROP INDEX #{quote_table_name(index_name)}"
|
1232
1027
|
end
|
1233
1028
|
|
@@ -1254,7 +1049,7 @@ module ArJdbc
|
|
1254
1049
|
klass.new(name, default, oid, type, ! notnull)
|
1255
1050
|
end
|
1256
1051
|
end
|
1257
|
-
|
1052
|
+
|
1258
1053
|
# Returns the list of a table's column names, data types, and default values.
|
1259
1054
|
#
|
1260
1055
|
# If the table name is not prefixed with a schema, the database will
|
@@ -1263,7 +1058,7 @@ module ArJdbc
|
|
1263
1058
|
# Query implementation notes:
|
1264
1059
|
# - format_type includes the column size constraint, e.g. varchar(50)
|
1265
1060
|
# - ::regclass is a function that gives the id for a table name
|
1266
|
-
def column_definitions(table_name)
|
1061
|
+
def column_definitions(table_name)
|
1267
1062
|
select_rows(<<-end_sql, 'SCHEMA')
|
1268
1063
|
SELECT a.attname, format_type(a.atttypid, a.atttypmod),
|
1269
1064
|
pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod
|
@@ -1275,7 +1070,7 @@ module ArJdbc
|
|
1275
1070
|
end_sql
|
1276
1071
|
end
|
1277
1072
|
private :column_definitions
|
1278
|
-
|
1073
|
+
|
1279
1074
|
def tables(name = nil)
|
1280
1075
|
select_values(<<-SQL, 'SCHEMA')
|
1281
1076
|
SELECT tablename
|
@@ -1290,7 +1085,7 @@ module ArJdbc
|
|
1290
1085
|
|
1291
1086
|
binds = [[ nil, table.gsub(/(^"|"$)/,'') ]]
|
1292
1087
|
binds << [ nil, schema ] if schema
|
1293
|
-
|
1088
|
+
|
1294
1089
|
exec_query_raw(<<-SQL, 'SCHEMA', binds).first["table_count"] > 0
|
1295
1090
|
SELECT COUNT(*) as table_count
|
1296
1091
|
FROM pg_tables
|
@@ -1298,9 +1093,10 @@ module ArJdbc
|
|
1298
1093
|
AND schemaname = #{schema ? "?" : "ANY (current_schemas(false))"}
|
1299
1094
|
SQL
|
1300
1095
|
end
|
1301
|
-
|
1302
|
-
|
1303
|
-
|
1096
|
+
|
1097
|
+
# @private
|
1098
|
+
IndexDefinition = ::ActiveRecord::ConnectionAdapters::IndexDefinition
|
1099
|
+
if ActiveRecord::VERSION::MAJOR < 3 ||
|
1304
1100
|
( ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR <= 1 )
|
1305
1101
|
# NOTE: make sure we accept 6 arguments (>= 3.2) as well as 5 (<= 3.1) :
|
1306
1102
|
# allow 6 on 3.1 : Struct.new(:table, :name, :unique, :columns, :lengths)
|
@@ -1310,7 +1106,7 @@ module ArJdbc
|
|
1310
1106
|
end
|
1311
1107
|
end
|
1312
1108
|
end
|
1313
|
-
|
1109
|
+
|
1314
1110
|
# Returns an array of indexes for the given table.
|
1315
1111
|
def indexes(table_name, name = nil)
|
1316
1112
|
# NOTE: maybe it's better to leave things of to the JDBC API ?!
|
@@ -1325,7 +1121,7 @@ module ArJdbc
|
|
1325
1121
|
AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname = ANY (current_schemas(false)) )
|
1326
1122
|
ORDER BY i.relname
|
1327
1123
|
SQL
|
1328
|
-
|
1124
|
+
|
1329
1125
|
result.map! do |row|
|
1330
1126
|
index_name = row[0]
|
1331
1127
|
unique = row[1].is_a?(String) ? row[1] == 't' : row[1] # JDBC gets us a boolean
|
@@ -1363,13 +1159,8 @@ module ArJdbc
|
|
1363
1159
|
result
|
1364
1160
|
end
|
1365
1161
|
|
1366
|
-
# #override due RETURNING clause - can't do an {#execute_insert}
|
1367
|
-
def exec_insert(sql, name, binds, pk = nil, sequence_name = nil) # :nodoc:
|
1368
|
-
execute(sql, name, binds)
|
1369
|
-
end
|
1370
|
-
|
1371
1162
|
private
|
1372
|
-
|
1163
|
+
|
1373
1164
|
def translate_exception(exception, message)
|
1374
1165
|
case exception.message
|
1375
1166
|
when /duplicate key value violates unique constraint/
|
@@ -1380,7 +1171,7 @@ module ArJdbc
|
|
1380
1171
|
super
|
1381
1172
|
end
|
1382
1173
|
end
|
1383
|
-
|
1174
|
+
|
1384
1175
|
# Extracts the table and schema name from +name+
|
1385
1176
|
def extract_schema_and_table(name)
|
1386
1177
|
schema, table = name.split('.', 2)
|
@@ -1407,34 +1198,27 @@ module ArJdbc
|
|
1407
1198
|
end
|
1408
1199
|
end
|
1409
1200
|
|
1410
|
-
|
1411
|
-
def extract_table_ref_from_insert_sql(sql) # :nodoc:
|
1201
|
+
def extract_table_ref_from_insert_sql(sql)
|
1412
1202
|
sql[/into\s+([^\(]*).*values\s*\(/i]
|
1413
1203
|
$1.strip if $1
|
1414
|
-
# sql.split(" ", 4)[2].gsub('"', '')
|
1415
1204
|
end
|
1416
|
-
|
1205
|
+
|
1206
|
+
def local_tz
|
1207
|
+
@local_tz ||= execute('SHOW TIME ZONE', 'SCHEMA').first["TimeZone"]
|
1208
|
+
end
|
1209
|
+
|
1417
1210
|
end
|
1418
1211
|
end
|
1419
1212
|
|
1213
|
+
require 'arjdbc/util/quoted_cache'
|
1214
|
+
|
1420
1215
|
module ActiveRecord::ConnectionAdapters
|
1421
|
-
|
1422
|
-
PostgreSQLJdbcConnection.class_eval do
|
1423
|
-
|
1424
|
-
# alias :java_native_database_types :set_native_database_types
|
1425
|
-
|
1426
|
-
# @override to prevent connection from loading hash from JDBC meta-data,
|
1427
|
-
# which can be expensive. We can do this since {#native_database_types} is
|
1428
|
-
# defined in the adapter to use a hash not relying on driver's meta-data
|
1429
|
-
def set_native_database_types; @native_types = {}; end
|
1430
|
-
|
1431
|
-
end
|
1432
|
-
|
1216
|
+
|
1433
1217
|
remove_const(:PostgreSQLColumn) if const_defined?(:PostgreSQLColumn)
|
1434
1218
|
|
1435
1219
|
class PostgreSQLColumn < JdbcColumn
|
1436
|
-
include ArJdbc::PostgreSQL::Column
|
1437
|
-
|
1220
|
+
include ::ArJdbc::PostgreSQL::Column
|
1221
|
+
|
1438
1222
|
def initialize(name, default, oid_type = nil, sql_type = nil, null = true)
|
1439
1223
|
# NOTE: we support AR <= 3.2 : (name, default, sql_type = nil, null = true)
|
1440
1224
|
null, sql_type, oid_type = !! sql_type, oid_type, nil unless oid_type.is_a?(Integer)
|
@@ -1447,26 +1231,25 @@ module ActiveRecord::ConnectionAdapters
|
|
1447
1231
|
super(name, default, sql_type, null)
|
1448
1232
|
end
|
1449
1233
|
end
|
1450
|
-
|
1234
|
+
|
1451
1235
|
end
|
1452
1236
|
|
1453
1237
|
remove_const(:PostgreSQLAdapter) if const_defined?(:PostgreSQLAdapter)
|
1454
|
-
|
1238
|
+
|
1455
1239
|
class PostgreSQLAdapter < JdbcAdapter
|
1456
|
-
include ArJdbc::PostgreSQL
|
1457
|
-
include ArJdbc::PostgreSQL::ExplainSupport
|
1458
|
-
|
1240
|
+
include ::ArJdbc::PostgreSQL
|
1241
|
+
include ::ArJdbc::PostgreSQL::ExplainSupport
|
1242
|
+
include ::ArJdbc::Util::QuotedCache
|
1243
|
+
|
1459
1244
|
def initialize(*args)
|
1460
|
-
super
|
1461
|
-
|
1462
1245
|
# @local_tz is initialized as nil to avoid warnings when connect tries to use it
|
1463
1246
|
@local_tz = nil
|
1247
|
+
|
1248
|
+
super # configure_connection happens in super
|
1249
|
+
|
1464
1250
|
@table_alias_length = nil
|
1465
|
-
|
1466
|
-
# configure_connection happens in super
|
1467
1251
|
|
1468
|
-
@
|
1469
|
-
@use_insert_returning = config.key?(:insert_returning) ?
|
1252
|
+
@use_insert_returning = config.key?(:insert_returning) ?
|
1470
1253
|
self.class.type_cast_config_to_boolean(config[:insert_returning]) : nil
|
1471
1254
|
end
|
1472
1255
|
|
@@ -1540,14 +1323,14 @@ module ActiveRecord::ConnectionAdapters
|
|
1540
1323
|
|
1541
1324
|
class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
|
1542
1325
|
include ColumnMethods
|
1543
|
-
|
1326
|
+
|
1544
1327
|
def primary_key(name, type = :primary_key, options = {})
|
1545
1328
|
return super unless type == :uuid
|
1546
1329
|
options[:default] ||= 'uuid_generate_v4()'
|
1547
1330
|
options[:primary_key] = true
|
1548
1331
|
column name, type, options
|
1549
1332
|
end if ActiveRecord::VERSION::MAJOR > 3 # 3.2 super expects (name)
|
1550
|
-
|
1333
|
+
|
1551
1334
|
def column(name, type = nil, options = {})
|
1552
1335
|
super
|
1553
1336
|
column = self[name]
|
@@ -1561,28 +1344,28 @@ module ActiveRecord::ConnectionAdapters
|
|
1561
1344
|
private
|
1562
1345
|
|
1563
1346
|
if ActiveRecord::VERSION::MAJOR > 3
|
1564
|
-
|
1347
|
+
|
1565
1348
|
def create_column_definition(name, type)
|
1566
1349
|
ColumnDefinition.new name, type
|
1567
1350
|
end
|
1568
|
-
|
1351
|
+
|
1569
1352
|
else # no #create_column_definition on 3.2
|
1570
|
-
|
1353
|
+
|
1571
1354
|
def new_column_definition(base, name, type)
|
1572
1355
|
definition = ColumnDefinition.new base, name, type
|
1573
1356
|
@columns << definition
|
1574
1357
|
@columns_hash[name] = definition
|
1575
1358
|
definition
|
1576
1359
|
end
|
1577
|
-
|
1360
|
+
|
1578
1361
|
end
|
1579
|
-
|
1362
|
+
|
1580
1363
|
end
|
1581
1364
|
|
1582
1365
|
def table_definition(*args)
|
1583
1366
|
new_table_definition(TableDefinition, *args)
|
1584
1367
|
end
|
1585
|
-
|
1368
|
+
|
1586
1369
|
class Table < ActiveRecord::ConnectionAdapters::Table
|
1587
1370
|
include ColumnMethods
|
1588
1371
|
end
|
@@ -1590,36 +1373,15 @@ module ActiveRecord::ConnectionAdapters
|
|
1590
1373
|
def update_table_definition(table_name, base)
|
1591
1374
|
Table.new(table_name, base)
|
1592
1375
|
end if ActiveRecord::VERSION::MAJOR > 3
|
1593
|
-
|
1376
|
+
|
1594
1377
|
def jdbc_connection_class(spec)
|
1595
1378
|
::ArJdbc::PostgreSQL.jdbc_connection_class
|
1596
1379
|
end
|
1597
1380
|
|
1381
|
+
# @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_column_class
|
1598
1382
|
def jdbc_column_class
|
1599
1383
|
::ActiveRecord::ConnectionAdapters::PostgreSQLColumn
|
1600
1384
|
end
|
1601
|
-
|
1602
|
-
# some QUOTING caching :
|
1603
|
-
|
1604
|
-
@@quoted_table_names = {}
|
1605
|
-
|
1606
|
-
def quote_table_name(name)
|
1607
|
-
unless quoted = @@quoted_table_names[name]
|
1608
|
-
quoted = super
|
1609
|
-
@@quoted_table_names[name] = quoted.freeze
|
1610
|
-
end
|
1611
|
-
quoted
|
1612
|
-
end
|
1613
|
-
|
1614
|
-
@@quoted_column_names = {}
|
1615
|
-
|
1616
|
-
def quote_column_name(name)
|
1617
|
-
unless quoted = @@quoted_column_names[name]
|
1618
|
-
quoted = super
|
1619
|
-
@@quoted_column_names[name] = quoted.freeze
|
1620
|
-
end
|
1621
|
-
quoted
|
1622
|
-
end
|
1623
|
-
|
1385
|
+
|
1624
1386
|
end
|
1625
1387
|
end
|