activerecord-jdbc-adapter 1.0.3-java → 50.1-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (268) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +33 -0
  3. data/.travis.yml +79 -0
  4. data/.yardopts +4 -0
  5. data/CONTRIBUTING.md +50 -0
  6. data/Gemfile +91 -0
  7. data/History.md +1191 -0
  8. data/LICENSE.txt +22 -17
  9. data/README.md +169 -0
  10. data/RUNNING_TESTS.md +127 -0
  11. data/Rakefile +294 -5
  12. data/Rakefile.jdbc +20 -0
  13. data/activerecord-jdbc-adapter.gemspec +55 -0
  14. data/lib/active_record/connection_adapters/as400_adapter.rb +2 -0
  15. data/lib/active_record/connection_adapters/db2_adapter.rb +1 -0
  16. data/lib/active_record/connection_adapters/firebird_adapter.rb +1 -0
  17. data/lib/active_record/connection_adapters/mariadb_adapter.rb +1 -0
  18. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +1 -0
  19. data/lib/activerecord-jdbc-adapter.rb +0 -5
  20. data/lib/arel/visitors/compat.rb +60 -0
  21. data/lib/arel/visitors/db2.rb +128 -6
  22. data/lib/arel/visitors/derby.rb +103 -10
  23. data/lib/arel/visitors/firebird.rb +79 -0
  24. data/lib/arel/visitors/h2.rb +25 -0
  25. data/lib/arel/visitors/hsqldb.rb +18 -10
  26. data/lib/arel/visitors/postgresql_jdbc.rb +6 -0
  27. data/lib/arel/visitors/sql_server.rb +225 -0
  28. data/lib/arel/visitors/sql_server/ng42.rb +293 -0
  29. data/lib/arjdbc.rb +11 -21
  30. data/lib/arjdbc/abstract/connection_management.rb +35 -0
  31. data/lib/arjdbc/abstract/core.rb +64 -0
  32. data/lib/arjdbc/abstract/database_statements.rb +64 -0
  33. data/lib/arjdbc/abstract/statement_cache.rb +58 -0
  34. data/lib/arjdbc/abstract/transaction_support.rb +86 -0
  35. data/lib/arjdbc/db2.rb +3 -1
  36. data/lib/arjdbc/db2/adapter.rb +630 -250
  37. data/lib/arjdbc/db2/as400.rb +130 -0
  38. data/lib/arjdbc/db2/column.rb +167 -0
  39. data/lib/arjdbc/db2/connection_methods.rb +44 -0
  40. data/lib/arjdbc/derby.rb +1 -5
  41. data/lib/arjdbc/derby/active_record_patch.rb +13 -0
  42. data/lib/arjdbc/derby/adapter.rb +409 -217
  43. data/lib/arjdbc/derby/connection_methods.rb +16 -14
  44. data/lib/arjdbc/derby/schema_creation.rb +15 -0
  45. data/lib/arjdbc/discover.rb +62 -50
  46. data/lib/arjdbc/firebird.rb +3 -1
  47. data/lib/arjdbc/firebird/adapter.rb +365 -62
  48. data/lib/arjdbc/firebird/connection_methods.rb +23 -0
  49. data/lib/arjdbc/h2.rb +2 -3
  50. data/lib/arjdbc/h2/adapter.rb +273 -6
  51. data/lib/arjdbc/h2/connection_methods.rb +23 -8
  52. data/lib/arjdbc/hsqldb.rb +2 -3
  53. data/lib/arjdbc/hsqldb/adapter.rb +204 -77
  54. data/lib/arjdbc/hsqldb/connection_methods.rb +24 -10
  55. data/lib/arjdbc/hsqldb/explain_support.rb +35 -0
  56. data/lib/arjdbc/hsqldb/schema_creation.rb +11 -0
  57. data/lib/arjdbc/informix.rb +4 -2
  58. data/lib/arjdbc/informix/adapter.rb +78 -54
  59. data/lib/arjdbc/informix/connection_methods.rb +8 -9
  60. data/lib/arjdbc/jdbc.rb +59 -2
  61. data/lib/arjdbc/jdbc/adapter.rb +356 -166
  62. data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
  63. data/lib/arjdbc/jdbc/adapter_require.rb +46 -0
  64. data/lib/arjdbc/jdbc/base_ext.rb +15 -0
  65. data/lib/arjdbc/jdbc/callbacks.rb +27 -18
  66. data/lib/arjdbc/jdbc/column.rb +79 -20
  67. data/lib/arjdbc/jdbc/connection.rb +5 -119
  68. data/lib/arjdbc/jdbc/connection_methods.rb +32 -4
  69. data/lib/arjdbc/jdbc/error.rb +65 -0
  70. data/lib/arjdbc/jdbc/extension.rb +41 -29
  71. data/lib/arjdbc/jdbc/java.rb +5 -6
  72. data/lib/arjdbc/jdbc/jdbc.rake +3 -126
  73. data/lib/arjdbc/jdbc/railtie.rb +2 -9
  74. data/lib/arjdbc/jdbc/rake_tasks.rb +3 -10
  75. data/lib/arjdbc/jdbc/serialized_attributes_helper.rb +3 -0
  76. data/lib/arjdbc/jdbc/type_cast.rb +166 -0
  77. data/lib/arjdbc/jdbc/type_converter.rb +35 -19
  78. data/lib/arjdbc/mssql.rb +6 -3
  79. data/lib/arjdbc/mssql/adapter.rb +630 -298
  80. data/lib/arjdbc/mssql/column.rb +200 -0
  81. data/lib/arjdbc/mssql/connection_methods.rb +66 -17
  82. data/lib/arjdbc/mssql/explain_support.rb +99 -0
  83. data/lib/arjdbc/mssql/limit_helpers.rb +189 -50
  84. data/lib/arjdbc/mssql/lock_methods.rb +77 -0
  85. data/lib/arjdbc/mssql/types.rb +343 -0
  86. data/lib/arjdbc/mssql/utils.rb +82 -0
  87. data/lib/arjdbc/mysql.rb +2 -3
  88. data/lib/arjdbc/mysql/adapter.rb +86 -356
  89. data/lib/arjdbc/mysql/connection_methods.rb +159 -23
  90. data/lib/arjdbc/oracle/adapter.rb +714 -263
  91. data/lib/arjdbc/postgresql.rb +2 -3
  92. data/lib/arjdbc/postgresql/_bc_time_cast_patch.rb +24 -0
  93. data/lib/arjdbc/postgresql/adapter.rb +570 -400
  94. data/lib/arjdbc/postgresql/base/array_decoder.rb +26 -0
  95. data/lib/arjdbc/postgresql/base/array_encoder.rb +25 -0
  96. data/lib/arjdbc/postgresql/base/array_parser.rb +95 -0
  97. data/lib/arjdbc/postgresql/base/pgconn.rb +11 -0
  98. data/lib/arjdbc/postgresql/column.rb +51 -0
  99. data/lib/arjdbc/postgresql/connection_methods.rb +57 -18
  100. data/lib/arjdbc/postgresql/name.rb +24 -0
  101. data/lib/arjdbc/postgresql/oid_types.rb +192 -0
  102. data/lib/arjdbc/railtie.rb +11 -0
  103. data/lib/arjdbc/sqlite3.rb +2 -3
  104. data/lib/arjdbc/sqlite3/adapter.rb +518 -198
  105. data/lib/arjdbc/sqlite3/connection_methods.rb +49 -24
  106. data/lib/arjdbc/sybase.rb +2 -2
  107. data/lib/arjdbc/sybase/adapter.rb +7 -6
  108. data/lib/arjdbc/tasks.rb +13 -0
  109. data/lib/arjdbc/tasks/database_tasks.rb +52 -0
  110. data/lib/arjdbc/tasks/databases.rake +91 -0
  111. data/lib/arjdbc/tasks/databases3.rake +215 -0
  112. data/lib/arjdbc/tasks/databases4.rake +39 -0
  113. data/lib/arjdbc/tasks/db2_database_tasks.rb +104 -0
  114. data/lib/arjdbc/tasks/derby_database_tasks.rb +95 -0
  115. data/lib/arjdbc/tasks/h2_database_tasks.rb +31 -0
  116. data/lib/arjdbc/tasks/hsqldb_database_tasks.rb +70 -0
  117. data/lib/arjdbc/tasks/jdbc_database_tasks.rb +169 -0
  118. data/lib/arjdbc/tasks/mssql_database_tasks.rb +46 -0
  119. data/lib/arjdbc/util/quoted_cache.rb +60 -0
  120. data/lib/arjdbc/util/serialized_attributes.rb +98 -0
  121. data/lib/arjdbc/util/table_copier.rb +110 -0
  122. data/lib/arjdbc/version.rb +1 -6
  123. data/lib/generators/jdbc/USAGE +9 -0
  124. data/lib/generators/jdbc/jdbc_generator.rb +8 -0
  125. data/lib/jdbc_adapter.rb +1 -1
  126. data/lib/jdbc_adapter/rake_tasks.rb +3 -2
  127. data/lib/jdbc_adapter/version.rb +2 -1
  128. data/pom.xml +114 -0
  129. data/rails_generators/jdbc_generator.rb +1 -1
  130. data/rails_generators/templates/config/initializers/jdbc.rb +8 -5
  131. data/rails_generators/templates/lib/tasks/jdbc.rake +7 -4
  132. data/rakelib/01-tomcat.rake +51 -0
  133. data/rakelib/02-test.rake +132 -0
  134. data/rakelib/bundler_ext.rb +11 -0
  135. data/rakelib/compile.rake +67 -22
  136. data/rakelib/db.rake +61 -0
  137. data/rakelib/rails.rake +204 -29
  138. data/src/java/arjdbc/ArJdbcModule.java +286 -0
  139. data/src/java/arjdbc/db2/DB2Module.java +76 -0
  140. data/src/java/arjdbc/db2/DB2RubyJdbcConnection.java +126 -0
  141. data/src/java/arjdbc/derby/DerbyModule.java +99 -243
  142. data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +152 -0
  143. data/src/java/arjdbc/firebird/FirebirdRubyJdbcConnection.java +174 -0
  144. data/src/java/arjdbc/{jdbc/JdbcConnectionFactory.java → h2/H2Module.java} +20 -6
  145. data/src/java/arjdbc/h2/H2RubyJdbcConnection.java +27 -12
  146. data/src/java/arjdbc/hsqldb/HSQLDBModule.java +73 -0
  147. data/src/java/arjdbc/informix/InformixRubyJdbcConnection.java +7 -6
  148. data/src/java/arjdbc/jdbc/AdapterJavaService.java +7 -29
  149. data/src/java/arjdbc/jdbc/Callable.java +44 -0
  150. data/src/java/arjdbc/jdbc/ConnectionFactory.java +132 -0
  151. data/src/java/arjdbc/jdbc/DataSourceConnectionFactory.java +157 -0
  152. data/src/java/arjdbc/jdbc/DriverConnectionFactory.java +63 -0
  153. data/src/java/arjdbc/jdbc/DriverWrapper.java +119 -0
  154. data/src/java/arjdbc/jdbc/JdbcResult.java +130 -0
  155. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +3622 -948
  156. data/src/java/arjdbc/mssql/MSSQLModule.java +90 -0
  157. data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +181 -0
  158. data/src/java/arjdbc/mysql/MySQLModule.java +99 -81
  159. data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +294 -0
  160. data/src/java/arjdbc/oracle/OracleModule.java +80 -0
  161. data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +387 -17
  162. data/src/java/arjdbc/postgresql/ByteaUtils.java +157 -0
  163. data/src/java/arjdbc/postgresql/PgResultSetMetaDataWrapper.java +23 -0
  164. data/src/java/arjdbc/postgresql/PostgreSQLModule.java +77 -0
  165. data/src/java/arjdbc/postgresql/PostgreSQLResult.java +184 -0
  166. data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +952 -0
  167. data/src/java/arjdbc/sqlite3/SQLite3Module.java +73 -0
  168. data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +525 -0
  169. data/src/java/arjdbc/util/CallResultSet.java +826 -0
  170. data/src/java/arjdbc/util/DateTimeUtils.java +580 -0
  171. data/src/java/arjdbc/util/ObjectSupport.java +65 -0
  172. data/src/java/arjdbc/util/QuotingUtils.java +138 -0
  173. data/src/java/arjdbc/util/StringCache.java +63 -0
  174. data/src/java/arjdbc/util/StringHelper.java +159 -0
  175. metadata +245 -268
  176. data/History.txt +0 -369
  177. data/Manifest.txt +0 -180
  178. data/README.txt +0 -181
  179. data/lib/active_record/connection_adapters/oracle_adapter.rb +0 -1
  180. data/lib/arel/engines/sql/compilers/db2_compiler.rb +0 -9
  181. data/lib/arel/engines/sql/compilers/derby_compiler.rb +0 -6
  182. data/lib/arel/engines/sql/compilers/h2_compiler.rb +0 -6
  183. data/lib/arel/engines/sql/compilers/hsqldb_compiler.rb +0 -15
  184. data/lib/arel/engines/sql/compilers/jdbc_compiler.rb +0 -6
  185. data/lib/arel/engines/sql/compilers/mssql_compiler.rb +0 -46
  186. data/lib/arel/visitors/mssql.rb +0 -44
  187. data/lib/arjdbc/jdbc/compatibility.rb +0 -51
  188. data/lib/arjdbc/jdbc/core_ext.rb +0 -24
  189. data/lib/arjdbc/jdbc/discover.rb +0 -18
  190. data/lib/arjdbc/jdbc/driver.rb +0 -44
  191. data/lib/arjdbc/jdbc/missing_functionality_helper.rb +0 -87
  192. data/lib/arjdbc/jdbc/quoted_primary_key.rb +0 -28
  193. data/lib/arjdbc/jdbc/require_driver.rb +0 -16
  194. data/lib/arjdbc/mimer.rb +0 -2
  195. data/lib/arjdbc/mimer/adapter.rb +0 -142
  196. data/lib/arjdbc/mssql/tsql_helper.rb +0 -61
  197. data/lib/arjdbc/oracle.rb +0 -3
  198. data/lib/arjdbc/oracle/connection_methods.rb +0 -11
  199. data/lib/pg.rb +0 -4
  200. data/rakelib/package.rake +0 -92
  201. data/rakelib/test.rake +0 -81
  202. data/src/java/arjdbc/jdbc/SQLBlock.java +0 -48
  203. data/src/java/arjdbc/mssql/MssqlRubyJdbcConnection.java +0 -127
  204. data/src/java/arjdbc/postgresql/PostgresqlRubyJdbcConnection.java +0 -57
  205. data/src/java/arjdbc/sqlite3/Sqlite3RubyJdbcConnection.java +0 -64
  206. data/test/abstract_db_create.rb +0 -117
  207. data/test/activerecord/connection_adapters/type_conversion_test.rb +0 -31
  208. data/test/activerecord/connections/native_jdbc_mysql/connection.rb +0 -25
  209. data/test/db/db2.rb +0 -11
  210. data/test/db/derby.rb +0 -12
  211. data/test/db/h2.rb +0 -11
  212. data/test/db/hsqldb.rb +0 -13
  213. data/test/db/informix.rb +0 -11
  214. data/test/db/jdbc.rb +0 -11
  215. data/test/db/jndi_config.rb +0 -40
  216. data/test/db/logger.rb +0 -3
  217. data/test/db/mssql.rb +0 -9
  218. data/test/db/mysql.rb +0 -10
  219. data/test/db/oracle.rb +0 -34
  220. data/test/db/postgres.rb +0 -9
  221. data/test/db/sqlite3.rb +0 -11
  222. data/test/db2_simple_test.rb +0 -66
  223. data/test/derby_migration_test.rb +0 -68
  224. data/test/derby_multibyte_test.rb +0 -12
  225. data/test/derby_simple_test.rb +0 -99
  226. data/test/generic_jdbc_connection_test.rb +0 -29
  227. data/test/h2_simple_test.rb +0 -41
  228. data/test/has_many_through.rb +0 -79
  229. data/test/helper.rb +0 -5
  230. data/test/hsqldb_simple_test.rb +0 -6
  231. data/test/informix_simple_test.rb +0 -48
  232. data/test/jdbc_common.rb +0 -25
  233. data/test/jndi_callbacks_test.rb +0 -40
  234. data/test/jndi_test.rb +0 -25
  235. data/test/manualTestDatabase.rb +0 -191
  236. data/test/models/add_not_null_column_to_table.rb +0 -12
  237. data/test/models/auto_id.rb +0 -18
  238. data/test/models/data_types.rb +0 -28
  239. data/test/models/entry.rb +0 -43
  240. data/test/models/mixed_case.rb +0 -25
  241. data/test/models/reserved_word.rb +0 -18
  242. data/test/models/string_id.rb +0 -18
  243. data/test/models/validates_uniqueness_of_string.rb +0 -19
  244. data/test/mssql_db_create_test.rb +0 -26
  245. data/test/mssql_identity_insert_test.rb +0 -19
  246. data/test/mssql_legacy_types_test.rb +0 -58
  247. data/test/mssql_limit_offset_test.rb +0 -136
  248. data/test/mssql_multibyte_test.rb +0 -18
  249. data/test/mssql_simple_test.rb +0 -55
  250. data/test/mysql_db_create_test.rb +0 -27
  251. data/test/mysql_info_test.rb +0 -113
  252. data/test/mysql_multibyte_test.rb +0 -10
  253. data/test/mysql_nonstandard_primary_key_test.rb +0 -42
  254. data/test/mysql_simple_test.rb +0 -49
  255. data/test/oracle_simple_test.rb +0 -18
  256. data/test/oracle_specific_test.rb +0 -83
  257. data/test/pick_rails_version.rb +0 -3
  258. data/test/postgres_db_create_test.rb +0 -32
  259. data/test/postgres_drop_db_test.rb +0 -16
  260. data/test/postgres_mixed_case_test.rb +0 -29
  261. data/test/postgres_nonseq_pkey_test.rb +0 -38
  262. data/test/postgres_reserved_test.rb +0 -22
  263. data/test/postgres_schema_search_path_test.rb +0 -44
  264. data/test/postgres_simple_test.rb +0 -51
  265. data/test/postgres_table_alias_length_test.rb +0 -15
  266. data/test/simple.rb +0 -546
  267. data/test/sqlite3_simple_test.rb +0 -233
  268. data/test/sybase_jtds_simple_test.rb +0 -28
