activerecord-jdbc-adapter 70.0-java → 70.1-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/Rakefile +1 -1
- data/activerecord-jdbc-adapter.gemspec +1 -1
- data/lib/arel/visitors/compat.rb +5 -33
- data/lib/arel/visitors/h2.rb +1 -13
- data/lib/arel/visitors/hsqldb.rb +1 -21
- data/lib/arel/visitors/sql_server.rb +2 -103
- data/lib/arjdbc/abstract/database_statements.rb +8 -0
- data/lib/arjdbc/discover.rb +0 -67
- data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
- data/lib/arjdbc/jdbc/column.rb +1 -26
- data/lib/arjdbc/jdbc.rb +0 -7
- data/lib/arjdbc/oracle/adapter.rb +3 -22
- data/lib/arjdbc/postgresql/adapter.rb +152 -3
- data/lib/arjdbc/postgresql/oid_types.rb +155 -108
- data/lib/arjdbc/sqlite3/adapter.rb +27 -18
- data/lib/arjdbc/tasks/database_tasks.rb +0 -15
- data/lib/arjdbc/util/serialized_attributes.rb +0 -22
- data/lib/arjdbc/version.rb +1 -1
- data/rakelib/02-test.rake +3 -18
- data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +5 -0
- metadata +2 -35
- data/lib/active_record/connection_adapters/as400_adapter.rb +0 -2
- data/lib/active_record/connection_adapters/db2_adapter.rb +0 -1
- data/lib/active_record/connection_adapters/derby_adapter.rb +0 -1
- data/lib/active_record/connection_adapters/informix_adapter.rb +0 -1
- data/lib/arel/visitors/db2.rb +0 -137
- data/lib/arel/visitors/derby.rb +0 -112
- data/lib/arel/visitors/firebird.rb +0 -79
- data/lib/arjdbc/db2/adapter.rb +0 -808
- data/lib/arjdbc/db2/as400.rb +0 -142
- data/lib/arjdbc/db2/column.rb +0 -131
- data/lib/arjdbc/db2/connection_methods.rb +0 -48
- data/lib/arjdbc/db2.rb +0 -4
- data/lib/arjdbc/derby/active_record_patch.rb +0 -13
- data/lib/arjdbc/derby/adapter.rb +0 -521
- data/lib/arjdbc/derby/connection_methods.rb +0 -20
- data/lib/arjdbc/derby/schema_creation.rb +0 -15
- data/lib/arjdbc/derby.rb +0 -3
- data/lib/arjdbc/firebird/adapter.rb +0 -413
- data/lib/arjdbc/firebird/connection_methods.rb +0 -23
- data/lib/arjdbc/firebird.rb +0 -4
- data/lib/arjdbc/informix/adapter.rb +0 -139
- data/lib/arjdbc/informix/connection_methods.rb +0 -9
- data/lib/arjdbc/sybase/adapter.rb +0 -47
- data/lib/arjdbc/sybase.rb +0 -2
- data/lib/arjdbc/tasks/db2_database_tasks.rb +0 -104
- data/lib/arjdbc/tasks/derby_database_tasks.rb +0 -95
- data/src/java/arjdbc/derby/DerbyModule.java +0 -178
- data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +0 -152
- data/src/java/arjdbc/firebird/FirebirdRubyJdbcConnection.java +0 -174
- data/src/java/arjdbc/informix/InformixRubyJdbcConnection.java +0 -75
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '095c3d28051b253315cdd1bec95a83683f3240b0f3315cfb8f9c3c4c0d124f41'
|
4
|
+
data.tar.gz: 13b5d48e4c1b0b16811da5a361cfd9bb687727b5bbad2f5b750540b0232408ee
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bc4801f970c8651e0ce8076b6544bf56d0e4decd77a9463439a8d5692f767aab896786680197c25b52d510465837290604970689b1b6cba26708385038f1fa39
|
7
|
+
data.tar.gz: 47e1df847914baefffadb80537b1ffd9dfcb218b2f5bfd26addefad934be7b31a0ade446c5838bea88b81897c34b13a7cef8e6b840540e89f4627f950949549c
|
data/Rakefile
CHANGED
@@ -26,7 +26,7 @@
|
|
26
26
|
|
27
27
|
require 'rake/clean'
|
28
28
|
|
29
|
-
CLEAN.include '
|
29
|
+
CLEAN.include 'test.db.*', '*test.sqlite3', 'test/reports'
|
30
30
|
CLEAN.include 'lib/**/*.jar', 'MANIFEST.MF', '*.log', 'target/*'
|
31
31
|
|
32
32
|
task :default => :jar # RubyGems extention will do a bare `rake' e.g. :
|
@@ -47,6 +47,6 @@ Gem::Specification.new do |gem|
|
|
47
47
|
#gem.add_development_dependency 'test-unit-context', '>= 0.3.0'
|
48
48
|
#gem.add_development_dependency 'mocha', '~> 0.13.1'
|
49
49
|
|
50
|
-
gem.rdoc_options = ["--main", "README.md"
|
50
|
+
gem.rdoc_options = ["--main", "README.md"]
|
51
51
|
end
|
52
52
|
|
data/lib/arel/visitors/compat.rb
CHANGED
@@ -4,44 +4,16 @@ module Arel
|
|
4
4
|
|
5
5
|
protected
|
6
6
|
|
7
|
-
|
8
|
-
def do_visit(x, a); visit(x); end # a = nil
|
9
|
-
else # > AREL 4.0
|
10
|
-
def do_visit(x, a); visit(x, a); end
|
11
|
-
end
|
7
|
+
def do_visit(x, a); visit(x, a); end
|
12
8
|
|
13
|
-
|
14
|
-
|
15
|
-
visit_Arel_Nodes_SelectCore(x)
|
16
|
-
end
|
17
|
-
else # > AREL 4.0
|
18
|
-
def do_visit_select_core(x, a)
|
19
|
-
visit_Arel_Nodes_SelectCore(x, a)
|
20
|
-
end
|
9
|
+
def do_visit_select_core(x, a)
|
10
|
+
visit_Arel_Nodes_SelectCore(x, a)
|
21
11
|
end
|
22
12
|
|
23
13
|
private
|
24
14
|
|
25
|
-
|
26
|
-
|
27
|
-
def limit_for(limit_or_node)
|
28
|
-
if limit_or_node.respond_to?(:expr)
|
29
|
-
expr = limit_or_node.expr
|
30
|
-
# NOTE(uwe): Different behavior for Arel 6.0.0 and 6.0.2
|
31
|
-
expr.respond_to?(:value) ? expr.value.to_i : expr.to_i
|
32
|
-
else
|
33
|
-
limit_or_node
|
34
|
-
end
|
35
|
-
end
|
36
|
-
else
|
37
|
-
def limit_for(limit_or_node)
|
38
|
-
limit_or_node.respond_to?(:expr) ? limit_or_node.expr.to_i : limit_or_node
|
39
|
-
end
|
40
|
-
end
|
41
|
-
else
|
42
|
-
def limit_for(limit_or_node)
|
43
|
-
limit_or_node.respond_to?(:expr) ? limit_or_node.expr.to_i : limit_or_node
|
44
|
-
end
|
15
|
+
def limit_for(limit_or_node)
|
16
|
+
limit_or_node.respond_to?(:expr) ? limit_or_node.expr.to_i : limit_or_node
|
45
17
|
end
|
46
18
|
module_function :limit_for
|
47
19
|
|
data/lib/arel/visitors/h2.rb
CHANGED
@@ -7,19 +7,7 @@ module Arel
|
|
7
7
|
def visit_Arel_Nodes_SelectStatement(o, *)
|
8
8
|
o.limit ||= Arel::Nodes::Limit.new(-1) if o.offset
|
9
9
|
super
|
10
|
-
end
|
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
|
10
|
+
end
|
23
11
|
end
|
24
12
|
end
|
25
13
|
end
|
data/lib/arel/visitors/hsqldb.rb
CHANGED
@@ -6,27 +6,7 @@ module Arel
|
|
6
6
|
def visit_Arel_Nodes_SelectStatement(o, *)
|
7
7
|
o.limit ||= Arel::Nodes::Limit.new(0) if o.offset
|
8
8
|
super
|
9
|
-
end
|
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
|
9
|
+
end
|
30
10
|
end
|
31
11
|
end
|
32
12
|
end
|
@@ -11,44 +11,6 @@ module Arel
|
|
11
11
|
|
12
12
|
private
|
13
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
14
|
# @private
|
53
15
|
MAX_LIMIT_VALUE = 9_223_372_036_854_775_807
|
54
16
|
|
@@ -60,14 +22,6 @@ module Arel
|
|
60
22
|
super
|
61
23
|
end
|
62
24
|
|
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
25
|
def visit_Arel_Nodes_Top o, a = nil
|
72
26
|
# `top` wouldn't really work here:
|
73
27
|
# User.select("distinct first_name").limit(10)
|
@@ -76,29 +30,6 @@ module Arel
|
|
76
30
|
a || ''
|
77
31
|
end
|
78
32
|
|
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
33
|
private
|
103
34
|
|
104
35
|
def self.possibly_private_method_defined?(name)
|
@@ -140,25 +71,7 @@ module Arel
|
|
140
71
|
visit(x, sql); sql << ', ' unless i == last
|
141
72
|
end
|
142
73
|
sql.value
|
143
|
-
end
|
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'
|
74
|
+
end
|
162
75
|
|
163
76
|
def over_row_num order_by
|
164
77
|
"ROW_NUMBER() OVER (#{order_by}) as _row_num"
|
@@ -174,20 +87,6 @@ module Arel
|
|
174
87
|
end
|
175
88
|
end
|
176
89
|
|
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
90
|
def primary_key_from_table t
|
192
91
|
return unless t
|
193
92
|
return t.primary_key if t.primary_key
|
@@ -219,7 +118,7 @@ module Arel
|
|
219
118
|
include ArJdbc::MSSQL::LimitHelpers::SqlServer2000ReplaceLimitOffset
|
220
119
|
end
|
221
120
|
|
222
|
-
load 'arel/visitors/sql_server/ng42.rb'
|
121
|
+
load 'arel/visitors/sql_server/ng42.rb'
|
223
122
|
|
224
123
|
end
|
225
124
|
end
|
@@ -10,6 +10,8 @@ module ArJdbc
|
|
10
10
|
NO_BINDS = [].freeze
|
11
11
|
|
12
12
|
def exec_insert(sql, name = nil, binds = NO_BINDS, pk = nil, sequence_name = nil)
|
13
|
+
sql = transform_query(sql)
|
14
|
+
|
13
15
|
if preventing_writes?
|
14
16
|
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
|
15
17
|
end
|
@@ -31,6 +33,8 @@ module ArJdbc
|
|
31
33
|
# It appears that at this point (AR 5.0) "prepare" should only ever be true
|
32
34
|
# if prepared statements are enabled
|
33
35
|
def exec_query(sql, name = nil, binds = NO_BINDS, prepare: false, async: false)
|
36
|
+
sql = transform_query(sql)
|
37
|
+
|
34
38
|
if preventing_writes? && write_query?(sql)
|
35
39
|
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
|
36
40
|
end
|
@@ -52,6 +56,8 @@ module ArJdbc
|
|
52
56
|
end
|
53
57
|
|
54
58
|
def exec_update(sql, name = nil, binds = NO_BINDS)
|
59
|
+
sql = transform_query(sql)
|
60
|
+
|
55
61
|
if preventing_writes?
|
56
62
|
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
|
57
63
|
end
|
@@ -70,6 +76,8 @@ module ArJdbc
|
|
70
76
|
alias :exec_delete :exec_update
|
71
77
|
|
72
78
|
def execute(sql, name = nil, async: false)
|
79
|
+
sql = transform_query(sql)
|
80
|
+
|
73
81
|
if preventing_writes? && write_query?(sql)
|
74
82
|
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
|
75
83
|
end
|
data/lib/arjdbc/discover.rb
CHANGED
@@ -23,26 +23,6 @@ module ArJdbc
|
|
23
23
|
require('arjdbc/sqlite3') || true if name =~ /sqlite/i
|
24
24
|
end
|
25
25
|
|
26
|
-
# Other supported adapters :
|
27
|
-
|
28
|
-
extension :Derby do |name, config|
|
29
|
-
if name =~ /derby/i
|
30
|
-
require 'arjdbc/derby'
|
31
|
-
|
32
|
-
if config && config[:username].nil? # set the database schema name (:username) :
|
33
|
-
begin
|
34
|
-
ArJdbc.with_meta_data_from_data_source_if_any(config) do
|
35
|
-
|meta_data| config[:username] = meta_data.getUserName
|
36
|
-
end
|
37
|
-
rescue => e
|
38
|
-
ArJdbc.warn("failed to set :username from (Derby) database meda-data: #{e.inspect}")
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
true
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
26
|
extension :H2 do |name|
|
47
27
|
require('arjdbc/h2') || true if name =~ /\.h2\./i
|
48
28
|
end
|
@@ -54,51 +34,4 @@ module ArJdbc
|
|
54
34
|
extension :MSSQL do |name|
|
55
35
|
require('arjdbc/mssql') || true if name =~ /sqlserver|tds|Microsoft SQL/i
|
56
36
|
end
|
57
|
-
|
58
|
-
extension :DB2 do |name, config|
|
59
|
-
if name =~ /db2/i && name !~ /as\/?400/i && config[:url] !~ /^jdbc:derby:net:/
|
60
|
-
require 'arjdbc/db2'
|
61
|
-
true
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
extension :AS400 do |name, config|
|
66
|
-
# The native JDBC driver always returns "DB2 UDB for AS/400"
|
67
|
-
if name =~ /as\/?400/i
|
68
|
-
require 'arjdbc/db2'
|
69
|
-
require 'arjdbc/db2/as400'
|
70
|
-
true
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
# NOTE: following ones are likely getting deprecated :
|
75
|
-
|
76
|
-
extension :FireBird do |name|
|
77
|
-
if name =~ /firebird/i
|
78
|
-
require 'arjdbc/firebird'
|
79
|
-
true
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
extension :Sybase do |name|
|
84
|
-
if name =~ /sybase|tds/i
|
85
|
-
require 'arjdbc/sybase'
|
86
|
-
true
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
extension :Informix do |name|
|
91
|
-
if name =~ /informix/i
|
92
|
-
require 'arjdbc/informix'
|
93
|
-
true
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
extension :Mimer do |name|
|
98
|
-
if name =~ /mimer/i
|
99
|
-
require 'arjdbc/mimer'
|
100
|
-
true
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
37
|
end
|
Binary file
|
data/lib/arjdbc/jdbc/column.rb
CHANGED
@@ -28,21 +28,6 @@ module ActiveRecord
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
-
if ArJdbc::AR52
|
32
|
-
# undefined method `cast' for #<ActiveRecord::ConnectionAdapters::SqlTypeMetadata> on AR52
|
33
|
-
else
|
34
|
-
default = args[0].cast(default)
|
35
|
-
|
36
|
-
sql_type = args.delete_at(1)
|
37
|
-
type = args.delete_at(0)
|
38
|
-
|
39
|
-
args.unshift(SqlTypeMetadata.new(:sql_type => sql_type, :type => type))
|
40
|
-
end
|
41
|
-
|
42
|
-
# super <= 4.1: (name, default, sql_type = nil, null = true)
|
43
|
-
# super >= 4.2: (name, default, cast_type, sql_type = nil, null = true)
|
44
|
-
# super >= 5.0: (name, default, sql_type_metadata = nil, null = true)
|
45
|
-
|
46
31
|
super(name, default, *args)
|
47
32
|
init_column(name, default, *args)
|
48
33
|
end
|
@@ -80,18 +65,8 @@ module ActiveRecord
|
|
80
65
|
end
|
81
66
|
|
82
67
|
class << self
|
83
|
-
|
84
|
-
include Jdbc::TypeCast if ::ActiveRecord::VERSION::STRING >= '4.2'
|
85
|
-
|
86
|
-
if ActiveRecord::VERSION::MAJOR > 3 && ActiveRecord::VERSION::STRING < '4.2'
|
87
|
-
|
88
|
-
# @private provides compatibility between AR 3.x/4.0 API
|
89
|
-
def string_to_date(value); value_to_date(value) end
|
90
|
-
|
91
|
-
end
|
92
|
-
|
68
|
+
include Jdbc::TypeCast
|
93
69
|
end
|
94
|
-
|
95
70
|
end
|
96
71
|
end
|
97
72
|
end
|
data/lib/arjdbc/jdbc.rb
CHANGED
@@ -285,7 +285,7 @@ module ArJdbc
|
|
285
285
|
execute "ALTER TABLE #{quote_table_name(table_name)} ADD CONSTRAINT #{quote_column_name(index_name)} #{index_type} (#{quoted_column_names})"
|
286
286
|
end
|
287
287
|
end
|
288
|
-
end
|
288
|
+
end
|
289
289
|
|
290
290
|
# @private
|
291
291
|
def add_index_options(table_name, column_name, options = {})
|
@@ -309,7 +309,7 @@ module ArJdbc
|
|
309
309
|
|
310
310
|
quoted_column_names = column_names.map { |e| quote_column_name_or_expression(e) }.join(", ")
|
311
311
|
[ index_name, index_type, quoted_column_names, tablespace, index_options ]
|
312
|
-
end
|
312
|
+
end
|
313
313
|
|
314
314
|
# @override
|
315
315
|
def remove_index(table_name, options = {})
|
@@ -327,12 +327,7 @@ module ArJdbc
|
|
327
327
|
end
|
328
328
|
execute "ALTER TABLE #{quote_table_name(table_name)} DROP CONSTRAINT #{quote_column_name(index_name)}" rescue nil
|
329
329
|
execute "DROP INDEX #{quote_column_name(index_name)}"
|
330
|
-
end
|
331
|
-
|
332
|
-
# @private
|
333
|
-
def remove_index(table_name, options = {})
|
334
|
-
execute "DROP INDEX #{index_name(table_name, options)}"
|
335
|
-
end unless AR42
|
330
|
+
end
|
336
331
|
|
337
332
|
def change_column_default(table_name, column_name, default)
|
338
333
|
execute "ALTER TABLE #{quote_table_name(table_name)} MODIFY #{quote_column_name(column_name)} DEFAULT #{quote(default)}"
|
@@ -361,25 +356,11 @@ module ArJdbc
|
|
361
356
|
"RENAME COLUMN #{quote_column_name(column_name)} TO #{quote_column_name(new_column_name)}"
|
362
357
|
end
|
363
358
|
|
364
|
-
if ActiveRecord::VERSION::MAJOR >= 4
|
365
|
-
|
366
359
|
# @override
|
367
360
|
def remove_column(table_name, column_name, type = nil, options = {})
|
368
361
|
do_remove_column(table_name, column_name)
|
369
362
|
end
|
370
363
|
|
371
|
-
else
|
372
|
-
|
373
|
-
# @override
|
374
|
-
def remove_column(table_name, *column_names)
|
375
|
-
for column_name in column_names.flatten
|
376
|
-
do_remove_column(table_name, column_name)
|
377
|
-
end
|
378
|
-
end
|
379
|
-
alias remove_columns remove_column
|
380
|
-
|
381
|
-
end
|
382
|
-
|
383
364
|
def do_remove_column(table_name, column_name)
|
384
365
|
execute "ALTER TABLE #{quote_table_name(table_name)} DROP COLUMN #{quote_column_name(column_name)}"
|
385
366
|
end
|
@@ -21,6 +21,7 @@ require 'arjdbc/abstract/transaction_support'
|
|
21
21
|
require 'arjdbc/postgresql/base/array_decoder'
|
22
22
|
require 'arjdbc/postgresql/base/array_encoder'
|
23
23
|
require 'arjdbc/postgresql/name'
|
24
|
+
require 'active_model'
|
24
25
|
|
25
26
|
module ArJdbc
|
26
27
|
# Strives to provide Rails built-in PostgreSQL adapter (API) compatibility.
|
@@ -320,6 +321,38 @@ module ArJdbc
|
|
320
321
|
exec_query("SELECT extname FROM pg_extension", "SCHEMA").cast_values
|
321
322
|
end
|
322
323
|
|
324
|
+
# Returns a list of defined enum types, and their values.
|
325
|
+
def enum_types
|
326
|
+
query = <<~SQL
|
327
|
+
SELECT
|
328
|
+
type.typname AS name,
|
329
|
+
string_agg(enum.enumlabel, ',' ORDER BY enum.enumsortorder) AS value
|
330
|
+
FROM pg_enum AS enum
|
331
|
+
JOIN pg_type AS type
|
332
|
+
ON (type.oid = enum.enumtypid)
|
333
|
+
GROUP BY type.typname;
|
334
|
+
SQL
|
335
|
+
exec_query(query, "SCHEMA").cast_values
|
336
|
+
end
|
337
|
+
|
338
|
+
# Given a name and an array of values, creates an enum type.
|
339
|
+
def create_enum(name, values)
|
340
|
+
sql_values = values.map { |s| "'#{s}'" }.join(", ")
|
341
|
+
query = <<~SQL
|
342
|
+
DO $$
|
343
|
+
BEGIN
|
344
|
+
IF NOT EXISTS (
|
345
|
+
SELECT 1 FROM pg_type t
|
346
|
+
WHERE t.typname = '#{name}'
|
347
|
+
) THEN
|
348
|
+
CREATE TYPE \"#{name}\" AS ENUM (#{sql_values});
|
349
|
+
END IF;
|
350
|
+
END
|
351
|
+
$$;
|
352
|
+
SQL
|
353
|
+
exec_query(query)
|
354
|
+
end
|
355
|
+
|
323
356
|
# Returns the configured supported identifier length supported by PostgreSQL
|
324
357
|
def max_identifier_length
|
325
358
|
@max_identifier_length ||= query_value("SHOW max_identifier_length", "SCHEMA").to_i
|
@@ -672,6 +705,37 @@ module ActiveRecord::ConnectionAdapters
|
|
672
705
|
class PostgreSQLAdapter < AbstractAdapter
|
673
706
|
class_attribute :create_unlogged_tables, default: false
|
674
707
|
|
708
|
+
##
|
709
|
+
# :singleton-method:
|
710
|
+
# PostgreSQL allows the creation of "unlogged" tables, which do not record
|
711
|
+
# data in the PostgreSQL Write-Ahead Log. This can make the tables faster,
|
712
|
+
# but significantly increases the risk of data loss if the database
|
713
|
+
# crashes. As a result, this should not be used in production
|
714
|
+
# environments. If you would like all created tables to be unlogged in
|
715
|
+
# the test environment you can add the following line to your test.rb
|
716
|
+
# file:
|
717
|
+
#
|
718
|
+
# ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.create_unlogged_tables = true
|
719
|
+
class_attribute :create_unlogged_tables, default: false
|
720
|
+
|
721
|
+
##
|
722
|
+
# :singleton-method:
|
723
|
+
# PostgreSQL supports multiple types for DateTimes. By default, if you use +datetime+
|
724
|
+
# in migrations, Rails will translate this to a PostgreSQL "timestamp without time zone".
|
725
|
+
# Change this in an initializer to use another NATIVE_DATABASE_TYPES. For example, to
|
726
|
+
# store DateTimes as "timestamp with time zone":
|
727
|
+
#
|
728
|
+
# ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.datetime_type = :timestamptz
|
729
|
+
#
|
730
|
+
# Or if you are adding a custom type:
|
731
|
+
#
|
732
|
+
# ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::NATIVE_DATABASE_TYPES[:my_custom_type] = { name: "my_custom_type_name" }
|
733
|
+
# ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.datetime_type = :my_custom_type
|
734
|
+
#
|
735
|
+
# If you're using +:ruby+ as your +config.active_record.schema_format+ and you change this
|
736
|
+
# setting, you should immediately run <tt>bin/rails db:migrate</tt> to update the types in your schema.rb.
|
737
|
+
class_attribute :datetime_type, default: :timestamp
|
738
|
+
|
675
739
|
# Try to use as much of the built in postgres logic as possible
|
676
740
|
# maybe someday we can extend the actual adapter
|
677
741
|
include ActiveRecord::ConnectionAdapters::PostgreSQL::ReferentialIntegrity
|
@@ -735,11 +799,96 @@ module ActiveRecord::ConnectionAdapters
|
|
735
799
|
|
736
800
|
private
|
737
801
|
|
738
|
-
|
739
|
-
|
802
|
+
FEATURE_NOT_SUPPORTED = "0A000" # :nodoc:
|
803
|
+
|
804
|
+
def execute_and_clear(sql, name, binds, prepare: false, async: false)
|
805
|
+
sql = transform_query(sql)
|
806
|
+
check_if_write_query(sql)
|
807
|
+
|
808
|
+
if !prepare || without_prepared_statement?(binds)
|
809
|
+
result = exec_no_cache(sql, name, binds, async: async)
|
810
|
+
else
|
811
|
+
result = exec_cache(sql, name, binds, async: async)
|
812
|
+
end
|
813
|
+
begin
|
814
|
+
ret = yield result
|
815
|
+
ensure
|
816
|
+
# Is this really result in AR PG?
|
817
|
+
# result.clear
|
818
|
+
end
|
819
|
+
ret
|
820
|
+
end
|
821
|
+
|
822
|
+
def exec_no_cache(sql, name, binds, async: false)
|
823
|
+
materialize_transactions
|
824
|
+
mark_transaction_written_if_write(sql)
|
825
|
+
|
826
|
+
# make sure we carry over any changes to ActiveRecord.default_timezone that have been
|
827
|
+
# made since we established the connection
|
828
|
+
update_typemap_for_default_timezone
|
829
|
+
|
830
|
+
type_casted_binds = type_casted_binds(binds)
|
831
|
+
log(sql, name, binds, type_casted_binds, async: async) do
|
832
|
+
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
833
|
+
@connection.exec_params(sql, type_casted_binds)
|
834
|
+
end
|
835
|
+
end
|
836
|
+
end
|
837
|
+
|
838
|
+
def exec_cache(sql, name, binds, async: false)
|
839
|
+
materialize_transactions
|
840
|
+
mark_transaction_written_if_write(sql)
|
841
|
+
update_typemap_for_default_timezone
|
842
|
+
|
843
|
+
stmt_key = prepare_statement(sql, binds)
|
844
|
+
type_casted_binds = type_casted_binds(binds)
|
845
|
+
|
846
|
+
log(sql, name, binds, type_casted_binds, stmt_key, async: async) do
|
847
|
+
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
848
|
+
@connection.exec_prepared(stmt_key, type_casted_binds)
|
849
|
+
end
|
850
|
+
end
|
851
|
+
rescue ActiveRecord::StatementInvalid => e
|
852
|
+
raise unless is_cached_plan_failure?(e)
|
853
|
+
|
854
|
+
# Nothing we can do if we are in a transaction because all commands
|
855
|
+
# will raise InFailedSQLTransaction
|
856
|
+
if in_transaction?
|
857
|
+
raise ActiveRecord::PreparedStatementCacheExpired.new(e.cause.message)
|
858
|
+
else
|
859
|
+
@lock.synchronize do
|
860
|
+
# outside of transactions we can simply flush this query and retry
|
861
|
+
@statements.delete sql_key(sql)
|
862
|
+
end
|
863
|
+
retry
|
864
|
+
end
|
865
|
+
end
|
866
|
+
|
867
|
+
# Annoyingly, the code for prepared statements whose return value may
|
868
|
+
# have changed is FEATURE_NOT_SUPPORTED.
|
869
|
+
#
|
870
|
+
# This covers various different error types so we need to do additional
|
871
|
+
# work to classify the exception definitively as a
|
872
|
+
# ActiveRecord::PreparedStatementCacheExpired
|
873
|
+
#
|
874
|
+
# Check here for more details:
|
875
|
+
# https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/backend/utils/cache/plancache.c#l573
|
876
|
+
def is_cached_plan_failure?(e)
|
877
|
+
pgerror = e.cause
|
878
|
+
pgerror.result.result_error_field(PG::PG_DIAG_SQLSTATE) == FEATURE_NOT_SUPPORTED &&
|
879
|
+
pgerror.result.result_error_field(PG::PG_DIAG_SOURCE_FUNCTION) == "RevalidateCachedQuery"
|
880
|
+
rescue
|
881
|
+
false
|
882
|
+
end
|
883
|
+
|
884
|
+
def in_transaction?
|
885
|
+
open_transactions > 0
|
886
|
+
end
|
887
|
+
|
888
|
+
# Returns the statement identifier for the client side cache
|
889
|
+
# of statements
|
740
890
|
def sql_key(sql)
|
741
891
|
"#{schema_search_path}-#{sql}"
|
742
892
|
end
|
743
|
-
|
744
893
|
end
|
745
894
|
end
|