activerecord-jdbc-alt-adapter 50.3.0-java

Sign up to get free protection for your applications and to get access to all the features.
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