@@ -0,0 +1,130 @@
1
+ require 'arjdbc/db2/adapter'
2
+
3
+ module ArJdbc
4
+ module AS400
5
+ include DB2
6
+
7
+ # @private
8
+ def self.extended(adapter); DB2.extended(adapter); end
9
+
10
+ # @private
11
+ def self.initialize!; DB2.initialize!; end
12
+
13
+ # @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_connection_class
14
+ def self.jdbc_connection_class; DB2.jdbc_connection_class; end
15
+
16
+ def self.column_selector
17
+ [ /as400/i, lambda { |config, column| column.extend(Column) } ]
18
+ end
19
+
20
+ # Boolean emulation can be disabled using :
21
+ #
22
+ # ArJdbc::AS400.emulate_booleans = false
23
+ #
24
+ def self.emulate_booleans; DB2.emulate_booleans; end
25
+ def self.emulate_booleans=(emulate); DB2.emulate_booleans = emulate; end
26
+
27
+ ADAPTER_NAME = 'AS400'.freeze
28
+
29
+ def adapter_name
30
+ ADAPTER_NAME
31
+ end
32
+
33
+ # @override
34
+ def prefetch_primary_key?(table_name = nil)
35
+ # TRUE if the table has no identity column
36
+ names = table_name.upcase.split(".")
37
+ sql = "SELECT 1 FROM SYSIBM.SQLPRIMARYKEYS WHERE "
38
+ sql << "TABLE_SCHEM = '#{names.first}' AND " if names.size == 2
39
+ sql << "TABLE_NAME = '#{names.last}'"
40
+ select_one(sql).nil?
41
+ end
42
+
43
+ # @override
44
+ def rename_column(table_name, column_name, new_column_name)
45
+ raise NotImplementedError, "rename_column is not supported on IBM iSeries"
46
+ end
47
+
48
+ # @override
49
+ def execute_table_change(sql, table_name, name = nil)
50
+ execute_and_auto_confirm(sql, name)
51
+ end
52
+
53
+ # holy moly batman! all this to tell AS400 "yes i am sure"
54
+ def execute_and_auto_confirm(sql, name = nil)
55
+
56
+ begin
57
+ @connection.execute_update "call qsys.qcmdexc('QSYS/CHGJOB INQMSGRPY(*SYSRPYL)',0000000031.00000)"
58
+ @connection.execute_update "call qsys.qcmdexc('ADDRPYLE SEQNBR(9876) MSGID(CPA32B2) RPY(''I'')',0000000045.00000)"
59
+ rescue Exception => e
60
+ raise "Could not call CHGJOB INQMSGRPY(*SYSRPYL) and ADDRPYLE SEQNBR(9876) MSGID(CPA32B2) RPY('I').\n" +
61
+ "Do you have authority to do this?\n\n#{e.inspect}"
62
+ end
63
+
64
+ begin
65
+ result = execute(sql, name)
66
+ rescue Exception
67
+ raise
68
+ else
69
+ # Return if all work fine
70
+ result
71
+ ensure
72
+
73
+ # Ensure default configuration restoration
74
+ begin
75
+ @connection.execute_update "call qsys.qcmdexc('QSYS/CHGJOB INQMSGRPY(*DFT)',0000000027.00000)"
76
+ @connection.execute_update "call qsys.qcmdexc('RMVRPYLE SEQNBR(9876)',0000000021.00000)"
77
+ rescue Exception => e
78
+ raise "Could not call CHGJOB INQMSGRPY(*DFT) and RMVRPYLE SEQNBR(9876).\n" +
79
+ "Do you have authority to do this?\n\n#{e.inspect}"
80
+ end
81
+
82
+ end
83
+ end
84
+ private :execute_and_auto_confirm
85
+
86
+ # disable all schemas browsing when default schema is specified
87
+ def table_exists?(name)
88
+ return false unless name
89
+ schema ? @connection.table_exists?(name, schema) : @connection.table_exists?(name)
90
+ end
91
+
92
+ DRIVER_NAME = 'com.ibm.as400.access.AS400JDBCDriver'.freeze
93
+
94
+ # @private
95
+ # @deprecated no longer used
96
+ def as400?
97
+ true
98
+ end
99
+
100
+ private
101
+
102
+ # @override
103
+ def db2_schema
104
+ @db2_schema = false unless defined? @db2_schema
105
+ return @db2_schema if @db2_schema != false
106
+ @db2_schema =
107
+ if config[:schema].present?
108
+ config[:schema]
109
+ elsif config[:jndi].present?
110
+ # Only found method to set db2_schema from jndi
111
+ result = select_one("SELECT CURRENT_SCHEMA FROM SYSIBM.SYSDUMMY1")
112
+ schema = result['00001']
113
+ # If the connection uses the library list schema name will be nil
114
+ if schema == '*LIBL'
115
+ schema = nil
116
+ end
117
+ schema
118
+ else
119
+ # AS400 implementation takes schema from library name (last part of URL)
120
+ # jdbc:as400://localhost/schema;naming=system;libraries=lib1,lib2
121
+ schema = nil
122
+ split = config[:url].split('/')
123
+ # Return nil if schema isn't defined
124
+ schema = split.last.split(';').first.strip if split.size == 4
125
+ schema
126
+ end
127
+ end
128
+
129
+ end
130
+ end
@@ -0,0 +1,167 @@
1
+ module ArJdbc
2
+ module DB2
3
+
4
+ # @see ActiveRecord::ConnectionAdapters::JdbcColumn#column_types
5
+ def self.column_selector
6
+ [ /(db2|zos)/i, lambda { |config, column| column.extend(Column) } ]
7
+ end
8
+
9
+ # @see ActiveRecord::ConnectionAdapters::JdbcColumn
10
+ module Column
11
+
12
+ # @private
13
+ def self.included(base)
14
+ # NOTE: assumes a standalone DB2Column class
15
+ class << base; include Cast; end
16
+ end
17
+
18
+ # @deprecated use `self.class.string_to_time`
19
+ def self.cast_to_date_or_time(value)
20
+ return value if value.is_a? Date
21
+ return nil if value.blank?
22
+ # https://github.com/jruby/activerecord-jdbc-adapter/commit/c225126e025df2e98ba3386c67e2a5bc5e5a73e6
23
+ return Time.now if value =~ /^CURRENT/
24
+ guess_date_or_time((value.is_a? Time) ? value : cast_to_time(value))
25
+ rescue
26
+ value
27
+ end
28
+
29
+ # @deprecated use `self.class.string_to_time` or `self.class.string_to_dummy_time`
30
+ def self.cast_to_time(value)
31
+ return value if value.is_a? Time
32
+ # AS400 returns a 2 digit year, LUW returns a 4 digit year
33
+ time = DateTime.parse(value).to_time rescue nil
34
+ return nil unless time
35
+ time_array = [time.year, time.month, time.day, time.hour, time.min, time.sec]
36
+ time_array[0] ||= 2000; time_array[1] ||= 1; time_array[2] ||= 1;
37
+ Time.send(ActiveRecord::Base.default_timezone, *time_array) rescue nil
38
+ end
39
+
40
+ # @deprecated
41
+ # @private
42
+ def self.guess_date_or_time(value)
43
+ return value if value.is_a? Date
44
+ ( value && value.hour == 0 && value.min == 0 && value.sec == 0 ) ?
45
+ Date.new(value.year, value.month, value.day) : value
46
+ end
47
+
48
+ # @override
49
+ def type_cast(value)
50
+ return nil if value.nil? || value == 'NULL' || value =~ /^\s*NULL\s*$/i
51
+ case type
52
+ when :string then value
53
+ when :integer then value.respond_to?(:to_i) ? value.to_i : (value ? 1 : 0)
54
+ when :primary_key then value.respond_to?(:to_i) ? value.to_i : (value ? 1 : 0)
55
+ when :float then value.to_f
56
+ when :date then self.class.string_to_date(value)
57
+ when :datetime then self.class.string_to_time(value)
58
+ when :timestamp then self.class.string_to_time(value)
59
+ when :time then self.class.string_to_dummy_time(value)
60
+ # TODO AS400 stores binary strings in EBCDIC (CCSID 65535), need to convert back to ASCII
61
+ else
62
+ super
63
+ end
64
+ end
65
+
66
+ # @override
67
+ def type_cast_code(var_name)
68
+ case type
69
+ when :date then "#{self.class.name}.string_to_date(#{var_name})"
70
+ when :datetime then "#{self.class.name}.string_to_time(#{var_name})"
71
+ when :timestamp then "#{self.class.name}.string_to_time(#{var_name})"
72
+ when :time then "#{self.class.name}.string_to_dummy_time(#{var_name})"
73
+ else
74
+ super
75
+ end
76
+ end
77
+
78
+ private
79
+
80
+ def simplified_type(field_type)
81
+ case field_type
82
+ when /^decimal\(1\)$/i then DB2.emulate_booleans? ? :boolean : :integer
83
+ when /smallint/i then DB2.emulate_booleans? ? :boolean : :integer
84
+ when /boolean/i then :boolean
85
+ when /^real|double/i then :float
86
+ when /int|serial/i then :integer
87
+ # if a numeric column has no scale, lets treat it as an integer.
88
+ # The AS400 rpg guys do this ALOT since they have no integer datatype ...
89
+ when /decimal|numeric|decfloat/i
90
+ extract_scale(field_type) == 0 ? :integer : :decimal
91
+ when /timestamp/i then :timestamp
92
+ when /datetime/i then :datetime
93
+ when /time/i then :time
94
+ when /date/i then :date
95
+ # DB2 provides three data types to store these data objects as strings of up to 2 GB in size:
96
+ # Character large objects (CLOBs)
97
+ # Use the CLOB data type to store SBCS or mixed data, such as documents that contain
98
+ # single character set. Use this data type if your data is larger (or might grow larger)
99
+ # than the VARCHAR data type permits.
100
+ # Double-byte character large objects (DBCLOBs)
101
+ # Use the DBCLOB data type to store large amounts of DBCS data, such as documents that
102
+ # use a DBCS character set.
103
+ # Binary large objects (BLOBs)
104
+ # Use the BLOB data type to store large amounts of noncharacter data, such as pictures,
105
+ # voice, and mixed media.
106
+ when /clob|text/i then :text # handles DBCLOB
107
+ when /^long varchar/i then :text # :limit => 32700
108
+ when /blob|binary/i then :binary
109
+ # varchar () for bit data, char () for bit data, long varchar for bit data
110
+ when /for bit data/i then :binary
111
+ when /xml/i then :xml
112
+ when /graphic/i then :graphic # vargraphic, long vargraphic
113
+ when /rowid/i then :rowid # rowid is a supported datatype on z/OS and i/5
114
+ else
115
+ super
116
+ end
117
+ end
118
+
119
+ # Post process default value from JDBC into a Rails-friendly format (columns{-internal})
120
+ def default_value(value)
121
+ # IBM i (AS400) will return an empty string instead of null for no default
122
+ return nil if value.blank?
123
+
124
+ # string defaults are surrounded by single quotes
125
+ return $1 if value =~ /^'(.*)'$/
126
+
127
+ value
128
+ end
129
+
130
+ module Cast
131
+
132
+ # @override
133
+ def string_to_date(value)
134
+ return nil unless value = current_date_time_parse(value)
135
+
136
+ super
137
+ end
138
+
139
+ # @override
140
+ def string_to_time(value)
141
+ return nil unless value = current_date_time_parse(value)
142
+
143
+ super
144
+ end
145
+
146
+ # @override
147
+ def string_to_dummy_time(value)
148
+ return nil unless value = current_date_time_parse(value)
149
+
150
+ super
151
+ end
152
+
153
+ private
154
+
155
+ def current_date_time_parse(value)
156
+ return value unless value.is_a?(String)
157
+ return nil if value.empty?
158
+ return Time.now if value.index('CURRENT') == 0
159
+
160
+ return value
161
+ end
162
+
163
+ end
164
+
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,44 @@
1
+ ArJdbc::ConnectionMethods.module_eval do
2
+ # @note Assumes DB2 driver (*db2jcc.jar*) is on class-path.
3
+ def db2_connection(config)
4
+ config[:adapter_spec] ||= ::ArJdbc::DB2
5
+
6
+ return jndi_connection(config) if jndi_config?(config)
7
+
8
+ config[:url] ||= begin
9
+ if config[:host] # Type 4 URL: jdbc:db2://server:port/database
10
+ config[:port] ||= 50000
11
+ "jdbc:db2://#{config[:host]}:#{config[:port]}/#{config[:database]}"
12
+ else # Type 2 URL: jdbc:db2:database
13
+ "jdbc:db2:#{config[:database]}"
14
+ end
15
+ end
16
+ config[:driver] ||= ::ArJdbc::DB2::DRIVER_NAME
17
+ config[:connection_alive_sql] ||= 'SELECT 1 FROM syscat.tables FETCH FIRST 1 ROWS ONLY'
18
+ jdbc_connection(config)
19
+ end
20
+ alias_method :jdbcdb2_connection, :db2_connection
21
+
22
+ # @note Assumes AS400 driver (*jt400.jar*) is on class-path.
23
+ def as400_connection(config)
24
+ config[:adapter_spec] ||= ::ArJdbc::AS400
25
+
26
+ return jndi_connection(config) if config[:jndi]
27
+
28
+ config[:url] ||= begin
29
+ # jdbc:as400://[host]
30
+ url = 'jdbc:as400://'
31
+ url << config[:host] if config[:host]
32
+ # jdbc:as400://myiSeries;database name=IASP1
33
+ url << ";database name=#{config[:database]}" if config[:database]
34
+ # jdbc:as400://[host];proxy server=HODServerName:proxyServerPort
35
+ url << ";proxy server=#{config[:proxy]}" if config[:proxy]
36
+ url
37
+ end
38
+ require 'arjdbc/db2/as400'
39
+ config[:driver] ||= ::ArJdbc::AS400::DRIVER_NAME
40
+ config[:connection_alive_sql] ||= 'SELECT 1 FROM sysibm.tables FETCH FIRST 1 ROWS ONLY'
41
+ jdbc_connection(config)
42
+ end
43
+ alias_method :jdbcas400_connection, :as400_connection
44
+ end
@@ -1,7 +1,3 @@
1
- require 'arjdbc/jdbc'
2
- jdbc_require_driver 'jdbc/derby'
1
+ require 'arjdbc'
3
2
  require 'arjdbc/derby/connection_methods'
