activerecord-jdbc-adapter-ficoh 1.3.21-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +35 -0
- data/.travis.yml +462 -0
- data/.yardopts +4 -0
- data/Appraisals +36 -0
- data/CONTRIBUTING.md +49 -0
- data/Gemfile +68 -0
- data/History.md +1191 -0
- data/LICENSE.txt +25 -0
- data/README.md +277 -0
- data/RUNNING_TESTS.md +88 -0
- data/Rakefile +298 -0
- data/Rakefile.jdbc +20 -0
- data/activerecord-jdbc-adapter.gemspec +63 -0
- data/lib/active_record/connection_adapters/as400_adapter.rb +2 -0
- data/lib/active_record/connection_adapters/db2_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/derby_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/firebird_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/h2_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/hsqldb_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/informix_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/jdbc_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/jndi_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/mariadb_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/mssql_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/mysql_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/oracle_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +1 -0
- data/lib/activerecord-jdbc-adapter.rb +1 -0
- data/lib/arel/visitors/compat.rb +64 -0
- data/lib/arel/visitors/db2.rb +137 -0
- data/lib/arel/visitors/derby.rb +112 -0
- data/lib/arel/visitors/firebird.rb +79 -0
- data/lib/arel/visitors/h2.rb +25 -0
- data/lib/arel/visitors/hsqldb.rb +32 -0
- data/lib/arel/visitors/postgresql_jdbc.rb +6 -0
- data/lib/arel/visitors/sql_server.rb +225 -0
- data/lib/arel/visitors/sql_server/ng42.rb +293 -0
- data/lib/arjdbc.rb +22 -0
- data/lib/arjdbc/db2.rb +4 -0
- data/lib/arjdbc/db2/adapter.rb +802 -0
- data/lib/arjdbc/db2/as400.rb +137 -0
- data/lib/arjdbc/db2/column.rb +177 -0
- data/lib/arjdbc/db2/connection_methods.rb +45 -0
- data/lib/arjdbc/derby.rb +3 -0
- data/lib/arjdbc/derby/active_record_patch.rb +13 -0
- data/lib/arjdbc/derby/adapter.rb +567 -0
- data/lib/arjdbc/derby/connection_methods.rb +16 -0
- data/lib/arjdbc/derby/schema_creation.rb +15 -0
- data/lib/arjdbc/discover.rb +104 -0
- data/lib/arjdbc/firebird.rb +4 -0
- data/lib/arjdbc/firebird/adapter.rb +468 -0
- data/lib/arjdbc/firebird/connection_methods.rb +20 -0
- data/lib/arjdbc/h2.rb +3 -0
- data/lib/arjdbc/h2/adapter.rb +335 -0
- data/lib/arjdbc/h2/connection_methods.rb +22 -0
- data/lib/arjdbc/hsqldb.rb +3 -0
- data/lib/arjdbc/hsqldb/adapter.rb +304 -0
- data/lib/arjdbc/hsqldb/connection_methods.rb +23 -0
- data/lib/arjdbc/hsqldb/explain_support.rb +35 -0
- data/lib/arjdbc/hsqldb/schema_creation.rb +11 -0
- data/lib/arjdbc/informix.rb +5 -0
- data/lib/arjdbc/informix/adapter.rb +160 -0
- data/lib/arjdbc/informix/connection_methods.rb +9 -0
- data/lib/arjdbc/jdbc.rb +62 -0
- data/lib/arjdbc/jdbc/adapter.rb +997 -0
- data/lib/arjdbc/jdbc/adapter_require.rb +46 -0
- data/lib/arjdbc/jdbc/arel_support.rb +149 -0
- data/lib/arjdbc/jdbc/base_ext.rb +34 -0
- data/lib/arjdbc/jdbc/callbacks.rb +52 -0
- data/lib/arjdbc/jdbc/column.rb +83 -0
- data/lib/arjdbc/jdbc/connection.rb +26 -0
- data/lib/arjdbc/jdbc/connection_methods.rb +59 -0
- data/lib/arjdbc/jdbc/driver.rb +44 -0
- data/lib/arjdbc/jdbc/error.rb +75 -0
- data/lib/arjdbc/jdbc/extension.rb +69 -0
- data/lib/arjdbc/jdbc/java.rb +13 -0
- data/lib/arjdbc/jdbc/type_cast.rb +154 -0
- data/lib/arjdbc/jdbc/type_converter.rb +142 -0
- data/lib/arjdbc/mssql.rb +7 -0
- data/lib/arjdbc/mssql/adapter.rb +822 -0
- data/lib/arjdbc/mssql/column.rb +207 -0
- data/lib/arjdbc/mssql/connection_methods.rb +72 -0
- data/lib/arjdbc/mssql/explain_support.rb +99 -0
- data/lib/arjdbc/mssql/limit_helpers.rb +231 -0
- data/lib/arjdbc/mssql/lock_methods.rb +77 -0
- data/lib/arjdbc/mssql/types.rb +343 -0
- data/lib/arjdbc/mssql/utils.rb +82 -0
- data/lib/arjdbc/mysql.rb +3 -0
- data/lib/arjdbc/mysql/adapter.rb +998 -0
- data/lib/arjdbc/mysql/bulk_change_table.rb +150 -0
- data/lib/arjdbc/mysql/column.rb +167 -0
- data/lib/arjdbc/mysql/connection_methods.rb +137 -0
- data/lib/arjdbc/mysql/explain_support.rb +82 -0
- data/lib/arjdbc/mysql/schema_creation.rb +58 -0
- data/lib/arjdbc/oracle.rb +4 -0
- data/lib/arjdbc/oracle/adapter.rb +968 -0
- data/lib/arjdbc/oracle/column.rb +136 -0
- data/lib/arjdbc/oracle/connection_methods.rb +21 -0
- data/lib/arjdbc/postgresql.rb +3 -0
- data/lib/arjdbc/postgresql/_bc_time_cast_patch.rb +21 -0
- data/lib/arjdbc/postgresql/adapter.rb +1498 -0
- data/lib/arjdbc/postgresql/base/array_parser.rb +95 -0
- data/lib/arjdbc/postgresql/base/oid.rb +412 -0
- data/lib/arjdbc/postgresql/base/pgconn.rb +8 -0
- data/lib/arjdbc/postgresql/base/schema_definitions.rb +132 -0
- data/lib/arjdbc/postgresql/column.rb +640 -0
- data/lib/arjdbc/postgresql/connection_methods.rb +44 -0
- data/lib/arjdbc/postgresql/explain_support.rb +53 -0
- data/lib/arjdbc/postgresql/oid/bytea.rb +3 -0
- data/lib/arjdbc/postgresql/oid_types.rb +265 -0
- data/lib/arjdbc/postgresql/schema_creation.rb +60 -0
- data/lib/arjdbc/railtie.rb +11 -0
- data/lib/arjdbc/sqlite3.rb +3 -0
- data/lib/arjdbc/sqlite3/adapter.rb +654 -0
- data/lib/arjdbc/sqlite3/connection_methods.rb +36 -0
- data/lib/arjdbc/sqlite3/explain_support.rb +29 -0
- data/lib/arjdbc/sybase.rb +2 -0
- data/lib/arjdbc/sybase/adapter.rb +47 -0
- data/lib/arjdbc/tasks.rb +13 -0
- data/lib/arjdbc/tasks/database_tasks.rb +66 -0
- data/lib/arjdbc/tasks/databases.rake +91 -0
- data/lib/arjdbc/tasks/databases3.rake +239 -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 +31 -0
- data/lib/arjdbc/tasks/hsqldb_database_tasks.rb +70 -0
- data/lib/arjdbc/tasks/jdbc_database_tasks.rb +169 -0
- data/lib/arjdbc/tasks/mssql_database_tasks.rb +46 -0
- data/lib/arjdbc/tasks/oracle/enhanced_structure_dump.rb +297 -0
- data/lib/arjdbc/tasks/oracle_database_tasks.rb +65 -0
- data/lib/arjdbc/util/quoted_cache.rb +60 -0
- data/lib/arjdbc/util/serialized_attributes.rb +98 -0
- data/lib/arjdbc/util/table_copier.rb +108 -0
- data/lib/arjdbc/version.rb +8 -0
- data/lib/generators/jdbc/USAGE +9 -0
- data/lib/generators/jdbc/jdbc_generator.rb +17 -0
- data/pom.xml +285 -0
- data/rails_generators/jdbc_generator.rb +15 -0
- data/rails_generators/templates/config/initializers/jdbc.rb +10 -0
- data/rails_generators/templates/lib/tasks/jdbc.rake +11 -0
- data/rakelib/01-tomcat.rake +51 -0
- data/rakelib/02-test.rake +151 -0
- data/rakelib/bundler_ext.rb +11 -0
- data/rakelib/db.rake +58 -0
- data/rakelib/rails.rake +77 -0
- data/src/java/arjdbc/ArJdbcModule.java +288 -0
- data/src/java/arjdbc/db2/DB2Module.java +77 -0
- data/src/java/arjdbc/db2/DB2RubyJdbcConnection.java +128 -0
- data/src/java/arjdbc/derby/DerbyModule.java +180 -0
- data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +153 -0
- data/src/java/arjdbc/firebird/FirebirdRubyJdbcConnection.java +190 -0
- data/src/java/arjdbc/h2/H2Module.java +50 -0
- data/src/java/arjdbc/h2/H2RubyJdbcConnection.java +86 -0
- data/src/java/arjdbc/hsqldb/HSQLDBModule.java +74 -0
- data/src/java/arjdbc/informix/InformixRubyJdbcConnection.java +76 -0
- data/src/java/arjdbc/jdbc/AdapterJavaService.java +43 -0
- data/src/java/arjdbc/jdbc/Callable.java +44 -0
- data/src/java/arjdbc/jdbc/ConnectionFactory.java +77 -0
- data/src/java/arjdbc/jdbc/DataSourceConnectionFactory.java +156 -0
- data/src/java/arjdbc/jdbc/DriverConnectionFactory.java +63 -0
- data/src/java/arjdbc/jdbc/DriverWrapper.java +128 -0
- data/src/java/arjdbc/jdbc/JdbcConnectionFactory.java +32 -0
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +4541 -0
- data/src/java/arjdbc/jdbc/SQLBlock.java +54 -0
- data/src/java/arjdbc/jdbc/WithResultSet.java +37 -0
- data/src/java/arjdbc/mssql/MSSQLModule.java +91 -0
- data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +193 -0
- data/src/java/arjdbc/mysql/MySQLModule.java +140 -0
- data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +456 -0
- data/src/java/arjdbc/oracle/OracleModule.java +81 -0
- data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +477 -0
- data/src/java/arjdbc/postgresql/ByteaUtils.java +171 -0
- data/src/java/arjdbc/postgresql/DriverImplementation.java +78 -0
- data/src/java/arjdbc/postgresql/PGDriverImplementation.java +535 -0
- data/src/java/arjdbc/postgresql/PostgreSQLModule.java +189 -0
- data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +489 -0
- data/src/java/arjdbc/sqlite3/SQLite3Module.java +93 -0
- data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +405 -0
- data/src/java/arjdbc/util/CallResultSet.java +826 -0
- data/src/java/arjdbc/util/DateTimeUtils.java +517 -0
- data/src/java/arjdbc/util/NumberUtils.java +50 -0
- data/src/java/arjdbc/util/ObjectSupport.java +65 -0
- data/src/java/arjdbc/util/QuotingUtils.java +139 -0
- data/src/java/arjdbc/util/StringCache.java +60 -0
- data/src/java/arjdbc/util/StringHelper.java +155 -0
- metadata +288 -0
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'arel/visitors/compat'
|
2
|
+
|
3
|
+
module Arel
|
4
|
+
module Visitors
|
5
|
+
class Firebird < Arel::Visitors::ToSql
|
6
|
+
|
7
|
+
if ArJdbc::AR42
|
8
|
+
def visit_Arel_Nodes_SelectStatement(o, a)
|
9
|
+
a = o.cores.inject(a) { |c, x| visit_Arel_Nodes_SelectCore(x, c) }
|
10
|
+
|
11
|
+
limit, offset = o.limit, o.offset
|
12
|
+
if limit || offset
|
13
|
+
select = a.parts[0]
|
14
|
+
|
15
|
+
sql = Arel::Collectors::SQLString.new
|
16
|
+
visit(limit, sql) if limit
|
17
|
+
if offset
|
18
|
+
sql << ' ' if limit
|
19
|
+
visit(offset, sql)
|
20
|
+
end
|
21
|
+
|
22
|
+
a.parts[0] = "#{select} #{sql.value}"
|
23
|
+
end
|
24
|
+
|
25
|
+
unless o.orders.empty?
|
26
|
+
a << ' ORDER BY '
|
27
|
+
last = o.orders.length - 1
|
28
|
+
o.orders.each_with_index do |x, i|
|
29
|
+
visit(x, a); a << ', ' unless last == i
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
a
|
34
|
+
end
|
35
|
+
|
36
|
+
def visit_Arel_Nodes_Limit(o, a)
|
37
|
+
a << "FIRST #{limit_for(o)}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def visit_Arel_Nodes_Offset(o, a)
|
41
|
+
a << 'SKIP '; visit(o.value, a)
|
42
|
+
end
|
43
|
+
|
44
|
+
else
|
45
|
+
|
46
|
+
def visit_Arel_Nodes_SelectStatement o, a = nil
|
47
|
+
if o.limit
|
48
|
+
limit = do_visit o.limit.expr, a
|
49
|
+
else
|
50
|
+
limit = nil
|
51
|
+
end
|
52
|
+
if o.offset
|
53
|
+
offset = do_visit o.offset.expr, a
|
54
|
+
else
|
55
|
+
offset = nil
|
56
|
+
end
|
57
|
+
|
58
|
+
sql = o.cores.map { |x| do_visit_select_core x, a }.join
|
59
|
+
@connection.insert_limit_offset!(sql, limit, offset) if limit || offset
|
60
|
+
|
61
|
+
unless o.orders.empty?
|
62
|
+
sql << ' ORDER BY '
|
63
|
+
last = o.orders.length - 1
|
64
|
+
o.orders.each_with_index do |x, i|
|
65
|
+
sql << do_visit(x, a); sql << ', ' unless last == i
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
sql
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
Arel::Collectors::Bind.class_eval do
|
78
|
+
attr_reader :parts
|
79
|
+
end if defined? Arel::Collectors::Bind
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'arel/visitors/compat'
|
2
|
+
require 'arel/visitors/hsqldb'
|
3
|
+
|
4
|
+
module Arel
|
5
|
+
module Visitors
|
6
|
+
class H2 < Arel::Visitors::HSQLDB
|
7
|
+
def visit_Arel_Nodes_SelectStatement(o, *)
|
8
|
+
o.limit ||= Arel::Nodes::Limit.new(-1) if o.offset
|
9
|
+
super
|
10
|
+
end if ArJdbc::AR42
|
11
|
+
|
12
|
+
def limit_offset sql, o
|
13
|
+
offset = o.offset || 0
|
14
|
+
offset = offset.expr unless (offset.nil? || offset == 0)
|
15
|
+
if limit = o.limit
|
16
|
+
"SELECT LIMIT #{offset} #{limit_for(limit)} #{sql[7..-1]}"
|
17
|
+
elsif offset > 0
|
18
|
+
"SELECT LIMIT #{offset} -1 #{sql[7..-1]}" # removes "SELECT "
|
19
|
+
else
|
20
|
+
sql
|
21
|
+
end
|
22
|
+
end unless ArJdbc::AR42
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'arel/visitors/compat'
|
2
|
+
|
3
|
+
module Arel
|
4
|
+
module Visitors
|
5
|
+
class HSQLDB < Arel::Visitors::ToSql
|
6
|
+
def visit_Arel_Nodes_SelectStatement(o, *)
|
7
|
+
o.limit ||= Arel::Nodes::Limit.new(0) if o.offset
|
8
|
+
super
|
9
|
+
end if ArJdbc::AR42
|
10
|
+
|
11
|
+
def visit_Arel_Nodes_SelectStatement o, a = nil
|
12
|
+
sql = limit_offset(o.cores.map { |x| do_visit_select_core x, a }.join, o)
|
13
|
+
sql << " ORDER BY #{o.orders.map { |x| do_visit x, a }.join(', ')}" unless o.orders.empty?
|
14
|
+
sql
|
15
|
+
end unless ArJdbc::AR42
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def limit_offset sql, o
|
20
|
+
offset = o.offset || 0
|
21
|
+
offset = offset.expr unless (offset.nil? || offset == 0)
|
22
|
+
if limit = o.limit
|
23
|
+
"SELECT LIMIT #{offset} #{limit_for(limit)} #{sql[7..-1]}"
|
24
|
+
elsif offset > 0
|
25
|
+
"SELECT LIMIT #{offset} 0 #{sql[7..-1]}" # removes "SELECT "
|
26
|
+
else
|
27
|
+
sql
|
28
|
+
end
|
29
|
+
end unless ArJdbc::AR42
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,225 @@
|
|
1
|
+
require 'arel/visitors/compat'
|
2
|
+
|
3
|
+
module Arel
|
4
|
+
module Visitors
|
5
|
+
ToSql.class_eval do
|
6
|
+
alias_method :_visit_Arel_Nodes_SelectStatement, :visit_Arel_Nodes_SelectStatement
|
7
|
+
end
|
8
|
+
# @note AREL set's up `Arel::Visitors::MSSQL` but its not usable as is ...
|
9
|
+
# @private
|
10
|
+
class SQLServer < const_defined?(:MSSQL) ? MSSQL : ToSql
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def visit_Arel_Nodes_SelectStatement(*args) # [o] AR <= 4.0 [o, a] on 4.1
|
15
|
+
o, a = args.first, args.last
|
16
|
+
|
17
|
+
return _visit_Arel_Nodes_SelectStatement(*args) if ! o.limit && ! o.offset
|
18
|
+
|
19
|
+
unless o.orders.empty?
|
20
|
+
select_order_by = do_visit_columns o.orders, a, 'ORDER BY '
|
21
|
+
end
|
22
|
+
|
23
|
+
select_count = false; sql = ''
|
24
|
+
o.cores.each do |x|
|
25
|
+
x = x.dup
|
26
|
+
core_order_by = select_order_by || determine_order_by(x, a)
|
27
|
+
if select_count? x
|
28
|
+
x.projections = [
|
29
|
+
Arel::Nodes::SqlLiteral.new(core_order_by ? over_row_num(core_order_by) : '*')
|
30
|
+
]
|
31
|
+
select_count = true
|
32
|
+
else
|
33
|
+
# NOTE: this should really be added here and we should built the
|
34
|
+
# wrapping SQL but than #replace_limit_offset! assumes it does that
|
35
|
+
# ... MS-SQL adapter code seems to be 'hacked' by a lot of people
|
36
|
+
#x.projections << Arel::Nodes::SqlLiteral.new over_row_num(order_by)
|
37
|
+
end
|
38
|
+
sql << do_visit_select_core(x, a)
|
39
|
+
end
|
40
|
+
|
41
|
+
#sql = "SELECT _t.* FROM (#{sql}) as _t WHERE #{get_offset_limit_clause(o)}"
|
42
|
+
select_order_by ||= "ORDER BY #{@connection.determine_order_clause(sql)}"
|
43
|
+
replace_limit_offset!(sql, limit_for(o.limit), o.offset && o.offset.value.to_i, select_order_by)
|
44
|
+
|
45
|
+
sql = "SELECT COUNT(*) AS count_id FROM (#{sql}) AS subquery" if select_count
|
46
|
+
|
47
|
+
add_lock!(sql, :lock => o.lock && true)
|
48
|
+
|
49
|
+
sql
|
50
|
+
end unless ArJdbc::AR42
|
51
|
+
|
52
|
+
# @private
|
53
|
+
MAX_LIMIT_VALUE = 9_223_372_036_854_775_807
|
54
|
+
|
55
|
+
def visit_Arel_Nodes_UpdateStatement(*args) # [o] AR <= 4.0 [o, a] on 4.1
|
56
|
+
o = args.first
|
57
|
+
if o.orders.any? && o.limit.nil?
|
58
|
+
o.limit = Nodes::Limit.new(MAX_LIMIT_VALUE)
|
59
|
+
end
|
60
|
+
super
|
61
|
+
end
|
62
|
+
|
63
|
+
def visit_Arel_Nodes_Lock o, a = nil
|
64
|
+
# MS-SQL doesn't support "SELECT...FOR UPDATE". Instead, it needs
|
65
|
+
# WITH(ROWLOCK,UPDLOCK) specified after each table in the FROM clause.
|
66
|
+
#
|
67
|
+
# we return nothing here and add the appropriate stuff with #add_lock!
|
68
|
+
#do_visit o.expr, a
|
69
|
+
end unless ArJdbc::AR42
|
70
|
+
|
71
|
+
def visit_Arel_Nodes_Top o, a = nil
|
72
|
+
# `top` wouldn't really work here:
|
73
|
+
# User.select("distinct first_name").limit(10)
|
74
|
+
# would generate "select top 10 distinct first_name from users",
|
75
|
+
# which is invalid should be "select distinct top 10 first_name ..."
|
76
|
+
a || ''
|
77
|
+
end
|
78
|
+
|
79
|
+
def visit_Arel_Nodes_Limit o, a = nil
|
80
|
+
"TOP (#{do_visit o.expr, a})"
|
81
|
+
end unless ArJdbc::AR42
|
82
|
+
|
83
|
+
def visit_Arel_Nodes_Ordering o, a = nil
|
84
|
+
expr = do_visit o.expr, a
|
85
|
+
if o.respond_to?(:direction)
|
86
|
+
"#{expr} #{o.ascending? ? 'ASC' : 'DESC'}"
|
87
|
+
else
|
88
|
+
expr
|
89
|
+
end
|
90
|
+
end unless ArJdbc::AR42
|
91
|
+
|
92
|
+
def visit_Arel_Nodes_Bin o, a = nil
|
93
|
+
expr = o.expr; sql = do_visit expr, a
|
94
|
+
if expr.respond_to?(:val) && expr.val.is_a?(Numeric)
|
95
|
+
sql
|
96
|
+
else
|
97
|
+
sql << " #{::ArJdbc::MSSQL.cs_equality_operator} "
|
98
|
+
sql
|
99
|
+
end
|
100
|
+
end unless ArJdbc::AR42
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
def self.possibly_private_method_defined?(name)
|
105
|
+
private_method_defined?(name) || method_defined?(name)
|
106
|
+
end
|
107
|
+
|
108
|
+
def select_count? x
|
109
|
+
x.projections.length == 1 && Arel::Nodes::Count === x.projections.first
|
110
|
+
end unless possibly_private_method_defined? :select_count?
|
111
|
+
|
112
|
+
def determine_order_by x, a
|
113
|
+
unless x.groups.empty?
|
114
|
+
do_visit_columns x.groups, a, 'ORDER BY '
|
115
|
+
else
|
116
|
+
table_pk = find_left_table_pk(x)
|
117
|
+
table_pk && "ORDER BY #{table_pk}"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def find_left_table_pk o
|
122
|
+
primary_key_from_table table_from_select_core(o)
|
123
|
+
end
|
124
|
+
|
125
|
+
def do_visit_columns(colls, a, sql)
|
126
|
+
last = colls.size - 1
|
127
|
+
colls.each_with_index do |x, i|
|
128
|
+
sql << do_visit(x, a); sql << ', ' unless i == last
|
129
|
+
end
|
130
|
+
sql
|
131
|
+
end
|
132
|
+
|
133
|
+
def do_visit_columns(colls, a, sql)
|
134
|
+
prefix = sql
|
135
|
+
sql = Arel::Collectors::PlainString.new
|
136
|
+
sql << prefix if prefix
|
137
|
+
|
138
|
+
last = colls.size - 1
|
139
|
+
colls.each_with_index do |x, i|
|
140
|
+
visit(x, sql); sql << ', ' unless i == last
|
141
|
+
end
|
142
|
+
sql.value
|
143
|
+
end if ArJdbc::AR42
|
144
|
+
|
145
|
+
def do_visit_columns(colls, a, sql)
|
146
|
+
non_simple_order = /\sASC|\sDESC|\sCASE|\sCOLLATE|[\.,\[\(]/i # MIN(width)
|
147
|
+
|
148
|
+
last = colls.size - 1
|
149
|
+
colls.each_with_index do |x, i|
|
150
|
+
coll = do_visit(x, a)
|
151
|
+
|
152
|
+
if coll !~ non_simple_order && coll.to_i == 0
|
153
|
+
sql << @connection.quote_column_name(coll)
|
154
|
+
else
|
155
|
+
sql << coll
|
156
|
+
end
|
157
|
+
|
158
|
+
sql << ', ' unless i == last
|
159
|
+
end
|
160
|
+
sql
|
161
|
+
end if Arel::VERSION < '4.0.0'
|
162
|
+
|
163
|
+
def over_row_num order_by
|
164
|
+
"ROW_NUMBER() OVER (#{order_by}) as _row_num"
|
165
|
+
end # unless possibly_private_method_defined? :row_num_literal
|
166
|
+
|
167
|
+
def table_from_select_core core
|
168
|
+
if Arel::Table === core.from
|
169
|
+
core.from
|
170
|
+
elsif Arel::Nodes::SqlLiteral === core.from
|
171
|
+
Arel::Table.new(core.from, @engine)
|
172
|
+
elsif Arel::Nodes::JoinSource === core.source
|
173
|
+
Arel::Nodes::SqlLiteral === core.source.left ? Arel::Table.new(core.source.left, @engine) : core.source.left
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def table_from_select_core core
|
178
|
+
table_finder = lambda do |x|
|
179
|
+
case x
|
180
|
+
when Arel::Table
|
181
|
+
x
|
182
|
+
when Arel::Nodes::SqlLiteral
|
183
|
+
Arel::Table.new(x, @engine)
|
184
|
+
when Arel::Nodes::Join
|
185
|
+
table_finder.call(x.left)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
table_finder.call(core.froms)
|
189
|
+
end if ActiveRecord::VERSION::STRING < '3.2'
|
190
|
+
|
191
|
+
def primary_key_from_table t
|
192
|
+
return unless t
|
193
|
+
return t.primary_key if t.primary_key
|
194
|
+
|
195
|
+
engine = t.engine
|
196
|
+
if engine_pk = engine.primary_key
|
197
|
+
pk = engine.arel_table[engine_pk]
|
198
|
+
return pk if pk
|
199
|
+
end
|
200
|
+
|
201
|
+
pk = (@primary_keys ||= {}).fetch(table_name = engine.table_name) do
|
202
|
+
pk_name = @connection.primary_key(table_name)
|
203
|
+
# some tables might be without primary key
|
204
|
+
@primary_keys[table_name] = pk_name && t[pk_name]
|
205
|
+
end
|
206
|
+
return pk if pk
|
207
|
+
|
208
|
+
column_name = engine.columns.first.try(:name)
|
209
|
+
column_name && t[column_name]
|
210
|
+
end
|
211
|
+
|
212
|
+
include ArJdbc::MSSQL::LockMethods
|
213
|
+
|
214
|
+
include ArJdbc::MSSQL::LimitHelpers::SqlServerReplaceLimitOffset
|
215
|
+
|
216
|
+
end
|
217
|
+
|
218
|
+
class SQLServer2000 < SQLServer
|
219
|
+
include ArJdbc::MSSQL::LimitHelpers::SqlServer2000ReplaceLimitOffset
|
220
|
+
end
|
221
|
+
|
222
|
+
load 'arel/visitors/sql_server/ng42.rb' if ArJdbc::AR42
|
223
|
+
|
224
|
+
end
|
225
|
+
end
|
@@ -0,0 +1,293 @@
|
|
1
|
+
module Arel
|
2
|
+
module Visitors
|
3
|
+
class SQLServerNG < SQLServer # Arel::Visitors::ToSql
|
4
|
+
|
5
|
+
OFFSET = " OFFSET "
|
6
|
+
ROWS = " ROWS"
|
7
|
+
FETCH = " FETCH NEXT "
|
8
|
+
FETCH0 = " FETCH FIRST (SELECT 0) "
|
9
|
+
ROWS_ONLY = " ROWS ONLY"
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
# SQLServer ToSql/Visitor (Overides)
|
14
|
+
|
15
|
+
#def visit_Arel_Nodes_BindParam o, collector
|
16
|
+
# collector.add_bind(o) { |i| "@#{i-1}" }
|
17
|
+
#end
|
18
|
+
|
19
|
+
def visit_Arel_Nodes_Bin o, collector
|
20
|
+
visit o.expr, collector
|
21
|
+
if o.expr.val.is_a? Numeric
|
22
|
+
collector
|
23
|
+
else
|
24
|
+
collector << " #{::ArJdbc::MSSQL.cs_equality_operator} "
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def visit_Arel_Nodes_UpdateStatement(o, a)
|
29
|
+
if o.orders.any? && o.limit.nil?
|
30
|
+
o.limit = Nodes::Limit.new(9_223_372_036_854_775_807)
|
31
|
+
end
|
32
|
+
super
|
33
|
+
end
|
34
|
+
|
35
|
+
def visit_Arel_Nodes_Lock o, collector
|
36
|
+
o.expr = Arel.sql('WITH(UPDLOCK)') if o.expr.to_s =~ /FOR UPDATE/
|
37
|
+
collector << SPACE
|
38
|
+
visit o.expr, collector
|
39
|
+
end
|
40
|
+
|
41
|
+
def visit_Arel_Nodes_Offset o, collector
|
42
|
+
collector << OFFSET
|
43
|
+
visit o.expr, collector
|
44
|
+
collector << ROWS
|
45
|
+
end
|
46
|
+
|
47
|
+
def visit_Arel_Nodes_Limit o, collector
|
48
|
+
if node_value(o) == 0
|
49
|
+
collector << FETCH0
|
50
|
+
collector << ROWS_ONLY
|
51
|
+
else
|
52
|
+
collector << FETCH
|
53
|
+
visit o.expr, collector
|
54
|
+
collector << ROWS_ONLY
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def visit_Arel_Nodes_SelectStatement o, collector
|
59
|
+
distinct_One_As_One_Is_So_Not_Fetch o
|
60
|
+
|
61
|
+
set_select_statement_lock o.lock
|
62
|
+
|
63
|
+
if o.with
|
64
|
+
collector = visit o.with, collector
|
65
|
+
collector << SPACE
|
66
|
+
end
|
67
|
+
|
68
|
+
return _visit_Arel_Nodes_SelectStatement(o, collector) if ! o.limit && ! o.offset
|
69
|
+
|
70
|
+
# collector = o.cores.inject(collector) { |c,x|
|
71
|
+
# visit_Arel_Nodes_SelectCore(x, c)
|
72
|
+
# }
|
73
|
+
|
74
|
+
unless o.orders.empty?
|
75
|
+
select_order_by = do_visit_columns o.orders, collector, 'ORDER BY '
|
76
|
+
end
|
77
|
+
|
78
|
+
select_count = false
|
79
|
+
collector = o.cores.inject(collector) do |c, x|
|
80
|
+
unless core_order_by = select_order_by
|
81
|
+
core_order_by = generate_order_by determine_order_by(o, x)
|
82
|
+
end
|
83
|
+
|
84
|
+
if select_count? x
|
85
|
+
x.projections = [ Arel::Nodes::SqlLiteral.new(over_row_num(core_order_by)) ]
|
86
|
+
select_count = true
|
87
|
+
else
|
88
|
+
# NOTE: this should really be added here and we should built the
|
89
|
+
# wrapping SQL but than #replace_limit_offset! assumes it does that
|
90
|
+
# ... MS-SQL adapter code seems to be 'hacked' by a lot of people
|
91
|
+
#x.projections << Arel::Nodes::SqlLiteral.new(over_row_num(select_order_by))
|
92
|
+
end if core_order_by
|
93
|
+
visit_Arel_Nodes_SelectCore(x, c)
|
94
|
+
end
|
95
|
+
# END collector = o.cores.inject(collector) { |c,x|
|
96
|
+
|
97
|
+
# collector = visit_Orders_And_Let_Fetch_Happen o, collector
|
98
|
+
# collector = visit_Make_Fetch_Happen o, collector
|
99
|
+
# collector # __method__ END
|
100
|
+
|
101
|
+
self.class.collector_proxy(collector) do |sql|
|
102
|
+
select_order_by ||= "ORDER BY #{@connection.determine_order_clause(sql)}"
|
103
|
+
replace_limit_offset!(sql, limit_for(o.limit), o.offset && o.offset.value.to_i, select_order_by)
|
104
|
+
sql = "SELECT COUNT(*) AS count_id FROM (#{sql}) AS subquery" if select_count
|
105
|
+
sql
|
106
|
+
end
|
107
|
+
|
108
|
+
ensure
|
109
|
+
set_select_statement_lock nil
|
110
|
+
end
|
111
|
+
|
112
|
+
def visit_Arel_Nodes_JoinSource o, collector
|
113
|
+
if o.left
|
114
|
+
collector = visit o.left, collector
|
115
|
+
collector = visit_Arel_Nodes_SelectStatement_SQLServer_Lock collector
|
116
|
+
end
|
117
|
+
if o.right.any?
|
118
|
+
collector << " " if o.left
|
119
|
+
collector = inject_join o.right, collector, ' '
|
120
|
+
end
|
121
|
+
collector
|
122
|
+
end
|
123
|
+
|
124
|
+
def visit_Arel_Nodes_OuterJoin o, collector
|
125
|
+
collector << "LEFT OUTER JOIN "
|
126
|
+
collector = visit o.left, collector
|
127
|
+
collector = visit_Arel_Nodes_SelectStatement_SQLServer_Lock collector, space: true
|
128
|
+
collector << " "
|
129
|
+
visit o.right, collector
|
130
|
+
end
|
131
|
+
|
132
|
+
# SQLServer ToSql/Visitor (Additions)
|
133
|
+
|
134
|
+
def visit_Arel_Nodes_SelectStatement_SQLServer_Lock collector, options = {}
|
135
|
+
if lock = select_statement_lock
|
136
|
+
collector = visit lock, collector
|
137
|
+
collector << SPACE if options[:space]
|
138
|
+
end
|
139
|
+
collector
|
140
|
+
end
|
141
|
+
|
142
|
+
def visit_Orders_And_Let_Fetch_Happen o, collector
|
143
|
+
make_Fetch_Possible_And_Deterministic o
|
144
|
+
unless o.orders.empty?
|
145
|
+
collector << SPACE
|
146
|
+
collector << ORDER_BY
|
147
|
+
len = o.orders.length - 1
|
148
|
+
o.orders.each_with_index { |x, i|
|
149
|
+
collector = visit(x, collector)
|
150
|
+
collector << COMMA unless len == i
|
151
|
+
}
|
152
|
+
end
|
153
|
+
collector
|
154
|
+
end
|
155
|
+
|
156
|
+
def visit_Make_Fetch_Happen o, collector
|
157
|
+
o.offset = Nodes::Offset.new(0) if o.limit && !o.offset
|
158
|
+
collector = visit o.offset, collector if o.offset
|
159
|
+
collector = visit o.limit, collector if o.limit
|
160
|
+
collector
|
161
|
+
end
|
162
|
+
|
163
|
+
# SQLServer Helpers
|
164
|
+
|
165
|
+
# attr_reader :select_statement_lock
|
166
|
+
def select_statement_lock
|
167
|
+
Thread.current[:'Arel::Visitors::SQLServerNG.select_statement_lock']
|
168
|
+
end
|
169
|
+
|
170
|
+
def set_select_statement_lock(lock) # @select_statement_lock = lock
|
171
|
+
Thread.current[:'Arel::Visitors::SQLServerNG.select_statement_lock'] = lock
|
172
|
+
end
|
173
|
+
|
174
|
+
def make_Fetch_Possible_And_Deterministic o
|
175
|
+
return if o.limit.nil? && o.offset.nil?
|
176
|
+
if o.orders.empty? # ORDER BY mandatory with OFFSET FETCH clause
|
177
|
+
t = table_From_Statement o
|
178
|
+
pk = primary_Key_From_Table t
|
179
|
+
return unless pk
|
180
|
+
# Prefer deterministic vs a simple `(SELECT NULL)` expr.
|
181
|
+
o.orders = [ pk.asc ]
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def distinct_One_As_One_Is_So_Not_Fetch o
|
186
|
+
core = o.cores.first
|
187
|
+
distinct = Nodes::Distinct === core.set_quantifier
|
188
|
+
oneasone = core.projections.all? { |x| x == ActiveRecord::FinderMethods::ONE_AS_ONE }
|
189
|
+
limitone = node_value(o.limit) == 1
|
190
|
+
if distinct && oneasone && limitone && !o.offset
|
191
|
+
core.projections = [Arel.sql("TOP(1) 1 AS [one]")]
|
192
|
+
o.limit = nil
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def table_From_Statement o
|
197
|
+
core = o.cores.first
|
198
|
+
if Arel::Table === core.from
|
199
|
+
core.from
|
200
|
+
elsif Arel::Nodes::SqlLiteral === core.from
|
201
|
+
Arel::Table.new(core.from)
|
202
|
+
elsif Arel::Nodes::JoinSource === core.source
|
203
|
+
Arel::Nodes::SqlLiteral === core.source.left ? Arel::Table.new(core.source.left, @engine) : core.source.left
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def primary_Key_From_Table t
|
208
|
+
return unless t
|
209
|
+
return t.primary_key if t.primary_key
|
210
|
+
if engine_pk = t.engine.primary_key
|
211
|
+
pk = t.engine.arel_table[engine_pk]
|
212
|
+
return pk if pk
|
213
|
+
end
|
214
|
+
pk = t.engine.connection.schema_cache.primary_keys(t.engine.table_name)
|
215
|
+
return pk if pk
|
216
|
+
column_name = t.engine.columns.first.try(:name)
|
217
|
+
column_name ? t[column_name] : nil
|
218
|
+
end
|
219
|
+
|
220
|
+
def determine_order_by o, x
|
221
|
+
if o.orders.any?
|
222
|
+
o.orders
|
223
|
+
elsif x.groups.any?
|
224
|
+
x.groups
|
225
|
+
else
|
226
|
+
pk = find_left_table_pk(x)
|
227
|
+
pk ? [ pk ] : nil # []
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
def generate_order_by orders
|
232
|
+
do_visit_columns orders, nil, 'ORDER BY '
|
233
|
+
end
|
234
|
+
|
235
|
+
SQLString = ActiveRecord::ConnectionAdapters::AbstractAdapter::SQLString
|
236
|
+
# BindCollector = ActiveRecord::ConnectionAdapters::AbstractAdapter::BindCollector
|
237
|
+
|
238
|
+
def self.collector_proxy(collector, &block)
|
239
|
+
if collector.is_a?(SQLString)
|
240
|
+
return SQLStringProxy.new(collector, block)
|
241
|
+
end
|
242
|
+
BindCollectorProxy.new(collector, block)
|
243
|
+
end
|
244
|
+
|
245
|
+
class BindCollectorProxy < ActiveRecord::ConnectionAdapters::AbstractAdapter::BindCollector
|
246
|
+
|
247
|
+
def initialize(collector, block); @delegate = collector; @block = block end
|
248
|
+
|
249
|
+
def << str; @delegate << str; self end
|
250
|
+
|
251
|
+
def add_bind bind; @delegate.add_bind bind; self end
|
252
|
+
|
253
|
+
def value; @delegate.value; end
|
254
|
+
|
255
|
+
#def substitute_binds bvs; @delegate.substitute_binds(bvs); self end
|
256
|
+
|
257
|
+
def compile(bvs, conn)
|
258
|
+
_yield_str @delegate.compile(bvs, conn)
|
259
|
+
end
|
260
|
+
|
261
|
+
private
|
262
|
+
|
263
|
+
def method_missing(name, *args, &block); @delegate.send(name, args, &block) end
|
264
|
+
|
265
|
+
def _yield_str(str); @block ? @block.call(str) : str end
|
266
|
+
|
267
|
+
end
|
268
|
+
|
269
|
+
class SQLStringProxy < ActiveRecord::ConnectionAdapters::AbstractAdapter::SQLString
|
270
|
+
|
271
|
+
def initialize(collector, block); @delegate = collector; @block = block end
|
272
|
+
|
273
|
+
def << str; @delegate << str; self end
|
274
|
+
|
275
|
+
def add_bind bind; @delegate.add_bind bind; self end
|
276
|
+
|
277
|
+
def compile(bvs, conn)
|
278
|
+
_yield_str @delegate.compile(bvs, conn)
|
279
|
+
end
|
280
|
+
|
281
|
+
private
|
282
|
+
|
283
|
+
def method_missing(name, *args, &block); @delegate.send(name, args, &block) end
|
284
|
+
|
285
|
+
def _yield_str(str); @block ? @block.call(str) : str end
|
286
|
+
|
287
|
+
end
|
288
|
+
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
Arel::Visitors::VISITORS['mssql'] = Arel::Visitors::VISITORS['sqlserver'] = Arel::Visitors::SQLServerNG
|