activerecord-jdbc-adapter 1.3.0.beta1 → 1.3.0.beta2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +12 -11
- data/.travis.yml +36 -7
- data/Appraisals +3 -3
- data/Gemfile +1 -1
- data/Gemfile.lock +13 -6
- data/History.txt +64 -0
- data/README.md +8 -1
- data/Rakefile +3 -1
- data/gemfiles/rails23.gemfile +1 -1
- data/gemfiles/rails23.gemfile.lock +6 -5
- data/gemfiles/rails30.gemfile +1 -1
- data/gemfiles/rails30.gemfile.lock +7 -6
- data/gemfiles/rails31.gemfile +1 -1
- data/gemfiles/rails31.gemfile.lock +6 -5
- data/gemfiles/rails32.gemfile +1 -1
- data/gemfiles/rails32.gemfile.lock +6 -5
- data/gemfiles/rails40.gemfile +2 -4
- data/gemfiles/rails40.gemfile.lock +37 -51
- data/lib/active_record/connection_adapters/as400_adapter.rb +2 -0
- data/lib/active_record/connection_adapters/db2_adapter.rb +1 -1
- data/lib/arel/visitors/db2.rb +5 -1
- data/lib/arel/visitors/hsqldb.rb +1 -0
- data/lib/arel/visitors/sql_server.rb +55 -13
- data/lib/arjdbc/db2/adapter.rb +197 -227
- data/lib/arjdbc/db2/as400.rb +124 -0
- data/lib/arjdbc/db2/connection_methods.rb +20 -1
- data/lib/arjdbc/derby/adapter.rb +17 -85
- data/lib/arjdbc/derby/connection_methods.rb +2 -1
- data/lib/arjdbc/discover.rb +55 -47
- data/lib/arjdbc/h2/adapter.rb +52 -18
- data/lib/arjdbc/h2/connection_methods.rb +10 -2
- data/lib/arjdbc/hsqldb/adapter.rb +33 -9
- data/lib/arjdbc/hsqldb/connection_methods.rb +10 -2
- data/lib/arjdbc/informix.rb +2 -1
- data/lib/arjdbc/jdbc.rb +5 -1
- data/lib/arjdbc/jdbc/adapter.rb +167 -89
- data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
- data/lib/arjdbc/jdbc/adapter_require.rb +46 -0
- data/lib/arjdbc/jdbc/base_ext.rb +25 -3
- data/lib/arjdbc/jdbc/callbacks.rb +9 -8
- data/lib/arjdbc/jdbc/column.rb +8 -20
- data/lib/arjdbc/jdbc/connection.rb +69 -80
- data/lib/arjdbc/jdbc/extension.rb +6 -8
- data/lib/arjdbc/jdbc/jdbc.rake +3 -141
- data/lib/arjdbc/jdbc/rake_tasks.rb +3 -10
- data/lib/arjdbc/mssql/adapter.rb +108 -34
- data/lib/arjdbc/mssql/connection_methods.rb +3 -1
- data/lib/arjdbc/mssql/limit_helpers.rb +3 -2
- data/lib/arjdbc/mssql/lock_helpers.rb +5 -1
- data/lib/arjdbc/mysql/adapter.rb +127 -70
- data/lib/arjdbc/mysql/connection_methods.rb +5 -2
- data/lib/arjdbc/oracle/adapter.rb +124 -94
- data/lib/arjdbc/oracle/connection_methods.rb +2 -1
- data/lib/arjdbc/postgresql/adapter.rb +99 -67
- data/lib/arjdbc/postgresql/column_cast.rb +3 -5
- data/lib/arjdbc/postgresql/connection_methods.rb +6 -6
- data/lib/arjdbc/railtie.rb +3 -1
- data/lib/arjdbc/sqlite3/adapter.rb +60 -43
- data/lib/arjdbc/sqlite3/connection_methods.rb +9 -9
- data/lib/arjdbc/sybase.rb +1 -1
- data/lib/arjdbc/tasks.rb +13 -0
- data/lib/arjdbc/tasks/database_tasks.rb +50 -0
- data/lib/arjdbc/tasks/databases.rake +89 -0
- data/lib/arjdbc/tasks/databases3.rake +203 -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 +29 -0
- data/lib/arjdbc/tasks/hsqldb_database_tasks.rb +70 -0
- data/lib/arjdbc/tasks/jdbc_database_tasks.rb +122 -0
- data/lib/arjdbc/tasks/mssql_database_tasks.rb +36 -0
- data/lib/arjdbc/tasks/oracle/enhanced_structure_dump.rb +297 -0
- data/lib/arjdbc/tasks/oracle_database_tasks.rb +62 -0
- data/lib/arjdbc/version.rb +1 -1
- data/pom.xml +11 -12
- data/rails_generators/jdbc_generator.rb +1 -1
- data/rails_generators/templates/config/initializers/jdbc.rb +8 -5
- data/rails_generators/templates/lib/tasks/jdbc.rake +7 -4
- data/rakelib/02-test.rake +42 -15
- data/rakelib/compile.rake +29 -2
- data/rakelib/db.rake +2 -1
- data/rakelib/rails.rake +23 -6
- data/src/java/arjdbc/ArJdbcModule.java +175 -0
- data/src/java/arjdbc/db2/DB2Module.java +2 -1
- data/src/java/arjdbc/derby/DerbyModule.java +5 -24
- data/src/java/arjdbc/hsqldb/HSQLDBModule.java +3 -2
- data/src/java/arjdbc/jdbc/AdapterJavaService.java +3 -46
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +1001 -259
- data/src/java/arjdbc/mssql/MSSQLModule.java +2 -1
- data/src/java/arjdbc/mysql/MySQLModule.java +4 -3
- data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +12 -7
- data/src/java/arjdbc/oracle/OracleModule.java +2 -1
- data/src/java/arjdbc/sqlite3/SQLite3Module.java +2 -1
- data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +12 -0
- data/test/db/db2.rb +14 -7
- data/test/db/db2/rake_test.rb +82 -0
- data/test/db/db2/rake_test_data.sql +35 -0
- data/test/db/db2/simple_test.rb +20 -0
- data/test/db/db2/unit_test.rb +3 -1
- data/test/db/derby.rb +7 -5
- data/test/db/derby/rake_test.rb +96 -0
- data/test/db/derby/simple_test.rb +10 -2
- data/test/db/h2.rb +6 -8
- data/test/db/h2/identity_column_test.rb +35 -0
- data/test/db/h2/offset_test.rb +49 -0
- data/test/db/h2/rake_test.rb +98 -0
- data/test/db/h2/schema_dump_test.rb +5 -1
- data/test/db/hsqldb.rb +6 -10
- data/test/db/hsqldb/rake_test.rb +101 -0
- data/test/db/hsqldb/schema_dump_test.rb +5 -1
- data/test/db/hsqldb/simple_test.rb +8 -0
- data/test/db/jndi_config.rb +1 -3
- data/test/db/jndi_pooled_config.rb +1 -3
- data/test/db/mssql/limit_offset_test.rb +23 -14
- data/test/db/mssql/rake_test.rb +143 -0
- data/test/db/mysql/_rails_test_mysql.32.out +1069 -1252
- data/test/db/mysql/nonstandard_primary_key_test.rb +21 -24
- data/test/db/mysql/rake_test.rb +97 -0
- data/test/db/mysql/schema_dump_test.rb +11 -11
- data/test/db/mysql/simple_test.rb +52 -3
- data/test/db/mysql/statement_escaping_test.rb +46 -0
- data/test/db/oracle/rake_test.rb +100 -0
- data/test/db/oracle/simple_test.rb +48 -0
- data/test/db/postgres/_rails_test_postgres.32.out +998 -1370
- data/test/db/postgres/active_schema_unit_test.rb +68 -0
- data/test/db/postgres/connection_test.rb +10 -2
- data/test/db/postgres/data_types_test.rb +2 -2
- data/test/db/postgres/ltree_test.rb +6 -5
- data/test/db/postgres/native_types_test.rb +1 -5
- data/test/db/postgres/rake_test.rb +117 -0
- data/test/db/postgres/schema_dump_test.rb +9 -2
- data/test/db/postgres/schema_test.rb +4 -2
- data/test/db/postgres/simple_test.rb +57 -16
- data/test/db/sqlite3.rb +3 -10
- data/test/db/sqlite3/_rails_test_sqlite3.32.out +1070 -1298
- data/test/db/sqlite3/rake_test.rb +71 -0
- data/test/db/sqlite3/simple_test.rb +9 -9
- data/test/has_many_through.rb +4 -1
- data/test/jdbc/db2.rb +14 -1
- data/test/jdbc_column_test.rb +23 -0
- data/test/{generic_jdbc_connection_test.rb → jdbc_connection_test.rb} +22 -17
- data/test/jndi_callbacks_test.rb +26 -28
- data/test/jndi_test.rb +7 -16
- data/test/models/data_types.rb +2 -1
- data/test/models/thing.rb +1 -0
- data/test/rails/mysql.rb +13 -0
- data/test/rails/sqlite3/version.rb +6 -0
- data/test/rails_stub.rb +31 -0
- data/test/rake_test_support.rb +298 -0
- data/test/serialize.rb +2 -4
- data/test/{helper.rb → shared_helper.rb} +0 -0
- data/test/simple.rb +167 -93
- data/test/test_helper.rb +52 -16
- metadata +388 -354
- data/lib/pg.rb +0 -26
- data/test/abstract_db_create.rb +0 -139
- data/test/activerecord/connection_adapters/type_conversion_test.rb +0 -36
- data/test/db/mssql/db_create_test.rb +0 -29
- data/test/db/mysql/db_create_test.rb +0 -33
- data/test/db/postgres/db_create_test.rb +0 -44
- data/test/db/postgres/db_drop_test.rb +0 -17
@@ -1,10 +1,3 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
# rails tasks already defined; load the override tasks now
|
5
|
-
load jdbc_rakefile
|
6
|
-
else
|
7
|
-
# rails tasks not loaded yet; load as an import
|
8
|
-
Rake.application.add_import(jdbc_rakefile)
|
9
|
-
end
|
10
|
-
end
|
1
|
+
# @deprecated
|
2
|
+
warn "[DEPRECATED] load 'arjdbc/tasks.rb' instead of 'arjdbc/jdbc/rake_tasks.rb'"
|
3
|
+
load 'arjdbc/tasks.rb'
|
data/lib/arjdbc/mssql/adapter.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
|
+
ArJdbc.load_java_part :MSSQL
|
2
|
+
|
1
3
|
require 'strscan'
|
2
4
|
require 'arjdbc/mssql/utils'
|
3
5
|
require 'arjdbc/mssql/tsql_methods'
|
4
6
|
require 'arjdbc/mssql/limit_helpers'
|
5
7
|
require 'arjdbc/mssql/lock_helpers'
|
6
8
|
require 'arjdbc/mssql/explain_support'
|
7
|
-
require 'arjdbc/jdbc/serialized_attributes_helper'
|
8
9
|
|
9
10
|
module ArJdbc
|
10
11
|
module MSSQL
|
@@ -12,39 +13,41 @@ module ArJdbc
|
|
12
13
|
include TSqlMethods
|
13
14
|
|
14
15
|
include ExplainSupport
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
def self.extended(base)
|
19
|
-
unless @@_lob_callback_added
|
20
|
-
ActiveRecord::Base.class_eval do
|
21
|
-
def after_save_with_mssql_lob
|
22
|
-
self.class.columns.select { |c| c.sql_type =~ /image/i }.each do |column|
|
23
|
-
value = ::ArJdbc::SerializedAttributesHelper.dump_column_value(self, column)
|
24
|
-
next if value.nil? || (value == '')
|
25
|
-
|
26
|
-
connection.write_large_object(
|
27
|
-
column.type == :binary, column.name,
|
28
|
-
self.class.table_name, self.class.primary_key,
|
29
|
-
quote_value(id), value
|
30
|
-
)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
ActiveRecord::Base.after_save :after_save_with_mssql_lob
|
36
|
-
@@_lob_callback_added = true
|
37
|
-
end
|
16
|
+
|
17
|
+
def self.extended(adapter) # :nodoc:
|
18
|
+
initialize!
|
38
19
|
|
39
|
-
if ( version =
|
20
|
+
if ( version = adapter.sqlserver_version ) == '2000'
|
40
21
|
extend LimitHelpers::SqlServer2000AddLimitOffset
|
41
22
|
else
|
42
23
|
extend LimitHelpers::SqlServerAddLimitOffset
|
43
24
|
end
|
44
|
-
|
45
|
-
base.configure_connection
|
25
|
+
adapter.config[:sqlserver_version] ||= version
|
46
26
|
end
|
47
27
|
|
28
|
+
@@_initialized = nil
|
29
|
+
|
30
|
+
def self.initialize!
|
31
|
+
return if @@_initialized; @@_initialized = true
|
32
|
+
|
33
|
+
require 'arjdbc/jdbc/serialized_attributes_helper'
|
34
|
+
ActiveRecord::Base.class_eval do
|
35
|
+
def after_save_with_mssql_lob
|
36
|
+
self.class.columns.select { |c| c.sql_type =~ /image/i }.each do |column|
|
37
|
+
value = ::ArJdbc::SerializedAttributesHelper.dump_column_value(self, column)
|
38
|
+
next if value.nil? || (value == '')
|
39
|
+
|
40
|
+
self.class.connection.write_large_object(
|
41
|
+
column.type == :binary, column.name,
|
42
|
+
self.class.table_name, self.class.primary_key,
|
43
|
+
self.class.connection.quote(id), value
|
44
|
+
)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
ActiveRecord::Base.after_save :after_save_with_mssql_lob
|
49
|
+
end
|
50
|
+
|
48
51
|
def configure_connection
|
49
52
|
use_database # config[:database]
|
50
53
|
end
|
@@ -72,7 +75,7 @@ module ArJdbc
|
|
72
75
|
@sqlserver_version ||= begin
|
73
76
|
config_version = config[:sqlserver_version]
|
74
77
|
config_version ? config_version.to_s :
|
75
|
-
select_value("SELECT @@version")[/Microsoft SQL Server\s
|
78
|
+
select_value("SELECT @@version")[/(Microsoft SQL Server\s+|Microsoft SQL Azure.+\n.+)(\d{4})/, 2]
|
76
79
|
end
|
77
80
|
end
|
78
81
|
|
@@ -310,13 +313,17 @@ module ArJdbc
|
|
310
313
|
quote_column_name(name)
|
311
314
|
end
|
312
315
|
|
316
|
+
# def quote_table_name_for_assignment(table, attr)
|
317
|
+
# quote_column_name(attr)
|
318
|
+
# end if ::ActiveRecord::VERSION::MAJOR > 3
|
319
|
+
|
313
320
|
def quote_column_name(name)
|
314
321
|
name.to_s.split('.').map do |n| # "[#{name}]"
|
315
322
|
n =~ /^\[.*\]$/ ? n : "[#{n.gsub(']', ']]')}]"
|
316
323
|
end.join('.')
|
317
324
|
end
|
318
325
|
|
319
|
-
ADAPTER_NAME = 'MSSQL'
|
326
|
+
ADAPTER_NAME = 'MSSQL'.freeze
|
320
327
|
|
321
328
|
def adapter_name # :nodoc:
|
322
329
|
ADAPTER_NAME
|
@@ -351,12 +358,13 @@ module ArJdbc
|
|
351
358
|
#
|
352
359
|
# http://blogs.msdn.com/b/mssqlisv/archive/2007/03/23/upgrading-to-sql-server-2005-and-default-schema-setting.aspx
|
353
360
|
|
354
|
-
# Returns the default schema (to be used for table resolution) used for
|
355
|
-
# the {#current_user}.
|
361
|
+
# Returns the default schema (to be used for table resolution) used for the {#current_user}.
|
356
362
|
def default_schema
|
357
363
|
return current_user if sqlserver_2000?
|
358
364
|
@default_schema ||=
|
359
|
-
|
365
|
+
@connection.execute_query_raw(
|
366
|
+
"SELECT default_schema_name FROM sys.database_principals WHERE name = CURRENT_USER"
|
367
|
+
).first['default_schema_name']
|
360
368
|
end
|
361
369
|
alias_method :current_schema, :default_schema
|
362
370
|
|
@@ -372,12 +380,16 @@ module ArJdbc
|
|
372
380
|
|
373
381
|
# `SELECT CURRENT_USER`
|
374
382
|
def current_user
|
375
|
-
@current_user ||=
|
383
|
+
@current_user ||= @connection.execute_query_raw("SELECT CURRENT_USER").first['']
|
376
384
|
end
|
377
385
|
|
378
386
|
def charset
|
379
387
|
select_value "SELECT SERVERPROPERTY('SqlCharSetName')"
|
380
388
|
end
|
389
|
+
|
390
|
+
def collation
|
391
|
+
select_value "SELECT SERVERPROPERTY('Collation')"
|
392
|
+
end
|
381
393
|
|
382
394
|
def current_database
|
383
395
|
select_value 'SELECT DB_NAME()'
|
@@ -410,6 +422,10 @@ module ArJdbc
|
|
410
422
|
def create_database(name, options = {})
|
411
423
|
execute "CREATE DATABASE #{quote_table_name(name)}"
|
412
424
|
end
|
425
|
+
|
426
|
+
def database_exists?(name)
|
427
|
+
select_value "SELECT name FROM sys.databases WHERE name = '#{name}'"
|
428
|
+
end
|
413
429
|
|
414
430
|
def rename_table(table_name, new_table_name)
|
415
431
|
clear_cached_table(table_name)
|
@@ -601,7 +617,23 @@ module ArJdbc
|
|
601
617
|
# NOTE: we allow to execute SQL as requested returning a results.
|
602
618
|
# e.g. this allows to use SQLServer's EXEC with a result set ...
|
603
619
|
sql = repair_special_columns to_sql(sql, binds)
|
604
|
-
|
620
|
+
if prepared_statements?
|
621
|
+
log(sql, name, binds) { @connection.execute_query(sql, binds) }
|
622
|
+
else
|
623
|
+
sql = suble_binds(sql, binds)
|
624
|
+
log(sql, name) { @connection.execute_query(sql) }
|
625
|
+
end
|
626
|
+
end
|
627
|
+
|
628
|
+
# @override
|
629
|
+
def exec_query_raw(sql, name = 'SQL', binds = [], &block) # :nodoc:
|
630
|
+
sql = repair_special_columns to_sql(sql, binds)
|
631
|
+
if prepared_statements?
|
632
|
+
log(sql, name, binds) { @connection.execute_query_raw(sql, binds, &block) }
|
633
|
+
else
|
634
|
+
sql = suble_binds(sql, binds)
|
635
|
+
log(sql, name) { @connection.execute_query_raw(sql, &block) }
|
636
|
+
end
|
605
637
|
end
|
606
638
|
|
607
639
|
private
|
@@ -671,7 +703,49 @@ module ArJdbc
|
|
671
703
|
end
|
672
704
|
|
673
705
|
module ActiveRecord::ConnectionAdapters
|
706
|
+
|
707
|
+
class MSSQLAdapter < JdbcAdapter
|
708
|
+
include ::ArJdbc::MSSQL
|
709
|
+
|
710
|
+
def initialize(*args)
|
711
|
+
::ArJdbc::MSSQL.initialize!
|
712
|
+
|
713
|
+
super # configure_connection happens in super
|
714
|
+
|
715
|
+
if ( version = self.sqlserver_version ) == '2000'
|
716
|
+
extend LimitHelpers::SqlServer2000AddLimitOffset
|
717
|
+
else
|
718
|
+
extend LimitHelpers::SqlServerAddLimitOffset
|
719
|
+
end
|
720
|
+
config[:sqlserver_version] ||= version
|
721
|
+
end
|
722
|
+
|
723
|
+
# some QUOTING caching :
|
724
|
+
|
725
|
+
@@quoted_table_names = {}
|
726
|
+
|
727
|
+
def quote_table_name(name)
|
728
|
+
unless quoted = @@quoted_table_names[name]
|
729
|
+
quoted = super
|
730
|
+
@@quoted_table_names[name] = quoted.freeze
|
731
|
+
end
|
732
|
+
quoted
|
733
|
+
end
|
734
|
+
|
735
|
+
@@quoted_column_names = {}
|
736
|
+
|
737
|
+
def quote_column_name(name)
|
738
|
+
unless quoted = @@quoted_column_names[name]
|
739
|
+
quoted = super
|
740
|
+
@@quoted_column_names[name] = quoted.freeze
|
741
|
+
end
|
742
|
+
quoted
|
743
|
+
end
|
744
|
+
|
745
|
+
end
|
746
|
+
|
674
747
|
class MSSQLColumn < JdbcColumn
|
675
748
|
include ArJdbc::MSSQL::Column
|
676
749
|
end
|
750
|
+
|
677
751
|
end
|
@@ -12,7 +12,9 @@ ArJdbc::ConnectionMethods.module_eval do
|
|
12
12
|
config[:host] ||= "localhost"
|
13
13
|
config[:port] ||= 1433
|
14
14
|
config[:driver] ||= defined?(::Jdbc::JTDS.driver_name) ? ::Jdbc::JTDS.driver_name : 'net.sourceforge.jtds.jdbc.Driver'
|
15
|
-
config[:adapter_spec]
|
15
|
+
config[:adapter_spec] ||= ::ArJdbc::MSSQL
|
16
|
+
config[:adapter_class] = ActiveRecord::ConnectionAdapters::MSSQLAdapter unless config.key?(:adapter_class)
|
17
|
+
config[:connection_alive_sql] ||= 'SELECT 1'
|
16
18
|
|
17
19
|
config[:url] ||= begin
|
18
20
|
url = "jdbc:jtds:sqlserver://#{config[:host]}:#{config[:port]}/#{config[:database]}"
|
@@ -23,11 +23,12 @@ module ArJdbc
|
|
23
23
|
rest_of_query = from_table + '.' + rest_of_query
|
24
24
|
end
|
25
25
|
new_sql = "#{select} t.* FROM (SELECT ROW_NUMBER() OVER(#{order}) AS _row_num, #{rest_of_query}"
|
26
|
-
new_sql << ") AS t WHERE t._row_num BETWEEN #{start_row
|
26
|
+
new_sql << ") AS t WHERE t._row_num BETWEEN #{start_row} AND #{end_row}"
|
27
27
|
sql.replace(new_sql)
|
28
28
|
end
|
29
29
|
sql
|
30
30
|
end
|
31
|
+
|
31
32
|
end
|
32
33
|
|
33
34
|
module SqlServerAddLimitOffset
|
@@ -116,7 +117,7 @@ module ArJdbc
|
|
116
117
|
if order =~ /(\w*id\w*)/i
|
117
118
|
$1
|
118
119
|
else
|
119
|
-
unquoted_name = unquote_table_name(table_name)
|
120
|
+
unquoted_name = Utils.unquote_table_name(table_name)
|
120
121
|
model = descendants.find { |m| m.table_name == table_name || m.table_name == unquoted_name }
|
121
122
|
model ? model.primary_key : 'id'
|
122
123
|
end
|
@@ -2,6 +2,9 @@ module ArJdbc
|
|
2
2
|
module MSSQL
|
3
3
|
module LockHelpers
|
4
4
|
module SqlServerAddLock
|
5
|
+
|
6
|
+
SELECT_FROM_WHERE_RE = /\A(\s*SELECT\s.*?)(\sFROM\s)(.*?)(\sWHERE\s.*|)\Z/mi # :nodoc:
|
7
|
+
|
5
8
|
# Microsoft SQL Server uses its own syntax for SELECT .. FOR UPDATE:
|
6
9
|
# SELECT .. FROM table1 WITH(ROWLOCK,UPDLOCK), table2 WITH(ROWLOCK,UPDLOCK) WHERE ..
|
7
10
|
#
|
@@ -14,7 +17,7 @@ module ArJdbc
|
|
14
17
|
add_lock!(subselect, options)
|
15
18
|
return sql.replace(prefix + subselect + suffix)
|
16
19
|
end
|
17
|
-
unless sql =~
|
20
|
+
unless sql =~ SELECT_FROM_WHERE_RE
|
18
21
|
# If you get this error, this driver probably needs to be fixed.
|
19
22
|
raise NotImplementedError, "Don't know how to add_lock! to SQL statement: #{sql.inspect}"
|
20
23
|
end
|
@@ -66,6 +69,7 @@ module ArJdbc
|
|
66
69
|
end
|
67
70
|
sql
|
68
71
|
end
|
72
|
+
|
69
73
|
end
|
70
74
|
end
|
71
75
|
end
|
data/lib/arjdbc/mysql/adapter.rb
CHANGED
@@ -1,14 +1,12 @@
|
|
1
|
+
ArJdbc.load_java_part :MySQL
|
2
|
+
|
1
3
|
require 'bigdecimal'
|
2
4
|
require 'active_record/connection_adapters/abstract/schema_definitions'
|
3
5
|
require 'arjdbc/mysql/explain_support'
|
4
6
|
|
5
7
|
module ArJdbc
|
6
8
|
module MySQL
|
7
|
-
|
8
|
-
def self.extended(adapter)
|
9
|
-
adapter.configure_connection
|
10
|
-
end
|
11
|
-
|
9
|
+
|
12
10
|
def configure_connection
|
13
11
|
variables = config[:variables] || {}
|
14
12
|
# By default, MySQL 'where id is null' selects the last inserted id. Turn this off.
|
@@ -57,6 +55,16 @@ module ArJdbc
|
|
57
55
|
config.key?(:strict) ? config[:strict] : ::ActiveRecord::VERSION::MAJOR > 3
|
58
56
|
end
|
59
57
|
|
58
|
+
@@emulate_booleans = true
|
59
|
+
|
60
|
+
# Boolean emulation can be disabled using (or using the adapter method) :
|
61
|
+
#
|
62
|
+
# ArJdbc::MySQL.emulate_booleans = false
|
63
|
+
#
|
64
|
+
# @see ActiveRecord::ConnectionAdapters::MysqlAdapter#emulate_booleans
|
65
|
+
def self.emulate_booleans; @@emulate_booleans; end
|
66
|
+
def self.emulate_booleans=(emulate); @@emulate_booleans = emulate; end
|
67
|
+
|
60
68
|
module Column
|
61
69
|
|
62
70
|
def extract_default(default)
|
@@ -79,15 +87,19 @@ module ArJdbc
|
|
79
87
|
end
|
80
88
|
|
81
89
|
def simplified_type(field_type)
|
90
|
+
if adapter.respond_to?(:emulate_booleans) && adapter.emulate_booleans
|
91
|
+
return :boolean if field_type.downcase.index('tinyint(1)')
|
92
|
+
end
|
93
|
+
|
82
94
|
case field_type
|
83
|
-
when /
|
84
|
-
when /
|
85
|
-
when /
|
95
|
+
when /enum/i, /set/i then :string
|
96
|
+
when /year/i then :integer
|
97
|
+
when /bit/i then :binary
|
86
98
|
else
|
87
99
|
super
|
88
100
|
end
|
89
101
|
end
|
90
|
-
|
102
|
+
|
91
103
|
def extract_limit(sql_type)
|
92
104
|
case sql_type
|
93
105
|
when /blob|text/i
|
@@ -126,6 +138,9 @@ module ArJdbc
|
|
126
138
|
type != :string && !null && default == ''
|
127
139
|
end
|
128
140
|
|
141
|
+
def adapter; end
|
142
|
+
private :adapter
|
143
|
+
|
129
144
|
end
|
130
145
|
|
131
146
|
ColumnExtensions = Column # :nodoc: backwards-compatibility
|
@@ -172,6 +187,16 @@ module ArJdbc
|
|
172
187
|
}
|
173
188
|
end
|
174
189
|
|
190
|
+
def new_visitor(config = nil)
|
191
|
+
visitor = ::Arel::Visitors::MySQL
|
192
|
+
( prepared_statements? ? visitor : bind_substitution(visitor) ).new(self)
|
193
|
+
end if defined? ::Arel::Visitors::MySQL
|
194
|
+
|
195
|
+
# @see #bind_substitution
|
196
|
+
class BindSubstitution < Arel::Visitors::MySQL # :nodoc:
|
197
|
+
include Arel::Visitors::BindVisitor
|
198
|
+
end if defined? Arel::Visitors::BindVisitor
|
199
|
+
|
175
200
|
def case_sensitive_equality_operator
|
176
201
|
"= BINARY"
|
177
202
|
end
|
@@ -289,7 +314,7 @@ module ArJdbc
|
|
289
314
|
|
290
315
|
# SCHEMA STATEMENTS ========================================
|
291
316
|
|
292
|
-
def structure_dump
|
317
|
+
def structure_dump # :nodoc:
|
293
318
|
if supports_views?
|
294
319
|
sql = "SHOW FULL TABLES WHERE Table_type = 'BASE TABLE'"
|
295
320
|
else
|
@@ -309,33 +334,53 @@ module ArJdbc
|
|
309
334
|
end
|
310
335
|
end
|
311
336
|
|
312
|
-
#
|
313
|
-
|
314
|
-
|
337
|
+
# Returns just a table's primary key
|
338
|
+
def primary_key(table)
|
339
|
+
#pk_and_sequence = pk_and_sequence_for(table)
|
340
|
+
#pk_and_sequence && pk_and_sequence.first
|
341
|
+
@connection.primary_keys(table).first
|
342
|
+
end
|
343
|
+
|
315
344
|
# Returns a table's primary key and belonging sequence.
|
316
|
-
|
317
|
-
|
318
|
-
result = execute("SHOW
|
319
|
-
result.
|
320
|
-
keys
|
345
|
+
# @note not used only here for potential compatibility with AR's adapter.
|
346
|
+
def pk_and_sequence_for(table)
|
347
|
+
result = execute("SHOW CREATE TABLE #{quote_table_name(table)}", 'SCHEMA').first
|
348
|
+
if result['Create Table'].to_s =~ /PRIMARY KEY\s+(?:USING\s+\w+\s+)?\((.+)\)/
|
349
|
+
keys = $1.split(","); keys.map! { |key| key.gsub(/[`"]/, "") }
|
350
|
+
return keys.length == 1 ? [ keys.first, nil ] : nil
|
351
|
+
else
|
352
|
+
return nil
|
321
353
|
end
|
322
|
-
keys.length == 1 ? [keys.first, nil] : nil
|
323
354
|
end
|
324
|
-
|
325
|
-
|
326
|
-
|
355
|
+
|
356
|
+
IndexDefinition = ::ActiveRecord::ConnectionAdapters::IndexDefinition
|
357
|
+
|
358
|
+
if ::ActiveRecord::VERSION::MAJOR > 3
|
359
|
+
|
360
|
+
INDEX_TYPES = [ :fulltext, :spatial ]
|
361
|
+
INDEX_USINGS = [ :btree, :hash ]
|
362
|
+
|
363
|
+
end
|
364
|
+
|
327
365
|
# Returns an array of indexes for the given table.
|
328
|
-
def indexes(table_name, name = nil)
|
366
|
+
def indexes(table_name, name = nil) # :nodoc:
|
329
367
|
indexes = []
|
330
368
|
current_index = nil
|
331
|
-
result = execute("SHOW KEYS FROM #{quote_table_name(table_name)}", name)
|
369
|
+
result = execute("SHOW KEYS FROM #{quote_table_name(table_name)}", name || 'SCHEMA')
|
332
370
|
result.each do |row|
|
333
|
-
key_name = row[
|
371
|
+
key_name = row['Key_name']
|
334
372
|
if current_index != key_name
|
335
|
-
next if key_name ==
|
373
|
+
next if key_name == 'PRIMARY' # skip the primary key
|
336
374
|
current_index = key_name
|
337
|
-
indexes <<
|
338
|
-
|
375
|
+
indexes <<
|
376
|
+
if self.class.const_defined?(:INDEX_TYPES) # AR 4.0
|
377
|
+
mysql_index_type = row['Index_type'].downcase.to_sym
|
378
|
+
index_type = INDEX_TYPES.include?(mysql_index_type) ? mysql_index_type : nil
|
379
|
+
index_using = INDEX_USINGS.include?(mysql_index_type) ? mysql_index_type : nil
|
380
|
+
IndexDefinition.new(row['Table'], key_name, row['Non_unique'].to_i == 0, [], [], nil, nil, index_type, index_using)
|
381
|
+
else
|
382
|
+
IndexDefinition.new(row['Table'], key_name, row['Non_unique'].to_i == 0, [], [])
|
383
|
+
end
|
339
384
|
end
|
340
385
|
|
341
386
|
indexes.last.columns << row["Column_name"]
|
@@ -343,26 +388,23 @@ module ArJdbc
|
|
343
388
|
end
|
344
389
|
indexes
|
345
390
|
end
|
346
|
-
|
347
|
-
def
|
391
|
+
|
392
|
+
def columns(table_name, name = nil) # :nodoc:
|
348
393
|
sql = "SHOW FIELDS FROM #{quote_table_name(table_name)}"
|
349
|
-
|
350
|
-
|
394
|
+
column = ::ActiveRecord::ConnectionAdapters::MysqlAdapter::Column
|
395
|
+
result = execute(sql, name || 'SCHEMA')
|
396
|
+
result.map! do |field|
|
397
|
+
column.new(field["Field"], field["Default"], field["Type"], field["Null"] == "YES")
|
351
398
|
end
|
399
|
+
result
|
352
400
|
end
|
353
401
|
|
354
|
-
|
355
|
-
def primary_key(table)
|
356
|
-
pk_and_sequence = pk_and_sequence_for(table)
|
357
|
-
pk_and_sequence && pk_and_sequence.first
|
358
|
-
end
|
359
|
-
|
360
|
-
def recreate_database(name, options = {}) #:nodoc:
|
402
|
+
def recreate_database(name, options = {}) # :nodoc:
|
361
403
|
drop_database(name)
|
362
404
|
create_database(name, options)
|
363
405
|
end
|
364
406
|
|
365
|
-
def create_database(name, options = {})
|
407
|
+
def create_database(name, options = {}) # :nodoc:
|
366
408
|
if options[:collation]
|
367
409
|
execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}` COLLATE `#{options[:collation]}`"
|
368
410
|
else
|
@@ -572,7 +614,7 @@ module ArJdbc
|
|
572
614
|
end
|
573
615
|
column
|
574
616
|
end
|
575
|
-
|
617
|
+
|
576
618
|
def show_create_table(table)
|
577
619
|
select_one("SHOW CREATE TABLE #{quote_table_name(table)}")
|
578
620
|
end
|
@@ -598,29 +640,41 @@ end
|
|
598
640
|
module ActiveRecord
|
599
641
|
module ConnectionAdapters
|
600
642
|
# Remove any vestiges of core/Ruby MySQL adapter
|
601
|
-
remove_const(:MysqlColumn) if const_defined?(:MysqlColumn)
|
602
643
|
remove_const(:MysqlAdapter) if const_defined?(:MysqlAdapter)
|
644
|
+
|
645
|
+
class MysqlAdapter < JdbcAdapter
|
646
|
+
include ::ArJdbc::MySQL
|
647
|
+
include ::ArJdbc::MySQL::ExplainSupport
|
648
|
+
|
649
|
+
# By default, the MysqlAdapter will consider all columns of type
|
650
|
+
# <tt>tinyint(1)</tt> as boolean. If you wish to disable this :
|
651
|
+
#
|
652
|
+
# ActiveRecord::ConnectionAdapters::Mysql[2]Adapter.emulate_booleans = false
|
653
|
+
#
|
654
|
+
def self.emulate_booleans; ::ArJdbc::MySQL.emulate_booleans; end
|
655
|
+
def self.emulate_booleans=(emulate); ::ArJdbc::MySQL.emulate_booleans = emulate; end
|
656
|
+
|
657
|
+
class Column < JdbcColumn
|
658
|
+
include ::ArJdbc::MySQL::Column
|
603
659
|
|
604
|
-
|
605
|
-
|
660
|
+
def initialize(name, *args)
|
661
|
+
if Hash === name
|
662
|
+
super
|
663
|
+
else
|
664
|
+
super(nil, name, *args)
|
665
|
+
end
|
666
|
+
end
|
606
667
|
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
else
|
611
|
-
super(nil, name, *args)
|
668
|
+
# @note {#ArJdbc::MySQL::Column} uses this to check for boolean emulation
|
669
|
+
def adapter
|
670
|
+
MysqlAdapter
|
612
671
|
end
|
672
|
+
|
613
673
|
end
|
614
674
|
|
615
|
-
end
|
616
|
-
|
617
|
-
class MysqlAdapter < JdbcAdapter
|
618
|
-
include ::ArJdbc::MySQL
|
619
|
-
include ::ArJdbc::MySQL::ExplainSupport
|
620
|
-
|
621
675
|
def initialize(*args)
|
622
676
|
super
|
623
|
-
configure_connection
|
677
|
+
# configure_connection happens in super
|
624
678
|
end
|
625
679
|
|
626
680
|
def jdbc_connection_class(spec)
|
@@ -628,9 +682,8 @@ module ActiveRecord
|
|
628
682
|
end
|
629
683
|
|
630
684
|
def jdbc_column_class
|
631
|
-
|
685
|
+
Column
|
632
686
|
end
|
633
|
-
alias_chained_method :columns, :query_cache, :jdbc_columns
|
634
687
|
|
635
688
|
# some QUOTING caching :
|
636
689
|
|
@@ -655,18 +708,22 @@ module ActiveRecord
|
|
655
708
|
end
|
656
709
|
|
657
710
|
end
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
module Mysql # :nodoc:
|
666
|
-
remove_const(:Error) if const_defined?(:Error)
|
667
|
-
class Error < ::ActiveRecord::JDBCError; end
|
711
|
+
|
712
|
+
if ActiveRecord::VERSION::MAJOR < 3 ||
|
713
|
+
( ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR <= 1 )
|
714
|
+
remove_const(:MysqlColumn) if const_defined?(:MysqlColumn)
|
715
|
+
MysqlColumn = MysqlAdapter::Column
|
716
|
+
end
|
668
717
|
|
669
|
-
|
670
|
-
|
718
|
+
if ActiveRecord::VERSION::MAJOR > 3 ||
|
719
|
+
( ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR >= 1 )
|
720
|
+
remove_const(:Mysql2Adapter) if const_defined?(:Mysql2Adapter)
|
721
|
+
Mysql2Adapter = MysqlAdapter
|
722
|
+
if ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR == 1
|
723
|
+
remove_const(:Mysql2Column) if const_defined?(:Mysql2Column)
|
724
|
+
Mysql2Column = MysqlAdapter::Column
|
725
|
+
end
|
726
|
+
end
|
727
|
+
|
671
728
|
end
|
672
729
|
end
|