4
3
  require 'arjdbc/derby/adapter'
5
-
6
-
7
-
@@ -0,0 +1,13 @@
1
+ # Needed because Rails is broken wrt to quoting of some values.
2
+ # Most databases are nice about it, but not Derby.
3
+ # The real issue is that you can't compare a CHAR value to a NUMBER column.
4
+ ActiveRecord::Associations::ClassMethods.module_eval do
5
+ private
6
+ def select_limited_ids_list(options, join_dependency)
7
+ return super unless connection.is_a?(ArJdbc::Derby)
8
+ connection.select_all(
9
+ construct_finder_sql_for_association_limiting(options, join_dependency),
10
+ "#{name} Load IDs For Limited Eager Loading"
11
+ ).collect { |row| connection.quote(row[primary_key], columns_hash[primary_key]) }.join(", ")
12
+ end
13
+ end
@@ -1,106 +1,261 @@
1
- require 'arjdbc/jdbc/missing_functionality_helper'
1
+ ArJdbc.load_java_part :Derby
2
2
 
3
- module ::ArJdbc
3
+ require 'arjdbc/util/table_copier'
4
+ require 'arjdbc/derby/schema_creation' # AR 4.x
5
+ require 'arel/visitors/derby'
6
+
7
+ module ArJdbc
4
8
  module Derby
