Skip to content

Commit

Permalink
Fix MySQL prepared statements
Browse files Browse the repository at this point in the history
  • Loading branch information
kddnewton committed Jan 30, 2017
1 parent 389d9ee commit 7e15007
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 24 deletions.
2 changes: 1 addition & 1 deletion lib/active_record/connection_adapters/odbc_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ def initialize_type_map(map)
map.register_type ODBC::SQL_TIMESTAMP, Type::DateTime.new
map.register_type ODBC::SQL_GUID, Type::String.new

alias_type map, ODBC::SQL_BIT, ODBC::SQL_BIT
alias_type map, ODBC::SQL_BIT, 'boolean'
alias_type map, ODBC::SQL_VARCHAR, ODBC::SQL_CHAR
alias_type map, ODBC::SQL_WCHAR, ODBC::SQL_CHAR
alias_type map, ODBC::SQL_WVARCHAR, ODBC::SQL_CHAR
Expand Down
16 changes: 15 additions & 1 deletion lib/odbc_adapter/adapters/mysql_odbc_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,22 @@ module Adapters
class MySQLODBCAdapter < ActiveRecord::ConnectionAdapters::ODBCAdapter
PRIMARY_KEY = 'INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY'.freeze

class BindSubstitution < Arel::Visitors::MySQL
include Arel::Visitors::BindVisitor
end

def arel_visitor
Arel::Visitors::MySQL.new(self)
BindSubstitution.new(self)
end

# Explicitly turning off prepared statements in the MySQL adapter because
# of a weird bug with SQLDescribeParam returning a string type for LIMIT
# parameters. This is blocking them from running with an error:
#
# You have an error in your SQL syntax; ...
# ... right syntax to use near ''1'' at line 1: ...
def prepared_statements
false
end

def truncate(table_name, name = nil)
Expand Down
2 changes: 1 addition & 1 deletion lib/odbc_adapter/column.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module ODBCAdapter
class Column < ActiveRecord::ConnectionAdapters::Column
attr_reader :native_type

def initialize(name, default, sql_type_metadata = nil, null = true, table_name = nil, default_function = nil, collation = nil, native_type = nil)
def initialize(name, default, sql_type_metadata = nil, null = true, table_name = nil, native_type = nil, default_function = nil, collation = nil)
super(name, default, sql_type_metadata, null, table_name, default_function, collation)
@native_type = native_type
end
Expand Down
32 changes: 15 additions & 17 deletions lib/odbc_adapter/database_statements.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,15 @@ module DatabaseStatements
SQL_NULLABLE = 1
SQL_NULLABLE_UNKNOWN = 2

# Returns an array of arrays containing the field values.
# Order is the same as that returned by #columns.
def select_rows(sql, name = nil)
log(sql, name) do
stmt = @connection.run(sql)
result = stmt.fetch_all
stmt.drop
result
end
end

# Executes the SQL statement in the context of this connection.
# Returns the number of rows affected.
def execute(sql, name = nil, binds = [])
log(sql, name) do
prepared_binds =
prepare_binds_for_database(binds).map { |bind| _type_cast(bind) }
@connection.do(sql, *prepared_binds)
if prepared_statements
@connection.do(sql, *prepared_binds(binds))
else
@connection.do(sql)
end
end
end

Expand All @@ -31,10 +22,13 @@ def execute(sql, name = nil, binds = [])
# the executed +sql+ statement.
def exec_query(sql, name = 'SQL', binds = [], prepare: false)
log(sql, name) do
prepared_binds =
prepare_binds_for_database(binds).map { |bind| _type_cast(bind) }
stmt =
if prepared_statements
@connection.run(sql, *prepared_binds(binds))
else
@connection.run(sql)
end

stmt = @connection.run(sql, *prepared_binds)
columns = stmt.columns
values = stmt.to_a
stmt.drop
Expand Down Expand Up @@ -138,5 +132,9 @@ def nullability(col_name, is_nullable, nullable)
# So force nullability of 'id' columns
col_name == 'id' ? false : result
end

def prepared_binds(binds)
prepare_binds_for_database(binds).map { |bind| _type_cast(bind) }
end
end
end
4 changes: 2 additions & 2 deletions lib/odbc_adapter/schema_statements.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def columns(table_name, name = nil)
# SQLColumns: IS_NULLABLE, SQLColumns: NULLABLE
col_nullable = nullability(col_name, col[17], col[10])

args = { sql_type: col_native_type, type: col_sql_type, limit: col_limit }
args = { sql_type: col_sql_type, type: col_sql_type, limit: col_limit }
args[:sql_type] = 'boolean' if col_native_type == self.class::BOOLEAN_TYPE

if [ODBC::SQL_DECIMAL, ODBC::SQL_NUMERIC].include?(col_sql_type)
Expand All @@ -83,7 +83,7 @@ def columns(table_name, name = nil)
end
sql_type_metadata = ActiveRecord::ConnectionAdapters::SqlTypeMetadata.new(**args)

cols << new_column(format_case(col_name), col_default, sql_type_metadata, col_nullable, table_name)
cols << new_column(format_case(col_name), col_default, sql_type_metadata, col_nullable, table_name, col_native_type)
end
end

Expand Down
4 changes: 2 additions & 2 deletions test/metadata_test.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
require 'test_helper'

class MetadataTest < Minitest::Test
def test_tables
assert_equal %w[ar_internal_metadata todos users], User.connection.tables.sort
def test_data_sources
assert_equal %w[ar_internal_metadata todos users], User.connection.data_sources.sort
end

def test_column_names
Expand Down

0 comments on commit 7e15007

Please # to comment.