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,11 @@
1
+ require 'rails/railtie'
2
+
3
+ module ArJdbc
4
+ class Railtie < ::Rails::Railtie
5
+ rake_tasks do
6
+ if defined? ActiveRecord::Railtie # only if AR being used
7
+ load File.expand_path('tasks.rb', File.dirname(__FILE__))
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ require 'arjdbc'
2
+ require 'arjdbc/sqlite3/adapter'
3
+ require 'arjdbc/sqlite3/connection_methods'
@@ -0,0 +1,678 @@
1
+ ArJdbc.load_java_part :SQLite3
2
+
3
+ require "arjdbc/abstract/core"
4
+ require "arjdbc/abstract/database_statements"
5
+ require 'arjdbc/abstract/statement_cache'
6
+ require "arjdbc/abstract/transaction_support"
7
+ require "active_record/connection_adapters/statement_pool"
8
+ require "active_record/connection_adapters/abstract/database_statements"
9
+ require "active_record/connection_adapters/sqlite3/explain_pretty_printer"
10
+ require "active_record/connection_adapters/sqlite3/quoting"
11
+ require "active_record/connection_adapters/sqlite3/schema_creation"
12
+
13
+ module ArJdbc
14
+ # All the code in this module is a copy of ConnectionAdapters::SQLite3Adapter from active_record 5.
15
+ # The constants at the front of this file are to allow the rest of the file to remain with no modifications
16
+ # from its original source. If you hack on this file try not to modify this module and instead try and
17
+ # put those overrides in SQL3Adapter below. We try and keep a copy of the Rails this adapter supports
18
+ # with the current goal of being able to diff changes easily over time and to also eventually remove
19
+ # this module from ARJDBC altogether.
20
+ module SQLite3
21
+ # DIFFERENCE: Some common constant names to reduce differences in rest of this module from AR5 version
22
+ ConnectionAdapters = ::ActiveRecord::ConnectionAdapters
23
+ IndexDefinition = ::ActiveRecord::ConnectionAdapters::IndexDefinition
24
+ Quoting = ::ActiveRecord::ConnectionAdapters::SQLite3::Quoting
25
+ RecordNotUnique = ::ActiveRecord::RecordNotUnique
26
+ SchemaCreation = ConnectionAdapters::SQLite3::SchemaCreation
27
+ SQLite3Adapter = ConnectionAdapters::AbstractAdapter
28
+
29
+ ADAPTER_NAME = 'SQLite'.freeze
30
+
31
+ include Quoting
32
+
33
+ NATIVE_DATABASE_TYPES = {
34
+ primary_key: "INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL",
35
+ string: { name: "varchar" },
36
+ text: { name: "text" },
37
+ integer: { name: "integer" },
38
+ float: { name: "float" },
39
+ decimal: { name: "decimal" },
40
+ datetime: { name: "datetime" },
41
+ time: { name: "time" },
42
+ date: { name: "date" },
43
+ binary: { name: "blob" },
44
+ boolean: { name: "boolean" }
45
+ }
46
+
47
+ class StatementPool < ConnectionAdapters::StatementPool
48
+ private
49
+
50
+ def dealloc(stmt)
51
+ stmt[:stmt].close unless stmt[:stmt].closed?
52
+ end
53
+ end
54
+
55
+ def schema_creation # :nodoc:
56
+ SQLite3::SchemaCreation.new self
57
+ end
58
+
59
+ def arel_visitor # :nodoc:
60
+ Arel::Visitors::SQLite.new(self)
61
+ end
62
+
63
+ def initialize(connection, logger, connection_options, config)
64
+ super(connection, logger, config)
65
+
66
+ @active = nil
67
+ @statements = StatementPool.new(self.class.type_cast_config_to_integer(config[:statement_limit]))
68
+ end
69
+
70
+ def supports_ddl_transactions?
71
+ true
72
+ end
73
+
74
+ def supports_savepoints?
75
+ true
76
+ end
77
+
78
+ def supports_partial_index?
79
+ sqlite_version >= "3.8.0"
80
+ end
81
+
82
+ # Returns true, since this connection adapter supports prepared statement
83
+ # caching.
84
+ def supports_statement_cache?
85
+ true
86
+ end
87
+
88
+ # Returns true, since this connection adapter supports migrations.
89
+ def supports_migrations? #:nodoc:
90
+ true
91
+ end
92
+
93
+ def supports_primary_key? #:nodoc:
94
+ true
95
+ end
96
+
97
+ def requires_reloading?
98
+ true
99
+ end
100
+
101
+ def supports_views?
102
+ true
103
+ end
104
+
105
+ def supports_datetime_with_precision?
106
+ true
107
+ end
108
+
109
+ def supports_multi_insert?
110
+ sqlite_version >= "3.7.11"
111
+ end
112
+
113
+ def active?
114
+ @active != false
115
+ end
116
+
117
+ # Disconnects from the database if already connected. Otherwise, this
118
+ # method does nothing.
119
+ def disconnect!
120
+ super
121
+ @active = false
122
+ @connection.close rescue nil
123
+ end
124
+
125
+ # Clears the prepared statements cache.
126
+ def clear_cache!
127
+ @statements.clear
128
+ end
129
+
130
+ def supports_index_sort_order?
131
+ true
132
+ end
133
+
134
+ def valid_type?(type)
135
+ true
136
+ end
137
+
138
+ # Returns 62. SQLite supports index names up to 64
139
+ # characters. The rest is used by Rails internally to perform
140
+ # temporary rename operations
141
+ def allowed_index_name_length
142
+ index_name_length - 2
143
+ end
144
+
145
+ def native_database_types #:nodoc:
146
+ NATIVE_DATABASE_TYPES
147
+ end
148
+
149
+ # Returns the current database encoding format as a string, eg: 'UTF-8'
150
+ def encoding
151
+ @connection.encoding.to_s
152
+ end
153
+
154
+ def supports_explain?
155
+ true
156
+ end
157
+
158
+ #--
159
+ # DATABASE STATEMENTS ======================================
160
+ #++
161
+
162
+ def explain(arel, binds = [])
163
+ sql = "EXPLAIN QUERY PLAN #{to_sql(arel, binds)}"
164
+ ::ActiveRecord::ConnectionAdapters::SQLite3::ExplainPrettyPrinter.new.pp(exec_query(sql, "EXPLAIN", []))
165
+ end
166
+
167
+ def exec_query(sql, name = nil, binds = [], prepare: false)
168
+ type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) }
169
+
170
+ log(sql, name, binds) do
171
+ # Don't cache statements if they are not prepared
172
+ unless prepare
173
+ stmt = @connection.prepare(sql)
174
+ begin
175
+ cols = stmt.columns
176
+ unless without_prepared_statement?(binds)
177
+ stmt.bind_params(type_casted_binds)
178
+ end
179
+ records = stmt.to_a
180
+ ensure
181
+ stmt.close
182
+ end
183
+ stmt = records
184
+ else
185
+ cache = @statements[sql] ||= {
186
+ :stmt => @connection.prepare(sql)
187
+ }
188
+ stmt = cache[:stmt]
189
+ cols = cache[:cols] ||= stmt.columns
190
+ stmt.reset!
191
+ stmt.bind_params(type_casted_binds)
192
+ end
193
+
194
+ ActiveRecord::Result.new(cols, stmt.to_a)
195
+ end
196
+ end
197
+
198
+ def exec_delete(sql, name = 'SQL', binds = [])
199
+ exec_query(sql, name, binds)
200
+ @connection.changes
201
+ end
202
+ alias :exec_update :exec_delete
203
+
204
+ def last_inserted_id(result)
205
+ @connection.last_insert_row_id
206
+ end
207
+
208
+ def execute(sql, name = nil) #:nodoc:
209
+ log(sql, name) { @connection.execute(sql) }
210
+ end
211
+
212
+ def begin_db_transaction #:nodoc:
213
+ log("begin transaction",nil) { @connection.transaction }
214
+ end
215
+
216
+ def commit_db_transaction #:nodoc:
217
+ log("commit transaction",nil) { @connection.commit }
218
+ end
219
+
220
+ def exec_rollback_db_transaction #:nodoc:
221
+ log("rollback transaction",nil) { @connection.rollback }
222
+ end
223
+
224
+ # SCHEMA STATEMENTS ========================================
225
+
226
+ def tables(name = nil) # :nodoc:
227
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
228
+ #tables currently returns both tables and views.
229
+ This behavior is deprecated and will be changed with Rails 5.1 to only return tables.
230
+ Use #data_sources instead.
231
+ MSG
232
+
233
+ if name
234
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
235
+ Passing arguments to #tables is deprecated without replacement.
236
+ MSG
237
+ end
238
+
239
+ data_sources
240
+ end
241
+
242
+ def data_sources
243
+ select_values("SELECT name FROM sqlite_master WHERE type IN ('table','view') AND name <> 'sqlite_sequence'", "SCHEMA")
244
+ end
245
+
246
+ def table_exists?(table_name)
247
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
248
+ #table_exists? currently checks both tables and views.
249
+ This behavior is deprecated and will be changed with Rails 5.1 to only check tables.
250
+ Use #data_source_exists? instead.
251
+ MSG
252
+
253
+ data_source_exists?(table_name)
254
+ end
255
+
256
+ def data_source_exists?(table_name)
257
+ return false unless table_name.present?
258
+
259
+ sql = "SELECT name FROM sqlite_master WHERE type IN ('table','view') AND name <> 'sqlite_sequence'"
260
+ sql << " AND name = #{quote(table_name)}"
261
+
262
+ select_values(sql, "SCHEMA").any?
263
+ end
264
+
265
+ def views # :nodoc:
266
+ select_values("SELECT name FROM sqlite_master WHERE type = 'view' AND name <> 'sqlite_sequence'", "SCHEMA")
267
+ end
268
+
269
+ def view_exists?(view_name) # :nodoc:
270
+ return false unless view_name.present?
271
+
272
+ sql = "SELECT name FROM sqlite_master WHERE type = 'view' AND name <> 'sqlite_sequence'"
273
+ sql << " AND name = #{quote(view_name)}"
274
+
275
+ select_values(sql, "SCHEMA").any?
276
+ end
277
+
278
+ # Returns an array of +Column+ objects for the table specified by +table_name+.
279
+ def columns(table_name) # :nodoc:
280
+ table_name = table_name.to_s
281
+ table_structure(table_name).map do |field|
282
+ case field["dflt_value"]
283
+ when /^null$/i
284
+ field["dflt_value"] = nil
285
+ when /^'(.*)'$/m
286
+ field["dflt_value"] = $1.gsub("''", "'")
287
+ when /^"(.*)"$/m
288
+ field["dflt_value"] = $1.gsub('""', '"')
289
+ end
290
+
291
+ collation = field["collation"]
292
+ sql_type = field["type"]
293
+ type_metadata = fetch_type_metadata(sql_type)
294
+ new_column(field["name"], field["dflt_value"], type_metadata, field["notnull"].to_i == 0, table_name, nil, collation)
295
+ end
296
+ end
297
+
298
+ # Returns an array of indexes for the given table.
299
+ def indexes(table_name, name = nil) #:nodoc:
300
+ exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", "SCHEMA").map do |row|
301
+ sql = <<-SQL
302
+ SELECT sql
303
+ FROM sqlite_master
304
+ WHERE name=#{quote(row['name'])} AND type='index'
305
+ UNION ALL
306
+ SELECT sql
307
+ FROM sqlite_temp_master
308
+ WHERE name=#{quote(row['name'])} AND type='index'
309
+ SQL
310
+ index_sql = exec_query(sql).first["sql"]
311
+ match = /\sWHERE\s+(.+)$/i.match(index_sql)
312
+ where = match[1] if match
313
+ IndexDefinition.new(
314
+ table_name,
315
+ row["name"],
316
+ row["unique"] != 0,
317
+ exec_query("PRAGMA index_info('#{row['name']}')", "SCHEMA").map { |col|
318
+ col["name"]
319
+ }, nil, nil, where)
320
+ end
321
+ end
322
+
323
+ def primary_keys(table_name) # :nodoc:
324
+ pks = table_structure(table_name).select { |f| f["pk"] > 0 }
325
+ pks.sort_by { |f| f["pk"] }.map { |f| f["name"] }
326
+ end
327
+
328
+ def remove_index(table_name, options = {}) #:nodoc:
329
+ index_name = index_name_for_remove(table_name, options)
330
+ exec_query "DROP INDEX #{quote_column_name(index_name)}"
331
+ end
332
+
333
+ # Renames a table.
334
+ #
335
+ # Example:
336
+ # rename_table('octopuses', 'octopi')
337
+ def rename_table(table_name, new_name)
338
+ exec_query "ALTER TABLE #{quote_table_name(table_name)} RENAME TO #{quote_table_name(new_name)}"
339
+ rename_table_indexes(table_name, new_name)
340
+ end
341
+
342
+ # See: http://www.sqlite.org/lang_altertable.html
343
+ # SQLite has an additional restriction on the ALTER TABLE statement
344
+ def valid_alter_table_type?(type)
345
+ type.to_sym != :primary_key
346
+ end
347
+
348
+ def add_column(table_name, column_name, type, options = {}) #:nodoc:
349
+ if valid_alter_table_type?(type)
350
+ super(table_name, column_name, type, options)
351
+ else
352
+ alter_table(table_name) do |definition|
353
+ definition.column(column_name, type, options)
354
+ end
355
+ end
356
+ end
357
+
358
+ def remove_column(table_name, column_name, type = nil, options = {}) #:nodoc:
359
+ alter_table(table_name) do |definition|
360
+ definition.remove_column column_name
361
+ end
362
+ end
363
+
364
+ def change_column_default(table_name, column_name, default_or_changes) #:nodoc:
365
+ default = extract_new_default_value(default_or_changes)
366
+
367
+ alter_table(table_name) do |definition|
368
+ definition[column_name].default = default
369
+ end
370
+ end
371
+
372
+ def change_column_null(table_name, column_name, null, default = nil) #:nodoc:
373
+ unless null || default.nil?
374
+ exec_query("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
375
+ end
376
+ alter_table(table_name) do |definition|
377
+ definition[column_name].null = null
378
+ end
379
+ end
380
+
381
+ def change_column(table_name, column_name, type, options = {}) #:nodoc:
382
+ alter_table(table_name) do |definition|
383
+ include_default = options_include_default?(options)
384
+ definition[column_name].instance_eval do
385
+ self.type = type
386
+ self.limit = options[:limit] if options.include?(:limit)
387
+ self.default = options[:default] if include_default
388
+ self.null = options[:null] if options.include?(:null)
389
+ self.precision = options[:precision] if options.include?(:precision)
390
+ self.scale = options[:scale] if options.include?(:scale)
391
+ self.collation = options[:collation] if options.include?(:collation)
392
+ end
393
+ end
394
+ end
395
+
396
+ def rename_column(table_name, column_name, new_column_name) #:nodoc:
397
+ column = column_for(table_name, column_name)
398
+ alter_table(table_name, rename: { column.name => new_column_name.to_s })
399
+ rename_column_indexes(table_name, column.name, new_column_name)
400
+ end
401
+
402
+ protected
403
+
404
+ def table_structure(table_name)
405
+ structure = exec_query("PRAGMA table_info(#{quote_table_name(table_name)})", "SCHEMA")
406
+ raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
407
+ table_structure_with_collation(table_name, structure)
408
+ end
409
+
410
+ def alter_table(table_name, options = {}) #:nodoc:
411
+ altered_table_name = "a#{table_name}"
412
+ caller = lambda { |definition| yield definition if block_given? }
413
+
414
+ transaction do
415
+ move_table(table_name, altered_table_name,
416
+ options.merge(temporary: true))
417
+ move_table(altered_table_name, table_name, &caller)
418
+ end
419
+ end
420
+
421
+ def move_table(from, to, options = {}, &block) #:nodoc:
422
+ copy_table(from, to, options, &block)
423
+ drop_table(from)
424
+ end
425
+
426
+ def copy_table(from, to, options = {}) #:nodoc:
427
+ from_primary_key = primary_key(from)
428
+ options[:id] = false
429
+ create_table(to, options) do |definition|
430
+ @definition = definition
431
+ @definition.primary_key(from_primary_key) if from_primary_key.present?
432
+ columns(from).each do |column|
433
+ column_name = options[:rename] ?
434
+ (options[:rename][column.name] ||
435
+ options[:rename][column.name.to_sym] ||
436
+ column.name) : column.name
437
+ next if column_name == from_primary_key
438
+
439
+ @definition.column(column_name, column.type,
440
+ limit: column.limit, default: column.default,
441
+ precision: column.precision, scale: column.scale,
442
+ null: column.null, collation: column.collation)
443
+ end
444
+ yield @definition if block_given?
445
+ end
446
+ copy_table_indexes(from, to, options[:rename] || {})
447
+ copy_table_contents(from, to,
448
+ @definition.columns.map(&:name),
449
+ options[:rename] || {})
450
+ end
451
+
452
+ def copy_table_indexes(from, to, rename = {}) #:nodoc:
453
+ indexes(from).each do |index|
454
+ name = index.name
455
+ if to == "a#{from}"
456
+ name = "t#{name}"
457
+ elsif from == "a#{to}"
458
+ name = name[1..-1]
459
+ end
460
+
461
+ to_column_names = columns(to).map(&:name)
462
+ columns = index.columns.map { |c| rename[c] || c }.select do |column|
463
+ to_column_names.include?(column)
464
+ end
465
+
466
+ unless columns.empty?
467
+ # index name can't be the same
468
+ opts = { name: name.gsub(/(^|_)(#{from})_/, "\\1#{to}_"), internal: true }
469
+ opts[:unique] = true if index.unique
470
+ add_index(to, columns, opts)
471
+ end
472
+ end
473
+ end
474
+
475
+ def copy_table_contents(from, to, columns, rename = {}) #:nodoc:
476
+ column_mappings = Hash[columns.map { |name| [name, name] }]
477
+ rename.each { |a| column_mappings[a.last] = a.first }
478
+ from_columns = columns(from).collect(&:name)
479
+ columns = columns.find_all { |col| from_columns.include?(column_mappings[col]) }
480
+ from_columns_to_copy = columns.map { |col| column_mappings[col] }
481
+ quoted_columns = columns.map { |col| quote_column_name(col) } * ","
482
+ quoted_from_columns = from_columns_to_copy.map { |col| quote_column_name(col) } * ","
483
+
484
+ exec_query("INSERT INTO #{quote_table_name(to)} (#{quoted_columns})
485
+ SELECT #{quoted_from_columns} FROM #{quote_table_name(from)}")
486
+ end
487
+
488
+ def sqlite_version
489
+ @sqlite_version ||= SQLite3Adapter::Version.new(select_value("select sqlite_version(*)"))
490
+ end
491
+
492
+ def translate_exception(exception, message)
493
+ case exception.message
494
+ # SQLite 3.8.2 returns a newly formatted error message:
495
+ # UNIQUE constraint failed: *table_name*.*column_name*
496
+ # Older versions of SQLite return:
497
+ # column *column_name* is not unique
498
+ when /column(s)? .* (is|are) not unique/, /UNIQUE constraint failed: .*/
499
+ RecordNotUnique.new(message)
500
+ else
501
+ super
502
+ end
503
+ end
504
+
505
+ private
506
+ COLLATE_REGEX = /.*\"(\w+)\".*collate\s+\"(\w+)\".*/i.freeze
507
+
508
+ def table_structure_with_collation(table_name, basic_structure)
509
+ collation_hash = {}
510
+ sql = "SELECT sql FROM
511
+ (SELECT * FROM sqlite_master UNION ALL
512
+ SELECT * FROM sqlite_temp_master)
513
+ WHERE type='table' and name='#{ table_name }' \;"
514
+
515
+ # Result will have following sample string
516
+ # CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
517
+ # "password_digest" varchar COLLATE "NOCASE");
518
+ result = exec_query(sql, 'SCHEMA').first
519
+
520
+ if result
521
+ # Splitting with left parentheses and picking up last will return all
522
+ # columns separated with comma(,).
523
+ columns_string = result["sql"].split('(').last
524
+
525
+ columns_string.split(',').each do |column_string|
526
+ # This regex will match the column name and collation type and will save
527
+ # the value in $1 and $2 respectively.
528
+ collation_hash[$1] = $2 if (COLLATE_REGEX =~ column_string)
529
+ end
530
+
531
+ basic_structure.map! do |column|
532
+ column_name = column['name']
533
+
534
+ if collation_hash.has_key? column_name
535
+ column['collation'] = collation_hash[column_name]
536
+ end
537
+
538
+ column
539
+ end
540
+ else
541
+ basic_structure.to_hash
542
+ end
543
+ end
544
+ end
545
+ end
546
+
547
+ module ActiveRecord::ConnectionAdapters
548
+ class SQLite3Column < JdbcColumn
549
+ def initialize(name, *args)
550
+ if Hash === name
551
+ super
552
+ else
553
+ super(nil, name, *args)
554
+ end
555
+ end
556
+
557
+ def self.string_to_binary(value)
558
+ value
559
+ end
560
+
561
+ def self.binary_to_string(value)
562
+ if value.respond_to?(:encoding) && value.encoding != Encoding::ASCII_8BIT
563
+ value = value.force_encoding(Encoding::ASCII_8BIT)
564
+ end
565
+ value
566
+ end
567
+
568
+ # @override {ActiveRecord::ConnectionAdapters::JdbcColumn#init_column}
569
+ def init_column(name, default, *args)
570
+ if default =~ /NULL/
571
+ @default = nil
572
+ else
573
+ super
574
+ end
575
+ end
576
+
577
+ # @override {ActiveRecord::ConnectionAdapters::JdbcColumn#default_value}
578
+ def default_value(value)
579
+ # JDBC returns column default strings with actual single quotes :
580
+ return $1 if value =~ /^'(.*)'$/
581
+
582
+ value
583
+ end
584
+
585
+ # @override {ActiveRecord::ConnectionAdapters::Column#type_cast}
586
+ def type_cast(value)
587
+ return nil if value.nil?
588
+ case type
589
+ when :string then value
590
+ when :primary_key
591
+ value.respond_to?(:to_i) ? value.to_i : ( value ? 1 : 0 )
592
+ when :float then value.to_f
593
+ when :decimal then self.class.value_to_decimal(value)
594
+ when :boolean then self.class.value_to_boolean(value)
595
+ else super
596
+ end
597
+ end
598
+
599
+ private
600
+
601
+ # @override {ActiveRecord::ConnectionAdapters::Column#simplified_type}
602
+ def simplified_type(field_type)
603
+ case field_type
604
+ when /boolean/i then :boolean
605
+ when /text/i then :text
606
+ when /varchar/i then :string
607
+ when /int/i then :integer
608
+ when /float/i then :float
609
+ when /real|decimal/i then
610
+ extract_scale(field_type) == 0 ? :integer : :decimal
611
+ when /datetime/i then :datetime
612
+ when /date/i then :date
613
+ when /time/i then :time
614
+ when /blob/i then :binary
615
+ else super
616
+ end
617
+ end
618
+
619
+ # @override {ActiveRecord::ConnectionAdapters::Column#extract_limit}
620
+ def extract_limit(sql_type)
621
+ return nil if sql_type =~ /^(real)\(\d+/i
622
+ super
623
+ end
624
+
625
+ def extract_precision(sql_type)
626
+ case sql_type
627
+ when /^(real)\((\d+)(,\d+)?\)/i then $2.to_i
628
+ else super
629
+ end
630
+ end
631
+
632
+ def extract_scale(sql_type)
633
+ case sql_type
634
+ when /^(real)\((\d+)\)/i then 0
635
+ when /^(real)\((\d+)(,(\d+))\)/i then $4.to_i
636
+ else super
637
+ end
638
+ end
639
+ end
640
+
641
+ remove_const(:SQLite3Adapter) if const_defined?(:SQLite3Adapter)
642
+
643
+ # Currently our adapter is named the same as what AR5 names its adapter. We will need to get
644
+ # this changed at some point so this can be a unique name and we can extend activerecord
645
+ # ActiveRecord::ConnectionAdapters::SQLite3Adapter. Once we can do that we can remove the
646
+ # module SQLite3 above and remove a majority of this file.
647
+ class SQLite3Adapter < AbstractAdapter
648
+ include ArJdbc::Abstract::Core
649
+ include ArJdbc::SQLite3
650
+ include ArJdbc::Abstract::DatabaseStatements
651
+ include ArJdbc::Abstract::StatementCache
652
+ include ArJdbc::Abstract::TransactionSupport
653
+
654
+ def begin_isolated_db_transaction(isolation)
655
+ raise ActiveRecord::TransactionIsolationError, 'adapter does not support setting transaction isolation'
656
+ end
657
+
658
+ # SQLite driver doesn't support all types of insert statements with executeUpdate so
659
+ # make it act like a regular query and the ids will be returned from #last_inserted_id
660
+ # example: INSERT INTO "aircraft" DEFAULT VALUES
661
+ def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil)
662
+ exec_query(sql, name, binds)
663
+ end
664
+
665
+ def jdbc_column_class
666
+ ::ActiveRecord::ConnectionAdapters::SQLite3Column
667
+ end
668
+
669
+ def jdbc_connection_class(spec)
670
+ self.class.jdbc_connection_class
671
+ end
672
+
673
+ # @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_connection_class
674
+ def self.jdbc_connection_class
675
+ ::ActiveRecord::ConnectionAdapters::SQLite3JdbcConnection
676
+ end
677
+ end
678
+ end