5
- def self.column_selector
6
- [/derby/i, lambda {|cfg,col| col.extend(::ArJdbc::Derby::Column)}]
7
- end
8
-
9
- def self.monkey_rails
10
- unless @already_monkeyd
11
- # Needed because Rails is broken wrt to quoting of
12
- # some values. Most databases are nice about it,
13
- # but not Derby. The real issue is that you can't
14
- # compare a CHAR value to a NUMBER column.
15
- ::ActiveRecord::Associations::ClassMethods.module_eval do
16
- private
17
-
18
- def select_limited_ids_list(options, join_dependency)
19
- connection.select_all(
20
- construct_finder_sql_for_association_limiting(options, join_dependency),
21
- "#{name} Load IDs For Limited Eager Loading"
22
- ).collect { |row| connection.quote(row[primary_key], columns_hash[primary_key]) }.join(", ")
23
- end
24
- end
9
+ include Util::TableCopier
25
10
 
26
- @already_monkeyd = true
27
- end
11
+ def self.extended(adapter)
12
+ require 'arjdbc/derby/active_record_patch'
28
13
  end
29
14
 
30
- def self.extended(*args)
31
- monkey_rails
15
+ def self.included(base)
16
+ require 'arjdbc/derby/active_record_patch'
32
17
  end
