activerecord-jdbc-alt-adapter 70.1.0-java → 71.0.0.alpha1-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 +4 -4
- data/.github/workflows/main.yml +135 -21
- data/.github/workflows/ruby.yml +10 -10
- data/.gitignore +1 -0
- data/.solargraph.yml +15 -0
- data/Gemfile +17 -4
- data/README.md +7 -3
- data/RUNNING_TESTS.md +36 -0
- data/activerecord-jdbc-adapter.gemspec +2 -2
- data/activerecord-jdbc-alt-adapter.gemspec +1 -1
- data/lib/arel/visitors/sqlserver.rb +10 -0
- data/lib/arjdbc/abstract/connection_management.rb +23 -10
- data/lib/arjdbc/abstract/core.rb +5 -6
- data/lib/arjdbc/abstract/database_statements.rb +35 -25
- data/lib/arjdbc/abstract/statement_cache.rb +1 -6
- data/lib/arjdbc/abstract/transaction_support.rb +37 -9
- data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
- data/lib/arjdbc/jdbc/column.rb +0 -34
- data/lib/arjdbc/jdbc/connection_methods.rb +1 -1
- data/lib/arjdbc/mssql/adapter.rb +93 -80
- data/lib/arjdbc/mssql/column.rb +1 -0
- data/lib/arjdbc/mssql/connection_methods.rb +7 -55
- data/lib/arjdbc/mssql/database_statements.rb +182 -71
- data/lib/arjdbc/mssql/explain_support.rb +8 -5
- data/lib/arjdbc/mssql/schema_creation.rb +1 -1
- data/lib/arjdbc/mssql/schema_definitions.rb +10 -0
- data/lib/arjdbc/mssql/schema_statements.rb +19 -11
- data/lib/arjdbc/mssql/server_version.rb +56 -0
- data/lib/arjdbc/mssql/utils.rb +23 -9
- data/lib/arjdbc/mysql/adapter.rb +64 -22
- data/lib/arjdbc/mysql/connection_methods.rb +43 -42
- data/lib/arjdbc/sqlite3/adapter.rb +218 -135
- data/lib/arjdbc/sqlite3/column.rb +103 -0
- data/lib/arjdbc/sqlite3/connection_methods.rb +7 -2
- data/lib/arjdbc/tasks/mssql_database_tasks.rb +9 -5
- data/lib/arjdbc/version.rb +1 -1
- data/rakelib/02-test.rake +1 -1
- data/rakelib/rails.rake +2 -0
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +4 -2
- data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +2 -1
- metadata +11 -14
- data/lib/arel/visitors/sql_server/ng42.rb +0 -294
- data/lib/arel/visitors/sql_server.rb +0 -124
- data/lib/arjdbc/mssql/limit_helpers.rb +0 -231
- data/lib/arjdbc/mssql/lock_methods.rb +0 -77
- data/lib/arjdbc/mssql/old_adapter.rb +0 -804
- data/lib/arjdbc/mssql/old_column.rb +0 -200
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
ArJdbc::ConnectionMethods.module_eval do
|
3
3
|
def sqlite3_connection(config)
|
4
|
+
raise ArgumentError, 'Configuration must not be empty' if config.blank?
|
5
|
+
|
4
6
|
config = config.deep_dup
|
5
7
|
config[:adapter_spec] ||= ::ArJdbc::SQLite3
|
6
8
|
config[:adapter_class] = ActiveRecord::ConnectionAdapters::SQLite3Adapter unless config.key?(:adapter_class)
|
@@ -18,7 +20,7 @@ ArJdbc::ConnectionMethods.module_eval do
|
|
18
20
|
parse_sqlite3_config!(config)
|
19
21
|
rescue Errno::ENOENT => error
|
20
22
|
if error.message.include?('No such file or directory')
|
21
|
-
raise ActiveRecord::NoDatabaseError
|
23
|
+
raise ActiveRecord::NoDatabaseError.new(connection_pool: ActiveRecord::ConnectionAdapters::NullPool.new)
|
22
24
|
else
|
23
25
|
raise
|
24
26
|
end
|
@@ -50,7 +52,10 @@ ArJdbc::ConnectionMethods.module_eval do
|
|
50
52
|
|
51
53
|
timeout = config[:timeout]
|
52
54
|
if timeout && timeout.to_s !~ /\A\d+\Z/
|
53
|
-
raise
|
55
|
+
raise ActiveRecord::StatementInvalid.new(
|
56
|
+
"TypeError: Timeout must be nil or a number (got: #{timeout}).",
|
57
|
+
connection_pool: ActiveRecord::ConnectionAdapters::NullPool.new
|
58
|
+
)
|
54
59
|
end
|
55
60
|
|
56
61
|
options = config[:properties]
|
@@ -5,10 +5,6 @@ require 'active_record/tasks/database_tasks'
|
|
5
5
|
module ArJdbc
|
6
6
|
module Tasks # :nodoc:
|
7
7
|
class MSSQLDatabaseTasks # :nodoc:
|
8
|
-
delegate :connection, to: ActiveRecord::Base
|
9
|
-
delegate :establish_connection, to: ActiveRecord::Base
|
10
|
-
delegate :clear_active_connections!, to: ActiveRecord::Base
|
11
|
-
|
12
8
|
def self.using_database_configurations?
|
13
9
|
true
|
14
10
|
end
|
@@ -45,7 +41,7 @@ module ArJdbc
|
|
45
41
|
end
|
46
42
|
|
47
43
|
def purge
|
48
|
-
clear_active_connections!
|
44
|
+
ActiveRecord::Base.connection_handler.clear_active_connections!(:all)
|
49
45
|
drop
|
50
46
|
create
|
51
47
|
end
|
@@ -70,6 +66,14 @@ module ArJdbc
|
|
70
66
|
|
71
67
|
attr_reader :db_config, :configuration_hash
|
72
68
|
|
69
|
+
def connection
|
70
|
+
ActiveRecord::Base.connection
|
71
|
+
end
|
72
|
+
|
73
|
+
def establish_connection(config = db_config)
|
74
|
+
ActiveRecord::Base.establish_connection(config)
|
75
|
+
end
|
76
|
+
|
73
77
|
def creation_options
|
74
78
|
{}.tap do |options|
|
75
79
|
options[:collation] = configuration_hash[:collation] if configuration_hash.include?(:collation)
|
data/lib/arjdbc/version.rb
CHANGED
data/rakelib/02-test.rake
CHANGED
@@ -40,7 +40,7 @@ def test_task_for(adapter, options = {})
|
|
40
40
|
test_task.libs.push *FileList["activerecord-jdbc#{adapter}*/lib"]
|
41
41
|
end
|
42
42
|
test_task.libs << 'test'
|
43
|
-
test_task.options = '--use-color=t'
|
43
|
+
test_task.options = '--use-color=t --progress-style=mark'
|
44
44
|
test_task.verbose = true if $VERBOSE
|
45
45
|
yield(test_task) if block_given?
|
46
46
|
end
|
data/rakelib/rails.rake
CHANGED
@@ -40,6 +40,7 @@ namespace :rails do
|
|
40
40
|
File.join(root_dir, 'lib'),
|
41
41
|
File.join(root_dir, driver, 'lib'),
|
42
42
|
File.join(root_dir, 'test/rails'),
|
43
|
+
File.join(root_dir, 'jdbc-sqlite3', 'lib'), # Added for connection management tests which hardcode sqlite3
|
43
44
|
ar_test_dir
|
44
45
|
]
|
45
46
|
|
@@ -57,6 +58,7 @@ namespace :rails do
|
|
57
58
|
ruby_opts_string += " -C \"#{ar_path}\""
|
58
59
|
ruby_opts_string += " -rbundler/setup"
|
59
60
|
ruby_opts_string += " -rminitest -rminitest/excludes" unless ENV['NO_EXCLUDES'].eql?('true')
|
61
|
+
ruby_opts_string += " -rmonkey_patches"
|
60
62
|
file_list = ENV["TEST"] ? FileList[ ENV["TEST"].split(',') ] : test_files_finder.call
|
61
63
|
file_list_string = file_list.map { |fn| "\"#{fn}\"" }.join(' ')
|
62
64
|
# test_loader_code = "-e \"ARGV.each{|f| require f}\"" # :direct
|
@@ -793,7 +793,8 @@ public class RubyJdbcConnection extends RubyObject {
|
|
793
793
|
// Unfortunately the result set gets closed when getMoreResults()
|
794
794
|
// is called, so we have to process the result sets as we get them
|
795
795
|
// this shouldn't be an issue in most cases since we're only getting 1 result set anyways
|
796
|
-
result = mapExecuteResult(context, connection, resultSet);
|
796
|
+
//result = mapExecuteResult(context, connection, resultSet);
|
797
|
+
result = mapToRawResult(context, connection, resultSet, false);
|
797
798
|
resultSet.close();
|
798
799
|
} else {
|
799
800
|
result = context.runtime.newFixnum(updateCount);
|
@@ -2735,8 +2736,9 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2735
2736
|
statement.setDouble(index, ((RubyNumeric) value).getDoubleValue());
|
2736
2737
|
}
|
2737
2738
|
else { // e.g. `BigDecimal '42.00000000000000000001'`
|
2739
|
+
Ruby runtime = context.runtime;
|
2738
2740
|
statement.setBigDecimal(index,
|
2739
|
-
RubyBigDecimal.newInstance(context,
|
2741
|
+
RubyBigDecimal.newInstance(context, runtime.getModule("BigDecimal"), value, RubyFixnum.zero(runtime)).getValue());
|
2740
2742
|
}
|
2741
2743
|
}
|
2742
2744
|
|
@@ -511,7 +511,8 @@ public class SQLite3RubyJdbcConnection extends RubyJdbcConnection {
|
|
511
511
|
statement.setDouble(index, ((RubyNumeric) value).getDoubleValue());
|
512
512
|
}
|
513
513
|
else { // e.g. `BigDecimal '42.00000000000000000001'`
|
514
|
-
|
514
|
+
Ruby runtime = context.runtime;
|
515
|
+
RubyBigDecimal val = RubyBigDecimal.newInstance(context, runtime.getModule("BigDecimal"), value, RubyFixnum.zero(runtime));
|
515
516
|
statement.setString(index, val.getValue().toString());
|
516
517
|
}
|
517
518
|
}
|
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-jdbc-alt-adapter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 71.0.0.alpha1
|
5
5
|
platform: java
|
6
6
|
authors:
|
7
7
|
- Nick Sieger, Ola Bini, Karol Bucek, Jesse Chavez, and JRuby contributors
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-07-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
15
15
|
requirements:
|
16
16
|
- - "~>"
|
17
17
|
- !ruby/object:Gem::Version
|
18
|
-
version: 7.
|
18
|
+
version: 7.1.3
|
19
19
|
name: activerecord
|
20
|
-
prerelease: false
|
21
20
|
type: :runtime
|
21
|
+
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 7.
|
26
|
+
version: 7.1.3
|
27
27
|
description: 'Fork of the ActiveRecord JDBC adapter with support for SQL Server and
|
28
28
|
Azure SQL, for more information and help look at the README file in the github repository.
|
29
29
|
AR-JDBC is a database adapter for Rails'' ActiveRecord component designed to be
|
@@ -42,6 +42,7 @@ files:
|
|
42
42
|
- ".github/workflows/ruby.yml"
|
43
43
|
- ".gitignore"
|
44
44
|
- ".nvimlog"
|
45
|
+
- ".solargraph.yml"
|
45
46
|
- ".travis.yml"
|
46
47
|
- ".yardopts"
|
47
48
|
- CONTRIBUTING.md
|
@@ -72,8 +73,6 @@ files:
|
|
72
73
|
- lib/arel/visitors/h2.rb
|
73
74
|
- lib/arel/visitors/hsqldb.rb
|
74
75
|
- lib/arel/visitors/postgresql_jdbc.rb
|
75
|
-
- lib/arel/visitors/sql_server.rb
|
76
|
-
- lib/arel/visitors/sql_server/ng42.rb
|
77
76
|
- lib/arel/visitors/sqlserver.rb
|
78
77
|
- lib/arjdbc.rb
|
79
78
|
- lib/arjdbc/abstract/connection_management.rb
|
@@ -118,15 +117,12 @@ files:
|
|
118
117
|
- lib/arjdbc/mssql/explain_support.rb
|
119
118
|
- lib/arjdbc/mssql/extensions/attribute_methods.rb
|
120
119
|
- lib/arjdbc/mssql/extensions/calculations.rb
|
121
|
-
- lib/arjdbc/mssql/limit_helpers.rb
|
122
|
-
- lib/arjdbc/mssql/lock_methods.rb
|
123
|
-
- lib/arjdbc/mssql/old_adapter.rb
|
124
|
-
- lib/arjdbc/mssql/old_column.rb
|
125
120
|
- lib/arjdbc/mssql/quoting.rb
|
126
121
|
- lib/arjdbc/mssql/schema_creation.rb
|
127
122
|
- lib/arjdbc/mssql/schema_definitions.rb
|
128
123
|
- lib/arjdbc/mssql/schema_dumper.rb
|
129
124
|
- lib/arjdbc/mssql/schema_statements.rb
|
125
|
+
- lib/arjdbc/mssql/server_version.rb
|
130
126
|
- lib/arjdbc/mssql/transaction.rb
|
131
127
|
- lib/arjdbc/mssql/types.rb
|
132
128
|
- lib/arjdbc/mssql/types/binary_types.rb
|
@@ -152,6 +148,7 @@ files:
|
|
152
148
|
- lib/arjdbc/railtie.rb
|
153
149
|
- lib/arjdbc/sqlite3.rb
|
154
150
|
- lib/arjdbc/sqlite3/adapter.rb
|
151
|
+
- lib/arjdbc/sqlite3/column.rb
|
155
152
|
- lib/arjdbc/sqlite3/connection_methods.rb
|
156
153
|
- lib/arjdbc/tasks.rb
|
157
154
|
- lib/arjdbc/tasks/database_tasks.rb
|
@@ -231,11 +228,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
231
228
|
version: '0'
|
232
229
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
233
230
|
requirements:
|
234
|
-
- - "
|
231
|
+
- - ">"
|
235
232
|
- !ruby/object:Gem::Version
|
236
|
-
version:
|
233
|
+
version: 1.3.1
|
237
234
|
requirements: []
|
238
|
-
rubygems_version: 3.3.
|
235
|
+
rubygems_version: 3.3.26
|
239
236
|
signing_key:
|
240
237
|
specification_version: 4
|
241
238
|
summary: ActiveRecord JDBC adapter, for use within JRuby on Rails and SQL Server
|
@@ -1,294 +0,0 @@
|
|
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
|
-
# FIXME: Arel::Visitors::VISITORS is not defined anymore
|
294
|
-
# Arel::Visitors::VISITORS['mssql'] = Arel::Visitors::VISITORS['sqlserver'] = Arel::Visitors::SQLServerNG
|
@@ -1,124 +0,0 @@
|
|
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
|
-
# @private
|
15
|
-
MAX_LIMIT_VALUE = 9_223_372_036_854_775_807
|
16
|
-
|
17
|
-
def visit_Arel_Nodes_UpdateStatement(*args) # [o] AR <= 4.0 [o, a] on 4.1
|
18
|
-
o = args.first
|
19
|
-
if o.orders.any? && o.limit.nil?
|
20
|
-
o.limit = Nodes::Limit.new(MAX_LIMIT_VALUE)
|
21
|
-
end
|
22
|
-
super
|
23
|
-
end
|
24
|
-
|
25
|
-
def visit_Arel_Nodes_Top o, a = nil
|
26
|
-
# `top` wouldn't really work here:
|
27
|
-
# User.select("distinct first_name").limit(10)
|
28
|
-
# would generate "select top 10 distinct first_name from users",
|
29
|
-
# which is invalid should be "select distinct top 10 first_name ..."
|
30
|
-
a || ''
|
31
|
-
end
|
32
|
-
|
33
|
-
private
|
34
|
-
|
35
|
-
def self.possibly_private_method_defined?(name)
|
36
|
-
private_method_defined?(name) || method_defined?(name)
|
37
|
-
end
|
38
|
-
|
39
|
-
def select_count? x
|
40
|
-
x.projections.length == 1 && Arel::Nodes::Count === x.projections.first
|
41
|
-
end unless possibly_private_method_defined? :select_count?
|
42
|
-
|
43
|
-
def determine_order_by x, a
|
44
|
-
unless x.groups.empty?
|
45
|
-
do_visit_columns x.groups, a, 'ORDER BY '
|
46
|
-
else
|
47
|
-
table_pk = find_left_table_pk(x)
|
48
|
-
table_pk && "ORDER BY #{table_pk}"
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def find_left_table_pk o
|
53
|
-
primary_key_from_table table_from_select_core(o)
|
54
|
-
end
|
55
|
-
|
56
|
-
def do_visit_columns(colls, a, sql)
|
57
|
-
last = colls.size - 1
|
58
|
-
colls.each_with_index do |x, i|
|
59
|
-
sql << do_visit(x, a); sql << ', ' unless i == last
|
60
|
-
end
|
61
|
-
sql
|
62
|
-
end
|
63
|
-
|
64
|
-
def do_visit_columns(colls, a, sql)
|
65
|
-
prefix = sql
|
66
|
-
sql = Arel::Collectors::PlainString.new
|
67
|
-
sql << prefix if prefix
|
68
|
-
|
69
|
-
last = colls.size - 1
|
70
|
-
colls.each_with_index do |x, i|
|
71
|
-
visit(x, sql); sql << ', ' unless i == last
|
72
|
-
end
|
73
|
-
sql.value
|
74
|
-
end
|
75
|
-
|
76
|
-
def over_row_num order_by
|
77
|
-
"ROW_NUMBER() OVER (#{order_by}) as _row_num"
|
78
|
-
end # unless possibly_private_method_defined? :row_num_literal
|
79
|
-
|
80
|
-
def table_from_select_core core
|
81
|
-
if Arel::Table === core.from
|
82
|
-
core.from
|
83
|
-
elsif Arel::Nodes::SqlLiteral === core.from
|
84
|
-
Arel::Table.new(core.from, @engine)
|
85
|
-
elsif Arel::Nodes::JoinSource === core.source
|
86
|
-
Arel::Nodes::SqlLiteral === core.source.left ? Arel::Table.new(core.source.left, @engine) : core.source.left
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
def primary_key_from_table t
|
91
|
-
return unless t
|
92
|
-
return t.primary_key if t.primary_key
|
93
|
-
|
94
|
-
engine = t.engine
|
95
|
-
if engine_pk = engine.primary_key
|
96
|
-
pk = engine.arel_table[engine_pk]
|
97
|
-
return pk if pk
|
98
|
-
end
|
99
|
-
|
100
|
-
pk = (@primary_keys ||= {}).fetch(table_name = engine.table_name) do
|
101
|
-
pk_name = @connection.primary_key(table_name)
|
102
|
-
# some tables might be without primary key
|
103
|
-
@primary_keys[table_name] = pk_name && t[pk_name]
|
104
|
-
end
|
105
|
-
return pk if pk
|
106
|
-
|
107
|
-
column_name = engine.columns.first.try(:name)
|
108
|
-
column_name && t[column_name]
|
109
|
-
end
|
110
|
-
|
111
|
-
include ArJdbc::MSSQL::LockMethods
|
112
|
-
|
113
|
-
include ArJdbc::MSSQL::LimitHelpers::SqlServerReplaceLimitOffset
|
114
|
-
|
115
|
-
end
|
116
|
-
|
117
|
-
class SQLServer2000 < SQLServer
|
118
|
-
include ArJdbc::MSSQL::LimitHelpers::SqlServer2000ReplaceLimitOffset
|
119
|
-
end
|
120
|
-
|
121
|
-
load 'arel/visitors/sql_server/ng42.rb'
|
122
|
-
|
123
|
-
end
|
124
|
-
end
|