activerecord-jdbc-alt-adapter 50.3.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.
Files changed (198) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +35 -0
  3. data/.travis.yml +100 -0
  4. data/.yardopts +4 -0
  5. data/CONTRIBUTING.md +50 -0
  6. data/Gemfile +92 -0
  7. data/History.md +1191 -0
  8. data/LICENSE.txt +26 -0
  9. data/README.md +240 -0
  10. data/RUNNING_TESTS.md +127 -0
  11. data/Rakefile +336 -0
  12. data/Rakefile.jdbc +20 -0
  13. data/activerecord-jdbc-adapter.gemspec +55 -0
  14. data/activerecord-jdbc-alt-adapter.gemspec +56 -0
  15. data/lib/active_record/connection_adapters/as400_adapter.rb +2 -0
  16. data/lib/active_record/connection_adapters/db2_adapter.rb +1 -0
  17. data/lib/active_record/connection_adapters/derby_adapter.rb +1 -0
  18. data/lib/active_record/connection_adapters/firebird_adapter.rb +1 -0
  19. data/lib/active_record/connection_adapters/h2_adapter.rb +1 -0
  20. data/lib/active_record/connection_adapters/hsqldb_adapter.rb +1 -0
  21. data/lib/active_record/connection_adapters/informix_adapter.rb +1 -0
  22. data/lib/active_record/connection_adapters/jdbc_adapter.rb +1 -0
  23. data/lib/active_record/connection_adapters/jndi_adapter.rb +1 -0
  24. data/lib/active_record/connection_adapters/mariadb_adapter.rb +1 -0
  25. data/lib/active_record/connection_adapters/mssql_adapter.rb +1 -0
  26. data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -0
  27. data/lib/active_record/connection_adapters/mysql_adapter.rb +1 -0
  28. data/lib/active_record/connection_adapters/postgresql_adapter.rb +1 -0
  29. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +1 -0
  30. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +1 -0
  31. data/lib/activerecord-jdbc-adapter.rb +1 -0
  32. data/lib/arel/visitors/compat.rb +60 -0
  33. data/lib/arel/visitors/db2.rb +137 -0
  34. data/lib/arel/visitors/derby.rb +112 -0
  35. data/lib/arel/visitors/firebird.rb +79 -0
  36. data/lib/arel/visitors/h2.rb +25 -0
  37. data/lib/arel/visitors/hsqldb.rb +32 -0
  38. data/lib/arel/visitors/postgresql_jdbc.rb +6 -0
  39. data/lib/arel/visitors/sql_server.rb +225 -0
  40. data/lib/arel/visitors/sql_server/ng42.rb +294 -0
  41. data/lib/arel/visitors/sqlserver.rb +214 -0
  42. data/lib/arjdbc.rb +19 -0
  43. data/lib/arjdbc/abstract/connection_management.rb +35 -0
  44. data/lib/arjdbc/abstract/core.rb +74 -0
  45. data/lib/arjdbc/abstract/database_statements.rb +64 -0
  46. data/lib/arjdbc/abstract/statement_cache.rb +58 -0
  47. data/lib/arjdbc/abstract/transaction_support.rb +86 -0
  48. data/lib/arjdbc/db2.rb +4 -0
  49. data/lib/arjdbc/db2/adapter.rb +789 -0
  50. data/lib/arjdbc/db2/as400.rb +130 -0
  51. data/lib/arjdbc/db2/column.rb +167 -0
  52. data/lib/arjdbc/db2/connection_methods.rb +44 -0
  53. data/lib/arjdbc/derby.rb +3 -0
  54. data/lib/arjdbc/derby/active_record_patch.rb +13 -0
  55. data/lib/arjdbc/derby/adapter.rb +540 -0
  56. data/lib/arjdbc/derby/connection_methods.rb +20 -0
  57. data/lib/arjdbc/derby/schema_creation.rb +15 -0
  58. data/lib/arjdbc/discover.rb +104 -0
  59. data/lib/arjdbc/firebird.rb +4 -0
  60. data/lib/arjdbc/firebird/adapter.rb +434 -0
  61. data/lib/arjdbc/firebird/connection_methods.rb +23 -0
  62. data/lib/arjdbc/h2.rb +3 -0
  63. data/lib/arjdbc/h2/adapter.rb +303 -0
  64. data/lib/arjdbc/h2/connection_methods.rb +27 -0
  65. data/lib/arjdbc/hsqldb.rb +3 -0
  66. data/lib/arjdbc/hsqldb/adapter.rb +297 -0
  67. data/lib/arjdbc/hsqldb/connection_methods.rb +28 -0
  68. data/lib/arjdbc/hsqldb/explain_support.rb +35 -0
  69. data/lib/arjdbc/hsqldb/schema_creation.rb +11 -0
  70. data/lib/arjdbc/informix.rb +5 -0
  71. data/lib/arjdbc/informix/adapter.rb +162 -0
  72. data/lib/arjdbc/informix/connection_methods.rb +9 -0
  73. data/lib/arjdbc/jdbc.rb +59 -0
  74. data/lib/arjdbc/jdbc/adapter.rb +475 -0
  75. data/lib/arjdbc/jdbc/adapter_require.rb +46 -0
  76. data/lib/arjdbc/jdbc/base_ext.rb +15 -0
  77. data/lib/arjdbc/jdbc/callbacks.rb +53 -0
  78. data/lib/arjdbc/jdbc/column.rb +97 -0
  79. data/lib/arjdbc/jdbc/connection.rb +14 -0
  80. data/lib/arjdbc/jdbc/connection_methods.rb +37 -0
  81. data/lib/arjdbc/jdbc/error.rb +65 -0
  82. data/lib/arjdbc/jdbc/extension.rb +59 -0
  83. data/lib/arjdbc/jdbc/java.rb +13 -0
  84. data/lib/arjdbc/jdbc/railtie.rb +2 -0
  85. data/lib/arjdbc/jdbc/rake_tasks.rb +3 -0
  86. data/lib/arjdbc/jdbc/serialized_attributes_helper.rb +3 -0
  87. data/lib/arjdbc/jdbc/type_cast.rb +166 -0
  88. data/lib/arjdbc/jdbc/type_converter.rb +142 -0
  89. data/lib/arjdbc/mssql.rb +7 -0
  90. data/lib/arjdbc/mssql/adapter.rb +384 -0
  91. data/lib/arjdbc/mssql/column.rb +29 -0
  92. data/lib/arjdbc/mssql/connection_methods.rb +79 -0
  93. data/lib/arjdbc/mssql/database_statements.rb +134 -0
  94. data/lib/arjdbc/mssql/errors.rb +6 -0
  95. data/lib/arjdbc/mssql/explain_support.rb +129 -0
  96. data/lib/arjdbc/mssql/extensions.rb +36 -0
  97. data/lib/arjdbc/mssql/limit_helpers.rb +231 -0
  98. data/lib/arjdbc/mssql/lock_methods.rb +77 -0
  99. data/lib/arjdbc/mssql/old_adapter.rb +804 -0
  100. data/lib/arjdbc/mssql/old_column.rb +200 -0
  101. data/lib/arjdbc/mssql/quoting.rb +101 -0
  102. data/lib/arjdbc/mssql/schema_creation.rb +31 -0
  103. data/lib/arjdbc/mssql/schema_definitions.rb +74 -0
  104. data/lib/arjdbc/mssql/schema_statements.rb +329 -0
  105. data/lib/arjdbc/mssql/transaction.rb +69 -0
  106. data/lib/arjdbc/mssql/types.rb +52 -0
  107. data/lib/arjdbc/mssql/types/binary_types.rb +33 -0
  108. data/lib/arjdbc/mssql/types/date_and_time_types.rb +134 -0
  109. data/lib/arjdbc/mssql/types/deprecated_types.rb +40 -0
  110. data/lib/arjdbc/mssql/types/numeric_types.rb +71 -0
  111. data/lib/arjdbc/mssql/types/string_types.rb +56 -0
  112. data/lib/arjdbc/mssql/utils.rb +66 -0
  113. data/lib/arjdbc/mysql.rb +3 -0
  114. data/lib/arjdbc/mysql/adapter.rb +140 -0
  115. data/lib/arjdbc/mysql/connection_methods.rb +166 -0
  116. data/lib/arjdbc/oracle/adapter.rb +863 -0
  117. data/lib/arjdbc/postgresql.rb +3 -0
  118. data/lib/arjdbc/postgresql/adapter.rb +687 -0
  119. data/lib/arjdbc/postgresql/base/array_decoder.rb +26 -0
  120. data/lib/arjdbc/postgresql/base/array_encoder.rb +25 -0
  121. data/lib/arjdbc/postgresql/base/array_parser.rb +95 -0
  122. data/lib/arjdbc/postgresql/base/pgconn.rb +11 -0
  123. data/lib/arjdbc/postgresql/column.rb +51 -0
  124. data/lib/arjdbc/postgresql/connection_methods.rb +67 -0
  125. data/lib/arjdbc/postgresql/name.rb +24 -0
  126. data/lib/arjdbc/postgresql/oid_types.rb +266 -0
  127. data/lib/arjdbc/railtie.rb +11 -0
  128. data/lib/arjdbc/sqlite3.rb +3 -0
  129. data/lib/arjdbc/sqlite3/adapter.rb +678 -0
  130. data/lib/arjdbc/sqlite3/connection_methods.rb +59 -0
  131. data/lib/arjdbc/sybase.rb +2 -0
  132. data/lib/arjdbc/sybase/adapter.rb +47 -0
  133. data/lib/arjdbc/tasks.rb +13 -0
  134. data/lib/arjdbc/tasks/database_tasks.rb +31 -0
  135. data/lib/arjdbc/tasks/databases.rake +48 -0
  136. data/lib/arjdbc/tasks/db2_database_tasks.rb +104 -0
  137. data/lib/arjdbc/tasks/derby_database_tasks.rb +95 -0
  138. data/lib/arjdbc/tasks/h2_database_tasks.rb +31 -0
  139. data/lib/arjdbc/tasks/hsqldb_database_tasks.rb +70 -0
  140. data/lib/arjdbc/tasks/jdbc_database_tasks.rb +169 -0
  141. data/lib/arjdbc/tasks/mssql_database_tasks.rb +46 -0
  142. data/lib/arjdbc/util/quoted_cache.rb +60 -0
  143. data/lib/arjdbc/util/serialized_attributes.rb +98 -0
  144. data/lib/arjdbc/util/table_copier.rb +110 -0
  145. data/lib/arjdbc/version.rb +3 -0
  146. data/lib/generators/jdbc/USAGE +9 -0
  147. data/lib/generators/jdbc/jdbc_generator.rb +17 -0
  148. data/lib/jdbc_adapter.rb +2 -0
  149. data/lib/jdbc_adapter/rake_tasks.rb +4 -0
  150. data/lib/jdbc_adapter/version.rb +4 -0
  151. data/pom.xml +114 -0
  152. data/rails_generators/jdbc_generator.rb +15 -0
  153. data/rails_generators/templates/config/initializers/jdbc.rb +10 -0
  154. data/rails_generators/templates/lib/tasks/jdbc.rake +11 -0
  155. data/rakelib/01-tomcat.rake +51 -0
  156. data/rakelib/02-test.rake +132 -0
  157. data/rakelib/bundler_ext.rb +11 -0
  158. data/rakelib/db.rake +75 -0
  159. data/rakelib/rails.rake +223 -0
  160. data/src/java/arjdbc/ArJdbcModule.java +276 -0
  161. data/src/java/arjdbc/db2/DB2Module.java +76 -0
  162. data/src/java/arjdbc/db2/DB2RubyJdbcConnection.java +126 -0
  163. data/src/java/arjdbc/derby/DerbyModule.java +178 -0
  164. data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +152 -0
  165. data/src/java/arjdbc/firebird/FirebirdRubyJdbcConnection.java +174 -0
  166. data/src/java/arjdbc/h2/H2Module.java +50 -0
  167. data/src/java/arjdbc/h2/H2RubyJdbcConnection.java +85 -0
  168. data/src/java/arjdbc/hsqldb/HSQLDBModule.java +73 -0
  169. data/src/java/arjdbc/informix/InformixRubyJdbcConnection.java +75 -0
  170. data/src/java/arjdbc/jdbc/AdapterJavaService.java +43 -0
  171. data/src/java/arjdbc/jdbc/Callable.java +44 -0
  172. data/src/java/arjdbc/jdbc/ConnectionFactory.java +45 -0
  173. data/src/java/arjdbc/jdbc/DataSourceConnectionFactory.java +156 -0
  174. data/src/java/arjdbc/jdbc/DriverConnectionFactory.java +63 -0
  175. data/src/java/arjdbc/jdbc/DriverWrapper.java +119 -0
  176. data/src/java/arjdbc/jdbc/JdbcResult.java +130 -0
  177. data/src/java/arjdbc/jdbc/RubyConnectionFactory.java +61 -0
  178. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +3979 -0
  179. data/src/java/arjdbc/mssql/MSSQLModule.java +90 -0
  180. data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +508 -0
  181. data/src/java/arjdbc/mysql/MySQLModule.java +152 -0
  182. data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +294 -0
  183. data/src/java/arjdbc/oracle/OracleModule.java +80 -0
  184. data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +455 -0
  185. data/src/java/arjdbc/postgresql/ByteaUtils.java +157 -0
  186. data/src/java/arjdbc/postgresql/PgDateTimeUtils.java +52 -0
  187. data/src/java/arjdbc/postgresql/PostgreSQLModule.java +77 -0
  188. data/src/java/arjdbc/postgresql/PostgreSQLResult.java +192 -0
  189. data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +948 -0
  190. data/src/java/arjdbc/sqlite3/SQLite3Module.java +73 -0
  191. data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +525 -0
  192. data/src/java/arjdbc/util/CallResultSet.java +826 -0
  193. data/src/java/arjdbc/util/DateTimeUtils.java +699 -0
  194. data/src/java/arjdbc/util/ObjectSupport.java +65 -0
  195. data/src/java/arjdbc/util/QuotingUtils.java +137 -0
  196. data/src/java/arjdbc/util/StringCache.java +63 -0
  197. data/src/java/arjdbc/util/StringHelper.java +145 -0
  198. metadata +269 -0
