activerecord-jdbc-adapter-ficoh 1.3.21-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 (191) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +35 -0
  3. data/.travis.yml +462 -0
  4. data/.yardopts +4 -0
  5. data/Appraisals +36 -0
  6. data/CONTRIBUTING.md +49 -0
  7. data/Gemfile +68 -0
  8. data/History.md +1191 -0
  9. data/LICENSE.txt +25 -0
  10. data/README.md +277 -0
  11. data/RUNNING_TESTS.md +88 -0
  12. data/Rakefile +298 -0
  13. data/Rakefile.jdbc +20 -0
  14. data/activerecord-jdbc-adapter.gemspec +63 -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/oracle_adapter.rb +1 -0
  29. data/lib/active_record/connection_adapters/postgresql_adapter.rb +1 -0
  30. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +1 -0
  31. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +1 -0
  32. data/lib/activerecord-jdbc-adapter.rb +1 -0
  33. data/lib/arel/visitors/compat.rb +64 -0
  34. data/lib/arel/visitors/db2.rb +137 -0
  35. data/lib/arel/visitors/derby.rb +112 -0
  36. data/lib/arel/visitors/firebird.rb +79 -0
  37. data/lib/arel/visitors/h2.rb +25 -0
  38. data/lib/arel/visitors/hsqldb.rb +32 -0
  39. data/lib/arel/visitors/postgresql_jdbc.rb +6 -0
  40. data/lib/arel/visitors/sql_server.rb +225 -0
  41. data/lib/arel/visitors/sql_server/ng42.rb +293 -0
  42. data/lib/arjdbc.rb +22 -0
  43. data/lib/arjdbc/db2.rb +4 -0
  44. data/lib/arjdbc/db2/adapter.rb +802 -0
  45. data/lib/arjdbc/db2/as400.rb +137 -0
  46. data/lib/arjdbc/db2/column.rb +177 -0
  47. data/lib/arjdbc/db2/connection_methods.rb +45 -0
  48. data/lib/arjdbc/derby.rb +3 -0
  49. data/lib/arjdbc/derby/active_record_patch.rb +13 -0
  50. data/lib/arjdbc/derby/adapter.rb +567 -0
  51. data/lib/arjdbc/derby/connection_methods.rb +16 -0
  52. data/lib/arjdbc/derby/schema_creation.rb +15 -0
  53. data/lib/arjdbc/discover.rb +104 -0
  54. data/lib/arjdbc/firebird.rb +4 -0
  55. data/lib/arjdbc/firebird/adapter.rb +468 -0
  56. data/lib/arjdbc/firebird/connection_methods.rb +20 -0
  57. data/lib/arjdbc/h2.rb +3 -0
  58. data/lib/arjdbc/h2/adapter.rb +335 -0
  59. data/lib/arjdbc/h2/connection_methods.rb +22 -0
  60. data/lib/arjdbc/hsqldb.rb +3 -0
  61. data/lib/arjdbc/hsqldb/adapter.rb +304 -0
  62. data/lib/arjdbc/hsqldb/connection_methods.rb +23 -0
  63. data/lib/arjdbc/hsqldb/explain_support.rb +35 -0
  64. data/lib/arjdbc/hsqldb/schema_creation.rb +11 -0
  65. data/lib/arjdbc/informix.rb +5 -0
  66. data/lib/arjdbc/informix/adapter.rb +160 -0
  67. data/lib/arjdbc/informix/connection_methods.rb +9 -0
  68. data/lib/arjdbc/jdbc.rb +62 -0
  69. data/lib/arjdbc/jdbc/adapter.rb +997 -0
  70. data/lib/arjdbc/jdbc/adapter_require.rb +46 -0
  71. data/lib/arjdbc/jdbc/arel_support.rb +149 -0
  72. data/lib/arjdbc/jdbc/base_ext.rb +34 -0
  73. data/lib/arjdbc/jdbc/callbacks.rb +52 -0
  74. data/lib/arjdbc/jdbc/column.rb +83 -0
  75. data/lib/arjdbc/jdbc/connection.rb +26 -0
  76. data/lib/arjdbc/jdbc/connection_methods.rb +59 -0
  77. data/lib/arjdbc/jdbc/driver.rb +44 -0
  78. data/lib/arjdbc/jdbc/error.rb +75 -0
  79. data/lib/arjdbc/jdbc/extension.rb +69 -0
  80. data/lib/arjdbc/jdbc/java.rb +13 -0
  81. data/lib/arjdbc/jdbc/type_cast.rb +154 -0
  82. data/lib/arjdbc/jdbc/type_converter.rb +142 -0
  83. data/lib/arjdbc/mssql.rb +7 -0
  84. data/lib/arjdbc/mssql/adapter.rb +822 -0
  85. data/lib/arjdbc/mssql/column.rb +207 -0
  86. data/lib/arjdbc/mssql/connection_methods.rb +72 -0
  87. data/lib/arjdbc/mssql/explain_support.rb +99 -0
  88. data/lib/arjdbc/mssql/limit_helpers.rb +231 -0
  89. data/lib/arjdbc/mssql/lock_methods.rb +77 -0
  90. data/lib/arjdbc/mssql/types.rb +343 -0
  91. data/lib/arjdbc/mssql/utils.rb +82 -0
  92. data/lib/arjdbc/mysql.rb +3 -0
  93. data/lib/arjdbc/mysql/adapter.rb +998 -0
  94. data/lib/arjdbc/mysql/bulk_change_table.rb +150 -0
  95. data/lib/arjdbc/mysql/column.rb +167 -0
  96. data/lib/arjdbc/mysql/connection_methods.rb +137 -0
  97. data/lib/arjdbc/mysql/explain_support.rb +82 -0
  98. data/lib/arjdbc/mysql/schema_creation.rb +58 -0
  99. data/lib/arjdbc/oracle.rb +4 -0
  100. data/lib/arjdbc/oracle/adapter.rb +968 -0
  101. data/lib/arjdbc/oracle/column.rb +136 -0
  102. data/lib/arjdbc/oracle/connection_methods.rb +21 -0
  103. data/lib/arjdbc/postgresql.rb +3 -0
  104. data/lib/arjdbc/postgresql/_bc_time_cast_patch.rb +21 -0
  105. data/lib/arjdbc/postgresql/adapter.rb +1498 -0
  106. data/lib/arjdbc/postgresql/base/array_parser.rb +95 -0
  107. data/lib/arjdbc/postgresql/base/oid.rb +412 -0
  108. data/lib/arjdbc/postgresql/base/pgconn.rb +8 -0
  109. data/lib/arjdbc/postgresql/base/schema_definitions.rb +132 -0
  110. data/lib/arjdbc/postgresql/column.rb +640 -0
  111. data/lib/arjdbc/postgresql/connection_methods.rb +44 -0
  112. data/lib/arjdbc/postgresql/explain_support.rb +53 -0
  113. data/lib/arjdbc/postgresql/oid/bytea.rb +3 -0
  114. data/lib/arjdbc/postgresql/oid_types.rb +265 -0
  115. data/lib/arjdbc/postgresql/schema_creation.rb +60 -0
  116. data/lib/arjdbc/railtie.rb +11 -0
  117. data/lib/arjdbc/sqlite3.rb +3 -0
  118. data/lib/arjdbc/sqlite3/adapter.rb +654 -0
  119. data/lib/arjdbc/sqlite3/connection_methods.rb +36 -0
  120. data/lib/arjdbc/sqlite3/explain_support.rb +29 -0
  121. data/lib/arjdbc/sybase.rb +2 -0
  122. data/lib/arjdbc/sybase/adapter.rb +47 -0
  123. data/lib/arjdbc/tasks.rb +13 -0
  124. data/lib/arjdbc/tasks/database_tasks.rb +66 -0
  125. data/lib/arjdbc/tasks/databases.rake +91 -0
  126. data/lib/arjdbc/tasks/databases3.rake +239 -0
  127. data/lib/arjdbc/tasks/databases4.rake +39 -0
  128. data/lib/arjdbc/tasks/db2_database_tasks.rb +104 -0
  129. data/lib/arjdbc/tasks/derby_database_tasks.rb +95 -0
  130. data/lib/arjdbc/tasks/h2_database_tasks.rb +31 -0
  131. data/lib/arjdbc/tasks/hsqldb_database_tasks.rb +70 -0
  132. data/lib/arjdbc/tasks/jdbc_database_tasks.rb +169 -0
  133. data/lib/arjdbc/tasks/mssql_database_tasks.rb +46 -0
  134. data/lib/arjdbc/tasks/oracle/enhanced_structure_dump.rb +297 -0
  135. data/lib/arjdbc/tasks/oracle_database_tasks.rb +65 -0
  136. data/lib/arjdbc/util/quoted_cache.rb +60 -0
  137. data/lib/arjdbc/util/serialized_attributes.rb +98 -0
  138. data/lib/arjdbc/util/table_copier.rb +108 -0
  139. data/lib/arjdbc/version.rb +8 -0
  140. data/lib/generators/jdbc/USAGE +9 -0
  141. data/lib/generators/jdbc/jdbc_generator.rb +17 -0
  142. data/pom.xml +285 -0
  143. data/rails_generators/jdbc_generator.rb +15 -0
  144. data/rails_generators/templates/config/initializers/jdbc.rb +10 -0
  145. data/rails_generators/templates/lib/tasks/jdbc.rake +11 -0
  146. data/rakelib/01-tomcat.rake +51 -0
  147. data/rakelib/02-test.rake +151 -0
  148. data/rakelib/bundler_ext.rb +11 -0
  149. data/rakelib/db.rake +58 -0
  150. data/rakelib/rails.rake +77 -0
  151. data/src/java/arjdbc/ArJdbcModule.java +288 -0
  152. data/src/java/arjdbc/db2/DB2Module.java +77 -0
  153. data/src/java/arjdbc/db2/DB2RubyJdbcConnection.java +128 -0
  154. data/src/java/arjdbc/derby/DerbyModule.java +180 -0
  155. data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +153 -0
  156. data/src/java/arjdbc/firebird/FirebirdRubyJdbcConnection.java +190 -0
  157. data/src/java/arjdbc/h2/H2Module.java +50 -0
  158. data/src/java/arjdbc/h2/H2RubyJdbcConnection.java +86 -0
  159. data/src/java/arjdbc/hsqldb/HSQLDBModule.java +74 -0
  160. data/src/java/arjdbc/informix/InformixRubyJdbcConnection.java +76 -0
  161. data/src/java/arjdbc/jdbc/AdapterJavaService.java +43 -0
  162. data/src/java/arjdbc/jdbc/Callable.java +44 -0
  163. data/src/java/arjdbc/jdbc/ConnectionFactory.java +77 -0
  164. data/src/java/arjdbc/jdbc/DataSourceConnectionFactory.java +156 -0
  165. data/src/java/arjdbc/jdbc/DriverConnectionFactory.java +63 -0
  166. data/src/java/arjdbc/jdbc/DriverWrapper.java +128 -0
  167. data/src/java/arjdbc/jdbc/JdbcConnectionFactory.java +32 -0
  168. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +4541 -0
  169. data/src/java/arjdbc/jdbc/SQLBlock.java +54 -0
  170. data/src/java/arjdbc/jdbc/WithResultSet.java +37 -0
  171. data/src/java/arjdbc/mssql/MSSQLModule.java +91 -0
  172. data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +193 -0
  173. data/src/java/arjdbc/mysql/MySQLModule.java +140 -0
  174. data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +456 -0
  175. data/src/java/arjdbc/oracle/OracleModule.java +81 -0
  176. data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +477 -0
  177. data/src/java/arjdbc/postgresql/ByteaUtils.java +171 -0
  178. data/src/java/arjdbc/postgresql/DriverImplementation.java +78 -0
  179. data/src/java/arjdbc/postgresql/PGDriverImplementation.java +535 -0
  180. data/src/java/arjdbc/postgresql/PostgreSQLModule.java +189 -0
  181. data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +489 -0
  182. data/src/java/arjdbc/sqlite3/SQLite3Module.java +93 -0
  183. data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +405 -0
  184. data/src/java/arjdbc/util/CallResultSet.java +826 -0
  185. data/src/java/arjdbc/util/DateTimeUtils.java +517 -0
  186. data/src/java/arjdbc/util/NumberUtils.java +50 -0
  187. data/src/java/arjdbc/util/ObjectSupport.java +65 -0
  188. data/src/java/arjdbc/util/QuotingUtils.java +139 -0
  189. data/src/java/arjdbc/util/StringCache.java +60 -0
  190. data/src/java/arjdbc/util/StringHelper.java +155 -0
  191. metadata +288 -0
