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.
- checksums.yaml +7 -0
- data/.gitignore +35 -0
- data/.travis.yml +462 -0
- data/.yardopts +4 -0
- data/Appraisals +36 -0
- data/CONTRIBUTING.md +49 -0
- data/Gemfile +68 -0
- data/History.md +1191 -0
- data/LICENSE.txt +25 -0
- data/README.md +277 -0
- data/RUNNING_TESTS.md +88 -0
- data/Rakefile +298 -0
- data/Rakefile.jdbc +20 -0
- data/activerecord-jdbc-adapter.gemspec +63 -0
- data/lib/active_record/connection_adapters/as400_adapter.rb +2 -0
- data/lib/active_record/connection_adapters/db2_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/derby_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/firebird_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/h2_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/hsqldb_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/informix_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/jdbc_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/jndi_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/mariadb_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/mssql_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/mysql_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/oracle_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +1 -0
- data/lib/activerecord-jdbc-adapter.rb +1 -0
- data/lib/arel/visitors/compat.rb +64 -0
- data/lib/arel/visitors/db2.rb +137 -0
- data/lib/arel/visitors/derby.rb +112 -0
- data/lib/arel/visitors/firebird.rb +79 -0
- data/lib/arel/visitors/h2.rb +25 -0
- data/lib/arel/visitors/hsqldb.rb +32 -0
- data/lib/arel/visitors/postgresql_jdbc.rb +6 -0
- data/lib/arel/visitors/sql_server.rb +225 -0
- data/lib/arel/visitors/sql_server/ng42.rb +293 -0
- data/lib/arjdbc.rb +22 -0
- data/lib/arjdbc/db2.rb +4 -0
- data/lib/arjdbc/db2/adapter.rb +802 -0
- data/lib/arjdbc/db2/as400.rb +137 -0
- data/lib/arjdbc/db2/column.rb +177 -0
- data/lib/arjdbc/db2/connection_methods.rb +45 -0
- data/lib/arjdbc/derby.rb +3 -0
- data/lib/arjdbc/derby/active_record_patch.rb +13 -0
- data/lib/arjdbc/derby/adapter.rb +567 -0
- data/lib/arjdbc/derby/connection_methods.rb +16 -0
- data/lib/arjdbc/derby/schema_creation.rb +15 -0
- data/lib/arjdbc/discover.rb +104 -0
- data/lib/arjdbc/firebird.rb +4 -0
- data/lib/arjdbc/firebird/adapter.rb +468 -0
- data/lib/arjdbc/firebird/connection_methods.rb +20 -0
- data/lib/arjdbc/h2.rb +3 -0
- data/lib/arjdbc/h2/adapter.rb +335 -0
- data/lib/arjdbc/h2/connection_methods.rb +22 -0
- data/lib/arjdbc/hsqldb.rb +3 -0
- data/lib/arjdbc/hsqldb/adapter.rb +304 -0
- data/lib/arjdbc/hsqldb/connection_methods.rb +23 -0
- data/lib/arjdbc/hsqldb/explain_support.rb +35 -0
- data/lib/arjdbc/hsqldb/schema_creation.rb +11 -0
- data/lib/arjdbc/informix.rb +5 -0
- data/lib/arjdbc/informix/adapter.rb +160 -0
- data/lib/arjdbc/informix/connection_methods.rb +9 -0
- data/lib/arjdbc/jdbc.rb +62 -0
- data/lib/arjdbc/jdbc/adapter.rb +997 -0
- data/lib/arjdbc/jdbc/adapter_require.rb +46 -0
- data/lib/arjdbc/jdbc/arel_support.rb +149 -0
- data/lib/arjdbc/jdbc/base_ext.rb +34 -0
- data/lib/arjdbc/jdbc/callbacks.rb +52 -0
- data/lib/arjdbc/jdbc/column.rb +83 -0
- data/lib/arjdbc/jdbc/connection.rb +26 -0
- data/lib/arjdbc/jdbc/connection_methods.rb +59 -0
- data/lib/arjdbc/jdbc/driver.rb +44 -0
- data/lib/arjdbc/jdbc/error.rb +75 -0
- data/lib/arjdbc/jdbc/extension.rb +69 -0
- data/lib/arjdbc/jdbc/java.rb +13 -0
- data/lib/arjdbc/jdbc/type_cast.rb +154 -0
- data/lib/arjdbc/jdbc/type_converter.rb +142 -0
- data/lib/arjdbc/mssql.rb +7 -0
- data/lib/arjdbc/mssql/adapter.rb +822 -0
- data/lib/arjdbc/mssql/column.rb +207 -0
- data/lib/arjdbc/mssql/connection_methods.rb +72 -0
- data/lib/arjdbc/mssql/explain_support.rb +99 -0
- data/lib/arjdbc/mssql/limit_helpers.rb +231 -0
- data/lib/arjdbc/mssql/lock_methods.rb +77 -0
- data/lib/arjdbc/mssql/types.rb +343 -0
- data/lib/arjdbc/mssql/utils.rb +82 -0
- data/lib/arjdbc/mysql.rb +3 -0
- data/lib/arjdbc/mysql/adapter.rb +998 -0
- data/lib/arjdbc/mysql/bulk_change_table.rb +150 -0
- data/lib/arjdbc/mysql/column.rb +167 -0
- data/lib/arjdbc/mysql/connection_methods.rb +137 -0
- data/lib/arjdbc/mysql/explain_support.rb +82 -0
- data/lib/arjdbc/mysql/schema_creation.rb +58 -0
- data/lib/arjdbc/oracle.rb +4 -0
- data/lib/arjdbc/oracle/adapter.rb +968 -0
- data/lib/arjdbc/oracle/column.rb +136 -0
- data/lib/arjdbc/oracle/connection_methods.rb +21 -0
- data/lib/arjdbc/postgresql.rb +3 -0
- data/lib/arjdbc/postgresql/_bc_time_cast_patch.rb +21 -0
- data/lib/arjdbc/postgresql/adapter.rb +1498 -0
- data/lib/arjdbc/postgresql/base/array_parser.rb +95 -0
- data/lib/arjdbc/postgresql/base/oid.rb +412 -0
- data/lib/arjdbc/postgresql/base/pgconn.rb +8 -0
- data/lib/arjdbc/postgresql/base/schema_definitions.rb +132 -0
- data/lib/arjdbc/postgresql/column.rb +640 -0
- data/lib/arjdbc/postgresql/connection_methods.rb +44 -0
- data/lib/arjdbc/postgresql/explain_support.rb +53 -0
- data/lib/arjdbc/postgresql/oid/bytea.rb +3 -0
- data/lib/arjdbc/postgresql/oid_types.rb +265 -0
- data/lib/arjdbc/postgresql/schema_creation.rb +60 -0
- data/lib/arjdbc/railtie.rb +11 -0
- data/lib/arjdbc/sqlite3.rb +3 -0
- data/lib/arjdbc/sqlite3/adapter.rb +654 -0
- data/lib/arjdbc/sqlite3/connection_methods.rb +36 -0
- data/lib/arjdbc/sqlite3/explain_support.rb +29 -0
- data/lib/arjdbc/sybase.rb +2 -0
- data/lib/arjdbc/sybase/adapter.rb +47 -0
- data/lib/arjdbc/tasks.rb +13 -0
- data/lib/arjdbc/tasks/database_tasks.rb +66 -0
- data/lib/arjdbc/tasks/databases.rake +91 -0
- data/lib/arjdbc/tasks/databases3.rake +239 -0
- data/lib/arjdbc/tasks/databases4.rake +39 -0
- data/lib/arjdbc/tasks/db2_database_tasks.rb +104 -0
- data/lib/arjdbc/tasks/derby_database_tasks.rb +95 -0
- data/lib/arjdbc/tasks/h2_database_tasks.rb +31 -0
- data/lib/arjdbc/tasks/hsqldb_database_tasks.rb +70 -0
- data/lib/arjdbc/tasks/jdbc_database_tasks.rb +169 -0
- data/lib/arjdbc/tasks/mssql_database_tasks.rb +46 -0
- data/lib/arjdbc/tasks/oracle/enhanced_structure_dump.rb +297 -0
- data/lib/arjdbc/tasks/oracle_database_tasks.rb +65 -0
- data/lib/arjdbc/util/quoted_cache.rb +60 -0
- data/lib/arjdbc/util/serialized_attributes.rb +98 -0
- data/lib/arjdbc/util/table_copier.rb +108 -0
- data/lib/arjdbc/version.rb +8 -0
- data/lib/generators/jdbc/USAGE +9 -0
- data/lib/generators/jdbc/jdbc_generator.rb +17 -0
- data/pom.xml +285 -0
- data/rails_generators/jdbc_generator.rb +15 -0
- data/rails_generators/templates/config/initializers/jdbc.rb +10 -0
- data/rails_generators/templates/lib/tasks/jdbc.rake +11 -0
- data/rakelib/01-tomcat.rake +51 -0
- data/rakelib/02-test.rake +151 -0
- data/rakelib/bundler_ext.rb +11 -0
- data/rakelib/db.rake +58 -0
- data/rakelib/rails.rake +77 -0
- data/src/java/arjdbc/ArJdbcModule.java +288 -0
- data/src/java/arjdbc/db2/DB2Module.java +77 -0
- data/src/java/arjdbc/db2/DB2RubyJdbcConnection.java +128 -0
- data/src/java/arjdbc/derby/DerbyModule.java +180 -0
- data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +153 -0
- data/src/java/arjdbc/firebird/FirebirdRubyJdbcConnection.java +190 -0
- data/src/java/arjdbc/h2/H2Module.java +50 -0
- data/src/java/arjdbc/h2/H2RubyJdbcConnection.java +86 -0
- data/src/java/arjdbc/hsqldb/HSQLDBModule.java +74 -0
- data/src/java/arjdbc/informix/InformixRubyJdbcConnection.java +76 -0
- data/src/java/arjdbc/jdbc/AdapterJavaService.java +43 -0
- data/src/java/arjdbc/jdbc/Callable.java +44 -0
- data/src/java/arjdbc/jdbc/ConnectionFactory.java +77 -0
- data/src/java/arjdbc/jdbc/DataSourceConnectionFactory.java +156 -0
- data/src/java/arjdbc/jdbc/DriverConnectionFactory.java +63 -0
- data/src/java/arjdbc/jdbc/DriverWrapper.java +128 -0
- data/src/java/arjdbc/jdbc/JdbcConnectionFactory.java +32 -0
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +4541 -0
- data/src/java/arjdbc/jdbc/SQLBlock.java +54 -0
- data/src/java/arjdbc/jdbc/WithResultSet.java +37 -0
- data/src/java/arjdbc/mssql/MSSQLModule.java +91 -0
- data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +193 -0
- data/src/java/arjdbc/mysql/MySQLModule.java +140 -0
- data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +456 -0
- data/src/java/arjdbc/oracle/OracleModule.java +81 -0
- data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +477 -0
- data/src/java/arjdbc/postgresql/ByteaUtils.java +171 -0
- data/src/java/arjdbc/postgresql/DriverImplementation.java +78 -0
- data/src/java/arjdbc/postgresql/PGDriverImplementation.java +535 -0
- data/src/java/arjdbc/postgresql/PostgreSQLModule.java +189 -0
- data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +489 -0
- data/src/java/arjdbc/sqlite3/SQLite3Module.java +93 -0
- data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +405 -0
- data/src/java/arjdbc/util/CallResultSet.java +826 -0
- data/src/java/arjdbc/util/DateTimeUtils.java +517 -0
- data/src/java/arjdbc/util/NumberUtils.java +50 -0
- data/src/java/arjdbc/util/ObjectSupport.java +65 -0
- data/src/java/arjdbc/util/QuotingUtils.java +139 -0
- data/src/java/arjdbc/util/StringCache.java +60 -0
- data/src/java/arjdbc/util/StringHelper.java +155 -0
- metadata +288 -0
@@ -0,0 +1,456 @@
|
|
1
|
+
/***** BEGIN LICENSE BLOCK *****
|
2
|
+
* Copyright (c) 2012-2013 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.mysql;
|
27
|
+
|
28
|
+
import arjdbc.jdbc.RubyJdbcConnection;
|
29
|
+
import arjdbc.jdbc.Callable;
|
30
|
+
import arjdbc.jdbc.DriverWrapper;
|
31
|
+
import arjdbc.util.DateTimeUtils;
|
32
|
+
|
33
|
+
import java.lang.reflect.Field;
|
34
|
+
import java.lang.reflect.InvocationTargetException;
|
35
|
+
import java.lang.reflect.Proxy;
|
36
|
+
import java.sql.Connection;
|
37
|
+
import java.sql.PreparedStatement;
|
38
|
+
import java.sql.SQLException;
|
39
|
+
import java.sql.ResultSet;
|
40
|
+
import java.sql.Statement;
|
41
|
+
import java.sql.Time;
|
42
|
+
import java.sql.Timestamp;
|
43
|
+
import java.sql.Types;
|
44
|
+
import java.util.regex.Matcher;
|
45
|
+
import java.util.regex.Pattern;
|
46
|
+
|
47
|
+
import org.jruby.Ruby;
|
48
|
+
import org.jruby.RubyArray;
|
49
|
+
import org.jruby.RubyClass;
|
50
|
+
import org.jruby.RubyFixnum;
|
51
|
+
import org.jruby.RubyFloat;
|
52
|
+
import org.jruby.RubyInteger;
|
53
|
+
import org.jruby.RubyModule;
|
54
|
+
import org.jruby.RubyString;
|
55
|
+
import org.jruby.exceptions.RaiseException;
|
56
|
+
import org.jruby.runtime.ObjectAllocator;
|
57
|
+
import org.jruby.runtime.ThreadContext;
|
58
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
59
|
+
import org.jruby.util.SafePropertyAccessor;
|
60
|
+
|
61
|
+
/**
|
62
|
+
*
|
63
|
+
* @author nicksieger
|
64
|
+
*/
|
65
|
+
@org.jruby.anno.JRubyClass(name = "ActiveRecord::ConnectionAdapters::MySQLJdbcConnection")
|
66
|
+
public class MySQLRubyJdbcConnection extends RubyJdbcConnection {
|
67
|
+
private static final long serialVersionUID = -8842614212147138733L;
|
68
|
+
|
69
|
+
public MySQLRubyJdbcConnection(Ruby runtime, RubyClass metaClass) {
|
70
|
+
super(runtime, metaClass);
|
71
|
+
}
|
72
|
+
|
73
|
+
public static RubyClass createMySQLJdbcConnectionClass(Ruby runtime, RubyClass jdbcConnection) {
|
74
|
+
RubyClass clazz = getConnectionAdapters(runtime).
|
75
|
+
defineClassUnder("MySQLJdbcConnection", jdbcConnection, ALLOCATOR);
|
76
|
+
clazz.defineAnnotatedMethods(MySQLRubyJdbcConnection.class);
|
77
|
+
return clazz;
|
78
|
+
}
|
79
|
+
|
80
|
+
public static RubyClass load(final Ruby runtime) {
|
81
|
+
RubyClass jdbcConnection = getJdbcConnection(runtime);
|
82
|
+
return createMySQLJdbcConnectionClass(runtime, jdbcConnection);
|
83
|
+
}
|
84
|
+
|
85
|
+
protected static ObjectAllocator ALLOCATOR = new ObjectAllocator() {
|
86
|
+
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
|
87
|
+
return new MySQLRubyJdbcConnection(runtime, klass);
|
88
|
+
}
|
89
|
+
};
|
90
|
+
|
91
|
+
@Override
|
92
|
+
protected DriverWrapper newDriverWrapper(final ThreadContext context, final String driver) {
|
93
|
+
DriverWrapper driverWrapper = super.newDriverWrapper(context, driver);
|
94
|
+
|
95
|
+
final java.sql.Driver jdbcDriver = driverWrapper.getDriverInstance();
|
96
|
+
if ( jdbcDriver.getClass().getName().startsWith("com.mysql.jdbc.") ) {
|
97
|
+
final int major = jdbcDriver.getMajorVersion();
|
98
|
+
final int minor = jdbcDriver.getMinorVersion();
|
99
|
+
if ( major < 5 ) {
|
100
|
+
final RubyClass errorClass = getConnectionNotEstablished(context.runtime);
|
101
|
+
throw new RaiseException(context.runtime, errorClass,
|
102
|
+
"MySQL adapter requires driver >= 5.0 got: " + major + "." + minor + "", false);
|
103
|
+
}
|
104
|
+
if ( major == 5 && minor < 1 ) { // need 5.1 for JDBC 4.0
|
105
|
+
// lightweight validation query: "/* ping */ SELECT 1"
|
106
|
+
setConfigValueIfNotSet(context, "connection_alive_sql", context.runtime.newString("/* ping */ SELECT 1"));
|
107
|
+
}
|
108
|
+
}
|
109
|
+
|
110
|
+
return driverWrapper;
|
111
|
+
}
|
112
|
+
|
113
|
+
@Override
|
114
|
+
protected boolean doExecute(final Statement statement, final String query)
|
115
|
+
throws SQLException {
|
116
|
+
return statement.execute(query, Statement.RETURN_GENERATED_KEYS);
|
117
|
+
}
|
118
|
+
|
119
|
+
@Override
|
120
|
+
protected IRubyObject mapGeneratedKeysOrUpdateCount(final ThreadContext context,
|
121
|
+
final Connection connection, final Statement statement) throws SQLException {
|
122
|
+
final Ruby runtime = context.runtime;
|
123
|
+
final IRubyObject key = mapGeneratedKeys(runtime, connection, statement);
|
124
|
+
return ( key == null || key.isNil() ) ?
|
125
|
+
RubyFixnum.newFixnum( runtime, statement.getUpdateCount() ) : key;
|
126
|
+
}
|
127
|
+
|
128
|
+
@Override
|
129
|
+
protected IRubyObject jdbcToRuby(
|
130
|
+
final ThreadContext context, final Ruby runtime,
|
131
|
+
final int column, final int type, final ResultSet resultSet)
|
132
|
+
throws SQLException {
|
133
|
+
if ( type == Types.BIT ) {
|
134
|
+
final int value = resultSet.getInt(column);
|
135
|
+
return resultSet.wasNull() ? runtime.getNil() : runtime.newFixnum(value);
|
136
|
+
}
|
137
|
+
return super.jdbcToRuby(context, runtime, column, type, resultSet);
|
138
|
+
}
|
139
|
+
|
140
|
+
@Override
|
141
|
+
protected boolean useByteStrings() {
|
142
|
+
final Boolean useByteStrings = byteStrings; // true by default :
|
143
|
+
return useByteStrings == null ? true : useByteStrings.booleanValue();
|
144
|
+
}
|
145
|
+
|
146
|
+
/*
|
147
|
+
@Override // optimized CLOBs
|
148
|
+
protected IRubyObject readerToRuby(final ThreadContext context,
|
149
|
+
final Ruby runtime, final ResultSet resultSet, final int column)
|
150
|
+
throws SQLException {
|
151
|
+
return bytesToUTF8String(context, runtime, resultSet, column);
|
152
|
+
} */
|
153
|
+
|
154
|
+
@Override // can not use statement.setTimestamp( int, Timestamp, Calendar )
|
155
|
+
protected void setTimestampParameter(final ThreadContext context,
|
156
|
+
final Connection connection, final PreparedStatement statement,
|
157
|
+
final int index, IRubyObject value,
|
158
|
+
final IRubyObject column, final int type) throws SQLException {
|
159
|
+
if ( value.isNil() ) statement.setNull(index, Types.TIMESTAMP);
|
160
|
+
else {
|
161
|
+
value = DateTimeUtils.getTimeInDefaultTimeZone(context, value);
|
162
|
+
if ( value instanceof RubyString ) { // yyyy-[m]m-[d]d hh:mm:ss[.f...]
|
163
|
+
final Timestamp timestamp = Timestamp.valueOf( value.toString() );
|
164
|
+
statement.setTimestamp( index, timestamp ); // assume local time-zone
|
165
|
+
}
|
166
|
+
else { // Time or DateTime ( ActiveSupport::TimeWithZone.to_time )
|
167
|
+
final double time = DateTimeUtils.adjustTimeFromDefaultZone(value);
|
168
|
+
final RubyFloat timeValue = context.runtime.newFloat( time );
|
169
|
+
statement.setTimestamp( index, DateTimeUtils.convertToTimestamp(timeValue) );
|
170
|
+
}
|
171
|
+
}
|
172
|
+
}
|
173
|
+
|
174
|
+
@Override // can not use statement.setTime( int, Time, Calendar )
|
175
|
+
protected void setTimeParameter(final ThreadContext context,
|
176
|
+
final Connection connection, final PreparedStatement statement,
|
177
|
+
final int index, IRubyObject value,
|
178
|
+
final IRubyObject column, final int type) throws SQLException {
|
179
|
+
if ( value.isNil() ) statement.setNull(index, Types.TIME);
|
180
|
+
else {
|
181
|
+
value = DateTimeUtils.getTimeInDefaultTimeZone(context, value);
|
182
|
+
if ( value instanceof RubyString ) {
|
183
|
+
final Time time = Time.valueOf( value.toString() );
|
184
|
+
statement.setTime( index, time ); // assume local time-zone
|
185
|
+
}
|
186
|
+
else { // Time or DateTime ( ActiveSupport::TimeWithZone.to_time )
|
187
|
+
final double timeValue = DateTimeUtils.adjustTimeFromDefaultZone(value);
|
188
|
+
final Time time = new Time(( (long) timeValue ) * 1000); // millis
|
189
|
+
// java.sql.Time is expected to be only up to second precision
|
190
|
+
statement.setTime( index, time );
|
191
|
+
}
|
192
|
+
}
|
193
|
+
}
|
194
|
+
|
195
|
+
@Override
|
196
|
+
protected final boolean isConnectionValid(final ThreadContext context, final Connection connection) {
|
197
|
+
if ( connection == null ) return false;
|
198
|
+
Statement statement = null;
|
199
|
+
try {
|
200
|
+
final RubyString aliveSQL = getAliveSQL(context);
|
201
|
+
final RubyInteger aliveTimeout = getAliveTimeout(context);
|
202
|
+
if ( aliveSQL != null ) {
|
203
|
+
// expect a SELECT/CALL SQL statement
|
204
|
+
statement = createStatement(context, connection);
|
205
|
+
if (aliveTimeout != null) {
|
206
|
+
statement.setQueryTimeout((int) aliveTimeout.getLongValue()); // 0 - no timeout
|
207
|
+
}
|
208
|
+
statement.execute( aliveSQL.toString() );
|
209
|
+
return true; // connection alive
|
210
|
+
}
|
211
|
+
else { // alive_sql nil (or not a statement we can execute)
|
212
|
+
return connection.isValid(aliveTimeout == null ? 0 : (int) aliveTimeout.getLongValue()); // since JDBC 4.0
|
213
|
+
// ... isValid(0) (default) means no timeout applied
|
214
|
+
}
|
215
|
+
}
|
216
|
+
catch (Exception e) {
|
217
|
+
debugMessage(context, "connection considered broken due: " + e.toString());
|
218
|
+
return false;
|
219
|
+
}
|
220
|
+
catch (AbstractMethodError e) { // non-JDBC 4.0 driver
|
221
|
+
warn( context,
|
222
|
+
"WARN: driver does not support checking if connection isValid()" +
|
223
|
+
" please make sure you're using a JDBC 4.0 compilant driver or" +
|
224
|
+
" set `connection_alive_sql: ...` in your database configuration" );
|
225
|
+
debugStackTrace(context, e);
|
226
|
+
throw e;
|
227
|
+
}
|
228
|
+
finally { close(statement); }
|
229
|
+
}
|
230
|
+
|
231
|
+
@Override
|
232
|
+
protected RubyArray indexes(final ThreadContext context,
|
233
|
+
final String tableName, final String name, final String schemaName) {
|
234
|
+
return withConnection(context, new Callable<RubyArray>() {
|
235
|
+
public RubyArray call(final Connection connection) throws SQLException {
|
236
|
+
final Ruby runtime = context.runtime;
|
237
|
+
final RubyModule IndexDefinition = getIndexDefinition(runtime);
|
238
|
+
final String jdbcTableName = caseConvertIdentifierForJdbc(connection, tableName);
|
239
|
+
final String jdbcSchemaName = caseConvertIdentifierForJdbc(connection, schemaName);
|
240
|
+
final RubyString rubyTableName = cachedString(
|
241
|
+
context, caseConvertIdentifierForJdbc(connection, tableName)
|
242
|
+
);
|
243
|
+
|
244
|
+
StringBuilder query = new StringBuilder(60).append("SHOW KEYS FROM ");
|
245
|
+
if ( jdbcSchemaName != null ) query.append(jdbcSchemaName).append('.');
|
246
|
+
query.append(jdbcTableName);
|
247
|
+
query.append(" WHERE key_name != 'PRIMARY'");
|
248
|
+
|
249
|
+
final RubyArray indexes = RubyArray.newArray(runtime, 8);
|
250
|
+
PreparedStatement statement = null;
|
251
|
+
ResultSet keySet = null;
|
252
|
+
|
253
|
+
try {
|
254
|
+
statement = connection.prepareStatement(query.toString());
|
255
|
+
keySet = statement.executeQuery();
|
256
|
+
|
257
|
+
String currentKeyName = null;
|
258
|
+
RubyArray currentColumns = null;
|
259
|
+
RubyArray currentLengths = null;
|
260
|
+
|
261
|
+
while ( keySet.next() ) {
|
262
|
+
final String keyName = caseConvertIdentifierForRails(connection, keySet.getString("key_name"));
|
263
|
+
|
264
|
+
if ( ! keyName.equals(currentKeyName) ) {
|
265
|
+
currentKeyName = keyName;
|
266
|
+
|
267
|
+
final boolean nonUnique = keySet.getBoolean("non_unique");
|
268
|
+
|
269
|
+
IRubyObject[] args = new IRubyObject[] {
|
270
|
+
rubyTableName, // table_name
|
271
|
+
RubyString.newUnicodeString(runtime, keyName), // index_name
|
272
|
+
nonUnique ? runtime.getFalse() : runtime.getTrue(), // unique
|
273
|
+
currentColumns = RubyArray.newArray(runtime, 4), // columns
|
274
|
+
currentLengths = RubyArray.newArray(runtime, 4) // lengths
|
275
|
+
};
|
276
|
+
|
277
|
+
indexes.append( IndexDefinition.callMethod(context, "new", args) ); // IndexDefinition.new
|
278
|
+
}
|
279
|
+
|
280
|
+
if ( currentColumns != null ) {
|
281
|
+
final String columnName = caseConvertIdentifierForRails(connection, keySet.getString("column_name"));
|
282
|
+
final int length = keySet.getInt("sub_part");
|
283
|
+
final boolean nullLength = length == 0 && keySet.wasNull();
|
284
|
+
|
285
|
+
currentColumns.callMethod(context, "<<", cachedString(context, columnName));
|
286
|
+
currentLengths.callMethod(context, "<<", nullLength ? context.nil : RubyFixnum.newFixnum(runtime, length));
|
287
|
+
}
|
288
|
+
}
|
289
|
+
|
290
|
+
return indexes;
|
291
|
+
}
|
292
|
+
finally {
|
293
|
+
close(keySet);
|
294
|
+
close(statement);
|
295
|
+
}
|
296
|
+
}
|
297
|
+
});
|
298
|
+
}
|
299
|
+
|
300
|
+
// MySQL does never storesUpperCaseIdentifiers() :
|
301
|
+
// storesLowerCaseIdentifiers() depends on "lower_case_table_names" server variable
|
302
|
+
|
303
|
+
@Override
|
304
|
+
protected final String caseConvertIdentifierForRails(
|
305
|
+
final Connection connection, final String value) throws SQLException {
|
306
|
+
if ( value == null ) return null;
|
307
|
+
return value;
|
308
|
+
}
|
309
|
+
|
310
|
+
@Override
|
311
|
+
protected final String caseConvertIdentifierForJdbc(
|
312
|
+
final Connection connection, final String value) throws SQLException {
|
313
|
+
if ( value == null ) return null;
|
314
|
+
if ( connection.getMetaData().storesLowerCaseIdentifiers() ) {
|
315
|
+
return value.toLowerCase();
|
316
|
+
}
|
317
|
+
return value;
|
318
|
+
}
|
319
|
+
|
320
|
+
@Override
|
321
|
+
protected Connection newConnection() throws RaiseException, SQLException {
|
322
|
+
final Connection connection = super.newConnection();
|
323
|
+
if ( doStopCleanupThread() ) shutdownCleanupThread();
|
324
|
+
if ( doKillCancelTimer(connection) ) killCancelTimer(connection);
|
325
|
+
return connection;
|
326
|
+
}
|
327
|
+
|
328
|
+
private static Boolean stopCleanupThread;
|
329
|
+
static {
|
330
|
+
final String stopThread = SafePropertyAccessor.getProperty("arjdbc.mysql.stop_cleanup_thread");
|
331
|
+
if ( stopThread != null ) stopCleanupThread = Boolean.parseBoolean(stopThread);
|
332
|
+
}
|
333
|
+
|
334
|
+
private static boolean doStopCleanupThread() throws SQLException {
|
335
|
+
// TODO when refactoring default behavior to "stop" consider not doing so for JNDI
|
336
|
+
return stopCleanupThread != null && stopCleanupThread.booleanValue();
|
337
|
+
}
|
338
|
+
|
339
|
+
private static boolean cleanupThreadShutdown;
|
340
|
+
|
341
|
+
@SuppressWarnings("unchecked")
|
342
|
+
private static void shutdownCleanupThread() {
|
343
|
+
if ( cleanupThreadShutdown ) return;
|
344
|
+
try {
|
345
|
+
Class<?> threadClass = Class.forName("com.mysql.jdbc.AbandonedConnectionCleanupThread");
|
346
|
+
threadClass.getMethod("shutdown").invoke(null);
|
347
|
+
}
|
348
|
+
catch (ClassNotFoundException e) {
|
349
|
+
debugMessage("missing MySQL JDBC cleanup thread: " + e);
|
350
|
+
}
|
351
|
+
catch (NoSuchMethodException e) {
|
352
|
+
debugMessage( e.toString() );
|
353
|
+
}
|
354
|
+
catch (IllegalAccessException e) {
|
355
|
+
debugMessage( e.toString() );
|
356
|
+
}
|
357
|
+
catch (InvocationTargetException e) {
|
358
|
+
debugMessage( e.getTargetException().toString() );
|
359
|
+
}
|
360
|
+
catch (SecurityException e) {
|
361
|
+
debugMessage( e.toString() );
|
362
|
+
}
|
363
|
+
finally { cleanupThreadShutdown = true; }
|
364
|
+
}
|
365
|
+
|
366
|
+
private static Boolean killCancelTimer;
|
367
|
+
static {
|
368
|
+
final String killTimer = SafePropertyAccessor.getProperty("arjdbc.mysql.kill_cancel_timer");
|
369
|
+
if ( killTimer != null ) killCancelTimer = Boolean.parseBoolean(killTimer);
|
370
|
+
}
|
371
|
+
|
372
|
+
private static boolean doKillCancelTimer(final Connection connection) throws SQLException {
|
373
|
+
if ( killCancelTimer == null ) {
|
374
|
+
synchronized (MySQLRubyJdbcConnection.class) {
|
375
|
+
final String version = connection.getMetaData().getDriverVersion();
|
376
|
+
if ( killCancelTimer == null ) {
|
377
|
+
String regex = "mysql\\-connector\\-java-(\\d)\\.(\\d)\\.(\\d+)";
|
378
|
+
Matcher match = Pattern.compile(regex).matcher(version);
|
379
|
+
if ( match.find() ) {
|
380
|
+
final int major = Integer.parseInt( match.group(1) );
|
381
|
+
final int minor = Integer.parseInt( match.group(2) );
|
382
|
+
if ( major < 5 || ( major == 5 && minor <= 1 ) ) {
|
383
|
+
final int patch = Integer.parseInt( match.group(3) );
|
384
|
+
killCancelTimer = patch < 11;
|
385
|
+
}
|
386
|
+
}
|
387
|
+
else {
|
388
|
+
killCancelTimer = Boolean.FALSE;
|
389
|
+
}
|
390
|
+
}
|
391
|
+
}
|
392
|
+
}
|
393
|
+
return killCancelTimer;
|
394
|
+
}
|
395
|
+
|
396
|
+
/**
|
397
|
+
* HACK HACK HACK See http://bugs.mysql.com/bug.php?id=36565
|
398
|
+
* MySQL's statement cancel timer can cause memory leaks, so cancel it
|
399
|
+
* if we loaded MySQL classes from the same class-loader as JRuby
|
400
|
+
*
|
401
|
+
* NOTE: MySQL Connector/J 5.1.11 (2010-01-21) fixed the issue !
|
402
|
+
*/
|
403
|
+
private void killCancelTimer(final Connection connection) {
|
404
|
+
final Ruby runtime = getRuntime();
|
405
|
+
if (connection.getClass().getClassLoader() == runtime.getJRubyClassLoader()) {
|
406
|
+
final Field field = cancelTimerField(runtime);
|
407
|
+
if ( field != null ) {
|
408
|
+
java.util.Timer timer = null;
|
409
|
+
try {
|
410
|
+
Connection unwrap = connection.unwrap(Connection.class);
|
411
|
+
// when failover is used (LoadBalancedMySQLConnection)
|
412
|
+
// we'll end up with a proxy returned not the real thing :
|
413
|
+
if ( Proxy.isProxyClass(unwrap.getClass()) ) return;
|
414
|
+
// connection likely: com.mysql.jdbc.JDBC4Connection
|
415
|
+
// or (for 3.0) super class: com.mysql.jdbc.ConnectionImpl
|
416
|
+
timer = (java.util.Timer) field.get( unwrap );
|
417
|
+
}
|
418
|
+
catch (SQLException e) {
|
419
|
+
debugMessage( e.toString() );
|
420
|
+
}
|
421
|
+
catch (IllegalAccessException e) {
|
422
|
+
debugMessage( e.toString() );
|
423
|
+
}
|
424
|
+
if ( timer != null ) timer.cancel();
|
425
|
+
}
|
426
|
+
}
|
427
|
+
}
|
428
|
+
|
429
|
+
private static Field cancelTimer = null;
|
430
|
+
private static boolean cancelTimerChecked = false;
|
431
|
+
|
432
|
+
private Field cancelTimerField(final Ruby runtime) {
|
433
|
+
if ( cancelTimerChecked ) return cancelTimer;
|
434
|
+
final String name = "com.mysql.jdbc.ConnectionImpl";
|
435
|
+
try {
|
436
|
+
Class<?> klass = runtime.getJavaSupport().loadJavaClass(name);
|
437
|
+
Field field = klass.getDeclaredField("cancelTimer");
|
438
|
+
field.setAccessible(true);
|
439
|
+
synchronized (MySQLRubyJdbcConnection.class) {
|
440
|
+
if ( cancelTimer == null ) cancelTimer = field;
|
441
|
+
}
|
442
|
+
}
|
443
|
+
catch (ClassNotFoundException e) {
|
444
|
+
debugMessage("missing MySQL JDBC connection impl: " + e);
|
445
|
+
}
|
446
|
+
catch (NoSuchFieldException e) {
|
447
|
+
debugMessage("MySQL's cancel timer seems to have changed: " + e);
|
448
|
+
}
|
449
|
+
catch (SecurityException e) {
|
450
|
+
debugMessage( e.toString() );
|
451
|
+
}
|
452
|
+
finally { cancelTimerChecked = true; }
|
453
|
+
return cancelTimer;
|
454
|
+
}
|
455
|
+
|
456
|
+
}
|