Skip to content

Commit

Permalink
Upgrade MySQL execute code to use RETURN_GENERATED_KEYS.
Browse files Browse the repository at this point in the history
This seems to work fine with 5.0.4 and should allow usage of 5.1.x.
  • Loading branch information
nicksieger committed Dec 6, 2010
1 parent 3f38691 commit a357d85
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 12 deletions.
17 changes: 17 additions & 0 deletions lib/arjdbc/mysql/adapter.rb
Expand Up @@ -14,6 +14,10 @@ def configure_connection
execute("SET SQL_AUTO_IS_NULL=0")
end

def self.jdbc_connection_class
::ActiveRecord::ConnectionAdapters::MySQLJdbcConnection
end

module Column
def extract_default(default)
if sql_type =~ /blob/i || type == :text
Expand Down Expand Up @@ -193,6 +197,13 @@ def structure_dump #:nodoc:
end
end

def jdbc_columns(table_name, name = nil)#:nodoc:
sql = "SHOW FIELDS FROM #{quote_table_name(table_name)}"
execute(sql, :skip_logging).map do |field|
::ActiveRecord::ConnectionAdapters::MysqlColumn.new(field["Field"], field["Default"], field["Type"], field["Null"] == "YES")
end
end

def recreate_database(name, options = {}) #:nodoc:
drop_database(name)
create_database(name, options)
Expand Down Expand Up @@ -389,9 +400,15 @@ def adapter_spec(config)
# return nil to avoid extending ArJdbc::MySQL, which we've already done
end

def jdbc_connection_class(spec)
::ArJdbc::MySQL.jdbc_connection_class
end

def jdbc_column_class
ActiveRecord::ConnectionAdapters::MysqlColumn
end

alias_chained_method :columns, :query_cache, :jdbc_columns
end
end

Expand Down
3 changes: 2 additions & 1 deletion src/java/arjdbc/jdbc/AdapterJavaService.java
Expand Up @@ -33,6 +33,7 @@
import arjdbc.informix.InformixRubyJdbcConnection;
import arjdbc.mssql.MssqlRubyJdbcConnection;
import arjdbc.mysql.MySQLModule;
import arjdbc.mysql.MySQLRubyJdbcConnection;
import arjdbc.oracle.OracleRubyJdbcConnection;
import arjdbc.postgresql.PostgresqlRubyJdbcConnection;
import arjdbc.sqlite3.Sqlite3RubyJdbcConnection;
Expand All @@ -55,8 +56,8 @@ public boolean basicLoad(final Ruby runtime) throws IOException {
OracleRubyJdbcConnection.createOracleJdbcConnectionClass(runtime, jdbcConnection);
Sqlite3RubyJdbcConnection.createSqlite3JdbcConnectionClass(runtime, jdbcConnection);
H2RubyJdbcConnection.createH2JdbcConnectionClass(runtime, jdbcConnection);
MySQLRubyJdbcConnection.createMySQLJdbcConnectionClass(runtime, jdbcConnection);
RubyModule arJdbc = runtime.getOrCreateModule("ArJdbc");

rubyApi = JavaEmbedUtils.newObjectAdapter();
MySQLModule.load(arJdbc);
DerbyModule.load(arJdbc, rubyApi);
Expand Down
28 changes: 18 additions & 10 deletions src/java/arjdbc/jdbc/RubyJdbcConnection.java
Expand Up @@ -217,18 +217,10 @@ public Object call(Connection c) throws SQLException {
String query = rubyApi.convertToRubyString(sql).getUnicodeValue();
try {
stmt = c.createStatement();
if (stmt.execute(query)) {
if (genericExecute(stmt, query)) {
return unmarshalResults(context, c.getMetaData(), stmt, false);
} else {
IRubyObject key = context.getRuntime().getNil();
if (c.getMetaData().supportsGetGeneratedKeys()) {
key = unmarshal_id_result(context.getRuntime(), stmt.getGeneratedKeys());
}
if (key.isNil()) {
return context.getRuntime().newFixnum(stmt.getUpdateCount());
} else {
return key;
}
return unmarshalKeysOrUpdateCount(context, c, stmt);
}
} catch (SQLException sqe) {
if (context.getRuntime().isDebug()) {
Expand All @@ -242,6 +234,22 @@ public Object call(Connection c) throws SQLException {
});
}

protected boolean genericExecute(Statement stmt, String query) throws SQLException {
return stmt.execute(query);
}

protected IRubyObject unmarshalKeysOrUpdateCount(ThreadContext context, Connection c, Statement stmt) throws SQLException {
IRubyObject key = context.getRuntime().getNil();
if (c.getMetaData().supportsGetGeneratedKeys()) {
key = unmarshal_id_result(context.getRuntime(), stmt.getGeneratedKeys());
}
if (key.isNil()) {
return context.getRuntime().newFixnum(stmt.getUpdateCount());
} else {
return key;
}
}

@JRubyMethod(name = "execute_id_insert", required = 2)
public IRubyObject execute_id_insert(final ThreadContext context, final IRubyObject sql,
final IRubyObject id) throws SQLException {
Expand Down
74 changes: 74 additions & 0 deletions src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java
@@ -0,0 +1,74 @@
/*
**** BEGIN LICENSE BLOCK *****
* Copyright (c) 2006-2010 Nick Sieger <nick@nicksieger.com>
* Copyright (c) 2006-2007 Ola Bini <ola.bini@gmail.com>
* Copyright (c) 2008-2009 Thomas E Enebo <enebo@acm.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
***** END LICENSE BLOCK *****/
package arjdbc.mysql;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;

import org.jruby.Ruby;
import org.jruby.RubyClass;
import org.jruby.runtime.ObjectAllocator;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;

import arjdbc.jdbc.RubyJdbcConnection;

/**
*
* @author nicksieger
*/
public class MySQLRubyJdbcConnection extends RubyJdbcConnection {
protected MySQLRubyJdbcConnection(Ruby runtime, RubyClass metaClass) {
super(runtime, metaClass);
}

protected boolean genericExecute(Statement stmt, String query) throws SQLException {
return stmt.execute(query, Statement.RETURN_GENERATED_KEYS);
}

protected IRubyObject unmarshalKeysOrUpdateCount(ThreadContext context, Connection c, Statement stmt) throws SQLException {
IRubyObject key = unmarshal_id_result(context.getRuntime(), stmt.getGeneratedKeys());
if (key.isNil()) {
return context.getRuntime().newFixnum(stmt.getUpdateCount());
}
return key;
}

public static RubyClass createMySQLJdbcConnectionClass(Ruby runtime, RubyClass jdbcConnection) {
RubyClass clazz = RubyJdbcConnection.getConnectionAdapters(runtime).defineClassUnder("MySQLJdbcConnection",
jdbcConnection, MYSQL_JDBCCONNECTION_ALLOCATOR);
clazz.defineAnnotatedMethods(MySQLRubyJdbcConnection.class);

return clazz;
}

private static ObjectAllocator MYSQL_JDBCCONNECTION_ALLOCATOR = new ObjectAllocator() {
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
return new MySQLRubyJdbcConnection(runtime, klass);
}
};
}
2 changes: 1 addition & 1 deletion test/mysql_info_test.rb
Expand Up @@ -96,7 +96,7 @@ def test_should_include_limit

def test_should_set_sqltype_to_longtext
text_column = @connection.columns('memos').find { |c| c.name == 'text' }
assert text_column.sql_type =~ /^longtext/
assert text_column.sql_type =~ /^longtext/i
end

def test_should_set_type_to_text
Expand Down

0 comments on commit a357d85

Please sign in to comment.