33
18
 
34
- def self.included(*args)
35
- monkey_rails
19
+ # @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_connection_class
20
+ def self.jdbc_connection_class
21
+ ::ActiveRecord::ConnectionAdapters::DerbyJdbcConnection
36
22
  end
37
23
 
24
+ # @see ActiveRecord::ConnectionAdapters::JdbcColumn#column_types
25
+ def self.column_selector
26
+ [ /derby/i, lambda { |config, column| column.extend(Column) } ]
27
+ end
28
+
29
+ # @private
30
+ @@emulate_booleans = true
31
+
32
+ # Boolean emulation can be disabled using :
33
+ #
34
+ # ArJdbc::Derby.emulate_booleans = false
35
+ #
36
+ def self.emulate_booleans?; @@emulate_booleans; end
37
+ # @deprecated Use {#emulate_booleans?} instead.
38
+ def self.emulate_booleans; @@emulate_booleans; end
39
+ # @see #emulate_booleans?
40
+ def self.emulate_booleans=(emulate); @@emulate_booleans = emulate; end
41
+
42
+ # @note Part of this module is implemented in "native" Java.
43
+ # @see ActiveRecord::ConnectionAdapters::JdbcColumn
38
44
  module Column
45
+
46
+ private
47
+
48
+ def extract_limit(sql_type)
49
+ case @sql_type = sql_type.downcase
50
+ when /^smallint/i then @sql_type = 'smallint'; limit = 2
51
+ when /^bigint/i then @sql_type = 'bigint'; limit = 8
52
+ when /^double/i then @sql_type = 'double'; limit = 8 # DOUBLE PRECISION
53
+ when /^real/i then @sql_type = 'real'; limit = 4
54
+ when /^integer/i then @sql_type = 'integer'; limit = 4
55
+ when /^datetime/i then @sql_type = 'datetime'; limit = nil
56
+ when /^timestamp/i then @sql_type = 'timestamp'; limit = nil
57
+ when /^time/i then @sql_type = 'time'; limit = nil
58
+ when /^date/i then @sql_type = 'date'; limit = nil
59
+ when /^xml/i then @sql_type = 'xml'; limit = nil
60
+ else
61
+ limit = super
62
+ # handle maximum length for a VARCHAR string :
63
+ limit = 32672 if ! limit && @sql_type.index('varchar') == 0
64
+ end
65
+ limit
66
+ end
67
+
39
68
  def simplified_type(field_type)
40
- return :boolean if field_type =~ /smallint/i
41
- return :float if field_type =~ /real/i
42
- super
69
+ case field_type
70
+ when /^smallint/i then Derby.emulate_booleans? ? :boolean : :integer
71
+ when /^bigint|int/i then :integer
72
+ when /^real|double/i then :float
73
+ when /^dec/i then # DEC is a DECIMAL alias
74
+ extract_scale(field_type) == 0 ? :integer : :decimal
75
+ when /^timestamp/i then :datetime
76
+ when /^xml/i then :xml
77
+ when 'long varchar' then :text
78
+ when /for bit data/i then :binary
79
+ # :name=>"long varchar for bit data", :limit=>32700
80
+ # :name=>"varchar() for bit data", :limit=>32672
81
+ # :name=>"char() for bit data", :limit=>254}
82
+ else
83
+ super
84
+ end
43
85
  end
44
86
 
45
87
  # Post process default value from JDBC into a Rails-friendly format (columns{-internal})
46
88
  def default_value(value)
47
- # jdbc returns column default strings with actual single quotes around the value.
89
+ # JDBC returns column default strings with actual single quotes around the value.
48
90
  return $1 if value =~ /^'(.*)'$/
49
-
91
+ return nil if value == "GENERATED_BY_DEFAULT"
50
92
  value
51
93
  end
52
- end
53
94
 
54
- def adapter_name #:nodoc:
55
- 'Derby'
56
95
  end
57
96
 
58
- def arel2_visitors
59
- require 'arel/visitors/derby'
60
- {'derby' => ::Arel::Visitors::Derby, 'jdbcderby' => ::Arel::Visitors::Derby}
97
+ ADAPTER_NAME = 'Derby'.freeze
98
+
99
+ def adapter_name
100
+ ADAPTER_NAME
61
101
  end
62
102
 
63
- include ArJdbc::MissingFunctionalityHelper
103
+ def configure_connection
104
+ # must be done or SELECT...FOR UPDATE won't work how we expect :
105
+ if tx_isolation = config[:transaction_isolation]
106
+ @connection.transaction_isolation = tx_isolation
107
+ end
108
+ # if a user name was specified upon connection, the user's name is the
109
+ # default schema for the connection, if a schema with that name exists
110
+ set_schema(config[:schema]) if config[:schema]
111
+ end
64
112
 
65
113
  def index_name_length
66
114
  128
67
115
  end
68
116
 
