Skip to content

Commit c68df3f

Browse files
committed
[core] better support for generated keys
JDBC offers an API to specify what keys to return. Rails knows the keys. Use that API directly to avoid loading too much data. E.g. pgjdbc appends "RETURNING *" to an insert query, effectively return _all_ columns. Since the jdbc driver does that, nobody ever noticed that the PG adapter is missing the code that appends the `RETURNING <pk>`
1 parent bc55874 commit c68df3f

File tree

3 files changed

+38
-9
lines changed

3 files changed

+38
-9
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
*.tgz
33
*~
44
*.log
5+
/log/
56
patches*
67
*#
78
TAGS
@@ -30,4 +31,4 @@ Gemfile.lock
3031
.idea
3132
.settings
3233
activerecord-jdbc.iml
33-
lib/arjdbc/jdbc/adapter_java.jar
34+
lib/arjdbc/jdbc/adapter_java.jar

lib/arjdbc/abstract/database_statements.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ def exec_insert(sql, name = nil, binds = NO_BINDS, pk = nil, sequence_name = nil
1313
binds = convert_legacy_binds_to_attributes(binds) if binds.first.is_a?(Array)
1414

1515
if without_prepared_statement?(binds)
16-
log(sql, name) { @connection.execute_insert(sql) }
16+
log(sql, name) { @connection.execute_insert(sql, pk) }
1717
else
1818
log(sql, name, binds) do
19-
@connection.execute_insert(sql, binds)
19+
@connection.execute_insert(sql, binds, pk)
2020
end
2121
end
2222
end

src/java/arjdbc/jdbc/RubyJdbcConnection.java

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -888,23 +888,45 @@ protected IRubyObject mapExecuteResult(final ThreadContext context,
888888
return mapQueryResult(context, connection, resultSet);
889889
}
890890

891+
private static String[] createStatementPk(IRubyObject pk) {
892+
String[] statementPk;
893+
if (pk instanceof RubyArray) {
894+
RubyArray ary = (RubyArray) pk;
895+
int size = ary.size();
896+
statementPk = new String[size];
897+
for (int i = 0; i < size; i++) {
898+
statementPk[i] = sqlString(ary.eltInternal(i));
899+
}
900+
} else {
901+
statementPk = new String[] { sqlString(pk) };
902+
}
903+
return statementPk;
904+
}
905+
891906
/**
892907
* Executes an INSERT SQL statement
893908
* @param context
894909
* @param sql
910+
* @param pk Rails PK
895911
* @return ActiveRecord::Result
896912
* @throws SQLException
897913
*/
898-
@JRubyMethod(name = "execute_insert", required = 1)
899-
public IRubyObject execute_insert(final ThreadContext context, final IRubyObject sql) {
914+
@JRubyMethod(name = "execute_insert", required = 2)
915+
public IRubyObject execute_insert(final ThreadContext context, final IRubyObject sql, final IRubyObject pk) {
900916
return withConnection(context, new Callable<IRubyObject>() {
901917
public IRubyObject call(final Connection connection) throws SQLException {
902918
Statement statement = null;
903919
final String query = sqlString(sql);
904920
try {
905921

906922
statement = createStatement(context, connection);
907-
statement.executeUpdate(query, Statement.RETURN_GENERATED_KEYS);
923+
924+
if (pk == context.nil || pk == context.fals || !supportsGeneratedKeys(connection)) {
925+
statement.executeUpdate(query, Statement.RETURN_GENERATED_KEYS);
926+
} else {
927+
statement.executeUpdate(query, createStatementPk(pk));
928+
}
929+
908930
return mapGeneratedKeys(context, connection, statement);
909931

910932
} catch (final SQLException e) {
@@ -922,18 +944,24 @@ public IRubyObject call(final Connection connection) throws SQLException {
922944
* @param context
923945
* @param sql
924946
* @param binds RubyArray of values to be bound to the query
947+
* @param pk Rails PK
925948
* @return ActiveRecord::Result
926949
* @throws SQLException
927950
*/
928-
@JRubyMethod(name = "execute_insert", required = 2)
929-
public IRubyObject execute_insert(final ThreadContext context, final IRubyObject sql, final IRubyObject binds) {
951+
@JRubyMethod(name = "execute_insert", required = 3)
952+
public IRubyObject execute_insert(final ThreadContext context, final IRubyObject sql, final IRubyObject binds,
953+
final IRubyObject pk) {
930954
return withConnection(context, new Callable<IRubyObject>() {
931955
public IRubyObject call(final Connection connection) throws SQLException {
932956
PreparedStatement statement = null;
933957
final String query = sqlString(sql);
934958
try {
959+
if (pk == context.nil || pk == context.fals || !supportsGeneratedKeys(connection)) {
960+
statement = connection.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
961+
} else {
962+
statement = connection.prepareStatement(query, createStatementPk(pk));
963+
}
935964

936-
statement = connection.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
937965
setStatementParameters(context, connection, statement, (RubyArray) binds);
938966
statement.executeUpdate();
939967
return mapGeneratedKeys(context, connection, statement);

0 commit comments

Comments
 (0)