activerecord-jdbc-adapter 1.0.3-java → 50.1-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 +7 -0
- data/.gitignore +33 -0
- data/.travis.yml +79 -0
- data/.yardopts +4 -0
- data/CONTRIBUTING.md +50 -0
- data/Gemfile +91 -0
- data/History.md +1191 -0
- data/LICENSE.txt +22 -17
- data/README.md +169 -0
- data/RUNNING_TESTS.md +127 -0
- data/Rakefile +294 -5
- data/Rakefile.jdbc +20 -0
- data/activerecord-jdbc-adapter.gemspec +55 -0
- data/lib/active_record/connection_adapters/as400_adapter.rb +2 -0
- data/lib/active_record/connection_adapters/db2_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/firebird_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/mariadb_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +1 -0
- data/lib/activerecord-jdbc-adapter.rb +0 -5
- data/lib/arel/visitors/compat.rb +60 -0
- data/lib/arel/visitors/db2.rb +128 -6
- data/lib/arel/visitors/derby.rb +103 -10
- data/lib/arel/visitors/firebird.rb +79 -0
- data/lib/arel/visitors/h2.rb +25 -0
- data/lib/arel/visitors/hsqldb.rb +18 -10
- data/lib/arel/visitors/postgresql_jdbc.rb +6 -0
- data/lib/arel/visitors/sql_server.rb +225 -0
- data/lib/arel/visitors/sql_server/ng42.rb +293 -0
- data/lib/arjdbc.rb +11 -21
- data/lib/arjdbc/abstract/connection_management.rb +35 -0
- data/lib/arjdbc/abstract/core.rb +64 -0
- data/lib/arjdbc/abstract/database_statements.rb +64 -0
- data/lib/arjdbc/abstract/statement_cache.rb +58 -0
- data/lib/arjdbc/abstract/transaction_support.rb +86 -0
- data/lib/arjdbc/db2.rb +3 -1
- data/lib/arjdbc/db2/adapter.rb +630 -250
- data/lib/arjdbc/db2/as400.rb +130 -0
- data/lib/arjdbc/db2/column.rb +167 -0
- data/lib/arjdbc/db2/connection_methods.rb +44 -0
- data/lib/arjdbc/derby.rb +1 -5
- data/lib/arjdbc/derby/active_record_patch.rb +13 -0
- data/lib/arjdbc/derby/adapter.rb +409 -217
- data/lib/arjdbc/derby/connection_methods.rb +16 -14
- data/lib/arjdbc/derby/schema_creation.rb +15 -0
- data/lib/arjdbc/discover.rb +62 -50
- data/lib/arjdbc/firebird.rb +3 -1
- data/lib/arjdbc/firebird/adapter.rb +365 -62
- data/lib/arjdbc/firebird/connection_methods.rb +23 -0
- data/lib/arjdbc/h2.rb +2 -3
- data/lib/arjdbc/h2/adapter.rb +273 -6
- data/lib/arjdbc/h2/connection_methods.rb +23 -8
- data/lib/arjdbc/hsqldb.rb +2 -3
- data/lib/arjdbc/hsqldb/adapter.rb +204 -77
- data/lib/arjdbc/hsqldb/connection_methods.rb +24 -10
- data/lib/arjdbc/hsqldb/explain_support.rb +35 -0
- data/lib/arjdbc/hsqldb/schema_creation.rb +11 -0
- data/lib/arjdbc/informix.rb +4 -2
- data/lib/arjdbc/informix/adapter.rb +78 -54
- data/lib/arjdbc/informix/connection_methods.rb +8 -9
- data/lib/arjdbc/jdbc.rb +59 -2
- data/lib/arjdbc/jdbc/adapter.rb +356 -166
- data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
- data/lib/arjdbc/jdbc/adapter_require.rb +46 -0
- data/lib/arjdbc/jdbc/base_ext.rb +15 -0
- data/lib/arjdbc/jdbc/callbacks.rb +27 -18
- data/lib/arjdbc/jdbc/column.rb +79 -20
- data/lib/arjdbc/jdbc/connection.rb +5 -119
- data/lib/arjdbc/jdbc/connection_methods.rb +32 -4
- data/lib/arjdbc/jdbc/error.rb +65 -0
- data/lib/arjdbc/jdbc/extension.rb +41 -29
- data/lib/arjdbc/jdbc/java.rb +5 -6
- data/lib/arjdbc/jdbc/jdbc.rake +3 -126
- data/lib/arjdbc/jdbc/railtie.rb +2 -9
- data/lib/arjdbc/jdbc/rake_tasks.rb +3 -10
- data/lib/arjdbc/jdbc/serialized_attributes_helper.rb +3 -0
- data/lib/arjdbc/jdbc/type_cast.rb +166 -0
- data/lib/arjdbc/jdbc/type_converter.rb +35 -19
- data/lib/arjdbc/mssql.rb +6 -3
- data/lib/arjdbc/mssql/adapter.rb +630 -298
- data/lib/arjdbc/mssql/column.rb +200 -0
- data/lib/arjdbc/mssql/connection_methods.rb +66 -17
- data/lib/arjdbc/mssql/explain_support.rb +99 -0
- data/lib/arjdbc/mssql/limit_helpers.rb +189 -50
- data/lib/arjdbc/mssql/lock_methods.rb +77 -0
- data/lib/arjdbc/mssql/types.rb +343 -0
- data/lib/arjdbc/mssql/utils.rb +82 -0
- data/lib/arjdbc/mysql.rb +2 -3
- data/lib/arjdbc/mysql/adapter.rb +86 -356
- data/lib/arjdbc/mysql/connection_methods.rb +159 -23
- data/lib/arjdbc/oracle/adapter.rb +714 -263
- data/lib/arjdbc/postgresql.rb +2 -3
- data/lib/arjdbc/postgresql/_bc_time_cast_patch.rb +24 -0
- data/lib/arjdbc/postgresql/adapter.rb +570 -400
- data/lib/arjdbc/postgresql/base/array_decoder.rb +26 -0
- data/lib/arjdbc/postgresql/base/array_encoder.rb +25 -0
- data/lib/arjdbc/postgresql/base/array_parser.rb +95 -0
- data/lib/arjdbc/postgresql/base/pgconn.rb +11 -0
- data/lib/arjdbc/postgresql/column.rb +51 -0
- data/lib/arjdbc/postgresql/connection_methods.rb +57 -18
- data/lib/arjdbc/postgresql/name.rb +24 -0
- data/lib/arjdbc/postgresql/oid_types.rb +192 -0
- data/lib/arjdbc/railtie.rb +11 -0
- data/lib/arjdbc/sqlite3.rb +2 -3
- data/lib/arjdbc/sqlite3/adapter.rb +518 -198
- data/lib/arjdbc/sqlite3/connection_methods.rb +49 -24
- data/lib/arjdbc/sybase.rb +2 -2
- data/lib/arjdbc/sybase/adapter.rb +7 -6
- data/lib/arjdbc/tasks.rb +13 -0
- data/lib/arjdbc/tasks/database_tasks.rb +52 -0
- data/lib/arjdbc/tasks/databases.rake +91 -0
- data/lib/arjdbc/tasks/databases3.rake +215 -0
- data/lib/arjdbc/tasks/databases4.rake +39 -0
- data/lib/arjdbc/tasks/db2_database_tasks.rb +104 -0
- data/lib/arjdbc/tasks/derby_database_tasks.rb +95 -0
- data/lib/arjdbc/tasks/h2_database_tasks.rb +31 -0
- data/lib/arjdbc/tasks/hsqldb_database_tasks.rb +70 -0
- data/lib/arjdbc/tasks/jdbc_database_tasks.rb +169 -0
- data/lib/arjdbc/tasks/mssql_database_tasks.rb +46 -0
- data/lib/arjdbc/util/quoted_cache.rb +60 -0
- data/lib/arjdbc/util/serialized_attributes.rb +98 -0
- data/lib/arjdbc/util/table_copier.rb +110 -0
- data/lib/arjdbc/version.rb +1 -6
- data/lib/generators/jdbc/USAGE +9 -0
- data/lib/generators/jdbc/jdbc_generator.rb +8 -0
- data/lib/jdbc_adapter.rb +1 -1
- data/lib/jdbc_adapter/rake_tasks.rb +3 -2
- data/lib/jdbc_adapter/version.rb +2 -1
- data/pom.xml +114 -0
- data/rails_generators/jdbc_generator.rb +1 -1
- data/rails_generators/templates/config/initializers/jdbc.rb +8 -5
- data/rails_generators/templates/lib/tasks/jdbc.rake +7 -4
- data/rakelib/01-tomcat.rake +51 -0
- data/rakelib/02-test.rake +132 -0
- data/rakelib/bundler_ext.rb +11 -0
- data/rakelib/compile.rake +67 -22
- data/rakelib/db.rake +61 -0
- data/rakelib/rails.rake +204 -29
- data/src/java/arjdbc/ArJdbcModule.java +286 -0
- data/src/java/arjdbc/db2/DB2Module.java +76 -0
- data/src/java/arjdbc/db2/DB2RubyJdbcConnection.java +126 -0
- data/src/java/arjdbc/derby/DerbyModule.java +99 -243
- data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +152 -0
- data/src/java/arjdbc/firebird/FirebirdRubyJdbcConnection.java +174 -0
- data/src/java/arjdbc/{jdbc/JdbcConnectionFactory.java → h2/H2Module.java} +20 -6
- data/src/java/arjdbc/h2/H2RubyJdbcConnection.java +27 -12
- data/src/java/arjdbc/hsqldb/HSQLDBModule.java +73 -0
- data/src/java/arjdbc/informix/InformixRubyJdbcConnection.java +7 -6
- data/src/java/arjdbc/jdbc/AdapterJavaService.java +7 -29
- data/src/java/arjdbc/jdbc/Callable.java +44 -0
- data/src/java/arjdbc/jdbc/ConnectionFactory.java +132 -0
- data/src/java/arjdbc/jdbc/DataSourceConnectionFactory.java +157 -0
- data/src/java/arjdbc/jdbc/DriverConnectionFactory.java +63 -0
- data/src/java/arjdbc/jdbc/DriverWrapper.java +119 -0
- data/src/java/arjdbc/jdbc/JdbcResult.java +130 -0
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +3622 -948
- data/src/java/arjdbc/mssql/MSSQLModule.java +90 -0
- data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +181 -0
- data/src/java/arjdbc/mysql/MySQLModule.java +99 -81
- data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +294 -0
- data/src/java/arjdbc/oracle/OracleModule.java +80 -0
- data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +387 -17
- data/src/java/arjdbc/postgresql/ByteaUtils.java +157 -0
- data/src/java/arjdbc/postgresql/PgResultSetMetaDataWrapper.java +23 -0
- data/src/java/arjdbc/postgresql/PostgreSQLModule.java +77 -0
- data/src/java/arjdbc/postgresql/PostgreSQLResult.java +184 -0
- data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +952 -0
- data/src/java/arjdbc/sqlite3/SQLite3Module.java +73 -0
- data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +525 -0
- data/src/java/arjdbc/util/CallResultSet.java +826 -0
- data/src/java/arjdbc/util/DateTimeUtils.java +580 -0
- data/src/java/arjdbc/util/ObjectSupport.java +65 -0
- data/src/java/arjdbc/util/QuotingUtils.java +138 -0
- data/src/java/arjdbc/util/StringCache.java +63 -0
- data/src/java/arjdbc/util/StringHelper.java +159 -0
- metadata +245 -268
- data/History.txt +0 -369
- data/Manifest.txt +0 -180
- data/README.txt +0 -181
- data/lib/active_record/connection_adapters/oracle_adapter.rb +0 -1
- 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/arel/visitors/mssql.rb +0 -44
- data/lib/arjdbc/jdbc/compatibility.rb +0 -51
- data/lib/arjdbc/jdbc/core_ext.rb +0 -24
- data/lib/arjdbc/jdbc/discover.rb +0 -18
- data/lib/arjdbc/jdbc/driver.rb +0 -44
- data/lib/arjdbc/jdbc/missing_functionality_helper.rb +0 -87
- data/lib/arjdbc/jdbc/quoted_primary_key.rb +0 -28
- data/lib/arjdbc/jdbc/require_driver.rb +0 -16
- data/lib/arjdbc/mimer.rb +0 -2
- data/lib/arjdbc/mimer/adapter.rb +0 -142
- data/lib/arjdbc/mssql/tsql_helper.rb +0 -61
- data/lib/arjdbc/oracle.rb +0 -3
- data/lib/arjdbc/oracle/connection_methods.rb +0 -11
- data/lib/pg.rb +0 -4
- data/rakelib/package.rake +0 -92
- data/rakelib/test.rake +0 -81
- data/src/java/arjdbc/jdbc/SQLBlock.java +0 -48
- data/src/java/arjdbc/mssql/MssqlRubyJdbcConnection.java +0 -127
- data/src/java/arjdbc/postgresql/PostgresqlRubyJdbcConnection.java +0 -57
- data/src/java/arjdbc/sqlite3/Sqlite3RubyJdbcConnection.java +0 -64
- data/test/abstract_db_create.rb +0 -117
- data/test/activerecord/connection_adapters/type_conversion_test.rb +0 -31
- data/test/activerecord/connections/native_jdbc_mysql/connection.rb +0 -25
- data/test/db/db2.rb +0 -11
- data/test/db/derby.rb +0 -12
- data/test/db/h2.rb +0 -11
- data/test/db/hsqldb.rb +0 -13
- data/test/db/informix.rb +0 -11
- data/test/db/jdbc.rb +0 -11
- data/test/db/jndi_config.rb +0 -40
- data/test/db/logger.rb +0 -3
- data/test/db/mssql.rb +0 -9
- data/test/db/mysql.rb +0 -10
- data/test/db/oracle.rb +0 -34
- data/test/db/postgres.rb +0 -9
- data/test/db/sqlite3.rb +0 -11
- data/test/db2_simple_test.rb +0 -66
- data/test/derby_migration_test.rb +0 -68
- data/test/derby_multibyte_test.rb +0 -12
- data/test/derby_simple_test.rb +0 -99
- data/test/generic_jdbc_connection_test.rb +0 -29
- data/test/h2_simple_test.rb +0 -41
- data/test/has_many_through.rb +0 -79
- data/test/helper.rb +0 -5
- data/test/hsqldb_simple_test.rb +0 -6
- data/test/informix_simple_test.rb +0 -48
- data/test/jdbc_common.rb +0 -25
- data/test/jndi_callbacks_test.rb +0 -40
- data/test/jndi_test.rb +0 -25
- data/test/manualTestDatabase.rb +0 -191
- data/test/models/add_not_null_column_to_table.rb +0 -12
- data/test/models/auto_id.rb +0 -18
- data/test/models/data_types.rb +0 -28
- data/test/models/entry.rb +0 -43
- data/test/models/mixed_case.rb +0 -25
- data/test/models/reserved_word.rb +0 -18
- data/test/models/string_id.rb +0 -18
- data/test/models/validates_uniqueness_of_string.rb +0 -19
- data/test/mssql_db_create_test.rb +0 -26
- data/test/mssql_identity_insert_test.rb +0 -19
- data/test/mssql_legacy_types_test.rb +0 -58
- data/test/mssql_limit_offset_test.rb +0 -136
- data/test/mssql_multibyte_test.rb +0 -18
- data/test/mssql_simple_test.rb +0 -55
- data/test/mysql_db_create_test.rb +0 -27
- data/test/mysql_info_test.rb +0 -113
- data/test/mysql_multibyte_test.rb +0 -10
- data/test/mysql_nonstandard_primary_key_test.rb +0 -42
- data/test/mysql_simple_test.rb +0 -49
- data/test/oracle_simple_test.rb +0 -18
- data/test/oracle_specific_test.rb +0 -83
- data/test/pick_rails_version.rb +0 -3
- data/test/postgres_db_create_test.rb +0 -32
- data/test/postgres_drop_db_test.rb +0 -16
- data/test/postgres_mixed_case_test.rb +0 -29
- data/test/postgres_nonseq_pkey_test.rb +0 -38
- data/test/postgres_reserved_test.rb +0 -22
- data/test/postgres_schema_search_path_test.rb +0 -44
- data/test/postgres_simple_test.rb +0 -51
- data/test/postgres_table_alias_length_test.rb +0 -15
- data/test/simple.rb +0 -546
- data/test/sqlite3_simple_test.rb +0 -233
- data/test/sybase_jtds_simple_test.rb +0 -28
data/lib/arjdbc/postgresql.rb
CHANGED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
ActiveRecord::ConnectionAdapters::PostgreSQL::OID::DateTime.class_eval do
|
|
2
|
+
def cast_value(value)
|
|
3
|
+
return value unless value.is_a?(::String)
|
|
4
|
+
|
|
5
|
+
case value
|
|
6
|
+
when 'infinity' then ::Float::INFINITY
|
|
7
|
+
when '-infinity' then -::Float::INFINITY
|
|
8
|
+
# when / BC$/
|
|
9
|
+
# astronomical_year = format("%04d", -value[/^\d+/].to_i + 1)
|
|
10
|
+
# super(value.sub(/ BC$/, "").sub(/^\d+/, astronomical_year))
|
|
11
|
+
# else
|
|
12
|
+
# super
|
|
13
|
+
else
|
|
14
|
+
if value.end_with?(' BC')
|
|
15
|
+
astronomical_year = format("%04d", -value[/^\d+/].to_i + 1)
|
|
16
|
+
DateTime.parse("#{value}"[0...-3].sub(/^\d+/, astronomical_year))
|
|
17
|
+
else
|
|
18
|
+
super
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def apply_seconds_precision(value); value end
|
|
24
|
+
end
|
|
@@ -1,404 +1,403 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
# frozen_string_literal: false
|
|
2
|
+
ArJdbc.load_java_part :PostgreSQL
|
|
3
|
+
|
|
4
|
+
require 'ipaddr'
|
|
5
|
+
require 'active_record/connection_adapters/abstract_adapter'
|
|
6
|
+
require 'active_record/connection_adapters/postgresql/column'
|
|
7
|
+
require 'active_record/connection_adapters/postgresql/explain_pretty_printer'
|
|
8
|
+
require 'active_record/connection_adapters/postgresql/quoting'
|
|
9
|
+
require 'active_record/connection_adapters/postgresql/referential_integrity'
|
|
10
|
+
require 'active_record/connection_adapters/postgresql/schema_dumper'
|
|
11
|
+
require 'active_record/connection_adapters/postgresql/schema_statements'
|
|
12
|
+
require 'active_record/connection_adapters/postgresql/type_metadata'
|
|
13
|
+
require 'active_record/connection_adapters/postgresql/utils'
|
|
14
|
+
require 'arjdbc/abstract/core'
|
|
15
|
+
require 'arjdbc/abstract/connection_management'
|
|
16
|
+
require 'arjdbc/abstract/database_statements'
|
|
17
|
+
require 'arjdbc/abstract/statement_cache'
|
|
18
|
+
require 'arjdbc/abstract/transaction_support'
|
|
19
|
+
require 'arjdbc/postgresql/base/array_decoder'
|
|
20
|
+
require 'arjdbc/postgresql/base/array_encoder'
|
|
21
|
+
require 'arjdbc/postgresql/name'
|
|
22
|
+
|
|
23
|
+
module ArJdbc
|
|
24
|
+
# Strives to provide Rails built-in PostgreSQL adapter (API) compatibility.
|
|
6
25
|
module PostgreSQL
|
|
7
|
-
def self.extended(mod)
|
|
8
|
-
mod.class.class_eval do
|
|
9
|
-
alias_chained_method :insert, :query_dirty, :insert
|
|
10
|
-
end
|
|
11
|
-
end
|
|
12
26
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
27
|
+
require 'arjdbc/postgresql/column'
|
|
28
|
+
require 'arel/visitors/postgresql_jdbc'
|
|
29
|
+
# @private
|
|
30
|
+
IndexDefinition = ::ActiveRecord::ConnectionAdapters::IndexDefinition
|
|
16
31
|
|
|
32
|
+
# @private
|
|
33
|
+
ForeignKeyDefinition = ::ActiveRecord::ConnectionAdapters::ForeignKeyDefinition
|
|
34
|
+
|
|
35
|
+
# @private
|
|
36
|
+
Type = ::ActiveRecord::Type
|
|
37
|
+
|
|
38
|
+
# @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_connection_class
|
|
17
39
|
def self.jdbc_connection_class
|
|
18
|
-
::ActiveRecord::ConnectionAdapters::
|
|
40
|
+
::ActiveRecord::ConnectionAdapters::PostgreSQLJdbcConnection
|
|
19
41
|
end
|
|
20
42
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
43
|
+
# @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_column_class
|
|
44
|
+
def jdbc_column_class; ::ActiveRecord::ConnectionAdapters::PostgreSQLColumn end
|
|
45
|
+
|
|
46
|
+
ADAPTER_NAME = 'PostgreSQL'.freeze
|
|
47
|
+
|
|
48
|
+
def adapter_name
|
|
49
|
+
ADAPTER_NAME
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# TODO: Update this to pull info from the DatabaseMetaData object?
|
|
53
|
+
def postgresql_version
|
|
54
|
+
@postgresql_version ||=
|
|
55
|
+
begin
|
|
56
|
+
version = @connection.database_product
|
|
57
|
+
if version =~ /PostgreSQL (\d+)\.(\d+)\.(\d+)/
|
|
58
|
+
($1.to_i * 10000) + ($2.to_i * 100) + $3.to_i
|
|
59
|
+
else
|
|
60
|
+
0
|
|
61
|
+
end
|
|
26
62
|
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def redshift?
|
|
66
|
+
# SELECT version() :
|
|
67
|
+
# 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
|
|
68
|
+
if ( redshift = config[:redshift] ).nil?
|
|
69
|
+
redshift = !! (@connection.database_product || '').index('Redshift')
|
|
27
70
|
end
|
|
71
|
+
redshift
|
|
72
|
+
end
|
|
73
|
+
private :redshift?
|
|
28
74
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
75
|
+
def use_insert_returning?
|
|
76
|
+
if @use_insert_returning.nil?
|
|
77
|
+
@use_insert_returning = supports_insert_with_returning?
|
|
78
|
+
end
|
|
79
|
+
@use_insert_returning
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def set_client_encoding(encoding)
|
|
83
|
+
ActiveRecord::Base.logger.warn "client_encoding is set by the driver and should not be altered, ('#{encoding}' ignored)"
|
|
84
|
+
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."
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Configures the encoding, verbosity, schema search path, and time zone of the connection.
|
|
88
|
+
# This is called on `connection.connect` and should not be called manually.
|
|
89
|
+
def configure_connection
|
|
90
|
+
#if encoding = config[:encoding]
|
|
91
|
+
# The client_encoding setting is set by the driver and should not be altered.
|
|
92
|
+
# If the driver detects a change it will abort the connection.
|
|
93
|
+
# see http://jdbc.postgresql.org/documentation/91/connect.html
|
|
94
|
+
# self.set_client_encoding(encoding)
|
|
95
|
+
#end
|
|
96
|
+
self.client_min_messages = config[:min_messages] || 'warning'
|
|
97
|
+
self.schema_search_path = config[:schema_search_path] || config[:schema_order]
|
|
98
|
+
|
|
99
|
+
# Use standard-conforming strings if available so we don't have to do the E'...' dance.
|
|
100
|
+
set_standard_conforming_strings
|
|
101
|
+
|
|
102
|
+
# If using Active Record's time zone support configure the connection to return
|
|
103
|
+
# TIMESTAMP WITH ZONE types in UTC.
|
|
104
|
+
# (SET TIME ZONE does not use an equals sign like other SET variables)
|
|
105
|
+
if ActiveRecord::Base.default_timezone == :utc
|
|
106
|
+
execute("SET time zone 'UTC'", 'SCHEMA')
|
|
107
|
+
elsif tz = local_tz
|
|
108
|
+
execute("SET time zone '#{tz}'", 'SCHEMA')
|
|
109
|
+
end unless redshift?
|
|
110
|
+
|
|
111
|
+
# SET statements from :variables config hash
|
|
112
|
+
# http://www.postgresql.org/docs/8.3/static/sql-set.html
|
|
113
|
+
(config[:variables] || {}).map do |k, v|
|
|
114
|
+
if v == ':default' || v == :default
|
|
115
|
+
# Sets the value to the global or compile default
|
|
116
|
+
execute("SET SESSION #{k} TO DEFAULT", 'SCHEMA')
|
|
117
|
+
elsif ! v.nil?
|
|
118
|
+
execute("SET SESSION #{k} TO #{quote(v)}", 'SCHEMA')
|
|
35
119
|
end
|
|
36
120
|
end
|
|
121
|
+
end
|
|
37
122
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
123
|
+
# @private
|
|
124
|
+
ActiveRecordError = ::ActiveRecord::ActiveRecordError
|
|
125
|
+
|
|
126
|
+
NATIVE_DATABASE_TYPES = {
|
|
127
|
+
bigserial: 'bigserial',
|
|
128
|
+
primary_key: 'serial primary key',
|
|
129
|
+
bigint: { name: 'bigint' },
|
|
130
|
+
binary: { name: 'bytea' },
|
|
131
|
+
bit: { name: 'bit' },
|
|
132
|
+
bit_varying: { name: 'bit varying' },
|
|
133
|
+
boolean: { name: 'boolean' },
|
|
134
|
+
box: { name: 'box' },
|
|
135
|
+
char: { name: 'char' },
|
|
136
|
+
cidr: { name: 'cidr' },
|
|
137
|
+
circle: { name: 'circle' },
|
|
138
|
+
citext: { name: 'citext' },
|
|
139
|
+
date: { name: 'date' },
|
|
140
|
+
daterange: { name: 'daterange' },
|
|
141
|
+
datetime: { name: 'timestamp' },
|
|
142
|
+
decimal: { name: 'decimal' }, # :limit => 1000
|
|
143
|
+
float: { name: 'float' },
|
|
144
|
+
hstore: { name: 'hstore' },
|
|
145
|
+
inet: { name: 'inet' },
|
|
146
|
+
int4range: { name: 'int4range' },
|
|
147
|
+
int8range: { name: 'int8range' },
|
|
148
|
+
integer: { name: 'integer' },
|
|
149
|
+
interval: { name: 'interval' }, # This doesn't get added to AR's postgres adapter until 5.1 but it fixes broken tests in 5.0 ...
|
|
150
|
+
json: { name: 'json' },
|
|
151
|
+
jsonb: { name: 'jsonb' },
|
|
152
|
+
line: { name: 'line' },
|
|
153
|
+
lseg: { name: 'lseg' },
|
|
154
|
+
ltree: { name: 'ltree' },
|
|
155
|
+
macaddr: { name: 'macaddr' },
|
|
156
|
+
money: { name: 'money' },
|
|
157
|
+
numeric: { name: 'numeric' },
|
|
158
|
+
numrange: { name: 'numrange' },
|
|
159
|
+
path: { name: 'path' },
|
|
160
|
+
point: { name: 'point' },
|
|
161
|
+
polygon: { name: 'polygon' },
|
|
162
|
+
serial: { name: 'serial' }, # auto-inc integer, bigserial, smallserial
|
|
163
|
+
string: { name: 'character varying' },
|
|
164
|
+
text: { name: 'text' },
|
|
165
|
+
time: { name: 'time' },
|
|
166
|
+
timestamp: { name: 'timestamp' },
|
|
167
|
+
tsrange: { name: 'tsrange' },
|
|
168
|
+
tstzrange: { name: 'tstzrange' },
|
|
169
|
+
tsvector: { name: 'tsvector' },
|
|
170
|
+
uuid: { name: 'uuid' },
|
|
171
|
+
xml: { name: 'xml' }
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
def native_database_types
|
|
175
|
+
NATIVE_DATABASE_TYPES
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def valid_type?(type)
|
|
179
|
+
!native_database_types[type].nil?
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Enable standard-conforming strings if available.
|
|
183
|
+
def set_standard_conforming_strings
|
|
184
|
+
self.standard_conforming_strings=(true)
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# Enable standard-conforming strings if available.
|
|
188
|
+
def standard_conforming_strings=(enable)
|
|
189
|
+
client_min_messages = self.client_min_messages
|
|
190
|
+
begin
|
|
191
|
+
self.client_min_messages = 'panic'
|
|
192
|
+
value = enable ? "on" : "off"
|
|
193
|
+
execute("SET standard_conforming_strings = #{value}", 'SCHEMA')
|
|
194
|
+
@standard_conforming_strings = ( value == "on" )
|
|
195
|
+
rescue
|
|
196
|
+
@standard_conforming_strings = :unsupported
|
|
197
|
+
ensure
|
|
198
|
+
self.client_min_messages = client_min_messages
|
|
47
199
|
end
|
|
200
|
+
end
|
|
48
201
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
202
|
+
def standard_conforming_strings?
|
|
203
|
+
if @standard_conforming_strings.nil?
|
|
204
|
+
client_min_messages = self.client_min_messages
|
|
205
|
+
begin
|
|
206
|
+
self.client_min_messages = 'panic'
|
|
207
|
+
value = select_one('SHOW standard_conforming_strings', 'SCHEMA')['standard_conforming_strings']
|
|
208
|
+
@standard_conforming_strings = ( value == "on" )
|
|
209
|
+
rescue
|
|
210
|
+
@standard_conforming_strings = :unsupported
|
|
211
|
+
ensure
|
|
212
|
+
self.client_min_messages = client_min_messages
|
|
55
213
|
end
|
|
56
214
|
end
|
|
215
|
+
@standard_conforming_strings == true # return false if :unsupported
|
|
216
|
+
end
|
|
57
217
|
|
|
58
|
-
|
|
59
|
-
def default_value(value)
|
|
60
|
-
# Boolean types
|
|
61
|
-
return "t" if value =~ /true/i
|
|
62
|
-
return "f" if value =~ /false/i
|
|
218
|
+
def supports_ddl_transactions?; true end
|
|
63
219
|
|
|
64
|
-
|
|
65
|
-
return $1 if value =~ /^'(.*)'::(bpchar|text|character varying|bytea)$/
|
|
220
|
+
def supports_explain?; true end
|
|
66
221
|
|
|
67
|
-
|
|
68
|
-
return value if value =~ /^-?[0-9]+(\.[0-9]*)?/
|
|
222
|
+
def supports_expression_index?; true end
|
|
69
223
|
|
|
70
|
-
|
|
71
|
-
return $1 if value =~ /^'(.+)'::(date|timestamp)/
|
|
224
|
+
def supports_foreign_keys?; true end
|
|
72
225
|
|
|
73
|
-
|
|
74
|
-
# and we can't know the value of that, so return nil.
|
|
75
|
-
return nil
|
|
76
|
-
end
|
|
77
|
-
end
|
|
226
|
+
def supports_index_sort_order?; true end
|
|
78
227
|
|
|
79
|
-
def
|
|
80
|
-
tp[:primary_key] = "serial primary key"
|
|
81
|
-
tp[:string][:limit] = 255
|
|
82
|
-
tp[:integer][:limit] = nil
|
|
83
|
-
tp[:boolean] = { :name => "boolean" }
|
|
84
|
-
tp[:float] = { :name => "float" }
|
|
85
|
-
tp[:decimal] = { :name => "decimal" }
|
|
86
|
-
tp
|
|
87
|
-
end
|
|
228
|
+
def supports_migrations?; true end
|
|
88
229
|
|
|
89
|
-
def
|
|
90
|
-
'PostgreSQL'
|
|
91
|
-
end
|
|
230
|
+
def supports_partial_index?; true end
|
|
92
231
|
|
|
93
|
-
def
|
|
94
|
-
{'jdbcpostgresql' => ::Arel::Visitors::PostgreSQL}
|
|
95
|
-
end
|
|
232
|
+
def supports_primary_key?; true end # Supports finding primary key on non-Active Record tables
|
|
96
233
|
|
|
97
|
-
def
|
|
98
|
-
@postgresql_version ||=
|
|
99
|
-
begin
|
|
100
|
-
value = select_value('SELECT version()')
|
|
101
|
-
if value =~ /PostgreSQL (\d+)\.(\d+)\.(\d+)/
|
|
102
|
-
($1.to_i * 10000) + ($2.to_i * 100) + $3.to_i
|
|
103
|
-
else
|
|
104
|
-
0
|
|
105
|
-
end
|
|
106
|
-
end
|
|
107
|
-
end
|
|
234
|
+
def supports_savepoints?; true end
|
|
108
235
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
end
|
|
236
|
+
def supports_transaction_isolation?(level = nil); true end
|
|
237
|
+
|
|
238
|
+
def supports_views?; true end
|
|
113
239
|
|
|
114
240
|
# Does PostgreSQL support standard conforming strings?
|
|
115
241
|
def supports_standard_conforming_strings?
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
client_min_messages_old = client_min_messages
|
|
120
|
-
self.client_min_messages = 'panic'
|
|
242
|
+
standard_conforming_strings?
|
|
243
|
+
@standard_conforming_strings != :unsupported
|
|
244
|
+
end
|
|
121
245
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
# PGresult instead.
|
|
125
|
-
has_support = select('SHOW standard_conforming_strings').to_a[0][0] rescue false
|
|
126
|
-
self.client_min_messages = client_min_messages_old
|
|
127
|
-
has_support
|
|
246
|
+
def supports_hex_escaped_bytea?
|
|
247
|
+
postgresql_version >= 90000
|
|
128
248
|
end
|
|
129
249
|
|
|
130
250
|
def supports_insert_with_returning?
|
|
131
251
|
postgresql_version >= 80200
|
|
132
252
|
end
|
|
133
253
|
|
|
134
|
-
|
|
135
|
-
|
|
254
|
+
# Range data-types weren't introduced until PostgreSQL 9.2.
|
|
255
|
+
def supports_ranges?
|
|
256
|
+
postgresql_version >= 90200
|
|
136
257
|
end
|
|
137
258
|
|
|
138
|
-
def
|
|
139
|
-
|
|
259
|
+
def supports_extensions?
|
|
260
|
+
postgresql_version >= 90200
|
|
140
261
|
end
|
|
141
262
|
|
|
142
|
-
def
|
|
143
|
-
|
|
263
|
+
def enable_extension(name)
|
|
264
|
+
execute("CREATE EXTENSION IF NOT EXISTS \"#{name}\"")
|
|
144
265
|
end
|
|
145
266
|
|
|
146
|
-
def
|
|
147
|
-
execute("
|
|
267
|
+
def disable_extension(name)
|
|
268
|
+
execute("DROP EXTENSION IF EXISTS \"#{name}\" CASCADE")
|
|
148
269
|
end
|
|
149
270
|
|
|
150
|
-
def
|
|
151
|
-
|
|
271
|
+
def extension_enabled?(name)
|
|
272
|
+
if supports_extensions?
|
|
273
|
+
rows = select_rows("SELECT EXISTS(SELECT * FROM pg_available_extensions WHERE name = '#{name}' AND installed_version IS NOT NULL)", 'SCHEMA')
|
|
274
|
+
available = rows.first.first # true/false or 't'/'f'
|
|
275
|
+
available == true || available == 't'
|
|
276
|
+
end
|
|
152
277
|
end
|
|
153
278
|
|
|
154
|
-
def
|
|
155
|
-
|
|
279
|
+
def extensions
|
|
280
|
+
if supports_extensions?
|
|
281
|
+
rows = select_rows "SELECT extname from pg_extension", "SCHEMA"
|
|
282
|
+
rows.map { |row| row.first }
|
|
283
|
+
else
|
|
284
|
+
[]
|
|
285
|
+
end
|
|
156
286
|
end
|
|
157
287
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
def table_alias_length
|
|
161
|
-
@table_alias_length ||= (postgresql_version >= 80000 ? select_one('SHOW max_identifier_length')['max_identifier_length'].to_i : 63)
|
|
288
|
+
def index_algorithms
|
|
289
|
+
{ :concurrently => 'CONCURRENTLY' }
|
|
162
290
|
end
|
|
163
291
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
292
|
+
# Set the authorized user for this session.
|
|
293
|
+
def session_auth=(user)
|
|
294
|
+
clear_cache!
|
|
295
|
+
execute "SET SESSION AUTHORIZATION #{user}"
|
|
167
296
|
end
|
|
168
297
|
|
|
169
|
-
#
|
|
170
|
-
def
|
|
171
|
-
unless
|
|
172
|
-
|
|
173
|
-
pk ||= default_pk
|
|
174
|
-
sequence ||= default_sequence
|
|
175
|
-
end
|
|
176
|
-
if pk
|
|
177
|
-
if sequence
|
|
178
|
-
quoted_sequence = quote_column_name(sequence)
|
|
179
|
-
|
|
180
|
-
select_value <<-end_sql, 'Reset sequence'
|
|
181
|
-
SELECT setval('#{quoted_sequence}', (SELECT COALESCE(MAX(#{quote_column_name pk})+(SELECT increment_by FROM #{quoted_sequence}), (SELECT min_value FROM #{quoted_sequence})) FROM #{quote_table_name(table)}), false)
|
|
182
|
-
end_sql
|
|
183
|
-
else
|
|
184
|
-
@logger.warn "#{table} has primary key #{pk} with no default sequence" if @logger
|
|
185
|
-
end
|
|
298
|
+
# Came from postgres_adapter
|
|
299
|
+
def get_advisory_lock(lock_id) # :nodoc:
|
|
300
|
+
unless lock_id.is_a?(Integer) && lock_id.bit_length <= 63
|
|
301
|
+
raise(ArgumentError, "Postgres requires advisory lock ids to be a signed 64 bit integer")
|
|
186
302
|
end
|
|
303
|
+
select_value("SELECT pg_try_advisory_lock(#{lock_id});")
|
|
187
304
|
end
|
|
188
305
|
|
|
189
|
-
#
|
|
190
|
-
def
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
result = select(<<-end_sql, 'PK and serial sequence')[0]
|
|
194
|
-
SELECT attr.attname, seq.relname
|
|
195
|
-
FROM pg_class seq,
|
|
196
|
-
pg_attribute attr,
|
|
197
|
-
pg_depend dep,
|
|
198
|
-
pg_namespace name,
|
|
199
|
-
pg_constraint cons
|
|
200
|
-
WHERE seq.oid = dep.objid
|
|
201
|
-
AND seq.relkind = 'S'
|
|
202
|
-
AND attr.attrelid = dep.refobjid
|
|
203
|
-
AND attr.attnum = dep.refobjsubid
|
|
204
|
-
AND attr.attrelid = cons.conrelid
|
|
205
|
-
AND attr.attnum = cons.conkey[1]
|
|
206
|
-
AND cons.contype = 'p'
|
|
207
|
-
AND dep.refobjid = '#{quote_table_name(table)}'::regclass
|
|
208
|
-
end_sql
|
|
209
|
-
|
|
210
|
-
if result.nil? or result.empty?
|
|
211
|
-
# If that fails, try parsing the primary key's default value.
|
|
212
|
-
# Support the 7.x and 8.0 nextval('foo'::text) as well as
|
|
213
|
-
# the 8.1+ nextval('foo'::regclass).
|
|
214
|
-
result = select(<<-end_sql, 'PK and custom sequence')[0]
|
|
215
|
-
SELECT attr.attname,
|
|
216
|
-
CASE
|
|
217
|
-
WHEN split_part(def.adsrc, '''', 2) ~ '.' THEN
|
|
218
|
-
substr(split_part(def.adsrc, '''', 2),
|
|
219
|
-
strpos(split_part(def.adsrc, '''', 2), '.')+1)
|
|
220
|
-
ELSE split_part(def.adsrc, '''', 2)
|
|
221
|
-
END as relname
|
|
222
|
-
FROM pg_class t
|
|
223
|
-
JOIN pg_attribute attr ON (t.oid = attrelid)
|
|
224
|
-
JOIN pg_attrdef def ON (adrelid = attrelid AND adnum = attnum)
|
|
225
|
-
JOIN pg_constraint cons ON (conrelid = adrelid AND adnum = conkey[1])
|
|
226
|
-
WHERE t.oid = '#{quote_table_name(table)}'::regclass
|
|
227
|
-
AND cons.contype = 'p'
|
|
228
|
-
AND def.adsrc ~* 'nextval'
|
|
229
|
-
end_sql
|
|
306
|
+
# Came from postgres_adapter
|
|
307
|
+
def release_advisory_lock(lock_id) # :nodoc:
|
|
308
|
+
unless lock_id.is_a?(Integer) && lock_id.bit_length <= 63
|
|
309
|
+
raise(ArgumentError, "Postgres requires advisory lock ids to be a signed 64 bit integer")
|
|
230
310
|
end
|
|
231
|
-
|
|
232
|
-
[result["attname"], result["relname"]]
|
|
233
|
-
rescue
|
|
234
|
-
nil
|
|
311
|
+
select_value("SELECT pg_advisory_unlock(#{lock_id})")
|
|
235
312
|
end
|
|
236
313
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
pk, sequence_name = *pk_and_sequence_for(table) unless pk
|
|
244
|
-
if pk
|
|
245
|
-
id_value = select_value("#{sql} RETURNING #{quote_column_name(pk)}")
|
|
246
|
-
clear_query_cache #FIXME: Why now?
|
|
247
|
-
return id_value
|
|
248
|
-
end
|
|
249
|
-
end
|
|
250
|
-
|
|
251
|
-
# Otherwise, plain insert
|
|
252
|
-
execute(sql, name)
|
|
253
|
-
|
|
254
|
-
# Don't need to look up id_value if we already have it.
|
|
255
|
-
# (and can't in case of non-sequence PK)
|
|
256
|
-
unless id_value
|
|
257
|
-
# If neither pk nor sequence name is given, look them up.
|
|
258
|
-
unless pk || sequence_name
|
|
259
|
-
pk, sequence_name = *pk_and_sequence_for(table)
|
|
260
|
-
end
|
|
314
|
+
# Returns the configured supported identifier length supported by PostgreSQL
|
|
315
|
+
def max_identifier_length
|
|
316
|
+
@max_identifier_length ||= select_one('SHOW max_identifier_length', 'SCHEMA'.freeze)['max_identifier_length'].to_i
|
|
317
|
+
end
|
|
318
|
+
alias table_alias_length max_identifier_length
|
|
319
|
+
alias index_name_length max_identifier_length
|
|
261
320
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
321
|
+
def exec_insert(sql, name, binds, pk = nil, sequence_name = nil)
|
|
322
|
+
val = super
|
|
323
|
+
if !use_insert_returning? && pk
|
|
324
|
+
unless sequence_name
|
|
325
|
+
table_ref = extract_table_ref_from_insert_sql(sql)
|
|
326
|
+
sequence_name = default_sequence_name(table_ref, pk)
|
|
327
|
+
return val unless sequence_name
|
|
266
328
|
end
|
|
329
|
+
last_insert_id_result(sequence_name)
|
|
330
|
+
else
|
|
331
|
+
val
|
|
267
332
|
end
|
|
268
|
-
id_value
|
|
269
333
|
end
|
|
270
334
|
|
|
271
|
-
def
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
parts = table_name.split(/\./)
|
|
275
|
-
table_name = parts.pop
|
|
276
|
-
schema_name = parts.join(".")
|
|
277
|
-
end
|
|
278
|
-
@connection.columns_internal(table_name, name, schema_name)
|
|
335
|
+
def explain(arel, binds = [])
|
|
336
|
+
sql = "EXPLAIN #{to_sql(arel, binds)}"
|
|
337
|
+
ActiveRecord::ConnectionAdapters::PostgreSQL::ExplainPrettyPrinter.new.pp(exec_query(sql, 'EXPLAIN', binds))
|
|
279
338
|
end
|
|
280
339
|
|
|
281
|
-
#
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
AND ( d.indkey[0]=a.attnum OR d.indkey[1]=a.attnum
|
|
293
|
-
OR d.indkey[2]=a.attnum OR d.indkey[3]=a.attnum
|
|
294
|
-
OR d.indkey[4]=a.attnum OR d.indkey[5]=a.attnum
|
|
295
|
-
OR d.indkey[6]=a.attnum OR d.indkey[7]=a.attnum
|
|
296
|
-
OR d.indkey[8]=a.attnum OR d.indkey[9]=a.attnum )
|
|
297
|
-
ORDER BY i.relname
|
|
298
|
-
SQL
|
|
299
|
-
|
|
300
|
-
current_index = nil
|
|
301
|
-
indexes = []
|
|
302
|
-
|
|
303
|
-
result.each do |row|
|
|
304
|
-
if current_index != row[0]
|
|
305
|
-
indexes << ::ActiveRecord::ConnectionAdapters::IndexDefinition.new(table_name, row[0], row[1] == "t", [])
|
|
306
|
-
current_index = row[0]
|
|
340
|
+
# @note Only for "better" AR 4.0 compatibility.
|
|
341
|
+
# @private
|
|
342
|
+
def query(sql, name = nil)
|
|
343
|
+
log(sql, name) do
|
|
344
|
+
result = []
|
|
345
|
+
@connection.execute_query_raw(sql, []) do |*values|
|
|
346
|
+
# We need to use #deep_dup here because it appears that
|
|
347
|
+
# the java method is reusing an object in some cases
|
|
348
|
+
# which makes all of the entries in the "result"
|
|
349
|
+
# array end up with the same values as the last row
|
|
350
|
+
result << values.deep_dup
|
|
307
351
|
end
|
|
308
|
-
|
|
309
|
-
indexes.last.columns << row[2]
|
|
352
|
+
result
|
|
310
353
|
end
|
|
311
|
-
|
|
312
|
-
indexes
|
|
313
|
-
end
|
|
314
|
-
|
|
315
|
-
def last_insert_id(table, sequence_name)
|
|
316
|
-
Integer(select_value("SELECT currval('#{sequence_name}')"))
|
|
317
|
-
end
|
|
318
|
-
|
|
319
|
-
def recreate_database(name)
|
|
320
|
-
drop_database(name)
|
|
321
|
-
create_database(name)
|
|
322
|
-
end
|
|
323
|
-
|
|
324
|
-
def create_database(name, options = {})
|
|
325
|
-
execute "CREATE DATABASE \"#{name}\" ENCODING='#{options[:encoding] || 'utf8'}'"
|
|
326
354
|
end
|
|
327
355
|
|
|
328
|
-
|
|
329
|
-
|
|
356
|
+
# We need to make sure to deallocate all the prepared statements
|
|
357
|
+
# since apparently calling close on the statement object
|
|
358
|
+
# doesn't always free the server resources and calling
|
|
359
|
+
# 'DISCARD ALL' fails if we are inside a transaction
|
|
360
|
+
def clear_cache!
|
|
361
|
+
super
|
|
362
|
+
@connection.execute 'DEALLOCATE ALL' if supports_statement_cache? && @connection.active?
|
|
330
363
|
end
|
|
331
364
|
|
|
332
|
-
def
|
|
333
|
-
|
|
365
|
+
def reset!
|
|
366
|
+
clear_cache!
|
|
367
|
+
reset_transaction
|
|
368
|
+
@connection.rollback # Have to deal with rollbacks differently than the AR adapter
|
|
369
|
+
@connection.execute 'DISCARD ALL'
|
|
370
|
+
@connection.configure_connection
|
|
334
371
|
end
|
|
335
372
|
|
|
336
|
-
def
|
|
337
|
-
|
|
373
|
+
def last_insert_id_result(sequence_name)
|
|
374
|
+
exec_query("SELECT currval('#{sequence_name}')", 'SQL')
|
|
338
375
|
end
|
|
339
376
|
|
|
340
377
|
def all_schemas
|
|
341
|
-
select('
|
|
378
|
+
select('SELECT nspname FROM pg_namespace').map { |row| row["nspname"] }
|
|
342
379
|
end
|
|
343
380
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
381
|
+
# Returns the current client message level.
|
|
382
|
+
def client_min_messages
|
|
383
|
+
return nil if redshift? # not supported on Redshift
|
|
384
|
+
# Need to use #execute so we don't try to access the type map before it is initialized
|
|
385
|
+
execute('SHOW client_min_messages', 'SCHEMA').values.first.first
|
|
347
386
|
end
|
|
348
387
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
raise "Could not figure out what database this url is for #{@config["url"]}"
|
|
356
|
-
end
|
|
357
|
-
end
|
|
358
|
-
|
|
359
|
-
ENV['PGHOST'] = @config[:host] if @config[:host]
|
|
360
|
-
ENV['PGPORT'] = @config[:port].to_s if @config[:port]
|
|
361
|
-
ENV['PGPASSWORD'] = @config[:password].to_s if @config[:password]
|
|
362
|
-
search_path = @config[:schema_search_path]
|
|
363
|
-
search_path = "--schema=#{search_path}" if search_path
|
|
364
|
-
|
|
365
|
-
@connection.connection.close
|
|
366
|
-
begin
|
|
367
|
-
definition = `pg_dump -i -U "#{@config[:username]}" -s -x -O #{search_path} #{database}`
|
|
368
|
-
raise "Error dumping database" if $?.exitstatus == 1
|
|
369
|
-
|
|
370
|
-
# need to patch away any references to SQL_ASCII as it breaks the JDBC driver
|
|
371
|
-
definition.gsub(/SQL_ASCII/, 'UNICODE')
|
|
372
|
-
ensure
|
|
373
|
-
reconnect!
|
|
374
|
-
end
|
|
375
|
-
end
|
|
376
|
-
|
|
377
|
-
# SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause.
|
|
378
|
-
#
|
|
379
|
-
# PostgreSQL requires the ORDER BY columns in the select list for distinct queries, and
|
|
380
|
-
# requires that the ORDER BY include the distinct column.
|
|
381
|
-
#
|
|
382
|
-
# distinct("posts.id", "posts.created_at desc")
|
|
383
|
-
def distinct(columns, order_by)
|
|
384
|
-
return "DISTINCT #{columns}" if order_by.blank?
|
|
385
|
-
|
|
386
|
-
# construct a clean list of column names from the ORDER BY clause, removing
|
|
387
|
-
# any asc/desc modifiers
|
|
388
|
-
order_columns = order_by.split(',').collect { |s| s.split.first }
|
|
389
|
-
order_columns.delete_if(&:blank?)
|
|
390
|
-
order_columns = order_columns.zip((0...order_columns.size).to_a).map { |s,i| "#{s} AS alias_#{i}" }
|
|
391
|
-
|
|
392
|
-
# return a DISTINCT ON() clause that's distinct on the columns we want but includes
|
|
393
|
-
# all the required columns for the ORDER BY to work properly
|
|
394
|
-
sql = "DISTINCT ON (#{columns}) #{columns}, "
|
|
395
|
-
sql << order_columns * ', '
|
|
388
|
+
# Set the client message level.
|
|
389
|
+
def client_min_messages=(level)
|
|
390
|
+
# NOTE: for now simply ignore the writer (no warn on Redshift) so that
|
|
391
|
+
# the AR copy-pasted PpstgreSQL parts stay the same as much as possible
|
|
392
|
+
return nil if redshift? # not supported on Redshift
|
|
393
|
+
execute("SET client_min_messages TO '#{level}'", 'SCHEMA')
|
|
396
394
|
end
|
|
397
395
|
|
|
398
396
|
# ORDER BY clause for the passed order option.
|
|
399
397
|
#
|
|
400
|
-
# PostgreSQL does not allow arbitrary ordering when using DISTINCT ON,
|
|
401
|
-
# by wrapping the
|
|
398
|
+
# PostgreSQL does not allow arbitrary ordering when using DISTINCT ON,
|
|
399
|
+
# so we work around this by wrapping the SQL as a sub-select and ordering
|
|
400
|
+
# in that query.
|
|
402
401
|
def add_order_by_for_association_limiting!(sql, options)
|
|
403
402
|
return sql if options[:order].blank?
|
|
404
403
|
|
|
@@ -409,36 +408,20 @@ module ::ArJdbc
|
|
|
409
408
|
sql.replace "SELECT * FROM (#{sql}) AS id_list ORDER BY #{order}"
|
|
410
409
|
end
|
|
411
410
|
|
|
412
|
-
|
|
413
|
-
return super unless column
|
|
414
|
-
|
|
415
|
-
if value.kind_of?(String) && column.type == :binary
|
|
416
|
-
"'#{escape_bytea(value)}'"
|
|
417
|
-
elsif value.kind_of?(String) && column.sql_type == 'xml'
|
|
418
|
-
"xml '#{quote_string(value)}'"
|
|
419
|
-
elsif value.kind_of?(Numeric) && column.sql_type == 'money'
|
|
420
|
-
# Not truly string input, so doesn't require (or allow) escape string syntax.
|
|
421
|
-
"'#{value}'"
|
|
422
|
-
elsif value.kind_of?(String) && column.sql_type =~ /^bit/
|
|
423
|
-
case value
|
|
424
|
-
when /^[01]*$/
|
|
425
|
-
"B'#{value}'" # Bit-string notation
|
|
426
|
-
when /^[0-9A-F]*$/i
|
|
427
|
-
"X'#{value}'" # Hexadecimal notation
|
|
428
|
-
end
|
|
429
|
-
else
|
|
430
|
-
super
|
|
431
|
-
end
|
|
432
|
-
end
|
|
411
|
+
# @note #quote_string implemented as native
|
|
433
412
|
|
|
434
|
-
def escape_bytea(
|
|
435
|
-
|
|
413
|
+
def escape_bytea(string)
|
|
414
|
+
return unless string
|
|
415
|
+
if supports_hex_escaped_bytea?
|
|
416
|
+
"\\x#{string.unpack("H*")[0]}"
|
|
417
|
+
else
|
|
436
418
|
result = ''
|
|
437
|
-
|
|
419
|
+
string.each_byte { |c| result << sprintf('\\\\%03o', c) }
|
|
438
420
|
result
|
|
439
421
|
end
|
|
440
422
|
end
|
|
441
423
|
|
|
424
|
+
# @override
|
|
442
425
|
def quote_table_name(name)
|
|
443
426
|
schema, name_part = extract_pg_identifier_from_name(name.to_s)
|
|
444
427
|
|
|
@@ -450,98 +433,285 @@ module ::ArJdbc
|
|
|
450
433
|
end
|
|
451
434
|
end
|
|
452
435
|
|
|
453
|
-
|
|
454
|
-
|
|
436
|
+
# @note #quote_column_name implemented as native
|
|
437
|
+
alias_method :quote_schema_name, :quote_column_name
|
|
438
|
+
|
|
439
|
+
# Need to clear the cache even though the AR adapter doesn't for some reason
|
|
440
|
+
def remove_column(table_name, column_name, type = nil, options = {})
|
|
441
|
+
super
|
|
442
|
+
clear_cache!
|
|
455
443
|
end
|
|
456
444
|
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
445
|
+
# @private
|
|
446
|
+
def column_for(table_name, column_name)
|
|
447
|
+
column_name = column_name.to_s
|
|
448
|
+
for column in columns(table_name)
|
|
449
|
+
return column if column.name == column_name
|
|
462
450
|
end
|
|
451
|
+
nil
|
|
463
452
|
end
|
|
464
453
|
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
454
|
+
# Returns the list of a table's column names, data types, and default values.
|
|
455
|
+
#
|
|
456
|
+
# If the table name is not prefixed with a schema, the database will
|
|
457
|
+
# take the first match from the schema search path.
|
|
458
|
+
#
|
|
459
|
+
# Query implementation notes:
|
|
460
|
+
# - format_type includes the column size constraint, e.g. varchar(50)
|
|
461
|
+
# - ::regclass is a function that gives the id for a table name
|
|
462
|
+
def column_definitions(table_name)
|
|
463
|
+
select_rows(<<-end_sql, 'SCHEMA')
|
|
464
|
+
SELECT a.attname, format_type(a.atttypid, a.atttypmod),
|
|
465
|
+
pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
|
|
466
|
+
(SELECT c.collname FROM pg_collation c, pg_type t
|
|
467
|
+
WHERE c.oid = a.attcollation AND t.oid = a.atttypid
|
|
468
|
+
AND a.attcollation <> t.typcollation),
|
|
469
|
+
col_description(a.attrelid, a.attnum) AS comment
|
|
470
|
+
FROM pg_attribute a
|
|
471
|
+
LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum
|
|
472
|
+
WHERE a.attrelid = '#{quote_table_name(table_name)}'::regclass
|
|
473
|
+
AND a.attnum > 0 AND NOT a.attisdropped
|
|
474
|
+
ORDER BY a.attnum
|
|
475
|
+
end_sql
|
|
476
|
+
end
|
|
477
|
+
private :column_definitions
|
|
478
|
+
|
|
479
|
+
def truncate(table_name, name = nil)
|
|
480
|
+
execute "TRUNCATE TABLE #{quote_table_name(table_name)}", name
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
# Returns an array of indexes for the given table.
|
|
484
|
+
def indexes(table_name, name = nil)
|
|
485
|
+
# FIXME: AR version => table = Utils.extract_schema_qualified_name(table_name.to_s)
|
|
486
|
+
schema, table = extract_schema_and_table(table_name.to_s)
|
|
487
|
+
|
|
488
|
+
result = query(<<-SQL, 'SCHEMA')
|
|
489
|
+
SELECT distinct i.relname, d.indisunique, d.indkey, pg_get_indexdef(d.indexrelid), t.oid,
|
|
490
|
+
pg_catalog.obj_description(i.oid, 'pg_class') AS comment,
|
|
491
|
+
(SELECT COUNT(*) FROM pg_opclass o
|
|
492
|
+
JOIN (SELECT unnest(string_to_array(d.indclass::text, ' '))::int oid) c
|
|
493
|
+
ON o.oid = c.oid WHERE o.opcdefault = 'f')
|
|
494
|
+
FROM pg_class t
|
|
495
|
+
INNER JOIN pg_index d ON t.oid = d.indrelid
|
|
496
|
+
INNER JOIN pg_class i ON d.indexrelid = i.oid
|
|
497
|
+
LEFT JOIN pg_namespace n ON n.oid = i.relnamespace
|
|
498
|
+
WHERE i.relkind = 'i'
|
|
499
|
+
AND d.indisprimary = 'f'
|
|
500
|
+
AND t.relname = '#{table}'
|
|
501
|
+
AND n.nspname = #{schema ? "'#{schema}'" : 'ANY (current_schemas(false))'}
|
|
502
|
+
ORDER BY i.relname
|
|
503
|
+
SQL
|
|
504
|
+
|
|
505
|
+
result.map do |row|
|
|
506
|
+
index_name = row[0]
|
|
507
|
+
# FIXME: These values [1,2] are returned in a different format than AR expects, maybe we could update it on the Java side to be more accurate
|
|
508
|
+
unique = row[1].is_a?(String) ? row[1] == 't' : row[1] # JDBC gets us a boolean
|
|
509
|
+
indkey = row[2].is_a?(Java::OrgPostgresqlUtil::PGobject) ? row[2].value : row[2]
|
|
510
|
+
indkey = indkey.split(" ").map(&:to_i)
|
|
511
|
+
inddef = row[3]
|
|
512
|
+
oid = row[4]
|
|
513
|
+
comment = row[5]
|
|
514
|
+
opclass = row[6]
|
|
515
|
+
|
|
516
|
+
using, expressions, where = inddef.scan(/ USING (\w+?) \((.+?)\)(?: WHERE (.+))?\z/).flatten
|
|
517
|
+
|
|
518
|
+
if indkey.include?(0) || opclass > 0
|
|
519
|
+
columns = expressions
|
|
520
|
+
else
|
|
521
|
+
columns = Hash[query(<<-SQL.strip_heredoc, "SCHEMA")].values_at(*indkey).compact
|
|
522
|
+
SELECT a.attnum, a.attname
|
|
523
|
+
FROM pg_attribute a
|
|
524
|
+
WHERE a.attrelid = #{oid}
|
|
525
|
+
AND a.attnum IN (#{indkey.join(",")})
|
|
526
|
+
SQL
|
|
527
|
+
|
|
528
|
+
# add info on sort order for columns (only desc order is explicitly specified, asc is the default)
|
|
529
|
+
orders = Hash[
|
|
530
|
+
expressions.scan(/(\w+) DESC/).flatten.map { |order_column| [order_column, :desc] }
|
|
531
|
+
]
|
|
532
|
+
end
|
|
533
|
+
|
|
534
|
+
IndexDefinition.new(table_name, index_name, unique, columns, [], orders, where, nil, using.to_sym, comment.presence)
|
|
535
|
+
end.compact
|
|
470
536
|
end
|
|
471
537
|
|
|
472
|
-
|
|
473
|
-
|
|
538
|
+
# @private
|
|
539
|
+
def column_name_for_operation(operation, node)
|
|
540
|
+
case operation
|
|
541
|
+
when 'maximum' then 'max'
|
|
542
|
+
when 'minimum' then 'min'
|
|
543
|
+
when 'average' then 'avg'
|
|
544
|
+
else operation.downcase
|
|
545
|
+
end
|
|
474
546
|
end
|
|
475
547
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
548
|
+
private
|
|
549
|
+
|
|
550
|
+
# Pulled from ActiveRecord's Postgres adapter and modified to use execute
|
|
551
|
+
def can_perform_case_insensitive_comparison_for?(column)
|
|
552
|
+
@case_insensitive_cache ||= {}
|
|
553
|
+
@case_insensitive_cache[column.sql_type] ||= begin
|
|
554
|
+
sql = <<-end_sql
|
|
555
|
+
SELECT exists(
|
|
556
|
+
SELECT * FROM pg_proc
|
|
557
|
+
WHERE proname = 'lower'
|
|
558
|
+
AND proargtypes = ARRAY[#{quote column.sql_type}::regtype]::oidvector
|
|
559
|
+
) OR exists(
|
|
560
|
+
SELECT * FROM pg_proc
|
|
561
|
+
INNER JOIN pg_cast
|
|
562
|
+
ON ARRAY[casttarget]::oidvector = proargtypes
|
|
563
|
+
WHERE proname = 'lower'
|
|
564
|
+
AND castsource = #{quote column.sql_type}::regtype
|
|
565
|
+
)
|
|
566
|
+
end_sql
|
|
567
|
+
select_value(sql, 'SCHEMA')
|
|
482
568
|
end
|
|
483
569
|
end
|
|
484
570
|
|
|
485
|
-
def
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
commit_db_transaction
|
|
571
|
+
def translate_exception(exception, message)
|
|
572
|
+
case exception.message
|
|
573
|
+
when /duplicate key value violates unique constraint/
|
|
574
|
+
::ActiveRecord::RecordNotUnique.new(message)
|
|
575
|
+
when /violates foreign key constraint/
|
|
576
|
+
::ActiveRecord::InvalidForeignKey.new(message)
|
|
577
|
+
when /value too long/
|
|
578
|
+
::ActiveRecord::ValueTooLong.new(message)
|
|
579
|
+
else
|
|
580
|
+
super
|
|
496
581
|
end
|
|
497
|
-
change_column_default(table_name, column_name, options[:default]) unless options[:default].nil?
|
|
498
582
|
end
|
|
499
583
|
|
|
500
|
-
|
|
501
|
-
|
|
584
|
+
# @private `Utils.extract_schema_and_table` from AR
|
|
585
|
+
def extract_schema_and_table(name)
|
|
586
|
+
result = name.scan(/[^".\s]+|"[^"]*"/)[0, 2]
|
|
587
|
+
result.each { |m| m.gsub!(/(^"|"$)/, '') }
|
|
588
|
+
result.unshift(nil) if result.size == 1 # schema == nil
|
|
589
|
+
result # [schema, table]
|
|
502
590
|
end
|
|
503
591
|
|
|
504
|
-
def
|
|
505
|
-
|
|
506
|
-
|
|
592
|
+
def extract_pg_identifier_from_name(name)
|
|
593
|
+
match_data = name[0, 1] == '"' ? name.match(/\"([^\"]+)\"/) : name.match(/([^\.]+)/)
|
|
594
|
+
|
|
595
|
+
if match_data
|
|
596
|
+
rest = name[match_data[0].length..-1]
|
|
597
|
+
rest = rest[1..-1] if rest[0, 1] == "."
|
|
598
|
+
[match_data[1], (rest.length > 0 ? rest : nil)]
|
|
507
599
|
end
|
|
508
|
-
execute("ALTER TABLE #{quote_table_name(table_name)} ALTER #{quote_column_name(column_name)} #{null ? 'DROP' : 'SET'} NOT NULL")
|
|
509
600
|
end
|
|
510
601
|
|
|
511
|
-
def
|
|
512
|
-
|
|
602
|
+
def extract_table_ref_from_insert_sql(sql)
|
|
603
|
+
sql[/into\s("[A-Za-z0-9_."\[\]\s]+"|[A-Za-z0-9_."\[\]]+)\s*/im]
|
|
604
|
+
$1.strip if $1
|
|
513
605
|
end
|
|
514
606
|
|
|
515
|
-
def
|
|
516
|
-
execute
|
|
607
|
+
def local_tz
|
|
608
|
+
@local_tz ||= execute('SHOW TIME ZONE', 'SCHEMA').first["TimeZone"]
|
|
517
609
|
end
|
|
518
610
|
|
|
519
|
-
|
|
520
|
-
|
|
611
|
+
end
|
|
612
|
+
end
|
|
613
|
+
|
|
614
|
+
require 'arjdbc/util/quoted_cache'
|
|
615
|
+
|
|
616
|
+
module ActiveRecord::ConnectionAdapters
|
|
617
|
+
|
|
618
|
+
# NOTE: seems needed on 4.x due loading of '.../postgresql/oid' which
|
|
619
|
+
# assumes: class PostgreSQLAdapter < AbstractAdapter
|
|
620
|
+
remove_const(:PostgreSQLAdapter) if const_defined?(:PostgreSQLAdapter)
|
|
621
|
+
|
|
622
|
+
class PostgreSQLAdapter < AbstractAdapter
|
|
623
|
+
|
|
624
|
+
# Try to use as much of the built in postgres logic as possible
|
|
625
|
+
# maybe someday we can extend the actual adapter
|
|
626
|
+
include ActiveRecord::ConnectionAdapters::PostgreSQL::ColumnDumper
|
|
627
|
+
include ActiveRecord::ConnectionAdapters::PostgreSQL::ReferentialIntegrity
|
|
628
|
+
include ActiveRecord::ConnectionAdapters::PostgreSQL::SchemaStatements
|
|
629
|
+
include ActiveRecord::ConnectionAdapters::PostgreSQL::Quoting
|
|
630
|
+
|
|
631
|
+
include Jdbc::ConnectionPoolCallbacks
|
|
521
632
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
633
|
+
include ArJdbc::Abstract::Core
|
|
634
|
+
include ArJdbc::Abstract::ConnectionManagement
|
|
635
|
+
include ArJdbc::Abstract::DatabaseStatements
|
|
636
|
+
include ArJdbc::Abstract::StatementCache
|
|
637
|
+
include ArJdbc::Abstract::TransactionSupport
|
|
638
|
+
include ArJdbc::PostgreSQL
|
|
639
|
+
|
|
640
|
+
require 'arjdbc/postgresql/oid_types'
|
|
641
|
+
include ::ArJdbc::PostgreSQL::OIDTypes
|
|
642
|
+
|
|
643
|
+
load 'arjdbc/postgresql/_bc_time_cast_patch.rb'
|
|
644
|
+
|
|
645
|
+
include ::ArJdbc::PostgreSQL::ColumnHelpers
|
|
646
|
+
|
|
647
|
+
include ::ArJdbc::Util::QuotedCache
|
|
648
|
+
|
|
649
|
+
# AR expects OID to be available on the adapter
|
|
650
|
+
OID = ActiveRecord::ConnectionAdapters::PostgreSQL::OID
|
|
651
|
+
|
|
652
|
+
def initialize(connection, logger = nil, config = {})
|
|
653
|
+
# @local_tz is initialized as nil to avoid warnings when connect tries to use it
|
|
654
|
+
@local_tz = nil
|
|
655
|
+
|
|
656
|
+
super # configure_connection happens in super
|
|
657
|
+
|
|
658
|
+
initialize_type_map(@type_map = Type::HashLookupTypeMap.new)
|
|
659
|
+
|
|
660
|
+
@use_insert_returning = @config.key?(:insert_returning) ?
|
|
661
|
+
self.class.type_cast_config_to_boolean(@config[:insert_returning]) : nil
|
|
662
|
+
end
|
|
663
|
+
|
|
664
|
+
def arel_visitor # :nodoc:
|
|
665
|
+
Arel::Visitors::PostgreSQL.new(self)
|
|
666
|
+
end
|
|
667
|
+
|
|
668
|
+
require 'active_record/connection_adapters/postgresql/schema_definitions'
|
|
669
|
+
|
|
670
|
+
ColumnDefinition = ActiveRecord::ConnectionAdapters::PostgreSQL::ColumnDefinition
|
|
671
|
+
ColumnMethods = ActiveRecord::ConnectionAdapters::PostgreSQL::ColumnMethods
|
|
672
|
+
TableDefinition = ActiveRecord::ConnectionAdapters::PostgreSQL::TableDefinition
|
|
673
|
+
Table = ActiveRecord::ConnectionAdapters::PostgreSQL::Table
|
|
674
|
+
|
|
675
|
+
def create_table_definition(*args) # :nodoc:
|
|
676
|
+
TableDefinition.new(*args)
|
|
677
|
+
end
|
|
678
|
+
|
|
679
|
+
def exec_query(sql, name = nil, binds = [], prepare: false)
|
|
680
|
+
super
|
|
681
|
+
rescue ActiveRecord::StatementInvalid => e
|
|
682
|
+
raise unless e.cause.message.include?('cached plan must not change result type'.freeze)
|
|
683
|
+
|
|
684
|
+
if open_transactions > 0
|
|
685
|
+
# In a transaction, have to fail it - See AR code for details
|
|
686
|
+
raise ActiveRecord::PreparedStatementCacheExpired.new(e.cause.message)
|
|
526
687
|
else
|
|
527
|
-
|
|
688
|
+
# Not in a transaction, clear the prepared statement and try again
|
|
689
|
+
delete_cached_statement(sql)
|
|
690
|
+
retry
|
|
528
691
|
end
|
|
529
692
|
end
|
|
530
693
|
|
|
531
|
-
|
|
532
|
-
|
|
694
|
+
public :sql_for_insert
|
|
695
|
+
|
|
696
|
+
def schema_creation # :nodoc:
|
|
697
|
+
PostgreSQL::SchemaCreation.new self
|
|
698
|
+
end
|
|
699
|
+
|
|
700
|
+
def update_table_definition(table_name, base)
|
|
701
|
+
Table.new(table_name, base)
|
|
702
|
+
end
|
|
703
|
+
|
|
704
|
+
def jdbc_connection_class(spec)
|
|
705
|
+
::ArJdbc::PostgreSQL.jdbc_connection_class
|
|
533
706
|
end
|
|
534
707
|
|
|
535
708
|
private
|
|
536
|
-
def extract_pg_identifier_from_name(name)
|
|
537
|
-
match_data = name[0,1] == '"' ? name.match(/\"([^\"]+)\"/) : name.match(/([^\.]+)/)
|
|
538
709
|
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
end
|
|
710
|
+
# Prepared statements aren't schema aware so we need to make sure we
|
|
711
|
+
# store different PreparedStatement objects for different schemas
|
|
712
|
+
def cached_statement_key(sql)
|
|
713
|
+
"#{schema_search_path}-#{sql}"
|
|
544
714
|
end
|
|
715
|
+
|
|
545
716
|
end
|
|
546
717
|
end
|
|
547
|
-
|