Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions lib/arjdbc/sqlite3/adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,24 @@ def foreign_keys(table_name)
end
end

# Returns a list of defined virtual tables (for Rails 8 compatibility)
VIRTUAL_TABLE_REGEX = /USING\s+(\w+)(?:\s*\((.*)\))?/im
def virtual_tables
query = <<~SQL
SELECT name, sql FROM sqlite_master
WHERE type = 'table' AND sql LIKE 'CREATE VIRTUAL TABLE%';
SQL

exec_query(query, "SCHEMA").cast_values.each_with_object({}) do |(name, sql), memo|
match = sql.match(VIRTUAL_TABLE_REGEX)
next unless match

module_name = match[1]
arguments = match[2] || ""
memo[name] = [module_name, arguments.strip]
end.to_a
end

def build_insert_sql(insert) # :nodoc:
sql = +"INSERT #{insert.into} #{insert.values_list}"

Expand Down
48 changes: 48 additions & 0 deletions src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,54 @@ public IRubyObject readonly_p(final ThreadContext context) throws SQLException {
// note: sqlite3 cext uses this same method but we do not combine all our statements
// into a single ; delimited string but leave it as an array of statements. This is
// because the JDBC way of handling batches is to use addBatch().
// Override execute to ensure Rails 8 compatibility
// Rails 8 SQLite3 adapter expects execute to always return something that responds to to_a
@Override
@JRubyMethod(name = "execute", required = 1)
public IRubyObject execute(final ThreadContext context, final IRubyObject sql) {
final String query = sqlString(sql);
return withConnection(context, connection -> {
Statement statement = null;
try {
statement = createStatement(context, connection);

// SQLite3 can support multiple statements in one query
// Process all results but return the last one for Rails compatibility
boolean hasResultSet = doExecute(statement, query);
int updateCount = statement.getUpdateCount();

IRubyObject result = newEmptyResult(context); // Default to empty result
Comment thread
enebo marked this conversation as resolved.
ResultSet resultSet;

while (hasResultSet || updateCount != -1) {

if (hasResultSet) {
resultSet = statement.getResultSet();
// For SELECT queries, return propr Result object
result = mapQueryResult(context, connection, resultSet);
resultSet.close();
} else {
// For INSERT/UPDATE/DELETE, return empty Result
// Rails 8 SQLite3 adapter will convert this to [] via to_a
result = newEmptyResult(context);
}

// Check to see if there is another result set
hasResultSet = statement.getMoreResults();
updateCount = statement.getUpdateCount();
}

return result;

} catch (final SQLException e) {
debugErrorSQL(context, query);
throw e;
} finally {
close(statement);
}
});
}

@JRubyMethod(name = "execute_batch2")
public IRubyObject execute_batch2(ThreadContext context, IRubyObject statementsArg) {
// Assume we will only call this with an array.
Expand Down
Loading