117
+ NATIVE_DATABASE_TYPES = {
118
+ :primary_key => "int GENERATED BY DEFAULT AS identity NOT NULL PRIMARY KEY",
119
+ :string => { :name => "varchar", :limit => 255 }, # 32672
120
+ :text => { :name => "clob" }, # 2,147,483,647
121
+ :char => { :name => "char", :limit => 254 }, # JDBC :limit => 254
122
+ :binary => { :name => "blob" }, # 2,147,483,647
123
+ :float => { :name => "float", :limit => 8 }, # DOUBLE PRECISION
124
+ :real => { :name => "real", :limit => 4 }, # JDBC :limit => 23
125
+ :double => { :name => "double", :limit => 8 }, # JDBC :limit => 52
126
+ :decimal => { :name => "decimal", :precision => 5, :scale => 0 }, # JDBC :limit => 31
127
+ :numeric => { :name => "decimal", :precision => 5, :scale => 0 }, # JDBC :limit => 31
128
+ :integer => { :name => "integer", :limit => 4 }, # JDBC :limit => 10
129
+ :smallint => { :name => "smallint", :limit => 2 }, # JDBC :limit => 5
130
+ :bigint => { :name => "bigint", :limit => 8 }, # JDBC :limit => 19
131
+ :date => { :name => "date" },
132
+ :time => { :name => "time" },
133
+ :datetime => { :name => "timestamp" },
134
+ :timestamp => { :name => "timestamp" },
135
+ :xml => { :name => "xml" },
136
+ :boolean => { :name => "smallint", :limit => 1 }, # TODO boolean (since 10.7)
137
+ :object => { :name => "object" },
138
+ }
139
+
140
+ # @private
141
+ def initialize_type_map(m)
142
+ super
143
+ m.register_type(%r(smallint)i) do |sql_type|
144
+ if Derby.emulate_booleans?
145
+ ActiveRecord::Type::Boolean.new
146
+ else
147
+ ActiveRecord::Type::Integer.new(:limit => 1)
148
+ end
149
+ end
150
+ m.alias_type %r(real)i, 'float'
151
+ end if AR42
152
+
153
+ def reset_column_information
154
+ initialize_type_map(type_map)
155
+ end if AR42
156
+
157
+ # @override
158
+ def native_database_types
159
+ NATIVE_DATABASE_TYPES
160
+ end
161
+
162
+ # UNTESTED
163
+ def existing_savepoint_name?(name)
164
+ (@connection.instance_variable_get('@savepoints') || {}).key? name
165
+ end
166
+
167
+ # Ensure the savepoint name is unused before creating it.
168
+ # @override
169
+ def create_savepoint(name = current_savepoint_name(true))
170
+ release_savepoint(name) if existing_savepoint_name?(name)
171
+ super(name)
172
+ end
173
+
174
+ # @override
175
+ def quote(value, column = nil)
176
+ return super if column && ArJdbc::AR42 && column.cast_type.is_a?(ActiveRecord::Type::Serialized)
177
+ return value.quoted_id if value.respond_to?(:quoted_id)
178
+ return value if sql_literal?(value)
179
+ return 'NULL' if value.nil?
180
+
181
+ column_type = column && column.type
182
+ if column_type == :string || column_type == :text
183
+ # Derby is not permissive
184
+ # e.g. sending an Integer to a VARCHAR column will fail
185
+ case value
186
+ when BigDecimal then value = value.to_s('F')
187
+ when Numeric then value = value.to_s
188
+ when true, false then value = value.to_s
189
+ when Date, Time then value = quoted_date(value)
190
+ else # on 2.3 attribute serialization needs to_yaml here
191
+ value = value.to_s if ActiveRecord::VERSION::MAJOR >= 3
192
+ end
193
+ end
194
+
195
+ case value
196
+ when String, ActiveSupport::Multibyte::Chars
197
+ if column_type == :text
198
+ "CAST('#{quote_string(value)}' AS CLOB)"
199
+ elsif column_type == :binary
200
+ "CAST(X'#{quote_binary(value)}' AS BLOB)"
201
+ elsif column_type == :xml
202
+ "XMLPARSE(DOCUMENT '#{quote_string(value)}' PRESERVE WHITESPACE)"
203
+ elsif column_type == :integer
204
+ value.to_i
205
+ elsif column_type == :float
206
+ value.to_f
207
+ else
208
+ "'#{quote_string(value)}'"
209
+ end
210
+ else
211
+ super
212
+ end
213
+ end
214
+
215
+ # @override
216
+ def quoted_date(value)
217
+ if value.acts_like?(:time) && value.respond_to?(:usec)
218
+ usec = sprintf("%06d", value.usec)
219
+ value = ::ActiveRecord::Base.default_timezone == :utc ? value.getutc : value.getlocal
220
+ "#{value.strftime("%Y-%m-%d %H:%M:%S")}.#{usec}"
221
+ else
222
+ super
223
+ end
224
+ end if ::ActiveRecord::VERSION::MAJOR >= 3
225
+
226
+ # @private In Derby, these cannot specify a limit.
227
+ NO_LIMIT_TYPES = [ :integer, :boolean, :timestamp, :datetime, :date, :time ]
228
+
69
229
  # Convert the specified column type to a SQL string.
70
- # In Derby, the following cannot specify a limit:
71
- # - integer
72
- # - boolean (smallint)
73
- # - timestamp
74
- # - date
75
- def type_to_sql(type, limit = nil, precision = nil, scale = nil) #:nodoc:
76
- return super unless [:integer, :boolean, :timestamp, :date].include? type
230
+ # @override
231
+ def type_to_sql(type, limit = nil, precision = nil, scale = nil)
232
+ return super unless NO_LIMIT_TYPES.include?(t = type.to_s.downcase.to_sym)
77
233
 
78
- native = native_database_types[type.to_s.downcase.to_sym]
79
- native.is_a?(Hash) ? native[:name] : native
234
+ native_type = NATIVE_DATABASE_TYPES[t]
235
+ native_type.is_a?(Hash) ? native_type[:name] : native_type
80
236
  end
81
237
 
82
- def modify_types(tp)
83
- tp[:primary_key] = "int generated by default as identity NOT NULL PRIMARY KEY"
84
- tp[:string][:limit] = 256
85
- tp[:integer][:limit] = nil
86
- tp[:boolean] = {:name => "smallint"}
87
- tp[:timestamp][:limit] = nil
88
- tp[:date][:limit] = nil
89
- tp
238
+ # @private
239
+ class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
240
+
241
+ def xml(*args)
242
+ options = args.extract_options!
243
+ column(args[0], 'xml', options)
244
+ end
245
+
90
246
  end
91
247
 
92
- # Override default -- fix case where ActiveRecord passes :default => nil, :null => true
93
- def add_column_options!(sql, options)
94
- options.delete(:default) if options.has_key?(:default) && options[:default].nil?
95
- sql << " DEFAULT #{quote(options.delete(:default))}" if options.has_key?(:default)
96
- super
248
+ def table_definition(*args)
249
+ new_table_definition(TableDefinition, *args)
97
250
  end
98
251
 
99
- def classes_for_table_name(table)
100
- ActiveRecord::Base.send(:subclasses).select {|klass| klass.table_name == table}
252
+ # @override
253
+ def empty_insert_statement_value
254
+ ::Arel::Visitors::Derby::VALUES_DEFAULT # Derby needs to know the columns
101
255
  end
102
256
 
103
257
  # Set the sequence to the max value of the table's column.
258
+ # @override
104
259
  def reset_sequence!(table, column, sequence = nil)
105
260
  mpk = select_value("SELECT MAX(#{quote_column_name(column)}) FROM #{quote_table_name(table)}")
106
261
  execute("ALTER TABLE #{quote_table_name(table)} ALTER COLUMN #{quote_column_name(column)} RESTART WITH #{mpk.to_i + 1}")
@@ -115,150 +270,71 @@ module ::ArJdbc
115
270
  end
116
271
  end
117
272
 
118
- def remove_index(table_name, options) #:nodoc:
273
+ def classes_for_table_name(table)
274
+ ActiveRecord::Base.send(:subclasses).select { |klass| klass.table_name == table }
275
+ end
276
+ private :classes_for_table_name
277
+
278
+ # @override
279
+ def remove_index(table_name, options)
119
280
  execute "DROP INDEX #{index_name(table_name, options)}"
120
281
  end
121
282
 
283
+ # @override
122
284
  def rename_table(name, new_name)
123
285
  execute "RENAME TABLE #{quote_table_name(name)} TO #{quote_table_name(new_name)}"
124
286
  end
125
287
 