@@ -0,0 +1,3 @@
1
+ require 'arjdbc'
2
+ require 'arjdbc/postgresql/adapter'
3
+ require 'arjdbc/postgresql/connection_methods'
@@ -0,0 +1,687 @@
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.
25
+ module PostgreSQL
26
+
27
+ require 'arjdbc/postgresql/column'
28
+ require 'arel/visitors/postgresql_jdbc'
29
+ # @private
30
+ IndexDefinition = ::ActiveRecord::ConnectionAdapters::IndexDefinition
31
+
32
+ # @private
33
+ ForeignKeyDefinition = ::ActiveRecord::ConnectionAdapters::ForeignKeyDefinition
34
+
35
+ # @private
36
+ Type = ::ActiveRecord::Type
37
+
38
+ # @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_connection_class
39
+ def self.jdbc_connection_class
40
+ ::ActiveRecord::ConnectionAdapters::PostgreSQLJdbcConnection
41
+ end
42
+
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 match = version.match(/([\d\.]*\d).*?/)
58
+ version = match[1].split('.').map(&:to_i)
59
+ # PostgreSQL version representation does not have more than 4 digits
60
+ # From version 10 onwards, PG has changed its versioning policy to
61
+ # limit it to only 2 digits. i.e. in 10.x, 10 being the major
62
+ # version and x representing the patch release
63
+ # Refer to:
64
+ # https://www.postgresql.org/support/versioning/
65
+ # https://www.postgresql.org/docs/10/static/libpq-status.html -> PQserverVersion()
66
+ # for more info
67
+
68
+ if version.size >= 3
69
+ (version[0] * 100 + version[1]) * 100 + version[2]
70
+ elsif version.size == 2
71
+ if version[0] >= 10
72
+ version[0] * 100 * 100 + version[1]
73
+ else
74
+ (version[0] * 100 + version[1]) * 100
75
+ end
76
+ elsif version.size == 1
77
+ version[0] * 100 * 100
78
+ else
79
+ 0
80
+ end
81
+ else
82
+ 0
83
+ end
84
+ end
85
+ end
86
+
87
+ def redshift?
88
+ # SELECT version() :
89
+ # 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
90
+ if ( redshift = config[:redshift] ).nil?
91
+ redshift = !! (@connection.database_product || '').index('Redshift')
92
+ end
93
+ redshift
94
+ end
95
+ private :redshift?
96
+
97
+ def use_insert_returning?
98
+ if @use_insert_returning.nil?
99
+ @use_insert_returning = supports_insert_with_returning?
100
+ end
101
+ @use_insert_returning
102
+ end
103
+
104
+ def set_client_encoding(encoding)
105
+ ActiveRecord::Base.logger.warn "client_encoding is set by the driver and should not be altered, ('#{encoding}' ignored)"
106
+ 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."
107
+ end
108
+
109
+ # Configures the encoding, verbosity, schema search path, and time zone of the connection.
110
+ # This is called on `connection.connect` and should not be called manually.
111
+ def configure_connection
112
+ #if encoding = config[:encoding]
113
+ # The client_encoding setting is set by the driver and should not be altered.
114
+ # If the driver detects a change it will abort the connection.
115
+ # see http://jdbc.postgresql.org/documentation/91/connect.html
116
+ # self.set_client_encoding(encoding)
117
+ #end
118
+ self.client_min_messages = config[:min_messages] || 'warning'
119
+ self.schema_search_path = config[:schema_search_path] || config[:schema_order]
120
+
121
+ # Use standard-conforming strings if available so we don't have to do the E'...' dance.
122
+ set_standard_conforming_strings
123
+
124
+ # If using Active Record's time zone support configure the connection to return
125
+ # TIMESTAMP WITH ZONE types in UTC.
126
+ # (SET TIME ZONE does not use an equals sign like other SET variables)
127
+ if ActiveRecord::Base.default_timezone == :utc
128
+ execute("SET time zone 'UTC'", 'SCHEMA')
129
+ elsif tz = local_tz
130
+ execute("SET time zone '#{tz}'", 'SCHEMA')
131
+ end unless redshift?
132
+
133
+ # SET statements from :variables config hash
134
+ # http://www.postgresql.org/docs/8.3/static/sql-set.html
135
+ (config[:variables] || {}).map do |k, v|
136
+ if v == ':default' || v == :default
137
+ # Sets the value to the global or compile default
138
+ execute("SET SESSION #{k} TO DEFAULT", 'SCHEMA')
139
+ elsif ! v.nil?
140
+ execute("SET SESSION #{k} TO #{quote(v)}", 'SCHEMA')
141
+ end
142
+ end
143
+ end
144
+
145
+ # @private
146
+ ActiveRecordError = ::ActiveRecord::ActiveRecordError
147
+
148
+ NATIVE_DATABASE_TYPES = {
149
+ bigserial: 'bigserial',
150
+ primary_key: 'serial primary key',
151
+ bigint: { name: 'bigint' },
152
+ binary: { name: 'bytea' },
153
+ bit: { name: 'bit' },
154
+ bit_varying: { name: 'bit varying' },
155
+ boolean: { name: 'boolean' },
156
+ box: { name: 'box' },
157
+ char: { name: 'char' },
158
+ cidr: { name: 'cidr' },
159
+ circle: { name: 'circle' },
160
+ citext: { name: 'citext' },
161
+ date: { name: 'date' },
162
+ daterange: { name: 'daterange' },
163
+ datetime: { name: 'timestamp' },
164
+ decimal: { name: 'decimal' }, # :limit => 1000
165
+ float: { name: 'float' },
166
+ hstore: { name: 'hstore' },
167
+ inet: { name: 'inet' },
168
+ int4range: { name: 'int4range' },
169
+ int8range: { name: 'int8range' },
170
+ integer: { name: 'integer' },
171
+ interval: { name: 'interval' }, # This doesn't get added to AR's postgres adapter until 5.1 but it fixes broken tests in 5.0 ...
172
+ json: { name: 'json' },
173
+ jsonb: { name: 'jsonb' },
174
+ line: { name: 'line' },
175
+ lseg: { name: 'lseg' },
176
+ ltree: { name: 'ltree' },
177
+ macaddr: { name: 'macaddr' },
178
+ money: { name: 'money' },
179
+ numeric: { name: 'numeric' },
180
+ numrange: { name: 'numrange' },
181
+ path: { name: 'path' },
182
+ point: { name: 'point' },
183
+ polygon: { name: 'polygon' },
184
+ serial: { name: 'serial' }, # auto-inc integer, bigserial, smallserial
185
+ string: { name: 'character varying' },
186
+ text: { name: 'text' },
187
+ time: { name: 'time' },
188
+ timestamp: { name: 'timestamp' },
189
+ tsrange: { name: 'tsrange' },
190
+ tstzrange: { name: 'tstzrange' },
191
+ tsvector: { name: 'tsvector' },
192
+ uuid: { name: 'uuid' },
193
+ xml: { name: 'xml' }
194
+ }
195
+
196
+ def native_database_types
197
+ NATIVE_DATABASE_TYPES
198
+ end
199
+
200
+ def valid_type?(type)
201
+ !native_database_types[type].nil?
202
+ end
203
+
204
+ # Enable standard-conforming strings if available.
205
+ def set_standard_conforming_strings
206
+ self.standard_conforming_strings=(true)
207
+ end
208
+
209
+ # Enable standard-conforming strings if available.
210
+ def standard_conforming_strings=(enable)
211
+ client_min_messages = self.client_min_messages
212
+ begin
213
+ self.client_min_messages = 'panic'
214
+ value = enable ? "on" : "off"
215
+ execute("SET standard_conforming_strings = #{value}", 'SCHEMA')
216
+ @standard_conforming_strings = ( value == "on" )
217
+ rescue
218
+ @standard_conforming_strings = :unsupported
219
+ ensure
220
+ self.client_min_messages = client_min_messages
221
+ end
222
+ end
223
+
224
+ def standard_conforming_strings?
225
+ if @standard_conforming_strings.nil?
226
+ client_min_messages = self.client_min_messages
227
+ begin
228
+ self.client_min_messages = 'panic'
229
+ value = select_one('SHOW standard_conforming_strings', 'SCHEMA')['standard_conforming_strings']
230
+ @standard_conforming_strings = ( value == "on" )
231
+ rescue
232
+ @standard_conforming_strings = :unsupported
233
+ ensure
234
+ self.client_min_messages = client_min_messages
235
+ end
236
+ end
237
+ @standard_conforming_strings == true # return false if :unsupported
238
+ end
239
+
240
+ def supports_ddl_transactions?; true end
241
+
242
+ def supports_advisory_locks?; true end
243
+
244
+ def supports_explain?; true end
245
+
246
+ def supports_expression_index?; true end
247
+
248
+ def supports_foreign_keys?; true end
249
+
250
+ def supports_index_sort_order?; true end
251
+
252
+ def supports_migrations?; true end
253
+
254
+ def supports_partial_index?; true end
255
+
256
+ def supports_primary_key?; true end # Supports finding primary key on non-Active Record tables
257
+
258
+ def supports_savepoints?; true end
259
+
260
+ def supports_transaction_isolation?(level = nil); true end
261
+
262
+ def supports_views?; true end
263
+
264
+ def supports_datetime_with_precision?; true end
265
+
266
+ def supports_comments?; true end
267
+
268
+ # Does PostgreSQL support standard conforming strings?
269
+ def supports_standard_conforming_strings?
270
+ standard_conforming_strings?
271
+ @standard_conforming_strings != :unsupported
272
+ end
273
+
274
+ def supports_hex_escaped_bytea?
275
+ postgresql_version >= 90000
276
+ end
277
+
278
+ def supports_materialized_views?
279
+ postgresql_version >= 90300
280
+ end
281
+
282
+ def supports_json?
283
+ postgresql_version >= 90200
284
+ end
285
+
286
+ def supports_insert_with_returning?
287
+ postgresql_version >= 80200
288
+ end
289
+
290
+ # Range data-types weren't introduced until PostgreSQL 9.2.
291
+ def supports_ranges?
292
+ postgresql_version >= 90200
293
+ end
294
+
295
+ def supports_extensions?
296
+ postgresql_version >= 90200
297
+ end
298
+
299
+ def enable_extension(name)
300
+ execute("CREATE EXTENSION IF NOT EXISTS \"#{name}\"")
301
+ end
302
+
303
+ def disable_extension(name)
304
+ execute("DROP EXTENSION IF EXISTS \"#{name}\" CASCADE")
305
+ end
306
+
307
+ def extension_enabled?(name)
308
+ if supports_extensions?
309
+ rows = select_rows("SELECT EXISTS(SELECT * FROM pg_available_extensions WHERE name = '#{name}' AND installed_version IS NOT NULL)", 'SCHEMA')
310
+ available = rows.first.first # true/false or 't'/'f'
311
+ available == true || available == 't'
312
+ end
313
+ end
314
+
315
+ def extensions
316
+ if supports_extensions?
317
+ rows = select_rows "SELECT extname from pg_extension", "SCHEMA"
318
+ rows.map { |row| row.first }
319
+ else
320
+ []
321
+ end
322
+ end
323
+
324
+ def index_algorithms
325
+ { :concurrently => 'CONCURRENTLY' }
326
+ end
327
+
328
+ # Set the authorized user for this session.
329
+ def session_auth=(user)
330
+ clear_cache!
331
+ execute "SET SESSION AUTHORIZATION #{user}"
332
+ end
333
+
334
+ # Came from postgres_adapter
335
+ def get_advisory_lock(lock_id) # :nodoc:
336
+ unless lock_id.is_a?(Integer) && lock_id.bit_length <= 63
337
+ raise(ArgumentError, "Postgres requires advisory lock ids to be a signed 64 bit integer")
338
+ end
339
+ select_value("SELECT pg_try_advisory_lock(#{lock_id});")
340
+ end
341
+
342
+ # Came from postgres_adapter
343
+ def release_advisory_lock(lock_id) # :nodoc:
344
+ unless lock_id.is_a?(Integer) && lock_id.bit_length <= 63
345
+ raise(ArgumentError, "Postgres requires advisory lock ids to be a signed 64 bit integer")
346
+ end
347
+ select_value("SELECT pg_advisory_unlock(#{lock_id})")
348
+ end
349
+
350
+ # Returns the configured supported identifier length supported by PostgreSQL
351
+ def max_identifier_length
352
+ @max_identifier_length ||= select_one('SHOW max_identifier_length', 'SCHEMA'.freeze)['max_identifier_length'].to_i
353
+ end
354
+ alias table_alias_length max_identifier_length
355
+ alias index_name_length max_identifier_length
356
+
357
+ def exec_insert(sql, name, binds, pk = nil, sequence_name = nil)
358
+ val = super
359
+ if !use_insert_returning? && pk
360
+ unless sequence_name
361
+ table_ref = extract_table_ref_from_insert_sql(sql)
362
+ sequence_name = default_sequence_name(table_ref, pk)
363
+ return val unless sequence_name
364
+ end
365
+ last_insert_id_result(sequence_name)
366
+ else
367
+ val
368
+ end
369
+ end
370
+
371
+ def explain(arel, binds = [])
372
+ sql = "EXPLAIN #{to_sql(arel, binds)}"
373
+ ActiveRecord::ConnectionAdapters::PostgreSQL::ExplainPrettyPrinter.new.pp(exec_query(sql, 'EXPLAIN', binds))
374
+ end
375
+
376
+ # @note Only for "better" AR 4.0 compatibility.
377
+ # @private
378
+ def query(sql, name = nil)
379
+ log(sql, name) do
380
+ result = []
381
+ @connection.execute_query_raw(sql, []) do |*values|
382
+ # We need to use #deep_dup here because it appears that
383
+ # the java method is reusing an object in some cases
384
+ # which makes all of the entries in the "result"
385
+ # array end up with the same values as the last row
386
+ result << values.deep_dup
387
+ end
388
+ result
389
+ end
390
+ end
391
+
392
+ # We need to make sure to deallocate all the prepared statements
393
+ # since apparently calling close on the statement object
394
+ # doesn't always free the server resources and calling
395
+ # 'DISCARD ALL' fails if we are inside a transaction
396
+ def clear_cache!
397
+ super
398
+ @connection.execute 'DEALLOCATE ALL' if supports_statement_cache? && @connection.active?
399
+ end
400
+
401
+ def reset!
402
+ clear_cache!
403
+ reset_transaction
404
+ @connection.rollback # Have to deal with rollbacks differently than the AR adapter
405
+ @connection.execute 'DISCARD ALL'
406
+ @connection.configure_connection
407
+ end
408
+
409
+ def default_sequence_name(table_name, pk = "id") #:nodoc:
410
+ serial_sequence(table_name, pk)
411
+ rescue ActiveRecord::StatementInvalid
412
+ %Q("#{table_name}_#{pk}_seq")
413
+ end
414
+
415
+ def last_insert_id_result(sequence_name)
416
+ exec_query("SELECT currval('#{sequence_name}')", 'SQL')
417
+ end
418
+
419
+ def all_schemas
420
+ select('SELECT nspname FROM pg_namespace').map { |row| row["nspname"] }
421
+ end
422
+
423
+ # Returns the current client message level.
424
+ def client_min_messages
425
+ return nil if redshift? # not supported on Redshift
426
+ # Need to use #execute so we don't try to access the type map before it is initialized
427
+ execute('SHOW client_min_messages', 'SCHEMA').values.first.first
428
+ end
429
+
430
+ # Set the client message level.
431
+ def client_min_messages=(level)
432
+ # NOTE: for now simply ignore the writer (no warn on Redshift) so that
433
+ # the AR copy-pasted PpstgreSQL parts stay the same as much as possible
434
+ return nil if redshift? # not supported on Redshift
435
+ execute("SET client_min_messages TO '#{level}'", 'SCHEMA')
436
+ end
437
+
438
+ # ORDER BY clause for the passed order option.
439
+ #
440
+ # PostgreSQL does not allow arbitrary ordering when using DISTINCT ON,
441
+ # so we work around this by wrapping the SQL as a sub-select and ordering
442
+ # in that query.
443
+ def add_order_by_for_association_limiting!(sql, options)
444
+ return sql if options[:order].blank?
445
+
446
+ order = options[:order].split(',').collect { |s| s.strip }.reject(&:blank?)
447
+ order.map! { |s| 'DESC' if s =~ /\bdesc$/i }
448
+ order = order.zip((0...order.size).to_a).map { |s,i| "id_list.alias_#{i} #{s}" }.join(', ')
449
+
450
+ sql.replace "SELECT * FROM (#{sql}) AS id_list ORDER BY #{order}"
451
+ end
452
+
453
+ # @note #quote_string implemented as native
454
+
455
+ def escape_bytea(string)
456
+ return unless string
457
+ if supports_hex_escaped_bytea?
458
+ "\\x#{string.unpack("H*")[0]}"
459
+ else
460
+ result = ''
461
+ string.each_byte { |c| result << sprintf('\\\\%03o', c) }
462
+ result
463
+ end
464
+ end
465
+
466
+ # @override
467
+ def quote_table_name(name)
468
+ schema, name_part = extract_pg_identifier_from_name(name.to_s)
469
+
470
+ unless name_part
471
+ quote_column_name(schema)
472
+ else
473
+ table_name, name_part = extract_pg_identifier_from_name(name_part)
474
+ "#{quote_column_name(schema)}.#{quote_column_name(table_name)}"
475
+ end
476
+ end
477
+
478
+ # @note #quote_column_name implemented as native
479
+ alias_method :quote_schema_name, :quote_column_name
480
+
481
+ # Need to clear the cache even though the AR adapter doesn't for some reason
482
+ def remove_column(table_name, column_name, type = nil, options = {})
483
+ super
484
+ clear_cache!
485
+ end
486
+
487
+ # @private
488
+ def column_for(table_name, column_name)
489
+ column_name = column_name.to_s
490
+ for column in columns(table_name)
491
+ return column if column.name == column_name
492
+ end
493
+ nil
494
+ end
495
+
496
+ # Returns the list of a table's column names, data types, and default values.
497
+ #
498
+ # If the table name is not prefixed with a schema, the database will
499
+ # take the first match from the schema search path.
500
+ #
501
+ # Query implementation notes:
502
+ # - format_type includes the column size constraint, e.g. varchar(50)
503
+ # - ::regclass is a function that gives the id for a table name
504
+ def column_definitions(table_name)
505
+ select_rows(<<-end_sql, 'SCHEMA')
506
+ SELECT a.attname, format_type(a.atttypid, a.atttypmod),
507
+ pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
508
+ (SELECT c.collname FROM pg_collation c, pg_type t
509
+ WHERE c.oid = a.attcollation AND t.oid = a.atttypid
510
+ AND a.attcollation <> t.typcollation),
511
+ col_description(a.attrelid, a.attnum) AS comment
512
+ FROM pg_attribute a
513
+ LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum
514
+ WHERE a.attrelid = '#{quote_table_name(table_name)}'::regclass
515
+ AND a.attnum > 0 AND NOT a.attisdropped
516
+ ORDER BY a.attnum
517
+ end_sql
518
+ end
519
+ private :column_definitions
520
+
521
+ def truncate(table_name, name = nil)
522
+ execute "TRUNCATE TABLE #{quote_table_name(table_name)}", name
523
+ end
524
+
525
+ # @private
526
+ def column_name_for_operation(operation, node)
527
+ case operation
528
+ when 'maximum' then 'max'
529
+ when 'minimum' then 'min'
530
+ when 'average' then 'avg'
531
+ else operation.downcase
532
+ end
533
+ end
534
+
535
+ private
536
+
537
+ # Pulled from ActiveRecord's Postgres adapter and modified to use execute
538
+ def can_perform_case_insensitive_comparison_for?(column)
539
+ @case_insensitive_cache ||= {}
540
+ @case_insensitive_cache[column.sql_type] ||= begin
541
+ sql = <<-end_sql
542
+ SELECT exists(
543
+ SELECT * FROM pg_proc
544
+ WHERE proname = 'lower'
545
+ AND proargtypes = ARRAY[#{quote column.sql_type}::regtype]::oidvector
546
+ ) OR exists(
547
+ SELECT * FROM pg_proc
548
+ INNER JOIN pg_cast
549
+ ON ARRAY[casttarget]::oidvector = proargtypes
550
+ WHERE proname = 'lower'
551
+ AND castsource = #{quote column.sql_type}::regtype
552
+ )
553
+ end_sql
554
+ select_value(sql, 'SCHEMA')
555
+ end
556
+ end
557
+
558
+ def translate_exception(exception, message)
559
+ case exception.message
560
+ when /duplicate key value violates unique constraint/
561
+ ::ActiveRecord::RecordNotUnique.new(message)
562
+ when /violates foreign key constraint/
563
+ ::ActiveRecord::InvalidForeignKey.new(message)
564
+ when /value too long/
565
+ ::ActiveRecord::ValueTooLong.new(message)
566
+ else
567
+ super
568
+ end
569
+ end
570
+
571
+ # @private `Utils.extract_schema_and_table` from AR
572
+ def extract_schema_and_table(name)
573
+ result = name.scan(/[^".\s]+|"[^"]*"/)[0, 2]
574
+ result.each { |m| m.gsub!(/(^"|"$)/, '') }
575
+ result.unshift(nil) if result.size == 1 # schema == nil
576
+ result # [schema, table]
577
+ end
578
+
579
+ def extract_pg_identifier_from_name(name)
580
+ match_data = name[0, 1] == '"' ? name.match(/\"([^\"]+)\"/) : name.match(/([^\.]+)/)
581
+
582
+ if match_data
583
+ rest = name[match_data[0].length..-1]
584
+ rest = rest[1..-1] if rest[0, 1] == "."
585
+ [match_data[1], (rest.length > 0 ? rest : nil)]
586
+ end
587
+ end
588
+
589
+ def extract_table_ref_from_insert_sql(sql)
590
+ sql[/into\s("[A-Za-z0-9_."\[\]\s]+"|[A-Za-z0-9_."\[\]]+)\s*/im]
591
+ $1.strip if $1
592
+ end
593
+
594
+ def local_tz
595
+ @local_tz ||= execute('SHOW TIME ZONE', 'SCHEMA').first["TimeZone"]
596
+ end
597
+
598
+ end
599
+ end
600
+
601
+ require 'arjdbc/util/quoted_cache'
602
+
603
+ module ActiveRecord::ConnectionAdapters
604
+
605
+ # NOTE: seems needed on 4.x due loading of '.../postgresql/oid' which
606
+ # assumes: class PostgreSQLAdapter < AbstractAdapter
607
+ remove_const(:PostgreSQLAdapter) if const_defined?(:PostgreSQLAdapter)
608
+
609
+ class PostgreSQLAdapter < AbstractAdapter
610
+
611
+ # Try to use as much of the built in postgres logic as possible
612
+ # maybe someday we can extend the actual adapter
613
+ include ActiveRecord::ConnectionAdapters::PostgreSQL::ColumnDumper
614
+ include ActiveRecord::ConnectionAdapters::PostgreSQL::ReferentialIntegrity
615
+ include ActiveRecord::ConnectionAdapters::PostgreSQL::SchemaStatements
616
+ include ActiveRecord::ConnectionAdapters::PostgreSQL::Quoting
617
+
618
+ include Jdbc::ConnectionPoolCallbacks
619
+
620
+ include ArJdbc::Abstract::Core
621
+ include ArJdbc::Abstract::ConnectionManagement
622
+ include ArJdbc::Abstract::DatabaseStatements
623
+ include ArJdbc::Abstract::StatementCache
624
+ include ArJdbc::Abstract::TransactionSupport
625
+ include ArJdbc::PostgreSQL
626
+
627
+ require 'arjdbc/postgresql/oid_types'
628
+ include ::ArJdbc::PostgreSQL::OIDTypes
629
+
630
+ include ::ArJdbc::PostgreSQL::ColumnHelpers
631
+
632
+ include ::ArJdbc::Util::QuotedCache
633
+
634
+ # AR expects OID to be available on the adapter
635
+ OID = ActiveRecord::ConnectionAdapters::PostgreSQL::OID
636
+
637
+ def initialize(connection, logger = nil, connection_parameters = nil, config = {})
638
+ # @local_tz is initialized as nil to avoid warnings when connect tries to use it
639
+ @local_tz = nil
640
+
641
+ super(connection, logger, config) # configure_connection happens in super
642
+
643
+ initialize_type_map(@type_map = Type::HashLookupTypeMap.new)
644
+
645
+ @use_insert_returning = @config.key?(:insert_returning) ?
646
+ self.class.type_cast_config_to_boolean(@config[:insert_returning]) : nil
647
+ end
648
+
649
+ def arel_visitor # :nodoc:
650
+ Arel::Visitors::PostgreSQL.new(self)
651
+ end
652
+
653
+ require 'active_record/connection_adapters/postgresql/schema_definitions'
654
+
655
+ ColumnDefinition = ActiveRecord::ConnectionAdapters::PostgreSQL::ColumnDefinition
656
+ ColumnMethods = ActiveRecord::ConnectionAdapters::PostgreSQL::ColumnMethods
657
+ TableDefinition = ActiveRecord::ConnectionAdapters::PostgreSQL::TableDefinition
658
+ Table = ActiveRecord::ConnectionAdapters::PostgreSQL::Table
659
+
660
+ def create_table_definition(*args) # :nodoc:
661
+ TableDefinition.new(*args)
662
+ end
663
+
664
+ public :sql_for_insert
665
+
666
+ def schema_creation # :nodoc:
667
+ PostgreSQL::SchemaCreation.new self
668
+ end
669
+
670
+ def update_table_definition(table_name, base)
671
+ Table.new(table_name, base)
672
+ end
673
+
674
+ def jdbc_connection_class(spec)
675
+ ::ArJdbc::PostgreSQL.jdbc_connection_class
676
+ end
677
+
678
+ private
679
+
680
+ # Prepared statements aren't schema aware so we need to make sure we
681
+ # store different PreparedStatement objects for different schemas
682
+ def sql_key(sql)
683
+ "#{schema_search_path}-#{sql}"
684
+ end
685
+
686
+ end
687
+ end