activerecord-jdbc-adapter-ficoh 1.3.21-java

Sign up to get free protection for your applications and to get access to all the features.
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,189 @@
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.postgresql;
25
+
26
+ import java.sql.ResultSet;
27
+ import java.sql.SQLException;
28
+
29
+ import org.jruby.Ruby;
30
+ import org.jruby.RubyModule;
31
+ import org.jruby.RubyString;
32
+ import org.jruby.anno.JRubyMethod;
33
+ import org.jruby.exceptions.RaiseException;
34
+ import org.jruby.runtime.ThreadContext;
35
+ import org.jruby.runtime.builtin.IRubyObject;
36
+ import org.jruby.util.ByteList;
37
+
38
+ import arjdbc.jdbc.WithResultSet;
39
+ import static arjdbc.jdbc.RubyJdbcConnection.debugMessage;
40
+ import static arjdbc.jdbc.RubyJdbcConnection.executeImpl;
41
+ import static arjdbc.jdbc.RubyJdbcConnection.executeQueryImpl;
42
+ import static arjdbc.util.QuotingUtils.quoteCharAndDecorateWith;
43
+ import static arjdbc.util.QuotingUtils.quoteCharWith;
44
+
45
+ /**
46
+ * ArJdbc::PostgreSQL
47
+ *
48
+ * @author kares
49
+ */
50
+ @org.jruby.anno.JRubyModule(name = "ArJdbc::PostgreSQL")
51
+ public class PostgreSQLModule {
52
+
53
+ public static RubyModule load(final RubyModule arJdbc) {
54
+ RubyModule postgreSQL = arJdbc.defineModuleUnder("PostgreSQL");
55
+ postgreSQL.defineAnnotatedMethods( PostgreSQLModule.class );
56
+ return postgreSQL;
57
+ }
58
+
59
+ public static RubyModule load(final Ruby runtime) {
60
+ return load( arjdbc.ArJdbcModule.get(runtime) );
61
+ }
62
+
63
+ @JRubyMethod(name = "quote_column_name", required = 1, frame = false)
64
+ public static IRubyObject quote_column_name(
65
+ final ThreadContext context,
66
+ final IRubyObject self,
67
+ final IRubyObject string) { // %("#{name.to_s.gsub("\"", "\"\"")}")
68
+ return quoteCharAndDecorateWith(context, string.asString(), '"', '"', (byte) '"', (byte) '"');
69
+ }
70
+
71
+ private static final ByteList BYTES_BACKSLASH = new ByteList(new byte[] { '\\' }, false);
72
+ private static final ByteList BYTES_ANDAND = new ByteList(new byte[] { '\\', '&', '\\', '&' }, false);
73
+
74
+ @JRubyMethod(name = "quote_string", required = 1, frame = false)
75
+ public static IRubyObject quote_string(
76
+ final ThreadContext context,
77
+ final IRubyObject self,
78
+ final IRubyObject string) {
79
+ final RubyString str = string.asString();
80
+ // quoted = string.gsub("'", "''")
81
+ RubyString quoted = quoteCharWith(context, str, '\'', '\'');
82
+
83
+ if ( ! standard_conforming_strings(context, self) ) { // minor branch
84
+ // quoted.gsub!(/\\/, '\&\&')
85
+ return quoted.callMethod(context, "gsub", new IRubyObject[] {
86
+ context.runtime.newString(BYTES_BACKSLASH),
87
+ context.runtime.newString(BYTES_ANDAND)
88
+ });
89
+ }
90
+ return quoted;
91
+ }
92
+
93
+ @JRubyMethod(name = "standard_conforming_strings?")
94
+ public static IRubyObject standard_conforming_strings_p(final ThreadContext context, final IRubyObject self) {
95
+ return context.runtime.newBoolean( standard_conforming_strings(context, self) );
96
+ }
97
+
98
+ private static boolean standard_conforming_strings(final ThreadContext context, final IRubyObject self) {
99
+ IRubyObject standard_conforming_strings =
100
+ self.getInstanceVariables().getInstanceVariable("@standard_conforming_strings");
101
+
102
+ if ( standard_conforming_strings == null ) {
103
+ synchronized (self) {
104
+ standard_conforming_strings = context.nil; // unsupported
105
+
106
+ final IRubyObject client_min_messages = self.callMethod(context, "client_min_messages");
107
+ final Ruby runtime = context.runtime;
108
+ try {
109
+ self.callMethod(context, "client_min_messages=", runtime.newString("panic"));
110
+ // NOTE: we no longer log this query as before ... with :
111
+ // select_one('SHOW standard_conforming_strings', 'SCHEMA')['standard_conforming_strings']
112
+ standard_conforming_strings = executeQueryImpl(context, self,
113
+ "SHOW standard_conforming_strings", 1, false, new WithResultSet<IRubyObject>() {
114
+ public IRubyObject call(final ResultSet resultSet) throws SQLException {
115
+ if ( resultSet != null && resultSet.next() ) {
116
+ final String result = resultSet.getString(1);
117
+ return runtime.newBoolean( "on".equals(result) );
118
+ }
119
+ return context.nil;
120
+ }
121
+ });
122
+ }
123
+ catch (SQLException e) { // unsupported
124
+ debugMessage(context.runtime, "standard conforming strings not supported: ", e);
125
+ }
126
+ catch (RaiseException e) { // unsupported
127
+ debugMessage(context.runtime, "standard conforming strings raised: ", e);
128
+ }
129
+ finally {
130
+ self.callMethod(context, "client_min_messages=", client_min_messages);
131
+ }
132
+
133
+ self.getInstanceVariables().setInstanceVariable("@standard_conforming_strings", standard_conforming_strings);
134
+ }
135
+ }
136
+
137
+ return standard_conforming_strings.isTrue();
138
+ }
139
+
140
+ @JRubyMethod(name = "standard_conforming_strings=")
141
+ public static IRubyObject set_standard_conforming_strings(final ThreadContext context, final IRubyObject self,
142
+ final IRubyObject enable) {
143
+ //
144
+ // client_min_messages = self.client_min_messages
145
+ // begin
146
+ // self.client_min_messages = 'panic'
147
+ // value = enable ? "on" : "off"
148
+ // execute("SET standard_conforming_strings = #{value}", 'SCHEMA')
149
+ // @standard_conforming_strings = ( value == "on" )
150
+ // rescue
151
+ // @standard_conforming_strings = :unsupported
152
+ // ensure
153
+ // self.client_min_messages = client_min_messages
154
+ // end
155
+ //
156
+ IRubyObject standard_conforming_strings = context.nil; // unsupported
157
+ final IRubyObject client_min_messages = self.callMethod(context, "client_min_messages");
158
+
159
+ try {
160
+ final Ruby runtime = context.runtime;
161
+ self.callMethod(context, "client_min_messages=", runtime.newString("panic"));
162
+
163
+ final String value;
164
+ if ( enable.isNil() || enable == runtime.getFalse() ) value = "off";
165
+ else value = "on";
166
+ // NOTE: we no longer log this query as before ... with :
167
+ // execute("SET standard_conforming_strings = #{value}", 'SCHEMA')
168
+ executeImpl(context, self, "SET standard_conforming_strings = " + value);
169
+
170
+ standard_conforming_strings = runtime.newBoolean( value == (Object) "on" );
171
+ }
172
+ catch (RaiseException e) {
173
+ // unsupported
174
+ }
175
+ finally {
176
+ self.callMethod(context, "client_min_messages=", client_min_messages);
177
+ }
178
+
179
+ return self.getInstanceVariables().setInstanceVariable("@standard_conforming_strings", standard_conforming_strings);
180
+ }
181
+
182
+ @JRubyMethod(name = "unescape_bytea", meta = true)
183
+ public static RubyString unescape_bytea(final ThreadContext context, final IRubyObject self, final IRubyObject escaped) {
184
+ final ByteList bytes = ((RubyString) escaped).getByteList();
185
+ final byte[] rawBytes = ByteaUtils.toBytes(bytes.unsafeBytes(), bytes.getBegin(), bytes.getRealSize());
186
+ return RubyString.newString(context.runtime, new ByteList(rawBytes, false));
187
+ }
188
+
189
+ }
@@ -0,0 +1,489 @@
1
+ /***** BEGIN LICENSE BLOCK *****
2
+ * Copyright (c) 2012-2015 Karol Bucek <self@kares.org>
3
+ * Copyright (c) 2006-2010 Nick Sieger <nick@nicksieger.com>
4
+ * Copyright (c) 2006-2007 Ola Bini <ola.bini@gmail.com>
5
+ * Copyright (c) 2008-2009 Thomas E Enebo <enebo@acm.org>
6
+ *
7
+ * Permission is hereby granted, free of charge, to any person obtaining
8
+ * a copy of this software and associated documentation files (the
9
+ * "Software"), to deal in the Software without restriction, including
10
+ * without limitation the rights to use, copy, modify, merge, publish,
11
+ * distribute, sublicense, and/or sell copies of the Software, and to
12
+ * permit persons to whom the Software is furnished to do so, subject to
13
+ * the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be
16
+ * included in all copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
+ ***** END LICENSE BLOCK *****/
26
+ package arjdbc.postgresql;
27
+
28
+ import java.io.ByteArrayInputStream;
29
+ import java.io.InputStream;
30
+ import java.lang.reflect.InvocationTargetException;
31
+ import java.sql.Array;
32
+ import java.sql.Connection;
33
+ import java.sql.PreparedStatement;
34
+ import java.sql.ResultSet;
35
+ import java.sql.SQLException;
36
+ import java.sql.Statement;
37
+ import java.sql.Types;
38
+
39
+ import org.jruby.Ruby;
40
+ import org.jruby.RubyArray;
41
+ import org.jruby.RubyBoolean;
42
+ import org.jruby.RubyClass;
43
+ import org.jruby.RubyFixnum;
44
+ import org.jruby.RubyFloat;
45
+ import org.jruby.RubyIO;
46
+ import org.jruby.RubyString;
47
+ import org.jruby.anno.JRubyMethod;
48
+ import org.jruby.runtime.ObjectAllocator;
49
+ import org.jruby.runtime.ThreadContext;
50
+ import org.jruby.runtime.builtin.IRubyObject;
51
+ import org.jruby.util.ByteList;
52
+ import org.jruby.util.SafePropertyAccessor;
53
+
54
+ import arjdbc.jdbc.DriverWrapper;
55
+ import arjdbc.util.DateTimeUtils;
56
+
57
+ /**
58
+ *
59
+ * @author enebo
60
+ */
61
+ @org.jruby.anno.JRubyClass(name = "ActiveRecord::ConnectionAdapters::PostgreSQLJdbcConnection")
62
+ public class PostgreSQLRubyJdbcConnection extends arjdbc.jdbc.RubyJdbcConnection {
63
+ private static final long serialVersionUID = 7235537759545717760L;
64
+
65
+ public PostgreSQLRubyJdbcConnection(Ruby runtime, RubyClass metaClass) {
66
+ super(runtime, metaClass);
67
+ }
68
+
69
+ public static RubyClass createPostgreSQLJdbcConnectionClass(Ruby runtime, RubyClass jdbcConnection) {
70
+ final RubyClass clazz = getConnectionAdapters(runtime).
71
+ defineClassUnder("PostgreSQLJdbcConnection", jdbcConnection, ALLOCATOR);
72
+ clazz.defineAnnotatedMethods(PostgreSQLRubyJdbcConnection.class);
73
+ return clazz;
74
+ }
75
+
76
+ public static RubyClass load(final Ruby runtime) {
77
+ RubyClass jdbcConnection = getJdbcConnection(runtime);
78
+ return createPostgreSQLJdbcConnectionClass(runtime, jdbcConnection);
79
+ }
80
+
81
+ protected static ObjectAllocator ALLOCATOR = new ObjectAllocator() {
82
+ public IRubyObject allocate(Ruby runtime, RubyClass klass) {
83
+ return new PostgreSQLRubyJdbcConnection(runtime, klass);
84
+ }
85
+ };
86
+
87
+ @Override
88
+ protected DriverWrapper newDriverWrapper(final ThreadContext context, final String driver) {
89
+ DriverWrapper driverWrapper = super.newDriverWrapper(context, driver);
90
+
91
+ final java.sql.Driver jdbcDriver = driverWrapper.getDriverInstance();
92
+ if ( jdbcDriver.getClass().getName().startsWith("org.postgresql.") ) {
93
+ try { // public static String getVersion()
94
+ final String version = (String) // "PostgreSQL 9.2 JDBC4 (build 1002)"
95
+ jdbcDriver.getClass().getMethod("getVersion").invoke(null);
96
+ if ( version != null && version.indexOf("JDBC3") >= 0 ) {
97
+ // config[:connection_alive_sql] ||= 'SELECT 1'
98
+ setConfigValueIfNotSet(context, "connection_alive_sql", context.runtime.newString("SELECT 1"));
99
+ }
100
+ }
101
+ catch (NoSuchMethodException e) { }
102
+ catch (SecurityException e) { }
103
+ catch (IllegalAccessException e) { }
104
+ catch (InvocationTargetException e) { }
105
+ }
106
+
107
+ return driverWrapper;
108
+ }
109
+
110
+ protected final IRubyObject beginTransaction(final ThreadContext context, final Connection connection,
111
+ final IRubyObject isolation) throws SQLException {
112
+ // NOTE: only reversed order - just to ~ match how Rails does it :
113
+ /* if ( connection.getAutoCommit() ) */ connection.setAutoCommit(false);
114
+ if ( isolation != null ) {
115
+ setTransactionIsolation(context, connection, isolation);
116
+ }
117
+ return context.nil;
118
+ }
119
+
120
+ final DriverImplementation driverImplementation = new PGDriverImplementation(); // currently no other supported
121
+
122
+ DriverImplementation driverImplementation() { return driverImplementation; }
123
+
124
+ // enables testing if the bug is fixed (please run our test-suite)
125
+ // using `rake test_postgresql JRUBY_OPTS="-J-Darjdbc.postgresql.generated_keys=true"`
126
+ protected static final boolean generatedKeys;
127
+ static {
128
+ String genKeys = SafePropertyAccessor.getProperty("arjdbc.postgresql.generated_keys");
129
+ if ( genKeys == null ) { // @deprecated system property name :
130
+ genKeys = SafePropertyAccessor.getProperty("arjdbc.postgresql.generated.keys");
131
+ }
132
+ generatedKeys = Boolean.parseBoolean(genKeys);
133
+ }
134
+
135
+ @Override
136
+ protected IRubyObject mapGeneratedKeys(
137
+ final Ruby runtime, final Connection connection,
138
+ final Statement statement, final Boolean singleResult)
139
+ throws SQLException {
140
+ // NOTE: PostgreSQL driver supports generated keys but does not work
141
+ // correctly for all cases e.g. for tables whene no keys are generated
142
+ // during an INSERT getGeneratedKeys return all inserted rows instead
143
+ // of an empty result set ... thus disabled until issue is resolved !
144
+ if ( ! generatedKeys ) return null; // not supported
145
+ // NOTE: generated-keys is implemented by the Postgre's JDBC driver by
146
+ // adding a "RETURNING" suffix after the executeUpdate passed query ...
147
+ return super.mapGeneratedKeys(runtime, connection, statement, singleResult);
148
+ }
149
+
150
+ // storesMixedCaseIdentifiers() return false;
151
+ // storesLowerCaseIdentifiers() return true;
152
+ // storesUpperCaseIdentifiers() return false;
153
+
154
+ @Override
155
+ protected final String caseConvertIdentifierForRails(final Connection connection, final String value)
156
+ throws SQLException {
157
+ return value;
158
+ }
159
+
160
+ @Override
161
+ protected final String caseConvertIdentifierForJdbc(final Connection connection, final String value)
162
+ throws SQLException {
163
+ return value;
164
+ }
165
+
166
+ @Override
167
+ protected final Connection newConnection() throws SQLException {
168
+ return driverImplementation().newConnection( getConnectionFactory().newConnection() );
169
+ }
170
+
171
+ @Override // due statement.setNull(index, Types.BLOB) not working :
172
+ // org.postgresql.util.PSQLException: ERROR: column "sample_binary" is of type bytea but expression is of type oid
173
+ protected void setBlobParameter(final ThreadContext context,
174
+ final Connection connection, final PreparedStatement statement,
175
+ final int index, final Object value,
176
+ final IRubyObject column, final int type) throws SQLException {
177
+ if ( value instanceof IRubyObject ) {
178
+ setBlobParameter(context, connection, statement, index, (IRubyObject) value, column, type);
179
+ }
180
+ else {
181
+ if ( value == null ) statement.setNull(index, Types.BINARY);
182
+ else {
183
+ statement.setBinaryStream(index, (InputStream) value);
184
+ }
185
+ }
186
+ }
187
+
188
+ @Override // due statement.setNull(index, Types.BLOB) not working :
189
+ // org.postgresql.util.PSQLException: ERROR: column "sample_binary" is of type bytea but expression is of type oid
190
+ protected void setBlobParameter(final ThreadContext context,
191
+ final Connection connection, final PreparedStatement statement,
192
+ final int index, final IRubyObject value,
193
+ final IRubyObject column, final int type) throws SQLException {
194
+ if ( value.isNil() ) {
195
+ statement.setNull(index, Types.BINARY);
196
+ }
197
+ else {
198
+ if ( value instanceof RubyIO ) { // IO/File
199
+ statement.setBinaryStream(index, ((RubyIO) value).getInStream());
200
+ }
201
+ else { // should be a RubyString
202
+ final ByteList blob = value.asString().getByteList();
203
+ statement.setBinaryStream(index,
204
+ new ByteArrayInputStream(blob.unsafeBytes(), blob.getBegin(), blob.getRealSize()),
205
+ blob.getRealSize() // length
206
+ );
207
+ }
208
+ }
209
+ }
210
+
211
+ @Override // to handle infinity timestamp values
212
+ protected void setTimestampParameter(final ThreadContext context,
213
+ final Connection connection, final PreparedStatement statement,
214
+ final int index, IRubyObject value,
215
+ final IRubyObject column, final int type) throws SQLException {
216
+
217
+ if ( ! driverImplementation().setTimestampParameter(context, connection, statement, index, value, column, type) ) {
218
+ super.setTimestampParameter(context, connection, statement, index, value, column, type);
219
+ }
220
+ }
221
+
222
+ @Override
223
+ protected void setStringParameter(final ThreadContext context,
224
+ final Connection connection, final PreparedStatement statement,
225
+ final int index, final IRubyObject value,
226
+ final IRubyObject column, final int type) throws SQLException {
227
+
228
+ if ( ! driverImplementation().setStringParameter(context, connection, statement, index, value, column, type) ) {
229
+ super.setStringParameter(context, connection, statement, index, value, column, type);
230
+ }
231
+ }
232
+
233
+ static int oid(final ThreadContext context, final IRubyObject column) {
234
+ // our column convention :
235
+ IRubyObject oid = column.getInstanceVariables().getInstanceVariable("@oid");
236
+ if ( oid == null || oid.isNil() ) { // only for user instantiated Column
237
+ throw new IllegalStateException("missing @oid for column: " + column.inspect());
238
+ }
239
+ return RubyFixnum.fix2int(oid);
240
+ }
241
+
242
+ @Override
243
+ protected void setObjectParameter(final ThreadContext context,
244
+ final Connection connection, final PreparedStatement statement,
245
+ final int index, Object value,
246
+ final IRubyObject column, final int type) throws SQLException {
247
+
248
+ if ( ! driverImplementation().setObjectParameter(context, connection, statement, index, value, column, type) ) {
249
+ super.setObjectParameter(context, connection, statement, index, value, column, type);
250
+ }
251
+ }
252
+
253
+ @Override
254
+ protected String resolveArrayBaseTypeName(final ThreadContext context,
255
+ final Object value, final IRubyObject column, final int type) {
256
+ String sqlType = column.callMethod(context, "sql_type").toString();
257
+ if ( sqlType.startsWith("character varying") ) return "text";
258
+ final int index = sqlType.indexOf('('); // e.g. "character varying(255)"
259
+ if ( index > 0 ) sqlType = sqlType.substring(0, index);
260
+ return sqlType;
261
+ }
262
+
263
+ //private static final int HSTORE_TYPE = 100000 + 1111;
264
+
265
+ @Override
266
+ protected int jdbcTypeFor(final ThreadContext context, final Ruby runtime,
267
+ final IRubyObject column, final Object value) throws SQLException {
268
+ // NOTE: likely wrong but native adapters handles this thus we should
269
+ // too - used from #table_exists? `binds << [ nil, schema ] if schema`
270
+ if ( column == null || column.isNil() ) return Types.VARCHAR; // assume type == :string
271
+ final int type = super.jdbcTypeFor(context, runtime, column, value);
272
+ /*
273
+ if ( type == Types.OTHER ) {
274
+ final IRubyObject columnType = column.callMethod(context, "type");
275
+ if ( "hstore" == (Object) columnType.asJavaString() ) {
276
+ return HSTORE_TYPE;
277
+ }
278
+ } */
279
+ return type;
280
+ }
281
+
282
+ /**
283
+ * Override jdbcToRuby type conversions to handle infinite timestamps.
284
+ * Handing timestamp off to ruby as string so adapter can perform type
285
+ * conversion to timestamp
286
+ */
287
+ @Override
288
+ protected IRubyObject jdbcToRuby(
289
+ final ThreadContext context, final Ruby runtime,
290
+ final int column, final int type, final ResultSet resultSet)
291
+ throws SQLException {
292
+ switch ( type ) {
293
+ case Types.BIT:
294
+ // we do get BIT for 't' 'f' as well as BIT strings e.g. "0110" :
295
+ final String bits = resultSet.getString(column);
296
+ if ( bits == null ) return context.nil;
297
+ if ( bits.length() > 1 ) {
298
+ return RubyString.newUnicodeString(runtime, bits);
299
+ }
300
+ return booleanToRuby(context, runtime, resultSet, column);
301
+ //case Types.JAVA_OBJECT: case Types.OTHER:
302
+ //return objectToRuby(runtime, resultSet, resultSet.getObject(column));
303
+ }
304
+ return super.jdbcToRuby(context, runtime, column, type, resultSet);
305
+ }
306
+
307
+ @Override
308
+ protected boolean useByteStrings() { return true; }
309
+
310
+ @Override
311
+ protected IRubyObject dateToRuby(final ThreadContext context,
312
+ final Ruby runtime, final ResultSet resultSet, final int column)
313
+ throws SQLException {
314
+
315
+ if ( rawDateTime != null && rawDateTime.booleanValue() ) {
316
+ final byte[] value = resultSet.getBytes(column);
317
+ if ( value == null ) {
318
+ if ( resultSet.wasNull() ) return context.nil;
319
+ return RubyString.newEmptyString(runtime); // ""
320
+ }
321
+ return RubyString.newString(runtime, new ByteList(value, false));
322
+ }
323
+
324
+ final String value = resultSet.getString(column);
325
+ if ( value == null ) return context.nil;
326
+
327
+ return DateTimeUtils.parseDate(context, value);
328
+ }
329
+
330
+ @Override
331
+ protected IRubyObject timeToRuby(final ThreadContext context,
332
+ final Ruby runtime, final ResultSet resultSet, final int column)
333
+ throws SQLException {
334
+ return timestampToRuby(context, runtime, resultSet, column);
335
+ }
336
+
337
+ @Override
338
+ protected IRubyObject timestampToRuby(final ThreadContext context,
339
+ final Ruby runtime, final ResultSet resultSet, final int column)
340
+ throws SQLException {
341
+
342
+ if ( rawDateTime != null && rawDateTime.booleanValue() ) {
343
+ final byte[] value = resultSet.getBytes(column);
344
+ if ( value == null ) {
345
+ if ( resultSet.wasNull() ) return context.nil;
346
+ return RubyString.newEmptyString(runtime); // ""
347
+ }
348
+ return RubyString.newString(runtime, new ByteList(value, false));
349
+ }
350
+
351
+ // NOTE: using Timestamp we would loose information such as BC :
352
+ // Timestamp: '0001-12-31 22:59:59.0' String: '0001-12-31 22:59:59 BC'
353
+
354
+ final String value = resultSet.getString(column);
355
+ if ( value == null ) return context.nil;
356
+
357
+ // string_to_time
358
+ final int len = value.length();
359
+ if ( (len == 8 || len == 9) && value.charAt(len - 1) == 'y' ) {
360
+ if ( value.charAt(0) == '-' ) { // 'infinity' / '-infinity'
361
+ return RubyFloat.newFloat(context.runtime, -RubyFloat.INFINITY);
362
+ }
363
+ return RubyFloat.newFloat(context.runtime, RubyFloat.INFINITY);
364
+ }
365
+ return DateTimeUtils.parseDateTime(context, value);
366
+ /*
367
+ final IRubyObject adapter = callMethod(context, "adapter"); // self.adapter
368
+ if ( usesType(runtime) ) {
369
+ return typeCastFromDatabase(context, adapter, runtime.newSymbol("timestamp"), strValue);
370
+ }
371
+
372
+ if ( adapter.isNil() ) return strValue; // NOTE: we warn on init_connection
373
+ return adapter.callMethod(context, "_string_to_timestamp", strValue);
374
+ */
375
+ }
376
+
377
+ @Override
378
+ protected IRubyObject arrayToRuby(final ThreadContext context,
379
+ final Ruby runtime, final ResultSet resultSet, final int column)
380
+ throws SQLException {
381
+ if ( rawArrayType == Boolean.TRUE ) { // pre AR 4.0 compatibility
382
+ return stringToRuby(context, runtime, resultSet, column);
383
+ }
384
+ // NOTE: avoid `finally { array.free(); }` on PostgreSQL due :
385
+ // java.sql.SQLFeatureNotSupportedException:
386
+ // Method org.postgresql.jdbc4.Jdbc4Array.free() is not yet implemented.
387
+ final Array value = resultSet.getArray(column);
388
+
389
+ if ( value == null /* || resultSet.wasNull() */ ) return context.nil;
390
+
391
+ final RubyArray array = RubyArray.newArray(runtime);
392
+
393
+ final ResultSet arrayResult = value.getResultSet(); // 1: index, 2: value
394
+ final int baseType = value.getBaseType();
395
+ while ( arrayResult.next() ) {
396
+ array.append( jdbcToRuby(context, runtime, 2, baseType, arrayResult) );
397
+ }
398
+ return array;
399
+ }
400
+
401
+ @Override
402
+ protected final IRubyObject objectToRuby(final ThreadContext context,
403
+ final Ruby runtime, final ResultSet resultSet, final int column)
404
+ throws SQLException {
405
+ return driverImplementation().objectToRuby(context, resultSet, column);
406
+ }
407
+
408
+ @Override
409
+ protected TableName extractTableName(
410
+ final Connection connection, String catalog, String schema,
411
+ final String tableName) throws IllegalArgumentException, SQLException {
412
+ // The postgres JDBC driver will default to searching every schema if no
413
+ // schema search path is given. Default to the 'public' schema instead:
414
+ if ( schema == null ) schema = "public";
415
+ return super.extractTableName(connection, catalog, schema, tableName);
416
+ }
417
+
418
+ static Boolean rawArrayType;
419
+ static {
420
+ final String arrayRaw = SafePropertyAccessor.getProperty("arjdbc.postgresql.array.raw");
421
+ if ( arrayRaw != null ) rawArrayType = Boolean.parseBoolean(arrayRaw);
422
+ }
423
+
424
+ @JRubyMethod(name = "raw_array_type?", meta = true)
425
+ public static IRubyObject useRawArrayType(final ThreadContext context, final IRubyObject self) {
426
+ if ( rawArrayType == null ) return context.nil;
427
+ return context.runtime.newBoolean(rawArrayType);
428
+ }
429
+
430
+ @JRubyMethod(name = "raw_array_type=", meta = true)
431
+ public static IRubyObject setRawArrayType(final IRubyObject self, final IRubyObject value) {
432
+ if ( value instanceof RubyBoolean ) {
433
+ rawArrayType = ((RubyBoolean) value).isTrue() ? Boolean.TRUE : Boolean.FALSE;
434
+ }
435
+ else {
436
+ rawArrayType = value.isNil() ? null : Boolean.TRUE;
437
+ }
438
+ return value;
439
+ }
440
+
441
+ static Boolean rawHstoreType;
442
+ static {
443
+ final String hstoreRaw = SafePropertyAccessor.getProperty("arjdbc.postgresql.hstore.raw");
444
+ if ( hstoreRaw != null ) rawHstoreType = Boolean.parseBoolean(hstoreRaw);
445
+ }
446
+
447
+ @JRubyMethod(name = "raw_hstore_type?", meta = true)
448
+ public static IRubyObject useRawHstoreType(final ThreadContext context, final IRubyObject self) {
449
+ if ( rawHstoreType == null ) return context.nil;
450
+ return context.runtime.newBoolean(rawHstoreType);
451
+ }
452
+
453
+ @JRubyMethod(name = "raw_hstore_type=", meta = true)
454
+ public static IRubyObject setRawHstoreType(final IRubyObject self, final IRubyObject value) {
455
+ if ( value instanceof RubyBoolean ) {
456
+ rawHstoreType = ((RubyBoolean) value).isTrue() ? Boolean.TRUE : Boolean.FALSE;
457
+ }
458
+ else {
459
+ rawHstoreType = value.isNil() ? null : Boolean.TRUE;
460
+ }
461
+ return value;
462
+ }
463
+
464
+ // whether to use "raw" interval values off by default - due native adapter compatibilty :
465
+ // RAW values :
466
+ // - 2 years 0 mons 0 days 0 hours 3 mins 0.00 secs
467
+ // - -1 years 0 mons -2 days 0 hours 0 mins 0.00 secs
468
+ // Rails style :
469
+ // - 2 years 00:03:00
470
+ // - -1 years -2 days
471
+ static boolean rawIntervalType = Boolean.getBoolean("arjdbc.postgresql.iterval.raw");
472
+
473
+ @JRubyMethod(name = "raw_interval_type?", meta = true)
474
+ public static IRubyObject useRawIntervalType(final ThreadContext context, final IRubyObject self) {
475
+ return context.runtime.newBoolean(rawIntervalType);
476
+ }
477
+
478
+ @JRubyMethod(name = "raw_interval_type=", meta = true)
479
+ public static IRubyObject setRawIntervalType(final IRubyObject self, final IRubyObject value) {
480
+ if ( value instanceof RubyBoolean ) {
481
+ rawIntervalType = ((RubyBoolean) value).isTrue();
482
+ }
483
+ else {
484
+ rawIntervalType = ! value.isNil();
485
+ }
486
+ return value;
487
+ }
488
+
489
+ }