activerecord-jdbc-alt-adapter 52.4.0-java → 61.0.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/.nvimlog +0 -0
- data/.travis.yml +63 -39
- data/Gemfile +11 -4
- data/README.md +55 -35
- data/Rakefile +1 -1
- data/Rakefile.jdbc +8 -1
- data/activerecord-jdbc-adapter.gemspec +6 -9
- data/activerecord-jdbc-alt-adapter.gemspec +9 -12
- data/lib/arel/visitors/postgresql_jdbc.rb +1 -1
- data/lib/arel/visitors/sqlserver.rb +49 -23
- data/lib/arjdbc/abstract/connection_management.rb +7 -0
- data/lib/arjdbc/abstract/core.rb +17 -23
- data/lib/arjdbc/abstract/database_statements.rb +30 -2
- data/lib/arjdbc/abstract/statement_cache.rb +2 -5
- data/lib/arjdbc/abstract/transaction_support.rb +22 -7
- data/lib/arjdbc/db2/column.rb +0 -39
- data/lib/arjdbc/derby/adapter.rb +1 -20
- data/lib/arjdbc/firebird/adapter.rb +0 -21
- data/lib/arjdbc/h2/adapter.rb +0 -15
- data/lib/arjdbc/hsqldb/adapter.rb +0 -14
- data/lib/arjdbc/informix/adapter.rb +0 -23
- data/lib/arjdbc/jdbc/adapter.rb +3 -1
- data/lib/arjdbc/jdbc/adapter_require.rb +3 -1
- data/lib/arjdbc/jdbc/base_ext.rb +3 -1
- data/lib/arjdbc/jdbc/callbacks.rb +2 -0
- data/lib/arjdbc/jdbc/column.rb +2 -0
- data/lib/arjdbc/jdbc/connection.rb +2 -0
- data/lib/arjdbc/jdbc/connection_methods.rb +2 -0
- data/lib/arjdbc/jdbc/error.rb +2 -0
- data/lib/arjdbc/jdbc/extension.rb +2 -0
- data/lib/arjdbc/jdbc/java.rb +3 -1
- data/lib/arjdbc/jdbc/railtie.rb +3 -1
- data/lib/arjdbc/jdbc/rake_tasks.rb +3 -1
- data/lib/arjdbc/jdbc/serialized_attributes_helper.rb +3 -1
- data/lib/arjdbc/jdbc/type_cast.rb +2 -0
- data/lib/arjdbc/jdbc/type_converter.rb +2 -0
- data/lib/arjdbc/mssql.rb +3 -1
- data/lib/arjdbc/mssql/adapter.rb +114 -36
- data/lib/arjdbc/mssql/column.rb +19 -1
- data/lib/arjdbc/mssql/connection_methods.rb +10 -2
- data/lib/arjdbc/mssql/database_limits.rb +9 -0
- data/lib/arjdbc/mssql/database_statements.rb +44 -6
- data/lib/arjdbc/mssql/errors.rb +2 -0
- data/lib/arjdbc/mssql/explain_support.rb +3 -1
- data/lib/arjdbc/mssql/extensions/attribute_methods.rb +6 -2
- data/lib/arjdbc/mssql/extensions/calculations.rb +2 -0
- data/lib/arjdbc/mssql/quoting.rb +38 -0
- data/lib/arjdbc/mssql/schema_creation.rb +25 -3
- data/lib/arjdbc/mssql/schema_definitions.rb +10 -0
- data/lib/arjdbc/mssql/schema_dumper.rb +2 -0
- data/lib/arjdbc/mssql/schema_statements.rb +92 -22
- data/lib/arjdbc/mssql/transaction.rb +2 -0
- data/lib/arjdbc/mssql/types.rb +2 -0
- data/lib/arjdbc/mssql/types/binary_types.rb +2 -0
- data/lib/arjdbc/mssql/types/date_and_time_types.rb +2 -0
- data/lib/arjdbc/mssql/types/deprecated_types.rb +2 -0
- data/lib/arjdbc/mssql/types/numeric_types.rb +2 -0
- data/lib/arjdbc/mssql/types/string_types.rb +2 -0
- data/lib/arjdbc/mssql/utils.rb +2 -0
- data/lib/arjdbc/mysql/adapter.rb +59 -21
- data/lib/arjdbc/mysql/connection_methods.rb +6 -1
- data/lib/arjdbc/postgresql/adapter.rb +257 -219
- data/lib/arjdbc/postgresql/base/array_decoder.rb +2 -0
- data/lib/arjdbc/postgresql/base/array_encoder.rb +4 -2
- data/lib/arjdbc/postgresql/base/array_parser.rb +4 -2
- data/lib/arjdbc/postgresql/base/pgconn.rb +2 -0
- data/lib/arjdbc/postgresql/column.rb +6 -4
- data/lib/arjdbc/postgresql/connection_methods.rb +1 -0
- data/lib/arjdbc/postgresql/name.rb +2 -0
- data/lib/arjdbc/postgresql/oid_types.rb +7 -4
- data/lib/arjdbc/sqlite3/adapter.rb +266 -221
- data/lib/arjdbc/sqlite3/connection_methods.rb +26 -4
- data/lib/arjdbc/tasks/databases.rake +21 -13
- data/lib/arjdbc/tasks/mssql_database_tasks.rb +126 -25
- data/lib/arjdbc/util/quoted_cache.rb +3 -1
- data/lib/arjdbc/util/serialized_attributes.rb +3 -1
- data/lib/arjdbc/util/table_copier.rb +3 -1
- data/lib/arjdbc/version.rb +3 -1
- data/pom.xml +4 -4
- data/rakelib/01-tomcat.rake +2 -2
- data/rakelib/rails.rake +1 -1
- data/src/java/arjdbc/ArJdbcModule.java +5 -5
- data/src/java/arjdbc/jdbc/DriverWrapper.java +1 -9
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +549 -691
- data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +88 -0
- data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +13 -23
- data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +125 -53
- data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +97 -103
- data/src/java/arjdbc/util/DateTimeUtils.java +12 -4
- metadata +10 -18
data/lib/arjdbc/mssql/types.rb
CHANGED
data/lib/arjdbc/mssql/utils.rb
CHANGED
data/lib/arjdbc/mysql/adapter.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
ArJdbc.load_java_part :MySQL
|
|
2
4
|
|
|
3
5
|
require 'bigdecimal'
|
|
@@ -19,7 +21,7 @@ module ActiveRecord
|
|
|
19
21
|
remove_const(:Mysql2Adapter) if const_defined?(:Mysql2Adapter)
|
|
20
22
|
|
|
21
23
|
class Mysql2Adapter < AbstractMysqlAdapter
|
|
22
|
-
ADAPTER_NAME = 'Mysql2'
|
|
24
|
+
ADAPTER_NAME = 'Mysql2'
|
|
23
25
|
|
|
24
26
|
include Jdbc::ConnectionPoolCallbacks
|
|
25
27
|
|
|
@@ -31,22 +33,31 @@ module ActiveRecord
|
|
|
31
33
|
|
|
32
34
|
include ArJdbc::MySQL
|
|
33
35
|
|
|
34
|
-
def initialize(connection, logger,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
@version = '8.1.5' if is_jndi
|
|
36
|
+
def initialize(connection, logger, connection_options, config)
|
|
37
|
+
superclass_config = config.reverse_merge(prepared_statements: false)
|
|
38
|
+
super(connection, logger, connection_options, superclass_config)
|
|
38
39
|
|
|
39
|
-
|
|
40
|
+
# configure_connection taken care of at ArJdbc::Abstract::Core
|
|
41
|
+
end
|
|
40
42
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
def self.database_exists?(config)
|
|
44
|
+
conn = ActiveRecord::Base.mysql2_connection(config)
|
|
45
|
+
conn && conn.really_valid?
|
|
46
|
+
rescue ActiveRecord::NoDatabaseError
|
|
47
|
+
false
|
|
48
|
+
ensure
|
|
49
|
+
conn.disconnect! if conn
|
|
50
|
+
end
|
|
43
51
|
|
|
44
|
-
|
|
45
|
-
#
|
|
52
|
+
def check_version
|
|
53
|
+
# for JNDI, don't check version as the whole connection should be lazy
|
|
54
|
+
return if ::ActiveRecord::ConnectionAdapters::JdbcConnection.jndi_config?(config)
|
|
55
|
+
|
|
56
|
+
super
|
|
46
57
|
end
|
|
47
58
|
|
|
48
59
|
def supports_json?
|
|
49
|
-
!mariadb? &&
|
|
60
|
+
!mariadb? && database_version >= '5.7.8'
|
|
50
61
|
end
|
|
51
62
|
|
|
52
63
|
def supports_comments?
|
|
@@ -61,6 +72,10 @@ module ActiveRecord
|
|
|
61
72
|
true
|
|
62
73
|
end
|
|
63
74
|
|
|
75
|
+
def supports_lazy_transactions?
|
|
76
|
+
true
|
|
77
|
+
end
|
|
78
|
+
|
|
64
79
|
def supports_transaction_isolation?
|
|
65
80
|
true
|
|
66
81
|
end
|
|
@@ -71,6 +86,25 @@ module ActiveRecord
|
|
|
71
86
|
|
|
72
87
|
# HELPER METHODS ===========================================
|
|
73
88
|
|
|
89
|
+
# from MySQL::DatabaseStatements
|
|
90
|
+
READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
|
|
91
|
+
:desc, :describe, :set, :show, :use
|
|
92
|
+
) # :nodoc:
|
|
93
|
+
private_constant :READ_QUERY
|
|
94
|
+
|
|
95
|
+
def write_query?(sql) # :nodoc:
|
|
96
|
+
!READ_QUERY.match?(sql)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def explain(arel, binds = [])
|
|
100
|
+
sql = "EXPLAIN #{to_sql(arel, binds)}"
|
|
101
|
+
start = Concurrent.monotonic_time
|
|
102
|
+
result = exec_query(sql, "EXPLAIN", binds)
|
|
103
|
+
elapsed = Concurrent.monotonic_time - start
|
|
104
|
+
|
|
105
|
+
MySQL::ExplainPrettyPrinter.new.pp(result, elapsed)
|
|
106
|
+
end
|
|
107
|
+
|
|
74
108
|
# Reloading the type map in abstract/statement_cache.rb blows up postgres
|
|
75
109
|
def clear_cache!
|
|
76
110
|
reload_type_map
|
|
@@ -136,7 +170,13 @@ module ActiveRecord
|
|
|
136
170
|
private
|
|
137
171
|
|
|
138
172
|
# e.g. "5.7.20-0ubuntu0.16.04.1"
|
|
139
|
-
def full_version
|
|
173
|
+
def full_version
|
|
174
|
+
schema_cache.database_version.full_version_string
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def get_full_version
|
|
178
|
+
@full_version ||= @connection.full_version
|
|
179
|
+
end
|
|
140
180
|
|
|
141
181
|
def jdbc_connection_class(spec)
|
|
142
182
|
::ActiveRecord::ConnectionAdapters::MySQLJdbcConnection
|
|
@@ -148,19 +188,17 @@ module ActiveRecord
|
|
|
148
188
|
|
|
149
189
|
# defined in MySQL::DatabaseStatements which is not included
|
|
150
190
|
def default_insert_value(column)
|
|
151
|
-
|
|
191
|
+
super unless column.auto_increment?
|
|
152
192
|
end
|
|
153
193
|
|
|
154
194
|
# FIXME: optimize insert_fixtures_set by using JDBC Statement.addBatch()/executeBatch()
|
|
155
|
-
def combine_multi_statements(total_sql)
|
|
156
|
-
total_sql
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
def with_multi_statements
|
|
160
|
-
yield
|
|
161
|
-
end
|
|
162
195
|
|
|
163
|
-
def
|
|
196
|
+
def combine_multi_statements(total_sql)
|
|
197
|
+
if total_sql.length == 1
|
|
198
|
+
total_sql.first
|
|
199
|
+
else
|
|
200
|
+
total_sql
|
|
201
|
+
end
|
|
164
202
|
end
|
|
165
203
|
end
|
|
166
204
|
end
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
ArJdbc::ConnectionMethods.module_eval do
|
|
3
3
|
def mysql_connection(config)
|
|
4
|
+
config = config.deep_dup
|
|
4
5
|
# NOTE: this isn't "really" necessary but Rails (in tests) assumes being able to :
|
|
5
6
|
# ActiveRecord::Base.mysql2_connection ActiveRecord::Base.configurations['arunit'].merge(database: ...)
|
|
6
7
|
config = symbolize_keys_if_necessary(config)
|
|
@@ -67,6 +68,7 @@ ArJdbc::ConnectionMethods.module_eval do
|
|
|
67
68
|
# with reconnect fail-over sets connection read-only (by default)
|
|
68
69
|
# properties['failOverReadOnly'] ||= 'false'
|
|
69
70
|
end
|
|
71
|
+
properties['noDatetimeStringSync'] = true unless properties.key?('noDatetimeStringSync')
|
|
70
72
|
end
|
|
71
73
|
if config[:sslkey] || sslcert = config[:sslcert] # || config[:use_ssl]
|
|
72
74
|
properties['useSSL'] ||= true # supported by MariaDB as well
|
|
@@ -89,11 +91,12 @@ ArJdbc::ConnectionMethods.module_eval do
|
|
|
89
91
|
properties['localSocket'] ||= socket if mariadb_driver
|
|
90
92
|
end
|
|
91
93
|
|
|
94
|
+
# properties['useJDBCCompliantTimezoneShift'] ||= true
|
|
92
95
|
# for the Connector/J 5.1 line this is true by default - but it requires some really nasty
|
|
93
96
|
# quirks to get casted Time values extracted properly according for AR's default_timezone
|
|
94
97
|
# - thus we're turning it off (should be off in newer driver versions >= 6 anyway)
|
|
95
98
|
# + also MariaDB driver is compilant and we would need to branch out based on driver
|
|
96
|
-
properties['useLegacyDatetimeCode'] = false
|
|
99
|
+
properties['useLegacyDatetimeCode'] = false # disables the effect of 'useTimezone'
|
|
97
100
|
|
|
98
101
|
jdbc_connection(config)
|
|
99
102
|
end
|
|
@@ -101,6 +104,8 @@ ArJdbc::ConnectionMethods.module_eval do
|
|
|
101
104
|
alias_method :mysql2_connection, :mysql_connection
|
|
102
105
|
|
|
103
106
|
def mariadb_connection(config)
|
|
107
|
+
config = config.deep_dup
|
|
108
|
+
|
|
104
109
|
config[:adapter_spec] ||= ::ArJdbc::MySQL
|
|
105
110
|
config[:adapter_class] = ActiveRecord::ConnectionAdapters::Mysql2Adapter unless config.key?(:adapter_class)
|
|
106
111
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# frozen_string_literal:
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
ArJdbc.load_java_part :PostgreSQL
|
|
3
3
|
|
|
4
4
|
require 'ipaddr'
|
|
@@ -42,46 +42,12 @@ module ArJdbc
|
|
|
42
42
|
# @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_column_class
|
|
43
43
|
def jdbc_column_class; ::ActiveRecord::ConnectionAdapters::PostgreSQLColumn end
|
|
44
44
|
|
|
45
|
-
ADAPTER_NAME = 'PostgreSQL'
|
|
45
|
+
ADAPTER_NAME = 'PostgreSQL'
|
|
46
46
|
|
|
47
47
|
def adapter_name
|
|
48
48
|
ADAPTER_NAME
|
|
49
49
|
end
|
|
50
50
|
|
|
51
|
-
def postgresql_version
|
|
52
|
-
@postgresql_version ||=
|
|
53
|
-
begin
|
|
54
|
-
version = @connection.database_product
|
|
55
|
-
if match = version.match(/([\d\.]*\d).*?/)
|
|
56
|
-
version = match[1].split('.').map(&:to_i)
|
|
57
|
-
# PostgreSQL version representation does not have more than 4 digits
|
|
58
|
-
# From version 10 onwards, PG has changed its versioning policy to
|
|
59
|
-
# limit it to only 2 digits. i.e. in 10.x, 10 being the major
|
|
60
|
-
# version and x representing the patch release
|
|
61
|
-
# Refer to:
|
|
62
|
-
# https://www.postgresql.org/support/versioning/
|
|
63
|
-
# https://www.postgresql.org/docs/10/static/libpq-status.html -> PQserverVersion()
|
|
64
|
-
# for more info
|
|
65
|
-
|
|
66
|
-
if version.size >= 3
|
|
67
|
-
(version[0] * 100 + version[1]) * 100 + version[2]
|
|
68
|
-
elsif version.size == 2
|
|
69
|
-
if version[0] >= 10
|
|
70
|
-
version[0] * 100 * 100 + version[1]
|
|
71
|
-
else
|
|
72
|
-
(version[0] * 100 + version[1]) * 100
|
|
73
|
-
end
|
|
74
|
-
elsif version.size == 1
|
|
75
|
-
version[0] * 100 * 100
|
|
76
|
-
else
|
|
77
|
-
0
|
|
78
|
-
end
|
|
79
|
-
else
|
|
80
|
-
0
|
|
81
|
-
end
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
|
|
85
51
|
def redshift?
|
|
86
52
|
# SELECT version() :
|
|
87
53
|
# PostgreSQL 8.0.2 on i686-pc-linux-gnu, compiled by GCC gcc (GCC) 3.4.2 20041017 (Red Hat 3.4.2-6.fc3), Redshift 1.0.647
|
|
@@ -92,13 +58,6 @@ module ArJdbc
|
|
|
92
58
|
end
|
|
93
59
|
private :redshift?
|
|
94
60
|
|
|
95
|
-
def use_insert_returning?
|
|
96
|
-
if @use_insert_returning.nil?
|
|
97
|
-
@use_insert_returning = supports_insert_with_returning?
|
|
98
|
-
end
|
|
99
|
-
@use_insert_returning
|
|
100
|
-
end
|
|
101
|
-
|
|
102
61
|
def set_client_encoding(encoding)
|
|
103
62
|
ActiveRecord::Base.logger.warn "client_encoding is set by the driver and should not be altered, ('#{encoding}' ignored)"
|
|
104
63
|
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."
|
|
@@ -128,6 +87,9 @@ module ArJdbc
|
|
|
128
87
|
execute("SET time zone '#{tz}'", 'SCHEMA')
|
|
129
88
|
end unless redshift?
|
|
130
89
|
|
|
90
|
+
# Set interval output format to ISO 8601 for ease of parsing by ActiveSupport::Duration.parse
|
|
91
|
+
execute("SET intervalstyle = iso_8601", "SCHEMA")
|
|
92
|
+
|
|
131
93
|
# SET statements from :variables config hash
|
|
132
94
|
# http://www.postgresql.org/docs/8.3/static/sql-set.html
|
|
133
95
|
(config[:variables] || {}).map do |k, v|
|
|
@@ -165,7 +127,7 @@ module ArJdbc
|
|
|
165
127
|
int4range: { name: 'int4range' },
|
|
166
128
|
int8range: { name: 'int8range' },
|
|
167
129
|
integer: { name: 'integer' },
|
|
168
|
-
interval: { name: 'interval' },
|
|
130
|
+
interval: { name: 'interval' },
|
|
169
131
|
json: { name: 'json' },
|
|
170
132
|
jsonb: { name: 'jsonb' },
|
|
171
133
|
line: { name: 'line' },
|
|
@@ -198,173 +160,241 @@ module ArJdbc
|
|
|
198
160
|
!native_database_types[type].nil?
|
|
199
161
|
end
|
|
200
162
|
|
|
201
|
-
# Enable standard-conforming strings if available.
|
|
202
163
|
def set_standard_conforming_strings
|
|
203
|
-
|
|
164
|
+
execute("SET standard_conforming_strings = on", "SCHEMA")
|
|
204
165
|
end
|
|
205
166
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
client_min_messages = self.client_min_messages
|
|
209
|
-
begin
|
|
210
|
-
self.client_min_messages = 'panic'
|
|
211
|
-
value = enable ? "on" : "off"
|
|
212
|
-
execute("SET standard_conforming_strings = #{value}", 'SCHEMA')
|
|
213
|
-
@standard_conforming_strings = ( value == "on" )
|
|
214
|
-
rescue
|
|
215
|
-
@standard_conforming_strings = :unsupported
|
|
216
|
-
ensure
|
|
217
|
-
self.client_min_messages = client_min_messages
|
|
218
|
-
end
|
|
167
|
+
def supports_bulk_alter?
|
|
168
|
+
true
|
|
219
169
|
end
|
|
220
170
|
|
|
221
|
-
def
|
|
222
|
-
|
|
223
|
-
client_min_messages = self.client_min_messages
|
|
224
|
-
begin
|
|
225
|
-
self.client_min_messages = 'panic'
|
|
226
|
-
value = select_one('SHOW standard_conforming_strings', 'SCHEMA')['standard_conforming_strings']
|
|
227
|
-
@standard_conforming_strings = ( value == "on" )
|
|
228
|
-
rescue
|
|
229
|
-
@standard_conforming_strings = :unsupported
|
|
230
|
-
ensure
|
|
231
|
-
self.client_min_messages = client_min_messages
|
|
232
|
-
end
|
|
233
|
-
end
|
|
234
|
-
@standard_conforming_strings == true # return false if :unsupported
|
|
171
|
+
def supports_index_sort_order?
|
|
172
|
+
true
|
|
235
173
|
end
|
|
236
174
|
|
|
237
|
-
def
|
|
175
|
+
def supports_partitioned_indexes?
|
|
176
|
+
database_version >= 110_000
|
|
177
|
+
end
|
|
238
178
|
|
|
239
|
-
def
|
|
179
|
+
def supports_partial_index?
|
|
180
|
+
true
|
|
181
|
+
end
|
|
240
182
|
|
|
241
|
-
def
|
|
183
|
+
def supports_expression_index?
|
|
184
|
+
true
|
|
185
|
+
end
|
|
242
186
|
|
|
243
|
-
def
|
|
187
|
+
def supports_transaction_isolation?
|
|
188
|
+
true
|
|
189
|
+
end
|
|
244
190
|
|
|
245
|
-
def supports_foreign_keys
|
|
191
|
+
def supports_foreign_keys?
|
|
192
|
+
true
|
|
193
|
+
end
|
|
246
194
|
|
|
247
|
-
def
|
|
195
|
+
def supports_check_constraints?
|
|
196
|
+
true
|
|
197
|
+
end
|
|
248
198
|
|
|
249
|
-
def
|
|
199
|
+
def supports_validate_constraints?
|
|
200
|
+
true
|
|
201
|
+
end
|
|
250
202
|
|
|
251
|
-
def
|
|
203
|
+
def supports_views?
|
|
204
|
+
true
|
|
205
|
+
end
|
|
252
206
|
|
|
253
|
-
def
|
|
207
|
+
def supports_datetime_with_precision?
|
|
208
|
+
true
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def supports_json?
|
|
212
|
+
database_version >= 90200
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def supports_comments?
|
|
216
|
+
true
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def supports_savepoints?
|
|
220
|
+
true
|
|
221
|
+
end
|
|
254
222
|
|
|
255
|
-
def
|
|
223
|
+
def supports_insert_returning?
|
|
224
|
+
true
|
|
225
|
+
end
|
|
256
226
|
|
|
257
|
-
def
|
|
227
|
+
def supports_insert_on_conflict?
|
|
228
|
+
database_version >= 90500
|
|
229
|
+
end
|
|
230
|
+
alias supports_insert_on_duplicate_skip? supports_insert_on_conflict?
|
|
231
|
+
alias supports_insert_on_duplicate_update? supports_insert_on_conflict?
|
|
232
|
+
alias supports_insert_conflict_target? supports_insert_on_conflict?
|
|
258
233
|
|
|
259
|
-
def
|
|
234
|
+
def index_algorithms
|
|
235
|
+
{ concurrently: 'CONCURRENTLY' }
|
|
236
|
+
end
|
|
260
237
|
|
|
261
|
-
def
|
|
238
|
+
def supports_ddl_transactions?
|
|
239
|
+
true
|
|
240
|
+
end
|
|
262
241
|
|
|
263
|
-
def
|
|
242
|
+
def supports_advisory_locks?
|
|
243
|
+
true
|
|
244
|
+
end
|
|
264
245
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
standard_conforming_strings?
|
|
268
|
-
@standard_conforming_strings != :unsupported
|
|
246
|
+
def supports_explain?
|
|
247
|
+
true
|
|
269
248
|
end
|
|
270
249
|
|
|
271
|
-
def
|
|
272
|
-
|
|
250
|
+
def supports_extensions?
|
|
251
|
+
database_version >= 90200
|
|
273
252
|
end
|
|
274
253
|
|
|
275
|
-
def
|
|
276
|
-
|
|
254
|
+
def supports_ranges?
|
|
255
|
+
database_version >= 90200
|
|
277
256
|
end
|
|
278
257
|
|
|
279
258
|
def supports_materialized_views?
|
|
280
|
-
|
|
259
|
+
database_version >= 90300
|
|
281
260
|
end
|
|
282
261
|
|
|
283
|
-
def
|
|
284
|
-
|
|
262
|
+
def supports_foreign_tables?
|
|
263
|
+
database_version >= 90300
|
|
285
264
|
end
|
|
286
265
|
|
|
287
|
-
def
|
|
288
|
-
|
|
266
|
+
def supports_pgcrypto_uuid?
|
|
267
|
+
database_version >= 90400
|
|
289
268
|
end
|
|
290
269
|
|
|
291
|
-
def
|
|
292
|
-
|
|
270
|
+
def supports_optimizer_hints?
|
|
271
|
+
unless defined?(@has_pg_hint_plan)
|
|
272
|
+
@has_pg_hint_plan = extension_available?("pg_hint_plan")
|
|
273
|
+
end
|
|
274
|
+
@has_pg_hint_plan
|
|
293
275
|
end
|
|
294
276
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
postgresql_version >= 90200
|
|
277
|
+
def supports_common_table_expressions?
|
|
278
|
+
true
|
|
298
279
|
end
|
|
299
280
|
|
|
300
|
-
def
|
|
301
|
-
|
|
281
|
+
def supports_lazy_transactions?
|
|
282
|
+
true
|
|
302
283
|
end
|
|
303
284
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
285
|
+
def get_advisory_lock(lock_id) # :nodoc:
|
|
286
|
+
unless lock_id.is_a?(Integer) && lock_id.bit_length <= 63
|
|
287
|
+
raise(ArgumentError, "PostgreSQL requires advisory lock ids to be a signed 64 bit integer")
|
|
288
|
+
end
|
|
289
|
+
query_value("SELECT pg_try_advisory_lock(#{lock_id})")
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
def release_advisory_lock(lock_id) # :nodoc:
|
|
293
|
+
unless lock_id.is_a?(Integer) && lock_id.bit_length <= 63
|
|
294
|
+
raise(ArgumentError, "PostgreSQL requires advisory lock ids to be a signed 64 bit integer")
|
|
295
|
+
end
|
|
296
|
+
query_value("SELECT pg_advisory_unlock(#{lock_id})")
|
|
307
297
|
end
|
|
308
298
|
|
|
309
299
|
def enable_extension(name)
|
|
310
|
-
|
|
300
|
+
exec_query("CREATE EXTENSION IF NOT EXISTS \"#{name}\"").tap {
|
|
301
|
+
reload_type_map
|
|
302
|
+
}
|
|
311
303
|
end
|
|
312
304
|
|
|
313
305
|
def disable_extension(name)
|
|
314
|
-
|
|
306
|
+
exec_query("DROP EXTENSION IF EXISTS \"#{name}\" CASCADE").tap {
|
|
307
|
+
reload_type_map
|
|
308
|
+
}
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
def extension_available?(name)
|
|
312
|
+
query_value("SELECT true FROM pg_available_extensions WHERE name = #{quote(name)}", "SCHEMA")
|
|
315
313
|
end
|
|
316
314
|
|
|
317
315
|
def extension_enabled?(name)
|
|
318
|
-
|
|
319
|
-
rows = select_rows("SELECT EXISTS(SELECT * FROM pg_available_extensions WHERE name = '#{name}' AND installed_version IS NOT NULL)", 'SCHEMA')
|
|
320
|
-
available = rows.first.first # true/false or 't'/'f'
|
|
321
|
-
available == true || available == 't'
|
|
322
|
-
end
|
|
316
|
+
query_value("SELECT installed_version IS NOT NULL FROM pg_available_extensions WHERE name = #{quote(name)}", "SCHEMA")
|
|
323
317
|
end
|
|
324
318
|
|
|
325
319
|
def extensions
|
|
326
|
-
|
|
327
|
-
rows = select_rows "SELECT extname from pg_extension", "SCHEMA"
|
|
328
|
-
rows.map { |row| row.first }
|
|
329
|
-
else
|
|
330
|
-
[]
|
|
331
|
-
end
|
|
320
|
+
exec_query("SELECT extname FROM pg_extension", "SCHEMA").cast_values
|
|
332
321
|
end
|
|
333
322
|
|
|
334
|
-
|
|
335
|
-
|
|
323
|
+
# Returns the configured supported identifier length supported by PostgreSQL
|
|
324
|
+
def max_identifier_length
|
|
325
|
+
@max_identifier_length ||= query_value("SHOW max_identifier_length", "SCHEMA").to_i
|
|
336
326
|
end
|
|
337
327
|
|
|
338
|
-
# Set the authorized user for this session
|
|
328
|
+
# Set the authorized user for this session
|
|
339
329
|
def session_auth=(user)
|
|
340
330
|
clear_cache!
|
|
341
|
-
execute
|
|
331
|
+
execute("SET SESSION AUTHORIZATION #{user}")
|
|
342
332
|
end
|
|
343
333
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
334
|
+
def use_insert_returning?
|
|
335
|
+
@use_insert_returning
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
def get_database_version # :nodoc:
|
|
339
|
+
begin
|
|
340
|
+
version = @connection.database_product
|
|
341
|
+
if match = version.match(/([\d\.]*\d).*?/)
|
|
342
|
+
version = match[1].split('.').map(&:to_i)
|
|
343
|
+
# PostgreSQL version representation does not have more than 4 digits
|
|
344
|
+
# From version 10 onwards, PG has changed its versioning policy to
|
|
345
|
+
# limit it to only 2 digits. i.e. in 10.x, 10 being the major
|
|
346
|
+
# version and x representing the patch release
|
|
347
|
+
# Refer to:
|
|
348
|
+
# https://www.postgresql.org/support/versioning/
|
|
349
|
+
# https://www.postgresql.org/docs/10/static/libpq-status.html -> PQserverVersion()
|
|
350
|
+
# for more info
|
|
351
|
+
|
|
352
|
+
if version.size >= 3
|
|
353
|
+
(version[0] * 100 + version[1]) * 100 + version[2]
|
|
354
|
+
elsif version.size == 2
|
|
355
|
+
if version[0] >= 10
|
|
356
|
+
version[0] * 100 * 100 + version[1]
|
|
357
|
+
else
|
|
358
|
+
(version[0] * 100 + version[1]) * 100
|
|
359
|
+
end
|
|
360
|
+
elsif version.size == 1
|
|
361
|
+
version[0] * 100 * 100
|
|
362
|
+
else
|
|
363
|
+
0
|
|
364
|
+
end
|
|
365
|
+
else
|
|
366
|
+
0
|
|
367
|
+
end
|
|
348
368
|
end
|
|
349
|
-
select_value("SELECT pg_try_advisory_lock(#{lock_id});")
|
|
350
369
|
end
|
|
351
370
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
371
|
+
def default_index_type?(index) # :nodoc:
|
|
372
|
+
index.using == :btree || super
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
def build_insert_sql(insert) # :nodoc:
|
|
376
|
+
sql = +"INSERT #{insert.into} #{insert.values_list}"
|
|
377
|
+
|
|
378
|
+
if insert.skip_duplicates?
|
|
379
|
+
sql << " ON CONFLICT #{insert.conflict_target} DO NOTHING"
|
|
380
|
+
elsif insert.update_duplicates?
|
|
381
|
+
sql << " ON CONFLICT #{insert.conflict_target} DO UPDATE SET "
|
|
382
|
+
sql << insert.touch_model_timestamps_unless { |column| "#{insert.model.quoted_table_name}.#{column} IS NOT DISTINCT FROM excluded.#{column}" }
|
|
383
|
+
sql << insert.updatable_columns.map { |column| "#{column}=excluded.#{column}" }.join(",")
|
|
356
384
|
end
|
|
357
|
-
|
|
385
|
+
|
|
386
|
+
sql << " RETURNING #{insert.returning}" if insert.returning
|
|
387
|
+
sql
|
|
358
388
|
end
|
|
359
389
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
390
|
+
def check_version # :nodoc:
|
|
391
|
+
if database_version < 90300
|
|
392
|
+
raise "Your version of PostgreSQL (#{database_version}) is too old. Active Record supports PostgreSQL >= 9.3."
|
|
393
|
+
end
|
|
363
394
|
end
|
|
364
|
-
alias table_alias_length max_identifier_length
|
|
365
|
-
alias index_name_length max_identifier_length
|
|
366
395
|
|
|
367
|
-
|
|
396
|
+
|
|
397
|
+
def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil)
|
|
368
398
|
val = super
|
|
369
399
|
if !use_insert_returning? && pk
|
|
370
400
|
unless sequence_name
|
|
@@ -378,25 +408,23 @@ module ArJdbc
|
|
|
378
408
|
end
|
|
379
409
|
end
|
|
380
410
|
|
|
411
|
+
def execute_batch(statements, name = nil)
|
|
412
|
+
execute(combine_multi_statements(statements), name)
|
|
413
|
+
end
|
|
414
|
+
|
|
381
415
|
def explain(arel, binds = [])
|
|
382
416
|
sql, binds = to_sql_and_binds(arel, binds)
|
|
383
417
|
ActiveRecord::ConnectionAdapters::PostgreSQL::ExplainPrettyPrinter.new.pp(exec_query("EXPLAIN #{sql}", 'EXPLAIN', binds))
|
|
384
418
|
end
|
|
385
419
|
|
|
386
|
-
#
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
# which makes all of the entries in the "result"
|
|
395
|
-
# array end up with the same values as the last row
|
|
396
|
-
result << values.deep_dup
|
|
397
|
-
end
|
|
398
|
-
result
|
|
399
|
-
end
|
|
420
|
+
# from ActiveRecord::ConnectionAdapters::PostgreSQL::DatabaseStatements
|
|
421
|
+
READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
|
|
422
|
+
:close, :declare, :fetch, :move, :set, :show
|
|
423
|
+
) # :nodoc:
|
|
424
|
+
private_constant :READ_QUERY
|
|
425
|
+
|
|
426
|
+
def write_query?(sql) # :nodoc:
|
|
427
|
+
!READ_QUERY.match?(sql)
|
|
400
428
|
end
|
|
401
429
|
|
|
402
430
|
# We need to make sure to deallocate all the prepared statements
|
|
@@ -427,6 +455,10 @@ module ArJdbc
|
|
|
427
455
|
exec_query("SELECT currval('#{sequence_name}')", 'SQL')
|
|
428
456
|
end
|
|
429
457
|
|
|
458
|
+
def build_truncate_statements(table_names)
|
|
459
|
+
["TRUNCATE TABLE #{table_names.map(&method(:quote_table_name)).join(", ")}"]
|
|
460
|
+
end
|
|
461
|
+
|
|
430
462
|
def all_schemas
|
|
431
463
|
select('SELECT nspname FROM pg_namespace').map { |row| row["nspname"] }
|
|
432
464
|
end
|
|
@@ -463,13 +495,7 @@ module ArJdbc
|
|
|
463
495
|
|
|
464
496
|
def escape_bytea(string)
|
|
465
497
|
return unless string
|
|
466
|
-
|
|
467
|
-
"\\x#{string.unpack("H*")[0]}"
|
|
468
|
-
else
|
|
469
|
-
result = ''
|
|
470
|
-
string.each_byte { |c| result << sprintf('\\\\%03o', c) }
|
|
471
|
-
result
|
|
472
|
-
end
|
|
498
|
+
"\\x#{string.unpack("H*")[0]}"
|
|
473
499
|
end
|
|
474
500
|
|
|
475
501
|
# @override
|
|
@@ -488,7 +514,7 @@ module ArJdbc
|
|
|
488
514
|
alias_method :quote_schema_name, :quote_column_name
|
|
489
515
|
|
|
490
516
|
# Need to clear the cache even though the AR adapter doesn't for some reason
|
|
491
|
-
def remove_column(table_name, column_name, type = nil, options
|
|
517
|
+
def remove_column(table_name, column_name, type = nil, **options)
|
|
492
518
|
super
|
|
493
519
|
clear_cache!
|
|
494
520
|
end
|
|
@@ -502,8 +528,31 @@ module ArJdbc
|
|
|
502
528
|
nil
|
|
503
529
|
end
|
|
504
530
|
|
|
531
|
+
|
|
532
|
+
# @private
|
|
533
|
+
def column_name_for_operation(operation, node)
|
|
534
|
+
case operation
|
|
535
|
+
when 'maximum' then 'max'
|
|
536
|
+
when 'minimum' then 'min'
|
|
537
|
+
when 'average' then 'avg'
|
|
538
|
+
else operation.downcase
|
|
539
|
+
end
|
|
540
|
+
end
|
|
541
|
+
|
|
542
|
+
private
|
|
543
|
+
|
|
505
544
|
# Returns the list of a table's column names, data types, and default values.
|
|
506
545
|
#
|
|
546
|
+
# The underlying query is roughly:
|
|
547
|
+
# SELECT column.name, column.type, default.value, column.comment
|
|
548
|
+
# FROM column LEFT JOIN default
|
|
549
|
+
# ON column.table_id = default.table_id
|
|
550
|
+
# AND column.num = default.column_num
|
|
551
|
+
# WHERE column.table_id = get_table_id('table_name')
|
|
552
|
+
# AND column.num > 0
|
|
553
|
+
# AND NOT column.is_dropped
|
|
554
|
+
# ORDER BY column.num
|
|
555
|
+
#
|
|
507
556
|
# If the table name is not prefixed with a schema, the database will
|
|
508
557
|
# take the first match from the schema search path.
|
|
509
558
|
#
|
|
@@ -511,82 +560,73 @@ module ArJdbc
|
|
|
511
560
|
# - format_type includes the column size constraint, e.g. varchar(50)
|
|
512
561
|
# - ::regclass is a function that gives the id for a table name
|
|
513
562
|
def column_definitions(table_name)
|
|
514
|
-
select_rows(
|
|
563
|
+
select_rows(<<~SQL, 'SCHEMA')
|
|
515
564
|
SELECT a.attname, format_type(a.atttypid, a.atttypmod),
|
|
516
565
|
pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
|
|
517
|
-
|
|
518
|
-
WHERE c.oid = a.attcollation AND t.oid = a.atttypid
|
|
519
|
-
AND a.attcollation <> t.typcollation),
|
|
520
|
-
col_description(a.attrelid, a.attnum) AS comment
|
|
566
|
+
c.collname, col_description(a.attrelid, a.attnum) AS comment
|
|
521
567
|
FROM pg_attribute a
|
|
522
568
|
LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum
|
|
569
|
+
LEFT JOIN pg_type t ON a.atttypid = t.oid
|
|
570
|
+
LEFT JOIN pg_collation c ON a.attcollation = c.oid AND a.attcollation <> t.typcollation
|
|
523
571
|
WHERE a.attrelid = #{quote(quote_table_name(table_name))}::regclass
|
|
524
572
|
AND a.attnum > 0 AND NOT a.attisdropped
|
|
525
573
|
ORDER BY a.attnum
|
|
526
|
-
|
|
574
|
+
SQL
|
|
527
575
|
end
|
|
528
|
-
private :column_definitions
|
|
529
576
|
|
|
530
|
-
def
|
|
531
|
-
|
|
577
|
+
def extract_table_ref_from_insert_sql(sql)
|
|
578
|
+
sql[/into\s("[A-Za-z0-9_."\[\]\s]+"|[A-Za-z0-9_."\[\]]+)\s*/im]
|
|
579
|
+
$1.strip if $1
|
|
532
580
|
end
|
|
533
581
|
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
case operation
|
|
537
|
-
when 'maximum' then 'max'
|
|
538
|
-
when 'minimum' then 'min'
|
|
539
|
-
when 'average' then 'avg'
|
|
540
|
-
else operation.downcase
|
|
541
|
-
end
|
|
582
|
+
def arel_visitor
|
|
583
|
+
Arel::Visitors::PostgreSQL.new(self)
|
|
542
584
|
end
|
|
543
585
|
|
|
544
|
-
private
|
|
545
|
-
|
|
546
586
|
# Pulled from ActiveRecord's Postgres adapter and modified to use execute
|
|
547
587
|
def can_perform_case_insensitive_comparison_for?(column)
|
|
548
588
|
@case_insensitive_cache ||= {}
|
|
549
589
|
@case_insensitive_cache[column.sql_type] ||= begin
|
|
550
|
-
sql =
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
590
|
+
sql = <<~SQL
|
|
591
|
+
SELECT exists(
|
|
592
|
+
SELECT * FROM pg_proc
|
|
593
|
+
WHERE proname = 'lower'
|
|
594
|
+
AND proargtypes = ARRAY[#{quote column.sql_type}::regtype]::oidvector
|
|
595
|
+
) OR exists(
|
|
596
|
+
SELECT * FROM pg_proc
|
|
597
|
+
INNER JOIN pg_cast
|
|
598
|
+
ON ARRAY[casttarget]::oidvector = proargtypes
|
|
599
|
+
WHERE proname = 'lower'
|
|
600
|
+
AND castsource = #{quote column.sql_type}::regtype
|
|
601
|
+
)
|
|
602
|
+
SQL
|
|
563
603
|
select_value(sql, 'SCHEMA')
|
|
564
604
|
end
|
|
565
605
|
end
|
|
566
606
|
|
|
567
|
-
def translate_exception(exception, message)
|
|
607
|
+
def translate_exception(exception, message:, sql:, binds:)
|
|
568
608
|
return super unless exception.is_a?(ActiveRecord::JDBCError)
|
|
569
609
|
|
|
570
610
|
# TODO: Can we base these on an error code of some kind?
|
|
571
611
|
case exception.message
|
|
572
612
|
when /duplicate key value violates unique constraint/
|
|
573
|
-
::ActiveRecord::RecordNotUnique.new(message)
|
|
613
|
+
::ActiveRecord::RecordNotUnique.new(message, sql: sql, binds: binds)
|
|
574
614
|
when /violates not-null constraint/
|
|
575
|
-
::ActiveRecord::NotNullViolation.new(message)
|
|
615
|
+
::ActiveRecord::NotNullViolation.new(message, sql: sql, binds: binds)
|
|
576
616
|
when /violates foreign key constraint/
|
|
577
|
-
::ActiveRecord::InvalidForeignKey.new(message)
|
|
617
|
+
::ActiveRecord::InvalidForeignKey.new(message, sql: sql, binds: binds)
|
|
578
618
|
when /value too long/
|
|
579
|
-
::ActiveRecord::ValueTooLong.new(message)
|
|
619
|
+
::ActiveRecord::ValueTooLong.new(message, sql: sql, binds: binds)
|
|
580
620
|
when /out of range/
|
|
581
|
-
::ActiveRecord::RangeError.new(message)
|
|
621
|
+
::ActiveRecord::RangeError.new(message, sql: sql, binds: binds)
|
|
582
622
|
when /could not serialize/
|
|
583
|
-
::ActiveRecord::SerializationFailure.new(message)
|
|
623
|
+
::ActiveRecord::SerializationFailure.new(message, sql: sql, binds: binds)
|
|
584
624
|
when /deadlock detected/
|
|
585
|
-
::ActiveRecord::Deadlocked.new(message)
|
|
625
|
+
::ActiveRecord::Deadlocked.new(message, sql: sql, binds: binds)
|
|
586
626
|
when /lock timeout/
|
|
587
|
-
::ActiveRecord::LockWaitTimeout.new(message)
|
|
627
|
+
::ActiveRecord::LockWaitTimeout.new(message, sql: sql, binds: binds)
|
|
588
628
|
when /canceling statement/ # This needs to come after lock timeout because the lock timeout message also contains "canceling statement"
|
|
589
|
-
::ActiveRecord::QueryCanceled.new(message)
|
|
629
|
+
::ActiveRecord::QueryCanceled.new(message, sql: sql, binds: binds)
|
|
590
630
|
else
|
|
591
631
|
super
|
|
592
632
|
end
|
|
@@ -610,11 +650,6 @@ module ArJdbc
|
|
|
610
650
|
end
|
|
611
651
|
end
|
|
612
652
|
|
|
613
|
-
def extract_table_ref_from_insert_sql(sql)
|
|
614
|
-
sql[/into\s("[A-Za-z0-9_."\[\]\s]+"|[A-Za-z0-9_."\[\]]+)\s*/im]
|
|
615
|
-
$1.strip if $1
|
|
616
|
-
end
|
|
617
|
-
|
|
618
653
|
def local_tz
|
|
619
654
|
@local_tz ||= execute('SHOW TIME ZONE', 'SCHEMA').first["TimeZone"]
|
|
620
655
|
end
|
|
@@ -635,6 +670,7 @@ module ActiveRecord::ConnectionAdapters
|
|
|
635
670
|
remove_const(:PostgreSQLAdapter) if const_defined?(:PostgreSQLAdapter)
|
|
636
671
|
|
|
637
672
|
class PostgreSQLAdapter < AbstractAdapter
|
|
673
|
+
class_attribute :create_unlogged_tables, default: false
|
|
638
674
|
|
|
639
675
|
# Try to use as much of the built in postgres logic as possible
|
|
640
676
|
# maybe someday we can extend the actual adapter
|
|
@@ -672,11 +708,16 @@ module ActiveRecord::ConnectionAdapters
|
|
|
672
708
|
initialize_type_map
|
|
673
709
|
|
|
674
710
|
@use_insert_returning = @config.key?(:insert_returning) ?
|
|
675
|
-
self.class.type_cast_config_to_boolean(@config[:insert_returning]) :
|
|
711
|
+
self.class.type_cast_config_to_boolean(@config[:insert_returning]) : true
|
|
676
712
|
end
|
|
677
713
|
|
|
678
|
-
def
|
|
679
|
-
|
|
714
|
+
def self.database_exists?(config)
|
|
715
|
+
conn = ActiveRecord::Base.postgresql_connection(config)
|
|
716
|
+
conn && conn.really_valid?
|
|
717
|
+
rescue ActiveRecord::NoDatabaseError
|
|
718
|
+
false
|
|
719
|
+
ensure
|
|
720
|
+
conn.disconnect! if conn
|
|
680
721
|
end
|
|
681
722
|
|
|
682
723
|
require 'active_record/connection_adapters/postgresql/schema_definitions'
|
|
@@ -685,11 +726,8 @@ module ActiveRecord::ConnectionAdapters
|
|
|
685
726
|
TableDefinition = ActiveRecord::ConnectionAdapters::PostgreSQL::TableDefinition
|
|
686
727
|
Table = ActiveRecord::ConnectionAdapters::PostgreSQL::Table
|
|
687
728
|
|
|
688
|
-
def create_table_definition(*args) # :nodoc:
|
|
689
|
-
TableDefinition.new(*args)
|
|
690
|
-
end
|
|
691
|
-
|
|
692
729
|
public :sql_for_insert
|
|
730
|
+
alias :postgresql_version :database_version
|
|
693
731
|
|
|
694
732
|
def jdbc_connection_class(spec)
|
|
695
733
|
::ArJdbc::PostgreSQL.jdbc_connection_class
|