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,580 @@
1
+ /*
2
+ * The MIT License
3
+ *
4
+ * Copyright 2014 Karol Bucek.
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in
14
+ * all copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ * THE SOFTWARE.
23
+ */
24
+ package arjdbc.util;
25
+
26
+ import java.sql.Date;
27
+ import java.sql.Time;
28
+ import java.sql.Timestamp;
29
+ import java.util.TimeZone;
30
+
31
+ import org.joda.time.DateTime;
32
+ import org.joda.time.DateTimeZone;
33
+ import org.joda.time.chrono.ISOChronology;
34
+ import org.jruby.Ruby;
35
+ import org.jruby.RubyFloat;
36
+ import org.jruby.RubyString;
37
+ import org.jruby.RubyTime;
38
+ import org.jruby.javasupport.Java;
39
+ import org.jruby.runtime.Block;
40
+ import org.jruby.runtime.ThreadContext;
41
+ import org.jruby.runtime.builtin.IRubyObject;
42
+ import org.jruby.util.ByteList;
43
+
44
+ import static arjdbc.util.StringHelper.decByte;
45
+
46
+ /**
47
+ * Utilities for handling/converting dates and times.
48
+ * @author kares
49
+ */
50
+ public abstract class DateTimeUtils {
51
+
52
+ @SuppressWarnings("deprecation")
53
+ public static ByteList timeToString(final Time time) {
54
+ final ByteList str = new ByteList(8); // hh:mm:ss
55
+
56
+ int hours = time.getHours();
57
+ int minutes = time.getMinutes();
58
+ int seconds = time.getSeconds();
59
+
60
+ str.append( decByte( hours / 10 ) );
61
+ str.append( decByte( hours % 10 ) );
62
+
63
+ str.append( ':' );
64
+
65
+ str.append( decByte( minutes / 10 ) );
66
+ str.append( decByte( minutes % 10 ) );
67
+
68
+ str.append( ':' );
69
+
70
+ str.append( decByte( seconds / 10 ) );
71
+ str.append( decByte( seconds % 10 ) );
72
+
73
+ return str;
74
+ }
75
+
76
+ private static final byte[] DUMMY_TIME_PREFIX = { '2','0','0','0','-','0','1','-','0','1' };
77
+
78
+ @SuppressWarnings("deprecation")
79
+ public static ByteList dummyTimeToString(final Timestamp time) {
80
+ final ByteList str = new ByteList(29); // yyyy-mm-dd hh:mm:ss.fffffffff
81
+
82
+ int hours = time.getHours();
83
+ int minutes = time.getMinutes();
84
+ int seconds = time.getSeconds();
85
+ int nanos = time.getNanos();
86
+
87
+ str.append( DUMMY_TIME_PREFIX );
88
+
89
+ str.append( ' ' );
90
+
91
+ formatTime(str, hours, minutes, seconds, nanos);
92
+
93
+ return str;
94
+ }
95
+
96
+ @SuppressWarnings("deprecation")
97
+ public static ByteList dateToString(final Date date) {
98
+ final ByteList str = new ByteList(10); // "2000-00-00"
99
+
100
+ int year = date.getYear() + 1900;
101
+ int month = date.getMonth() + 1;
102
+ int day = date.getDate();
103
+
104
+ str.append( decByte( ( year / 1000 ) % 10 ) );
105
+ str.append( decByte( ( year / 100 ) % 10 ) );
106
+ str.append( decByte( ( year / 10 ) % 10 ) );
107
+ str.append( decByte( year % 10 ) );
108
+
109
+ str.append( '-' );
110
+
111
+ str.append( decByte( month / 10 ) );
112
+ str.append( decByte( month % 10 ) );
113
+
114
+ str.append( '-' );
115
+
116
+ str.append( decByte( day / 10 ) );
117
+ str.append( decByte( day % 10 ) );
118
+
119
+ return str;
120
+ }
121
+
122
+ @SuppressWarnings("deprecation")
123
+ public static ByteList timestampToString(final Timestamp timestamp) {
124
+ final ByteList str = new ByteList(29); // yyyy-mm-dd hh:mm:ss.fffffffff
125
+
126
+ int year = timestamp.getYear() + 1900;
127
+ int month = timestamp.getMonth() + 1;
128
+ int day = timestamp.getDate();
129
+ int hours = timestamp.getHours();
130
+ int minutes = timestamp.getMinutes();
131
+ int seconds = timestamp.getSeconds();
132
+ int nanos = timestamp.getNanos();
133
+
134
+ str.append( decByte( ( year / 1000 ) % 10 ) );
135
+ str.append( decByte( ( year / 100 ) % 10 ) );
136
+ str.append( decByte( ( year / 10 ) % 10 ) );
137
+ str.append( decByte( year % 10 ) );
138
+
139
+ str.append( '-' );
140
+
141
+ str.append( decByte( month / 10 ) );
142
+ str.append( decByte( month % 10 ) );
143
+
144
+ str.append( '-' );
145
+
146
+ str.append( decByte( day / 10 ) );
147
+ str.append( decByte( day % 10 ) );
148
+
149
+ if ( hours != 0 || minutes != 0 || seconds != 0 || nanos != 0 ) {
150
+ str.append( ' ' );
151
+
152
+ formatTime(str, hours, minutes, seconds, nanos);
153
+ }
154
+
155
+ return str;
156
+ }
157
+
158
+ private static final int NANO_DIGITS_RAILS_CAN_MANAGE = 6; // 'normally' would have been 8
159
+
160
+ private static void formatTime(final ByteList str,
161
+ final int hours, final int minutes, final int seconds, final int nanos) {
162
+
163
+ str.append( decByte( hours / 10 ) );
164
+ str.append( decByte( hours % 10 ) );
165
+
166
+ str.append( ':' );
167
+
168
+ str.append( decByte( minutes / 10 ) );
169
+ str.append( decByte( minutes % 10 ) );
170
+
171
+ str.append( ':' );
172
+
173
+ str.append( decByte( seconds / 10 ) );
174
+ str.append( decByte( seconds % 10 ) );
175
+
176
+ if ( nanos != 0 ) {
177
+ str.append( '.' );
178
+ // NOTE: Rails (still) terrible at handling full nanos precision: '12:30:00.99990000'
179
+ int pow = 100000000; // nanos <= 999999999
180
+ for ( int i = 0; i < NANO_DIGITS_RAILS_CAN_MANAGE; i++ ) {
181
+ final int b = nanos / pow;
182
+ if ( b == 0 ) break; // done (no trailing zeros)
183
+ str.append( decByte( b % 10 ) );
184
+ pow = pow / 10;
185
+ }
186
+ }
187
+ }
188
+
189
+ @SuppressWarnings("deprecation")
190
+ public static RubyTime newDummyTime(final ThreadContext context, final Time time, final DateTimeZone defaultZone) {
191
+
192
+ final int hours = time.getHours();
193
+ final int minutes = time.getMinutes();
194
+ final int seconds = time.getSeconds();
195
+ //final int offset = time.getTimezoneOffset();
196
+
197
+ DateTime dateTime = new DateTime(2000, 1, 1, hours, minutes, seconds, defaultZone);
198
+ return RubyTime.newTime(context.runtime, dateTime, 0);
199
+ }
200
+
201
+ @SuppressWarnings("deprecation")
202
+ public static RubyTime newDummyTime(final ThreadContext context, final Timestamp time, final DateTimeZone defaultZone) {
203
+
204
+ final int hours = time.getHours();
205
+ final int minutes = time.getMinutes();
206
+ final int seconds = time.getSeconds();
207
+ final int nanos = time.getNanos(); // max 999-999-999
208
+
209
+ DateTime dateTime = new DateTime(2000, 1, 1, hours, minutes, seconds, defaultZone);
210
+ return RubyTime.newTime(context.runtime, dateTime, nanos);
211
+ }
212
+
213
+ @SuppressWarnings("deprecation")
214
+ public static RubyTime newTime(final ThreadContext context, final Timestamp timestamp, final DateTimeZone defaultZone) {
215
+
216
+ final int year = timestamp.getYear() + 1900;
217
+ final int month = timestamp.getMonth() + 1;
218
+ final int day = timestamp.getDate();
219
+ final int hours = timestamp.getHours();
220
+ final int minutes = timestamp.getMinutes();
221
+ final int seconds = timestamp.getSeconds();
222
+ final int nanos = timestamp.getNanos(); // max 999-999-999
223
+
224
+ DateTime dateTime = new DateTime(year, month, day, hours, minutes, seconds, 0, defaultZone);
225
+ return RubyTime.newTime(context.runtime, dateTime, nanos);
226
+ }
227
+
228
+ @SuppressWarnings("deprecation")
229
+ public static RubyTime newDateAsTime(final ThreadContext context, final Date date, final DateTimeZone zone) {
230
+
231
+ final int year = date.getYear() + 1900;
232
+ final int month = date.getMonth() + 1;
233
+ final int day = date.getDate();
234
+
235
+ DateTime dateTime = new DateTime(year, month, day, 0, 0, 0, 0, zone);
236
+ return RubyTime.newTime(context.runtime, dateTime, 0);
237
+ }
238
+
239
+ @SuppressWarnings("deprecation")
240
+ public static IRubyObject newDate(final ThreadContext context, final Date date, final DateTimeZone zone) {
241
+
242
+ final int year = date.getYear() + 1900;
243
+ final int month = date.getMonth() + 1;
244
+ final int day = date.getDate();
245
+
246
+ return newDate(context, year, month, day, ISOChronology.getInstance(zone));
247
+ }
248
+
249
+ // @Deprecated
250
+ public static Timestamp convertToTimestamp(final RubyFloat value) {
251
+ final Timestamp timestamp = new Timestamp(value.getLongValue() * 1000); // millis
252
+
253
+ // for usec we shall not use: ((long) floatValue * 1000000) % 1000
254
+ // if ( usec >= 0 ) timestamp.setNanos( timestamp.getNanos() + usec * 1000 );
255
+ // due doubles inaccurate precision it's better to parse to_s :
256
+ final ByteList strValue = ((RubyString) value.to_s()).getByteList();
257
+ final int dot1 = strValue.lastIndexOf('.') + 1, dot4 = dot1 + 3;
258
+ final int len = strValue.getRealSize() - strValue.getBegin();
259
+ if ( dot1 > 0 && dot4 < len ) { // skip .123 but handle .1234
260
+ final int end = Math.min( len - dot4, 3 );
261
+ CharSequence usecSeq = strValue.subSequence(dot4, end);
262
+ final int usec = Integer.parseInt( usecSeq.toString() );
263
+ if ( usec < 10 ) { // 0.1234 ~> 4
264
+ timestamp.setNanos( timestamp.getNanos() + usec * 100 );
265
+ }
266
+ else if ( usec < 100 ) { // 0.12345 ~> 45
267
+ timestamp.setNanos( timestamp.getNanos() + usec * 10 );
268
+ }
269
+ else { // if ( usec < 1000 ) { // 0.123456 ~> 456
270
+ timestamp.setNanos( timestamp.getNanos() + usec );
271
+ }
272
+ }
273
+
274
+ return timestamp;
275
+ }
276
+
277
+ public static double adjustTimeFromDefaultZone(final IRubyObject value) {
278
+ // Time's to_f is : ( millis * 1000 + usec ) / 1_000_000.0
279
+ final double time = value.convertToFloat().getDoubleValue(); // to_f
280
+ // NOTE: MySQL assumes default TZ thus need to adjust to match :
281
+ final int offset = TimeZone.getDefault().getOffset((long) time * 1000);
282
+ // Time's to_f is : ( millis * 1000 + usec ) / 1_000_000.0
283
+ return time - ( offset / 1000.0 );
284
+ }
285
+
286
+ public static IRubyObject parseDate(final ThreadContext context, final CharSequence str, final DateTimeZone defaultZone)
287
+ throws IllegalArgumentException {
288
+ final int len = str.length();
289
+
290
+ int year; int month; int day;
291
+
292
+ int start = nonSpaceIndex(str, 0, len); // Skip leading whitespace
293
+ int end = nonDigitIndex(str, start, len);
294
+
295
+ if ( end >= len ) {
296
+ throw new IllegalArgumentException("unexpected date value: '" + str + "'");
297
+ }
298
+
299
+ // year
300
+ year = extractIntValue(str, start, end);
301
+ start = end + 1; // Skip '-'
302
+
303
+ // month
304
+ end = nonDigitIndex(str, start, len);
305
+ month = extractIntValue(str, start, end);
306
+
307
+ //sep = str.charAt(end);
308
+ //if ( sep != '-' ) {
309
+ // throw new NumberFormatException("expected date to be dash-separated, got '" + sep + "'");
310
+ //}
311
+
312
+ start = end + 1; // Skip '-'
313
+
314
+ // day of month
315
+ end = nonDigitIndex(str, start, len);
316
+ day = extractIntValue(str, start, end);
317
+
318
+ return newDate(context, year, month, day, ISOChronology.getInstance(defaultZone));
319
+ }
320
+
321
+ public static IRubyObject parseTime(final ThreadContext context, final CharSequence str, final DateTimeZone defaultZone)
322
+ throws IllegalArgumentException {
323
+ final int len = str.length();
324
+
325
+ int hour; int minute; int second;
326
+ int millis = 0; long nanos = 0;
327
+
328
+ int start = nonSpaceIndex(str, 0, len); // Skip leading whitespace
329
+ int end = nonDigitIndex(str, start, len);
330
+
331
+ if ( end >= len ) {
332
+ throw new IllegalArgumentException("unexpected date value: '" + str + "'");
333
+ }
334
+
335
+ // hours
336
+ hour = extractIntValue(str, start, end);
337
+ start = end + 1; // Skip ':'
338
+
339
+ end = nonDigitIndex(str, start, len);
340
+ // minutes
341
+ minute = extractIntValue(str, start, end);
342
+ start = end + 1; // Skip ':'
343
+
344
+ end = nonDigitIndex(str, start, len);
345
+ // seconds
346
+ second = extractIntValue(str, start, end);
347
+ start = end;
348
+
349
+ // Fractional seconds.
350
+ if ( start < len && str.charAt(start) == '.' ) {
351
+ end = nonDigitIndex(str, start + 1, len); // Skip '.'
352
+ int numlen = end - (start + 1);
353
+ if (numlen <= 3) {
354
+ millis = extractIntValue(str, start + 1, end);
355
+ for ( ; numlen < 3; ++numlen ) millis *= 10;
356
+ }
357
+ else {
358
+ nanos = extractIntValue(str, start + 1, end);
359
+ for ( ; numlen < 9; ++numlen ) nanos *= 10;
360
+ }
361
+ //start = end;
362
+ }
363
+
364
+ DateTime dateTime = new DateTime(2000, 1, 1, hour, minute, second, millis, defaultZone);
365
+ return RubyTime.newTime(context.runtime, dateTime, nanos);
366
+ }
367
+
368
+ public static RubyTime parseDateTime(final ThreadContext context, final CharSequence str, final DateTimeZone defaultZone)
369
+ throws IllegalArgumentException {
370
+
371
+ boolean hasDate = false;
372
+ int year = 2000; int month = 1; int day = 1;
373
+ boolean hasTime = false;
374
+ int minute = 0; int hour = 0; int second = 0;
375
+ int millis = 0; long nanos = 0;
376
+
377
+ DateTimeZone zone = defaultZone; boolean bcEra = false;
378
+
379
+ // We try to parse these fields in order; all are optional
380
+ // (but some combinations don't make sense, e.g. if you have
381
+ // both date and time then they must be whitespace-separated).
382
+ // At least one of date and time must be present.
383
+
384
+ // leading whitespace
385
+ // yyyy-mm-dd
386
+ // whitespace
387
+ // hh:mm:ss
388
+ // whitespace
389
+ // timezone in one of the formats: +hh, -hh, +hh:mm, -hh:mm
390
+ // whitespace
391
+ // if date is present, an era specifier: AD or BC
392
+ // trailing whitespace
393
+
394
+ final int len = str.length();
395
+
396
+ int start = nonSpaceIndex(str, 0, len); // Skip leading whitespace
397
+ int end = nonDigitIndex(str, start, len);
398
+
399
+ // Possibly read date.
400
+ if ( end < len && str.charAt(end) == '-' ) {
401
+ hasDate = true;
402
+
403
+ // year
404
+ year = extractIntValue(str, start, end);
405
+ start = end + 1; // Skip '-'
406
+
407
+ // month
408
+ end = nonDigitIndex(str, start, len);
409
+ month = extractIntValue(str, start, end);
410
+
411
+ char sep = str.charAt(end);
412
+ if ( sep != '-' ) {
413
+ throw new IllegalArgumentException("expected date to be dash-separated, got '" + sep + "'");
414
+ }
415
+
416
+ start = end + 1; // Skip '-'
417
+
418
+ // day of month
419
+ end = nonDigitIndex(str, start, len);
420
+ day = extractIntValue(str, start, end);
421
+
422
+ start = nonSpaceIndex(str, end, len); // Skip trailing whitespace
423
+ }
424
+
425
+ // Possibly read time.
426
+ if ( start < len && Character.isDigit( str.charAt(start) ) ) {
427
+ hasTime = true;
428
+
429
+ // hours
430
+ end = nonDigitIndex(str, start, len);
431
+ hour = extractIntValue(str, start, end);
432
+
433
+ //sep = str.charAt(end);
434
+ //if ( sep != ':' ) {
435
+ // throw new IllegalArgumentException("expected time to be colon-separated, got '" + sep + "'");
436
+ //}
437
+
438
+ start = end + 1; // Skip ':'
439
+
440
+ // minutes
441
+ end = nonDigitIndex(str, start, len);
442
+ minute = extractIntValue(str, start, end);
443
+
444
+ //sep = str.charAt(end);
445
+ //if ( sep != ':' ) {
446
+ // throw new IllegalArgumentException("expected time to be colon-separated, got '" + sep + "'");
447
+ //}
448
+
449
+ start = end + 1; // Skip ':'
450
+
451
+ // seconds
452
+ end = nonDigitIndex(str, start, len);
453
+ second = extractIntValue(str, start, end);
454
+ start = end;
455
+
456
+ // Fractional seconds.
457
+ if ( start < len && str.charAt(start) == '.' ) {
458
+ end = nonDigitIndex(str, start + 1, len); // Skip '.'
459
+ int numlen = end - (start + 1);
460
+ if (numlen <= 3) {
461
+ millis = extractIntValue(str, start + 1, end);
462
+ for ( ; numlen < 3; ++numlen ) millis *= 10;
463
+ }
464
+ else {
465
+ // Make sure we always define millis to work around bug in
466
+ // strftime('%6N') in older version of JRuby (discovered in 9.1.16.0)
467
+ millis = extractIntValue(str, start + 1, start + 4);
468
+ nanos = extractIntValue(str, start + 4, end);
469
+ for ( ; numlen < 9; ++numlen ) nanos *= 10;
470
+ }
471
+
472
+ start = end;
473
+ }
474
+
475
+ start = nonSpaceIndex(str, start, len); // Skip trailing whitespace
476
+ }
477
+
478
+ // Possibly read timezone.
479
+ char sep = start < len ? str.charAt(start) : '\0';
480
+ if ( sep == '+' || sep == '-' ) {
481
+ int zoneSign = (sep == '-') ? -1 : 1;
482
+ int hoursOffset, minutesOffset, secondsOffset;
483
+
484
+ end = nonDigitIndex(str, start + 1, len); // Skip +/-
485
+ hoursOffset = extractIntValue(str, start + 1, end);
486
+ start = end;
487
+
488
+ if ( start < len && str.charAt(start) == ':' ) {
489
+ end = nonDigitIndex(str, start + 1, len); // Skip ':'
490
+ minutesOffset = extractIntValue(str, start + 1, end);
491
+ start = end;
492
+ } else {
493
+ minutesOffset = 0;
494
+ }
495
+
496
+ secondsOffset = 0;
497
+ if ( start < len && str.charAt(start) == ':' ) {
498
+ end = nonDigitIndex(str, start + 1, len); // Skip ':'
499
+ secondsOffset = extractIntValue(str, start + 1, end);
500
+ start = end;
501
+ }
502
+
503
+ // Setting offset does not seem to work correctly in all
504
+ // cases.. So get a fresh calendar for a synthetic timezone
505
+ // instead
506
+
507
+ int offset = zoneSign * hoursOffset * 60;
508
+ if (offset < 0) {
509
+ offset = offset - Math.abs(minutesOffset);
510
+ } else {
511
+ offset = offset + minutesOffset;
512
+ }
513
+ offset = (offset * 60 + secondsOffset) * 1000;
514
+ zone = DateTimeZone.forOffsetMillis(offset);
515
+
516
+ start = nonSpaceIndex(str, start, len); // Skip trailing whitespace
517
+ }
518
+
519
+ if ( hasDate && start < len ) {
520
+ final char e1 = str.charAt(start);
521
+ if ( e1 == 'A' && str.charAt(start + 1) == 'D' ) {
522
+ bcEra = false; start += 2;
523
+ }
524
+ else if ( e1 == 'B' && str.charAt(start + 1) == 'C' ) {
525
+ bcEra = true; start += 2;
526
+ }
527
+ }
528
+
529
+ if ( start < len ) {
530
+ throw new IllegalArgumentException("trailing junk: '" + str.subSequence(start, len - start) + "' on '" + str + "'");
531
+ }
532
+ if ( ! hasTime && ! hasDate ) {
533
+ throw new IllegalArgumentException("'"+ str +"' has neither date nor time");
534
+ }
535
+
536
+ if ( bcEra ) year = -1 * year + 1; // since JODA is treating year 0 as non-existent
537
+
538
+ DateTime dateTime = new DateTime(year, month, day, hour, minute, second, millis, zone);
539
+ return RubyTime.newTime(context.runtime, dateTime, nanos);
540
+ }
541
+
542
+ private static IRubyObject newDate(final ThreadContext context, final int year, final int month, final int day,
543
+ final ISOChronology chronology) {
544
+ // NOTE: JRuby really needs a native date.rb until than its a bit costly going from ...
545
+ // java.sql.Date -> allocating a DateTime proxy, help a bit by shooting at the internals
546
+ //
547
+ // def initialize(dt_or_ajd=0, of=0, sg=ITALY, sub_millis=0)
548
+ // if JODA::DateTime === dt_or_ajd
549
+ // @dt = dt_or_ajd
550
+
551
+ DateTime dateTime = new DateTime(year, month, day, 0, 0, 0, 0, chronology);
552
+
553
+ final Ruby runtime = context.runtime;
554
+ return runtime.getClass("Date").newInstance(context, Java.getInstance(runtime, dateTime), Block.NULL_BLOCK);
555
+ }
556
+
557
+ @SuppressWarnings("deprecation")
558
+ private static int nonSpaceIndex(final CharSequence str, int beg, int len) {
559
+ for ( int i = beg; i < len; i++ ) {
560
+ if ( ! Character.isSpace( str.charAt(i) ) ) return i;
561
+ }
562
+ return len;
563
+ }
564
+
565
+ private static int nonDigitIndex(final CharSequence str, int beg, int len) {
566
+ for ( int i = beg; i < len; i++ ) {
567
+ if ( ! Character.isDigit( str.charAt(i) ) ) return i;
568
+ }
569
+ return len;
570
+ }
571
+
572
+ private static int extractIntValue(final CharSequence str, int beg, int end) {
573
+ int n = 0;
574
+ for ( int i = beg; i < end; i++ ) {
575
+ n = 10 * n + ( str.charAt(i) - '0' );
576
+ }
577
+ return n;
578
+ }
579
+
580
+ }