126
- AUTO_INC_STMT2 = "SELECT AUTOINCREMENTSTART, AUTOINCREMENTINC, COLUMNNAME, REFERENCEID, COLUMNDEFAULT FROM SYS.SYSCOLUMNS WHERE REFERENCEID = (SELECT T.TABLEID FROM SYS.SYSTABLES T WHERE T.TABLENAME = '%s') AND COLUMNNAME = '%s'"
127
-
128
- def add_quotes(name)
129
- return name unless name
130
- %Q{"#{name}"}
131
- end
132
-
133
- def strip_quotes(str)
134
- return str unless str
135
- return str unless /^(["']).*\1$/ =~ str
136
- str[1..-2]
137
- end
138
-
139
- def expand_double_quotes(name)
140
- return name unless name && name['"']
141
- name.gsub(/"/,'""')
142
- end
143
-
144
- def auto_increment_stmt(tname, cname)
145
- stmt = AUTO_INC_STMT2 % [tname, strip_quotes(cname)]
146
- data = execute(stmt).first
147
- if data
148
- start = data['autoincrementstart']
149
- if start
150
- coldef = ""
151
- coldef << " GENERATED " << (data['columndefault'].nil? ? "ALWAYS" : "BY DEFAULT ")
152
- coldef << "AS IDENTITY (START WITH "
153
- coldef << start
154
- coldef << ", INCREMENT BY "
155
- coldef << data['autoincrementinc']
156
- coldef << ")"
157
- return coldef
158
- end
159
- end
160
- ""
161
- end
162
-
163
-
164
288
  def add_column(table_name, column_name, type, options = {})
165
289
  add_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
166
290
  add_column_options!(add_column_sql, options)
167
291
  execute(add_column_sql)
168
- end
292
+ end unless const_defined? :SchemaCreation
169
293
 
170
- def execute(sql, name = nil)
171
- if sql =~ /\A\s*(UPDATE|INSERT)/i
172
- i = sql =~ /\swhere\s/im
173
- if i
174
- sql[i..-1] = sql[i..-1].gsub(/!=\s*NULL/, 'IS NOT NULL').gsub(/=\sNULL/i, 'IS NULL')
175
- end
176
- else
177
- sql.gsub!(/= NULL/i, 'IS NULL')
178
- end
294
+ # @override fix case where AR passes `:default => nil, :null => true`
295
+ def add_column_options!(sql, options)
296
+ options.delete(:default) if options.has_key?(:default) && options[:default].nil?
297
+ sql << " DEFAULT #{quote(options.delete(:default))}" if options.has_key?(:default)
179
298
  super
180
- end
299
+ end unless const_defined? :SchemaCreation
181
300
 
182
- # SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause.
183
- #
184
- # Derby requires the ORDER BY columns in the select list for distinct queries, and
185
- # requires that the ORDER BY include the distinct column.
186
- #
187
- # distinct("posts.id", "posts.created_at desc")
188
- #
189
- # Based on distinct method for PostgreSQL Adapter
190
- def distinct(columns, order_by)
191
- return "DISTINCT #{columns}" if order_by.blank?
192
-
193
- # construct a clean list of column names from the ORDER BY clause, removing
194
- # any asc/desc modifiers
195
- order_columns = order_by.split(',').collect { |s| s.split.first }
196
- order_columns.delete_if(&:blank?)
197
- order_columns = order_columns.zip((0...order_columns.size).to_a).map { |s,i| "#{s} AS alias_#{i}" }
198
-
199
- # return a DISTINCT clause that's distinct on the columns we want but includes
200
- # all the required columns for the ORDER BY to work properly
201
- sql = "DISTINCT #{columns}, #{order_columns * ', '}"
202
- sql
203
- end
204
-
205
- SIZEABLE = %w(VARCHAR CLOB BLOB)
206
-
207
- def structure_dump #:nodoc:
208
- definition=""
209
- rs = @connection.connection.meta_data.getTables(nil,nil,nil,["TABLE"].to_java(:string))
210
- while rs.next
211
- tname = rs.getString(3)
212
- definition << "CREATE TABLE #{tname} (\n"
213
- rs2 = @connection.connection.meta_data.getColumns(nil,nil,tname,nil)
214
- first_col = true
215
- while rs2.next
216
- col_name = add_quotes(rs2.getString(4));
217
- default = ""
218
- d1 = rs2.getString(13)
219
- if d1 =~ /^GENERATED_/
220
- default = auto_increment_stmt(tname, col_name)
221
- elsif d1
222
- default = " DEFAULT #{d1}"
223
- end
301
+ if ActiveRecord::VERSION::MAJOR >= 4
224
302
 
225
- type = rs2.getString(6)
226
- col_size = rs2.getString(7)
227
- nulling = (rs2.getString(18) == 'NO' ? " NOT NULL" : "")
228
- create_col_string = add_quotes(expand_double_quotes(strip_quotes(col_name))) +
229
- " " +
230
- type +
231
- (SIZEABLE.include?(type) ? "(#{col_size})" : "") +
232
- nulling +
233
- default
234
- if !first_col
235
- create_col_string = ",\n #{create_col_string}"
236
- else
237
- create_col_string = " #{create_col_string}"
238
- end
303
+ # @override
304
+ def remove_column(table_name, column_name, type = nil, options = {})
305
+ do_remove_column(table_name, column_name)
306
+ end
239
307
 
240
- definition << create_col_string
308
+ else
241
309
 
242
- first_col = false
243
- end
244
- definition << ");\n\n"
310
+ # @override
311
+ def remove_column(table_name, *column_names)
312
+ for column_name in column_names.flatten
313
+ do_remove_column(table_name, column_name)
245
314
  end
246
- definition
315
+ end
316
+ alias remove_columns remove_column
317
+
247
318
  end
248
319
 
249
- def remove_column(table_name, column_name)
320
+ def do_remove_column(table_name, column_name)
250
321
  execute "ALTER TABLE #{quote_table_name(table_name)} DROP COLUMN #{quote_column_name(column_name)} RESTRICT"
251
322
  end
323
+ private :do_remove_column
252
324
 
253
- # Notes about changing in Derby:
254
- # http://db.apache.org/derby/docs/10.2/ref/rrefsqlj81859.html#rrefsqlj81859__rrefsqlj37860)
255
- #
256
- # We support changing columns using the strategy outlined in:
257
- # https://issues.apache.org/jira/browse/DERBY-1515
258
- #
259
- # This feature has not made it into a formal release and is not in Java 6. We will
260
- # need to conditionally support this somehow (supposed to arrive for 10.3.0.0)
325
+ # @override
261
326
  def change_column(table_name, column_name, type, options = {})
327
+ # TODO this needs a review since now we're likely to be on >= 10.8
328
+
329
+ # Notes about changing in Derby:
330
+ # http://db.apache.org/derby/docs/10.2/ref/rrefsqlj81859.html#rrefsqlj81859__rrefsqlj37860)
331
+ #
332
+ # We support changing columns using the strategy outlined in:
333
+ # https://issues.apache.org/jira/browse/DERBY-1515
334
+ #
335
+ # This feature has not made it into a formal release and is not in Java 6.
336
+ # We will need to conditionally support this (supposed to arrive for 10.3.0.0).
337
+
262
338
  # null/not nulling is easy, handle that separately
263
339
  if options.include?(:null)
264
340
  # This seems to only work with 10.2 of Derby
@@ -272,14 +348,17 @@ module ::ArJdbc
272
348
  # anything left to do?
273
349
  unless options.empty?
274
350
  begin
275
- execute "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} SET DATA TYPE #{type_to_sql(type, options[:limit])}"
351
+ execute "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN " <<
352
+ " #{quote_column_name(column_name)} SET DATA TYPE #{type_to_sql(type, options[:limit])}"
276
353
  rescue
277
354
  transaction do
278
355
  temp_new_column_name = "#{column_name}_newtype"
279
356
  # 1) ALTER TABLE t ADD COLUMN c1_newtype NEWTYPE;
280
357
  add_column table_name, temp_new_column_name, type, options
281
358
  # 2) UPDATE t SET c1_newtype = c1;
282
- execute "UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(temp_new_column_name)} = CAST(#{quote_column_name(column_name)} AS #{type_to_sql(type, options[:limit])})"
359
+ execute "UPDATE #{quote_table_name(table_name)} SET " <<
360
+ " #{quote_column_name(temp_new_column_name)} = " <<
361
+ " CAST(#{quote_column_name(column_name)} AS #{type_to_sql(type, options[:limit])})"
283
362
  # 3) ALTER TABLE t DROP COLUMN c1;
284
363
  remove_column table_name, column_name
285
364
  # 4) ALTER TABLE t RENAME COLUMN c1_newtype to c1;
@@ -289,60 +368,173 @@ module ::ArJdbc
289
368
  end
290
369
  end
291
370
 
292
- def rename_column(table_name, column_name, new_column_name) #:nodoc:
293
- execute "RENAME COLUMN #{quote_table_name(table_name)}.#{quote_column_name(column_name)} TO #{quote_column_name(new_column_name)}"
371
+ # @override
372
+ def rename_column(table_name, column_name, new_column_name)
373
+ execute "RENAME COLUMN #{quote_table_name(table_name)}.#{quote_column_name(column_name)} " <<
374
+ " TO #{quote_column_name(new_column_name)}"
294
375
  end
295
376
 
377
+ # SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause.
378
+ #
379
+ # Derby requires the ORDER BY columns in the select list for distinct queries, and
380
+ # requires that the ORDER BY include the distinct column.
381
+ # ```
382
+ # distinct("posts.id", "posts.created_at desc")
383
+ # ```
384
+ # @note This is based on distinct method for the PostgreSQL Adapter.
385
+ # @override
386
+ def distinct(columns, order_by)
387
+ "DISTINCT #{columns_for_distinct(columns, order_by)}"
388
+ end
389
+
390
+ # @override Since AR 4.0 (on 4.1 {#distinct} is gone and won't be called).
391
+ def columns_for_distinct(columns, orders)
392
+ return columns if orders.blank?
393
+
394
+ # construct a clean list of column names from the ORDER BY clause,
395
+ # removing any ASC/DESC modifiers
396
+ order_columns = [ orders ]; order_columns.flatten! # AR 3.x vs 4.x
397
+ order_columns.map! do |column|
398
+ column = column.to_sql unless column.is_a?(String) # handle AREL node
399
+ column.split(',').collect! { |s| s.split.first }
400
+ end.flatten!
401
+ order_columns.reject!(&:blank?)
402
+ order_columns = order_columns.zip (0...order_columns.size).to_a
403
+ order_columns = order_columns.map { |s, i| "#{s} AS alias_#{i}" }
404
+
405
+ columns = [ columns ]; columns.flatten!
406
+ columns.push( *order_columns ).join(', ')
407
+ # return a DISTINCT clause that's distinct on the columns we want but
408
+ # includes all the required columns for the ORDER BY to work properly
409
+ end
410
+
411
+ # @override
296
412
  def primary_keys(table_name)
297
413
  @connection.primary_keys table_name.to_s.upcase
298
414
  end
299
415
 
300
- def columns(table_name, name=nil)
301
- @connection.columns_internal(table_name.to_s, name, derby_schema)
416
+ # @override
417
+ def tables(name = nil)
418
+ @connection.tables(nil, current_schema)
302
419
  end
303
420
 
304
- def tables
305
- @connection.tables(nil, derby_schema)
421
+ # @override
422
+ def supports_ddl_transactions?; true end
423
+
424
+ # @override
425
+ def supports_foreign_keys?; true end
426
+
427
+ def truncate(table_name, name = nil)
428
+ execute "TRUNCATE TABLE #{quote_table_name(table_name)}", name
306
429
  end
307
430
 
308
- def recreate_database(db_name)
309
- tables.each do |t|
310
- drop_table t
311
- end
431
+ # @return [String] the current schema name
432
+ def current_schema
433
+ @current_schema ||=
434
+ select_value "SELECT CURRENT SCHEMA FROM SYS.SYSSCHEMAS FETCH FIRST 1 ROWS ONLY", 'SCHEMA'
312
435
  end
313
436
 
314
- def quote_column_name(name) #:nodoc:
315
- %Q{"#{name.to_s.upcase.gsub(/"/, '""')}"}
437
+ # Change the current (implicit) Derby schema to be used for this connection.
438
+ def set_schema(schema)
439
+ @current_schema = nil
440
+ execute "SET SCHEMA #{schema}", 'SCHEMA'
316
441
  end
442
+ alias_method :current_schema=, :set_schema
317
443
 
318
- def quoted_true
319
- '1'
444
+ # Creates a new Derby schema.
445
+ # @see #set_schema
446
+ def create_schema(schema)
447
+ execute "CREATE SCHEMA #{schema}", 'Create Schema'
320
448
  end
321
449
 
322
- def quoted_false
323
- '0'
450
+ # Drops an existing schema, needs to be empty (no DB objects).
451
+ def drop_schema(schema)
452
+ execute "DROP SCHEMA #{schema} RESTRICT", 'Drop Schema'
324
453
  end
325
454
 
326
- def add_limit_offset!(sql, options) #:nodoc:
327
- if options[:offset]
328
- sql << " OFFSET #{options[:offset]} ROWS"
329
- end
330
- if options[:limit]
331
- #ROWS/ROW and FIRST/NEXT mean the same
332
- sql << " FETCH FIRST #{options[:limit]} ROWS ONLY"
333
- end
455
+ # @private
456
+ def recreate_database(name = nil, options = {})
457
+ drop_database(name)
458
+ create_database(name, options)
459
+ end
460
+
461
+ # @private
462
+ def create_database(name = nil, options = {}); end
463
+
464
+ # @private
465
+ def drop_database(name = nil)
466
+ tables.each { |table| drop_table(table) }
467
+ end
468
+
469
+ # @override
470
+ def quote_column_name(name)
471
+ %Q{"#{name.to_s.upcase.gsub('"', '""')}"}
472
+ end
473
+
474
+ # @override
475
+ def quote_table_name_for_assignment(table, attr)
476
+ quote_column_name(attr)
477
+ end if ::ActiveRecord::VERSION::MAJOR > 3
478
+
479
+ # @note Only used with (non-AREL) ActiveRecord **2.3**.
480
+ # @see Arel::Visitors::Derby
481
+ def add_limit_offset!(sql, options)
482
+ sql << " OFFSET #{options[:offset]} ROWS" if options[:offset]
483
+ # ROWS/ROW and FIRST/NEXT mean the same
484
+ sql << " FETCH FIRST #{options[:limit]} ROWS ONLY" if options[:limit]
485
+ end if ::ActiveRecord::VERSION::MAJOR < 3
486
+
487
+ # @override
488
+ def execute(sql, name = nil, binds = [])
489
+ sql = to_sql(sql, binds)
490
+ insert = self.class.insert?(sql)
491
+ update = ! insert && ! self.class.select?(sql)
492
+ sql = correct_is_null(sql, insert || update)
493
+ super(sql, name, binds)
494
+ end
495
+
496
+ # Returns the value of an identity column of the last *INSERT* statement
497
+ # made over this connection.
498
+ # @note Check the *IDENTITY_VAL_LOCAL* function for documentation.
499
+ # @return [Fixnum]
500
+ def last_insert_id
501
+ @connection.identity_val_local
334
502
  end
335
503
 
336
504
  private
337
- # Derby appears to define schemas using the username
338
- def derby_schema
339
- if @config.has_key?(:schema)
340
- config[:schema]
505
+
506
+ def correct_is_null(sql, insert_or_update = false)
507
+ if insert_or_update
508
+ if ( i = sql =~ /\sWHERE\s/im )
509
+ where_part = sql[i..-1]; sql = sql.dup
510
+ where_part.gsub!(/!=\s*NULL/i, 'IS NOT NULL')
511
+ where_part.gsub!(/=\sNULL/i, 'IS NULL')
512
+ sql[i..-1] = where_part
513
+ end
514
+ sql
341
515
  else
342
- (@config[:username] && @config[:username].to_s) || ''
516
+ sql.gsub(/=\sNULL/i, 'IS NULL')
343
517
  end
344
518
  end
345
- end
346
- end
347
519
 
520
+ # NOTE: only setup query analysis on AR <= 3.0 since on 3.1 {#exec_query},
521
+ # {#exec_insert} will be used for AR generated queries/inserts etc.
522
+ # Also there's prepared statement support and {#execute} is meant to stay
523
+ # as a way of running non-prepared SQL statements (returning raw results).
524
+ if ActiveRecord::VERSION::MAJOR < 3 ||
525
+ ( ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR < 1 )
348
526
 
527
+ def _execute(sql, name = nil)
528
+ if self.class.insert?(sql)
529
+ @connection.execute_insert(sql)
530
+ elsif self.class.select?(sql)
531
+ @connection.execute_query_raw(sql)
532
+ else
533
+ @connection.execute_update(sql)
534
+ end
535
+ end
536
+
537
+ end
538
+
539
+ end
540
+ end