@@ -0,0 +1,171 @@
1
+ /*
2
+ * The MIT License
3
+ *
4
+ * Copyright 2015 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.postgresql;
25
+
26
+ /**
27
+ * Based on JDBC PostgreSQL driver's <code>org.postgresql.util.PGbytea</code>.
28
+ *
29
+ * @author kares
30
+ */
31
+ abstract class ByteaUtils {
32
+
33
+ //static byte[] toBytes(final byte[] s) {
34
+ // return toBytes(s, 0, s.length);
35
+ //}
36
+
37
+ /*
38
+ * Converts a PG bytea raw value (i.e. the raw binary representation
39
+ * of the bytea data type) into a java byte[]
40
+ */
41
+ static byte[] toBytes(final byte[] s, final int off, final int len) {
42
+ // Starting with PG 9.0, a new hex format is supported
43
+ // that starts with "\x". Figure out which format we're
44
+ // dealing with here.
45
+ //
46
+ if ( s.length < 2 || s[0] != '\\' || s[1] != 'x' ) {
47
+ return toBytesOctalEscaped(s, off, len);
48
+ }
49
+ return toBytesHexEscaped(s, off, len);
50
+ }
51
+
52
+ private static byte[] toBytesHexEscaped(final byte[] s, final int off, final int len) {
53
+ final byte[] out = new byte[(len - 2) / 2];
54
+ for (int i = 0; i < out.length; i++) {
55
+ final int j = off + (2 + i * 2);
56
+ byte b1 = hexByte( s[j] );
57
+ byte b2 = hexByte( s[j + 1] );
58
+ out[i] = (byte) ((b1 << 4) | b2);
59
+ }
60
+ return out;
61
+ }
62
+
63
+ private static byte hexByte(final byte b) {
64
+ // 0-9 == 48-57
65
+ if (b <= 57) return (byte) (b - 48);
66
+
67
+ // a-f == 97-102
68
+ if (b >= 97) return (byte) (b - 97 + 10);
69
+
70
+ // A-F == 65-70
71
+ return (byte) (b - 65 + 10);
72
+ }
73
+
74
+ private static final int MAX_3_BUFF_SIZE = 2 * 1024 * 1024;
75
+
76
+ private static byte[] toBytesOctalEscaped(final byte[] s, final int off, final int len) {
77
+ final byte[] out;
78
+ final int end = off + len;
79
+ int correctSize = len;
80
+ if ( len > MAX_3_BUFF_SIZE ) {
81
+ // count backslash escapes, they will be either
82
+ // backslashes or an octal escape \\ or \003
83
+ //
84
+ for ( int i = off; i < end; ++i ) {
85
+ if ( s[i] == '\\' ) {
86
+ byte next = s[ ++i ];
87
+ if (next == '\\') {
88
+ --correctSize;
89
+ }
90
+ else {
91
+ correctSize -= 3;
92
+ }
93
+ }
94
+ }
95
+ out = new byte[correctSize];
96
+ }
97
+ else {
98
+ out = new byte[len];
99
+ }
100
+
101
+ int pos = 0;
102
+ for ( int i = off; i < end; i++ ) {
103
+ final byte b = s[i];
104
+ if ( b == (byte) '\\' ) {
105
+ final byte b1 = s[++i];
106
+ if ( b1 == (byte) '\\' ) { // escaped \
107
+ out[ pos++ ] = (byte) '\\';
108
+ }
109
+ else {
110
+ int thebyte = (b1 - 48) * 64 + (s[++i] - 48) * 8 + (s[++i] - 48);
111
+ if ( thebyte > 127 ) thebyte -= 256;
112
+ out[ pos++ ] = (byte) thebyte;
113
+ }
114
+ }
115
+ else {
116
+ out[ pos++ ] = b;
117
+ }
118
+ }
119
+
120
+ if ( pos == correctSize ) return out;
121
+
122
+ final byte[] out2 = new byte[pos];
123
+ System.arraycopy(out, 0, out2, 0, pos);
124
+ return out2;
125
+ }
126
+
127
+ /*
128
+ * Converts a java byte[] into a PG bytea string (i.e. the text
129
+ * representation of the bytea data type)
130
+ */
131
+ /*
132
+ public static String toPGString(byte[] p_buf) {
133
+ if (p_buf == null)
134
+ return null;
135
+ StringBuffer l_strbuf = new StringBuffer(2 * p_buf.length);
136
+ for (int i = 0; i < p_buf.length; i++)
137
+ {
138
+ int l_int = (int)p_buf[i];
139
+ if (l_int < 0)
140
+ {
141
+ l_int = 256 + l_int;
142
+ }
143
+ //we escape the same non-printable characters as the backend
144
+ //we must escape all 8bit characters otherwise when convering
145
+ //from java unicode to the db character set we may end up with
146
+ //question marks if the character set is SQL_ASCII
147
+ if (l_int < 040 || l_int > 0176)
148
+ {
149
+ //escape charcter with the form \000, but need two \\ because of
150
+ //the Java parser
151
+ l_strbuf.append("\\");
152
+ l_strbuf.append((char)(((l_int >> 6) & 0x3) + 48));
153
+ l_strbuf.append((char)(((l_int >> 3) & 0x7) + 48));
154
+ l_strbuf.append((char)((l_int & 0x07) + 48));
155
+ }
156
+ else if (p_buf[i] == (byte)'\\')
157
+ {
158
+ //escape the backslash character as \\, but need four \\\\ because
159
+ //of the Java parser
160
+ l_strbuf.append("\\\\");
161
+ }
162
+ else
163
+ {
164
+ //other characters are left alone
165
+ l_strbuf.append((char)p_buf[i]);
166
+ }
167
+ }
168
+ return l_strbuf.toString();
169
+ } */
170
+
171
+ }
@@ -0,0 +1,78 @@
1
+ /*
2
+ * The MIT License
3
+ *
4
+ * Copyright 2015 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.postgresql;
25
+
26
+ import java.sql.Connection;
27
+ import java.sql.PreparedStatement;
28
+ import java.sql.ResultSet;
29
+ import java.sql.SQLException;
30
+ import org.jruby.runtime.ThreadContext;
31
+ import org.jruby.runtime.builtin.IRubyObject;
32
+
33
+ /**
34
+ * Driver specifics hidden behind curtains.
35
+ *
36
+ * @author kares
37
+ */
38
+ interface DriverImplementation {
39
+
40
+ Connection newConnection(final Connection connection) throws SQLException ;
41
+
42
+ //
43
+
44
+ IRubyObject objectToRuby(final ThreadContext context,
45
+ final ResultSet resultSet, final int column) throws SQLException ;
46
+
47
+ // prepared statements :
48
+
49
+ boolean setStringParameter(final ThreadContext context,
50
+ final Connection connection, final PreparedStatement statement,
51
+ final int index, final IRubyObject value,
52
+ final IRubyObject column, final int type) throws SQLException ;
53
+
54
+ boolean setTimestampParameter(final ThreadContext context,
55
+ final Connection connection, final PreparedStatement statement,
56
+ final int index, IRubyObject value,
57
+ final IRubyObject column, final int type) throws SQLException ;
58
+
59
+ boolean setObjectParameter(final ThreadContext context,
60
+ final Connection connection, final PreparedStatement statement,
61
+ final int index, Object value,
62
+ final IRubyObject column, final int type) throws SQLException ;
63
+
64
+ /*
65
+ public void setJsonParameter(final ThreadContext context,
66
+ final PreparedStatement statement, final int index,
67
+ Object value, final IRubyObject column) throws SQLException ;
68
+
69
+ public void setRangeParameter(final ThreadContext context,
70
+ final PreparedStatement statement, final int index,
71
+ final Object value, final IRubyObject column,
72
+ final String columnType) throws SQLException ;
73
+
74
+ public void setTsVectorParameter(
75
+ final PreparedStatement statement, final int index,
76
+ Object value) throws SQLException ; */
77
+
78
+ }
@@ -0,0 +1,535 @@
1
+ /*
2
+ * The MIT License
3
+ *
4
+ * Copyright 2015 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.postgresql;
25
+
26
+ import java.sql.Connection;
27
+ import java.sql.PreparedStatement;
28
+ import java.sql.ResultSet;
29
+ import java.sql.SQLException;
30
+ import java.sql.Timestamp;
31
+ import java.sql.Types;
32
+ import java.util.Map;
33
+ import java.util.UUID;
34
+
35
+ import org.jruby.RubyFloat;
36
+ import org.jruby.RubyHash;
37
+ import org.jruby.RubyString;
38
+ import org.jruby.javasupport.JavaUtil;
39
+ import org.jruby.runtime.ThreadContext;
40
+ import org.jruby.runtime.builtin.IRubyObject;
41
+ import org.jruby.util.ByteList;
42
+ import org.jruby.util.SafePropertyAccessor;
43
+
44
+ import org.postgresql.PGConnection;
45
+ import org.postgresql.PGStatement;
46
+ import org.postgresql.core.BaseConnection;
47
+ import org.postgresql.jdbc4.Jdbc4Array;
48
+ import org.postgresql.util.PGInterval;
49
+ import org.postgresql.util.PGobject;
50
+
51
+ import arjdbc.util.NumberUtils;
52
+ import static arjdbc.jdbc.RubyJdbcConnection.isAr42;
53
+
54
+ /**
55
+ * Official JDBC driver internals.
56
+ *
57
+ * @author kares
58
+ */
59
+ public final class PGDriverImplementation implements DriverImplementation {
60
+
61
+ private static final boolean initConnection;
62
+ static {
63
+ String initConn = SafePropertyAccessor.getProperty("arjdbc.postgresql.connection.init", "true");
64
+ initConnection = Boolean.parseBoolean(initConn);
65
+ }
66
+
67
+ public static void initConnection(final Connection connection) throws SQLException {
68
+ final PGConnection pgConnection;
69
+ if ( connection instanceof PGConnection ) {
70
+ pgConnection = (PGConnection) connection;
71
+ }
72
+ else {
73
+ pgConnection = connection.unwrap(PGConnection.class);
74
+ }
75
+ pgConnection.addDataType("daterange", DateRangeType.class);
76
+ pgConnection.addDataType("tsrange", TsRangeType.class);
77
+ pgConnection.addDataType("tstzrange", TstzRangeType.class);
78
+ pgConnection.addDataType("int4range", Int4RangeType.class);
79
+ pgConnection.addDataType("int8range", Int8RangeType.class);
80
+ pgConnection.addDataType("numrange", NumRangeType.class);
81
+ }
82
+
83
+ public Connection newConnection(final Connection connection) throws SQLException {
84
+ if ( initConnection ) initConnection(connection);
85
+ return connection;
86
+ }
87
+
88
+ public IRubyObject objectToRuby(final ThreadContext context,
89
+ final ResultSet resultSet, final int column) throws SQLException {
90
+
91
+ final Object object = resultSet.getObject(column);
92
+
93
+ if ( object == null ) return context.nil;
94
+
95
+ final Class<?> objectClass = object.getClass();
96
+ if ( objectClass == UUID.class ) {
97
+ return RubyString.newString( context.runtime, object.toString() );
98
+ }
99
+
100
+ if ( objectClass == PGInterval.class ) {
101
+ if ( PostgreSQLRubyJdbcConnection.rawIntervalType ) {
102
+ final String value = ((PGInterval) object).getValue();
103
+ return RubyString.newString( context.runtime, value );
104
+ }
105
+ return RubyString.newString( context.runtime, formatInterval(object) );
106
+ }
107
+
108
+ if ( object instanceof PGobject ) {
109
+ // PG 9.2 JSON type will be returned here as well
110
+ return RubyString.newString( context.runtime, object.toString() );
111
+ }
112
+
113
+ if ( object instanceof Map ) { // hstore
114
+ if ( PostgreSQLRubyJdbcConnection.rawHstoreType == Boolean.TRUE ) {
115
+ return RubyString.newString( context.runtime, resultSet.getString(column) );
116
+ }
117
+ // by default we avoid double parsing by driver and than column :
118
+ final RubyHash rubyObject = RubyHash.newHash(context.runtime);
119
+ rubyObject.putAll((Map) object); // converts keys/values to ruby
120
+ return rubyObject;
121
+ }
122
+
123
+ return JavaUtil.convertJavaToRuby(context.runtime, object);
124
+ }
125
+
126
+ private static final byte[] _years_ = { ' ','y','e','a','r','s',' ' };
127
+ private static final byte[] _months_ = { ' ','m','o','n','t','h','s',' ' };
128
+ private static final byte[] _days_ = { ' ','d','a','y','s',' ' };
129
+
130
+ // NOTE: do not use PG classes in the API so that loading is delayed ! still?
131
+ private static ByteList formatInterval(final Object object) {
132
+ final PGInterval interval = (PGInterval) object;
133
+
134
+ final ByteList str = new ByteList(32);
135
+
136
+ final int years = interval.getYears();
137
+ if ( years != 0 ) {
138
+ NumberUtils.appendInteger(years, str).append(_years_);
139
+ }
140
+ final int months = interval.getMonths();
141
+ if ( months != 0 ) {
142
+ NumberUtils.appendInteger(months, str).append(_months_);
143
+ }
144
+ final int days = interval.getDays();
145
+ if ( days != 0 ) {
146
+ NumberUtils.appendInteger(days, str).append(_days_);
147
+ }
148
+ final int hours = interval.getHours();
149
+ final int mins = interval.getMinutes();
150
+ final int secs = (int) interval.getSeconds();
151
+ if ( hours != 0 || mins != 0 || secs != 0 ) { // xx:yy:zz if not all 00
152
+ if ( hours < 10 ) str.append('0');
153
+ NumberUtils.appendInteger(hours, str).append(':');
154
+ if ( mins < 10 ) str.append('0');
155
+ NumberUtils.appendInteger(mins, str).append(':');
156
+ if ( secs < 10 ) str.append('0');
157
+ NumberUtils.appendInteger(secs, str);
158
+ }
159
+ else {
160
+ final int size = str.getRealSize();
161
+ if ( size > 1 ) str.setRealSize(size - 1); // " " at the end
162
+ }
163
+
164
+ return str;
165
+ }
166
+
167
+ public boolean setStringParameter(final ThreadContext context,
168
+ final Connection connection, final PreparedStatement statement,
169
+ final int index, final IRubyObject value,
170
+ final IRubyObject column, final int type) throws SQLException {
171
+ final RubyString sqlType;
172
+ if ( column != null && ! column.isNil() ) {
173
+ sqlType = (RubyString) column.callMethod(context, "sql_type");
174
+ }
175
+ else {
176
+ sqlType = null;
177
+ }
178
+
179
+ if ( value.isNil() ) {
180
+ if ( PostgreSQLRubyJdbcConnection.rawArrayType == Boolean.TRUE ) { // array's type is :string
181
+ if ( sqlType != null && arrayLike(sqlType) ) {
182
+ statement.setNull(index, Types.ARRAY); return true;
183
+ }
184
+ statement.setNull(index, type); return true;
185
+ }
186
+ statement.setNull(index, Types.VARCHAR);
187
+ }
188
+ else {
189
+ final String valueStr = value.asString().toString();
190
+ if ( sqlType != null ) {
191
+ if ( PostgreSQLRubyJdbcConnection.rawArrayType == Boolean.TRUE && arrayLike(sqlType) ) {
192
+ final int oid = PostgreSQLRubyJdbcConnection.oid(context, column);
193
+ Jdbc4Array valueArr = new Jdbc4Array(connection.unwrap(BaseConnection.class), oid, valueStr);
194
+ statement.setArray(index, valueArr); return true;
195
+ }
196
+ if ( sqlType.getByteList().startsWith( INTERVAL ) ) {
197
+ statement.setObject( index, new PGInterval( valueStr ) ); return true;
198
+ }
199
+ }
200
+ statement.setString( index, valueStr );
201
+ }
202
+
203
+ return true;
204
+ }
205
+
206
+ private static final ByteList INTERVAL =
207
+ new ByteList( new byte[] { 'i','n','t','e','r','v','a','l' }, false );
208
+
209
+ private static boolean arrayLike(final RubyString sqlType) {
210
+ final int size = sqlType.size(); // does bytes.getRealSize()
211
+ if ( size <= 2 ) return false;
212
+ final ByteList bytes = sqlType.getByteList();
213
+ return bytes.charAt(size - 2) == '[' && bytes.charAt(size - 1) == ']';
214
+ }
215
+
216
+ // to handle infinity timestamp values
217
+ public boolean setTimestampParameter(final ThreadContext context,
218
+ final Connection connection, final PreparedStatement statement,
219
+ final int index, IRubyObject value,
220
+ final IRubyObject column, final int type) throws SQLException {
221
+
222
+ if ( value instanceof RubyFloat ) {
223
+ final double doubleValue = ( (RubyFloat) value ).getValue();
224
+ if ( Double.isInfinite(doubleValue) ) {
225
+ final Timestamp timestamp;
226
+ if ( doubleValue < 0 ) {
227
+ timestamp = new Timestamp(PGStatement.DATE_NEGATIVE_INFINITY);
228
+ }
229
+ else {
230
+ timestamp = new Timestamp(PGStatement.DATE_POSITIVE_INFINITY);
231
+ }
232
+ statement.setTimestamp( index, timestamp );
233
+ return true;
234
+ }
235
+ }
236
+
237
+ return false;
238
+ }
239
+
240
+ public boolean setObjectParameter(final ThreadContext context,
241
+ final Connection connection, final PreparedStatement statement,
242
+ final int index, Object value,
243
+ final IRubyObject column, final int type) throws SQLException {
244
+
245
+ final String columnType = column.callMethod(context, "type").asJavaString();
246
+
247
+ if ( columnType == (Object) "uuid" ) {
248
+ setUUIDParameter(statement, index, value);
249
+ return true;
250
+ }
251
+
252
+ if ( columnType == (Object) "json" ) {
253
+ setJsonParameter(context, statement, index, value, column, false);
254
+ return true;
255
+ }
256
+ if ( columnType == (Object) "jsonb" ) {
257
+ setJsonParameter(context, statement, index, value, column, true);
258
+ return true;
259
+ }
260
+
261
+ if ( columnType == (Object) "tsvector" ) {
262
+ setTsVectorParameter(statement, index, value);
263
+ return true;
264
+ }
265
+
266
+ if ( columnType == (Object) "hstore" ) {
267
+ setHstoreParameter(context, statement, index, value, column);
268
+ return true;
269
+ }
270
+
271
+ if ( columnType == (Object) "cidr" || columnType == (Object) "inet"
272
+ || columnType == (Object) "macaddr" ) {
273
+ setAddressParameter(context, statement, index, value, column, columnType);
274
+ return true;
275
+ }
276
+
277
+ if ( columnType != null && columnType.endsWith("range") ) {
278
+ setRangeParameter(context, statement, index, value, column, columnType);
279
+ return true;
280
+ }
281
+
282
+ return false;
283
+ }
284
+
285
+ static void setUUIDParameter(
286
+ final PreparedStatement statement, final int index,
287
+ Object value) throws SQLException {
288
+
289
+ if ( value instanceof IRubyObject ) {
290
+ final IRubyObject rubyValue = (IRubyObject) value;
291
+ if ( rubyValue.isNil() ) {
292
+ statement.setNull(index, Types.OTHER); return;
293
+ }
294
+ }
295
+ else if ( value == null ) {
296
+ statement.setNull(index, Types.OTHER); return;
297
+ }
298
+
299
+ final Object uuid = UUID.fromString( value.toString() );
300
+ statement.setObject(index, uuid);
301
+ }
302
+
303
+ static void setAddressParameter(final ThreadContext context,
304
+ final PreparedStatement statement, final int index,
305
+ Object value, final IRubyObject column,
306
+ final String columnType) throws SQLException {
307
+
308
+ if ( value instanceof IRubyObject ) {
309
+ final IRubyObject rubyValue = (IRubyObject) value;
310
+ if ( rubyValue.isNil() ) {
311
+ statement.setNull(index, Types.OTHER); return;
312
+ }
313
+ if ( ! isAr42(column) ) { // Value has already been cast for AR42
314
+ value = column.getMetaClass().callMethod(context, "cidr_to_string", rubyValue);
315
+ }
316
+ }
317
+ else if ( value == null ) {
318
+ statement.setNull(index, Types.OTHER); return;
319
+ }
320
+
321
+ final PGobject pgAddress = new PGobject();
322
+ pgAddress.setType(columnType);
323
+ pgAddress.setValue(value.toString());
324
+ statement.setObject(index, pgAddress);
325
+ }
326
+
327
+ static void setJsonParameter(final ThreadContext context,
328
+ final PreparedStatement statement, final int index,
329
+ Object value, final IRubyObject column, final boolean jsonb) throws SQLException {
330
+
331
+ if ( value instanceof IRubyObject ) {
332
+ final IRubyObject rubyValue = (IRubyObject) value;
333
+ if ( rubyValue.isNil() ) {
334
+ statement.setNull(index, Types.OTHER); return;
335
+ }
336
+ if ( ! isAr42(column) ) {
337
+ final String method = jsonb ? "jsonb_to_string" : "json_to_string";
338
+ value = column.getMetaClass().callMethod(context, method, rubyValue);
339
+ }
340
+ }
341
+ else if ( value == null ) {
342
+ statement.setNull(index, Types.OTHER); return;
343
+ }
344
+
345
+ final PGobject pgJson = new PGobject();
346
+ pgJson.setType(jsonb ? "jsonb" : "json");
347
+ pgJson.setValue(value.toString());
348
+ statement.setObject(index, pgJson);
349
+ }
350
+
351
+ static void setHstoreParameter(final ThreadContext context,
352
+ final PreparedStatement statement, final int index,
353
+ Object value, final IRubyObject column) throws SQLException {
354
+
355
+ if ( value instanceof IRubyObject ) {
356
+ final IRubyObject rubyValue = (IRubyObject) value;
357
+ if ( rubyValue.isNil() ) {
358
+ statement.setNull(index, Types.OTHER); return;
359
+ }
360
+ if ( ! isAr42(column) ) {
361
+ value = column.getMetaClass().callMethod(context, "hstore_to_string", rubyValue);
362
+ }
363
+ }
364
+ else if ( value == null ) {
365
+ statement.setNull(index, Types.OTHER); return;
366
+ }
367
+
368
+ final PGobject hstore = new PGobject();
369
+ hstore.setType("hstore");
370
+ hstore.setValue(value.toString());
371
+ statement.setObject(index, hstore);
372
+ }
373
+
374
+ static void setTsVectorParameter(
375
+ final PreparedStatement statement, final int index,
376
+ Object value) throws SQLException {
377
+
378
+ if ( value instanceof IRubyObject ) {
379
+ final IRubyObject rubyValue = (IRubyObject) value;
380
+ if ( rubyValue.isNil() ) {
381
+ statement.setNull(index, Types.OTHER); return;
382
+ }
383
+ }
384
+ else if ( value == null ) {
385
+ statement.setNull(index, Types.OTHER); return;
386
+ }
387
+
388
+ final PGobject pgTsVector = new PGobject();
389
+ pgTsVector.setType("tsvector");
390
+ pgTsVector.setValue(value.toString());
391
+ statement.setObject(index, pgTsVector);
392
+ }
393
+
394
+ static void setRangeParameter(final ThreadContext context,
395
+ final PreparedStatement statement, final int index,
396
+ final Object value, final IRubyObject column,
397
+ final String columnType) throws SQLException {
398
+
399
+ final String rangeValue;
400
+
401
+ if ( value instanceof IRubyObject ) {
402
+ final IRubyObject rubyValue = (IRubyObject) value;
403
+ if ( rubyValue.isNil() ) {
404
+ statement.setNull(index, Types.OTHER); return;
405
+ }
406
+ if ( isAr42(column) ) {
407
+ rangeValue = rubyValue.toString(); // expect a type_casted RubyString
408
+ }
409
+ else {
410
+ rangeValue = column.getMetaClass().callMethod(context, "range_to_string", rubyValue).toString();
411
+ }
412
+ }
413
+ else {
414
+ if ( value == null ) {
415
+ statement.setNull(index, Types.OTHER); return;
416
+ }
417
+ rangeValue = value.toString();
418
+ }
419
+
420
+ final Object pgRange;
421
+ if ( columnType == (Object) "daterange" ) {
422
+ pgRange = new DateRangeType(rangeValue);
423
+ }
424
+ else if ( columnType == (Object) "tsrange" ) {
425
+ pgRange = new TsRangeType(rangeValue);
426
+ }
427
+ else if ( columnType == (Object) "tstzrange" ) {
428
+ pgRange = new TstzRangeType(rangeValue);
429
+ }
430
+ else if ( columnType == (Object) "int4range" ) {
431
+ pgRange = new Int4RangeType(rangeValue);
432
+ }
433
+ else if ( columnType == (Object) "int8range" ) {
434
+ pgRange = new Int8RangeType(rangeValue);
435
+ }
436
+ else { // if ( columnType == (Object) "numrange" )
437
+ pgRange = new NumRangeType(rangeValue);
438
+ }
439
+ statement.setObject(index, pgRange);
440
+ }
441
+
442
+ // NOTE: without these custom registered Postgre (driver) types
443
+ // ... we can not set range parameters in prepared statements !
444
+
445
+ public static final class DateRangeType extends PGobject {
446
+
447
+ private static final long serialVersionUID = -5378414736244196691L;
448
+
449
+ public DateRangeType() {
450
+ setType("daterange");
451
+ }
452
+
453
+ public DateRangeType(final String value) throws SQLException {
454
+ this();
455
+ this.value = value;
456
+ }
457
+
458
+ }
459
+
460
+ public static final class TsRangeType extends PGobject {
461
+
462
+ private static final long serialVersionUID = -2991390995527988409L;
463
+
464
+ public TsRangeType() {
465
+ setType("tsrange");
466
+ }
467
+
468
+ public TsRangeType(final String value) throws SQLException {
469
+ this();
470
+ this.value = value;
471
+ }
472
+
473
+ }
474
+
475
+ public static final class TstzRangeType extends PGobject {
476
+
477
+ private static final long serialVersionUID = 6492535255861743334L;
478
+
479
+ public TstzRangeType() {
480
+ setType("tstzrange");
481
+ }
482
+
483
+ public TstzRangeType(final String value) throws SQLException {
484
+ this();
485
+ this.value = value;
486
+ }
487
+
488
+ }
489
+
490
+ public static final class Int4RangeType extends PGobject {
491
+
492
+ private static final long serialVersionUID = 4490562039665289763L;
493
+
494
+ public Int4RangeType() {
495
+ setType("int4range");
496
+ }
497
+
498
+ public Int4RangeType(final String value) throws SQLException {
499
+ this();
500
+ this.value = value;
501
+ }
502
+
503
+ }
504
+
505
+ public static final class Int8RangeType extends PGobject {
506
+
507
+ private static final long serialVersionUID = -1458706215346897102L;
508
+
509
+ public Int8RangeType() {
510
+ setType("int8range");
511
+ }
512
+
513
+ public Int8RangeType(final String value) throws SQLException {
514
+ this();
515
+ this.value = value;
516
+ }
517
+
518
+ }
519
+
520
+ public static final class NumRangeType extends PGobject {
521
+
522
+ private static final long serialVersionUID = 5892509252900362510L;
523
+
524
+ public NumRangeType() {
525
+ setType("numrange");
526
+ }
527
+
528
+ public NumRangeType(final String value) throws SQLException {
529
+ this();
530
+ this.value = value;
531
+ }
532
+
533
+ }
534
+
535
+ }