activerecord-jdbc-alt-adapter 71.0.0.alpha2-java → 71.0.0-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/ruby.yml +9 -9
- data/Gemfile +2 -2
- data/README.md +3 -2
- data/lib/arel/visitors/sqlserver.rb +15 -2
- data/lib/arjdbc/abstract/connection_management.rb +5 -6
- data/lib/arjdbc/abstract/database_statements.rb +3 -13
- data/lib/arjdbc/abstract/relation_query_attribute_monkey_patch.rb +24 -0
- data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
- data/lib/arjdbc/mssql/adapter.rb +2 -0
- data/lib/arjdbc/mssql.rb +1 -1
- data/lib/arjdbc/mysql/adapter.rb +2 -0
- data/lib/arjdbc/postgresql/adapter.rb +184 -64
- data/lib/arjdbc/postgresql/database_statements.rb +20 -0
- data/lib/arjdbc/sqlite3/adapter.rb +10 -0
- data/lib/arjdbc/version.rb +1 -1
- metadata +6 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 973f3cfa750c3424b5de9105f177584edea8ebe705d50b20e4b9f6d989a4919f
|
|
4
|
+
data.tar.gz: e7f86bfeb49f90f2767e3bdcc3e0101a58149e97421e8d7b96da8f59fc469959
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f276911281e38f162526b603959f5798fa5d09c73284a79078376126b5fade87add2e4a4345242029a4b4e39097b5a6964651483576f51ed8bee3ac7b6e586a3
|
|
7
|
+
data.tar.gz: 8e5d458add630631bfaa82605f20d28c80310e25787c9db2c94c1b8cc677ac8ff6e0730c97b6271a333cbfe919da8a35ad8deb7911aeedc89c3021629e0c5370
|
data/.github/workflows/ruby.yml
CHANGED
|
@@ -27,7 +27,7 @@ jobs:
|
|
|
27
27
|
ruby-version: ['jruby-head']
|
|
28
28
|
db: ['mysql2']
|
|
29
29
|
test_targets: ["rails:test_mysql2"]
|
|
30
|
-
ar_version: ["7-
|
|
30
|
+
ar_version: ["7-2-stable"]
|
|
31
31
|
prepared_statements: ['false', 'true']
|
|
32
32
|
driver: ['MySQL']
|
|
33
33
|
|
|
@@ -42,7 +42,7 @@ jobs:
|
|
|
42
42
|
AR_VERSION: ${{ matrix.ar_version }}
|
|
43
43
|
PREPARED_STATEMENTS: ${{ matrix.prepared_statements }}
|
|
44
44
|
DRIVER: ${{ matrix.driver }}
|
|
45
|
-
JRUBY_OPTS: "-J-Xms64M -J-Xmx1024M"
|
|
45
|
+
JRUBY_OPTS: "-J-Xms64M -J-Xmx1024M --dev"
|
|
46
46
|
|
|
47
47
|
steps:
|
|
48
48
|
- uses: actions/checkout@v4
|
|
@@ -79,7 +79,7 @@ jobs:
|
|
|
79
79
|
ruby-version: [ 'jruby-head' ]
|
|
80
80
|
db: [ 'postgresql' ]
|
|
81
81
|
test_targets: [ "rails:test_postgresql" ]
|
|
82
|
-
ar_version: ["7-
|
|
82
|
+
ar_version: ["7-2-stable"]
|
|
83
83
|
prepared_statements: [ 'false', 'true' ]
|
|
84
84
|
|
|
85
85
|
services:
|
|
@@ -95,7 +95,7 @@ jobs:
|
|
|
95
95
|
env:
|
|
96
96
|
DB: ${{ matrix.db }}
|
|
97
97
|
AR_VERSION: ${{ matrix.ar_version }}
|
|
98
|
-
JRUBY_OPTS: "-J-Xms64M -J-Xmx1024M"
|
|
98
|
+
JRUBY_OPTS: "-J-Xms64M -J-Xmx1024M --dev"
|
|
99
99
|
PREPARED_STATEMENTS: ${{ matrix.prepared_statements }}
|
|
100
100
|
PGHOST: localhost
|
|
101
101
|
PGPORT: 5432
|
|
@@ -129,12 +129,12 @@ jobs:
|
|
|
129
129
|
ruby-version: ['jruby-head']
|
|
130
130
|
db: ['sqlite3']
|
|
131
131
|
test_targets: ["rails:test_sqlite3"]
|
|
132
|
-
ar_version: ["7-
|
|
132
|
+
ar_version: ["7-2-stable"]
|
|
133
133
|
|
|
134
134
|
env:
|
|
135
135
|
DB: ${{ matrix.db }}
|
|
136
136
|
AR_VERSION: ${{ matrix.ar_version }}
|
|
137
|
-
JRUBY_OPTS: "-J-Xms64M -J-Xmx1024M"
|
|
137
|
+
JRUBY_OPTS: "-J-Xms64M -J-Xmx1024M --dev"
|
|
138
138
|
|
|
139
139
|
steps:
|
|
140
140
|
- uses: actions/checkout@v4
|
|
@@ -149,7 +149,7 @@ jobs:
|
|
|
149
149
|
rake jar # compiles ext generates: lib/arjdbc/jdbc/adapter_java.jar
|
|
150
150
|
- name: Run tests
|
|
151
151
|
run: |
|
|
152
|
-
bundle exec rake ${{ matrix.test_targets }}
|
|
152
|
+
bundle exec rake ${{ matrix.test_targets }} --trace
|
|
153
153
|
|
|
154
154
|
test-arjdbc-mysql:
|
|
155
155
|
|
|
@@ -173,7 +173,7 @@ jobs:
|
|
|
173
173
|
env:
|
|
174
174
|
DB: ${{ matrix.db }}
|
|
175
175
|
DRIVER: ${{ matrix.driver }}
|
|
176
|
-
JRUBY_OPTS: "-J-Xms64M -J-Xmx1024M"
|
|
176
|
+
JRUBY_OPTS: "-J-Xms64M -J-Xmx1024M --dev"
|
|
177
177
|
MY_USER: root
|
|
178
178
|
MY_PASSWORD: root
|
|
179
179
|
PREPARED_STATEMENTS: ${{ matrix.prepared_statements }}
|
|
@@ -222,7 +222,7 @@ jobs:
|
|
|
222
222
|
env:
|
|
223
223
|
DB: ${{ matrix.db }}
|
|
224
224
|
DRIVER: ${{ matrix.driver }}
|
|
225
|
-
JRUBY_OPTS: "-J-Xms64M -J-Xmx1024M"
|
|
225
|
+
JRUBY_OPTS: "-J-Xms64M -J-Xmx1024M --dev"
|
|
226
226
|
PREPARED_STATEMENTS: ${{ matrix.prepared_statements }}
|
|
227
227
|
INSERT_RETURNING: ${{ matrix.insert_returning }}
|
|
228
228
|
PGHOST: localhost
|
data/Gemfile
CHANGED
|
@@ -62,13 +62,13 @@ group :test do
|
|
|
62
62
|
gem 'mocha', '~> 1.2', require: false # Rails has '~> 0.14'
|
|
63
63
|
|
|
64
64
|
gem 'bcrypt', '~> 3.1.11', require: false
|
|
65
|
-
gem 'jdbc-mssql', '~> 12.
|
|
65
|
+
gem 'jdbc-mssql', '~> 12.6', require: nil
|
|
66
66
|
# gem 'pry-debugger-jruby', platform: :jruby
|
|
67
67
|
end
|
|
68
68
|
|
|
69
69
|
group :rails do
|
|
70
70
|
group :test do
|
|
71
|
-
gem 'minitest', require: nil
|
|
71
|
+
gem 'minitest', '~> 5.24.0', require: nil
|
|
72
72
|
gem 'minitest-excludes', require: nil
|
|
73
73
|
gem 'minitest-rg', require: nil
|
|
74
74
|
|
data/README.md
CHANGED
|
@@ -145,9 +145,10 @@ Versions are targeted at certain versions of Rails and live on their own branche
|
|
|
145
145
|
| 60.x | 6.0.x | 60-stable | 9.2.7 | 8 |
|
|
146
146
|
| 61.x | 6.1.x | 61-stable | 9.2.7 | 8 |
|
|
147
147
|
| 70.x | 7.0.x | 70-stable | 9.3.0 | 8 |
|
|
148
|
-
| 71.x | 7.1.x |
|
|
148
|
+
| 71.x | 7.1.x | 71-stable | 9.4.3 | 8 |
|
|
149
|
+
| 72.x | 7.2.x | master | 9.4.3 | 8 |
|
|
149
150
|
|
|
150
|
-
Note:
|
|
151
|
+
Note: 72.x is still under development and not supported yet.
|
|
151
152
|
|
|
152
153
|
Note that JRuby 9.1.x and JRuby 9.2.x are at end-of-life. We recommend Java 8
|
|
153
154
|
at a minimum for all versions.
|
|
@@ -241,8 +241,21 @@ module Arel
|
|
|
241
241
|
|
|
242
242
|
# column_name = schema_cache.primary_keys(t.name) || column_cache(t.name).first.try(:second).try(:name)
|
|
243
243
|
# NOTE: for table name aliases columns_hash('table_alias') requires to return an empty hash.
|
|
244
|
-
|
|
245
|
-
|
|
244
|
+
primary_keys = @connection.schema_cache.primary_keys(t.name)
|
|
245
|
+
column_name = nil
|
|
246
|
+
|
|
247
|
+
case primary_keys
|
|
248
|
+
when NilClass
|
|
249
|
+
column_name = @connection.schema_cache.columns_hash(t.name).first.try(:second).try(:name)
|
|
250
|
+
when String
|
|
251
|
+
column_name = primary_keys
|
|
252
|
+
when Array
|
|
253
|
+
candidate_columns = @connection.schema_cache.columns_hash(t.name).slice(*primary_keys).values
|
|
254
|
+
candidate_column = candidate_columns.find(&:identity?)
|
|
255
|
+
candidate_column ||= candidate_columns.first
|
|
256
|
+
column_name = candidate_column.try(:name)
|
|
257
|
+
end
|
|
258
|
+
|
|
246
259
|
column_name ? t[column_name] : nil
|
|
247
260
|
end
|
|
248
261
|
|
|
@@ -78,18 +78,6 @@ module ArJdbc
|
|
|
78
78
|
end
|
|
79
79
|
alias :exec_delete :exec_update
|
|
80
80
|
|
|
81
|
-
def execute(sql, name = nil, async: false, allow_retry: false, materialize_transactions: true)
|
|
82
|
-
sql = transform_query(sql)
|
|
83
|
-
|
|
84
|
-
if preventing_writes? && write_query?(sql)
|
|
85
|
-
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
mark_transaction_written_if_write(sql)
|
|
89
|
-
|
|
90
|
-
raw_execute(sql, name, async: async, allow_retry: allow_retry, materialize_transactions: materialize_transactions)
|
|
91
|
-
end
|
|
92
|
-
|
|
93
81
|
# overridden to support legacy binds
|
|
94
82
|
def select_all(arel, name = nil, binds = NO_BINDS, preparable: nil, async: false)
|
|
95
83
|
binds = convert_legacy_binds_to_attributes(binds) if binds.first.is_a?(Array)
|
|
@@ -107,7 +95,9 @@ module ArJdbc
|
|
|
107
95
|
def raw_execute(sql, name, async: false, allow_retry: false, materialize_transactions: true)
|
|
108
96
|
log(sql, name, async: async) do
|
|
109
97
|
with_raw_connection(allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |conn|
|
|
110
|
-
conn.execute(sql)
|
|
98
|
+
result = conn.execute(sql)
|
|
99
|
+
verified!
|
|
100
|
+
result
|
|
111
101
|
end
|
|
112
102
|
end
|
|
113
103
|
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_model/attribute"
|
|
4
|
+
|
|
5
|
+
module ActiveRecord
|
|
6
|
+
# NOTE: improved implementation for hash methods that is used to
|
|
7
|
+
# compare objects. AR and arel commonly use `[a, b] - [b]` operations and
|
|
8
|
+
# JRuby internally uses the hash method to implement that operation,
|
|
9
|
+
# on the other hand, CRuby does not use the hash method
|
|
10
|
+
# for small arrays (length <= 16).
|
|
11
|
+
class Relation
|
|
12
|
+
# monkey patch
|
|
13
|
+
module RelationQueryAttributeMonkeyPatch
|
|
14
|
+
def hash
|
|
15
|
+
# [self.class, name, value_for_database, type].hash
|
|
16
|
+
[self.class, name, value_before_type_cast, type].hash
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class QueryAttribute
|
|
21
|
+
prepend RelationQueryAttributeMonkeyPatch
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
Binary file
|
data/lib/arjdbc/mssql/adapter.rb
CHANGED
|
@@ -30,6 +30,8 @@ require 'arjdbc/mssql/errors'
|
|
|
30
30
|
require 'arjdbc/mssql/schema_creation'
|
|
31
31
|
require 'arjdbc/mssql/database_limits'
|
|
32
32
|
|
|
33
|
+
require "arjdbc/abstract/relation_query_attribute_monkey_patch"
|
|
34
|
+
|
|
33
35
|
module ActiveRecord
|
|
34
36
|
module ConnectionAdapters
|
|
35
37
|
# MSSQL (SQLServer) adapter class definition
|
data/lib/arjdbc/mssql.rb
CHANGED
data/lib/arjdbc/mysql/adapter.rb
CHANGED
|
@@ -11,6 +11,8 @@ require 'arjdbc/abstract/database_statements'
|
|
|
11
11
|
require 'arjdbc/abstract/statement_cache'
|
|
12
12
|
require 'arjdbc/abstract/transaction_support'
|
|
13
13
|
|
|
14
|
+
require "arjdbc/abstract/relation_query_attribute_monkey_patch"
|
|
15
|
+
|
|
14
16
|
module ActiveRecord
|
|
15
17
|
module ConnectionAdapters
|
|
16
18
|
AbstractMysqlAdapter.class_eval do
|
|
@@ -22,10 +22,13 @@ require 'arjdbc/abstract/transaction_support'
|
|
|
22
22
|
require 'arjdbc/postgresql/base/array_decoder'
|
|
23
23
|
require 'arjdbc/postgresql/base/array_encoder'
|
|
24
24
|
require 'arjdbc/postgresql/name'
|
|
25
|
+
require 'arjdbc/postgresql/database_statements'
|
|
25
26
|
require 'arjdbc/postgresql/schema_statements'
|
|
26
27
|
|
|
27
28
|
require 'active_model'
|
|
28
29
|
|
|
30
|
+
require "arjdbc/abstract/relation_query_attribute_monkey_patch"
|
|
31
|
+
|
|
29
32
|
module ArJdbc
|
|
30
33
|
# Strives to provide Rails built-in PostgreSQL adapter (API) compatibility.
|
|
31
34
|
module PostgreSQL
|
|
@@ -120,7 +123,8 @@ module ArJdbc
|
|
|
120
123
|
citext: { name: 'citext' },
|
|
121
124
|
date: { name: 'date' },
|
|
122
125
|
daterange: { name: 'daterange' },
|
|
123
|
-
datetime: {
|
|
126
|
+
datetime: {}, # set dynamically based on datetime_type
|
|
127
|
+
timestamptz: { name: 'timestamptz' },
|
|
124
128
|
decimal: { name: 'decimal' }, # :limit => 1000
|
|
125
129
|
float: { name: 'float' },
|
|
126
130
|
hstore: { name: 'hstore' },
|
|
@@ -150,17 +154,10 @@ module ArJdbc
|
|
|
150
154
|
tstzrange: { name: 'tstzrange' },
|
|
151
155
|
tsvector: { name: 'tsvector' },
|
|
152
156
|
uuid: { name: 'uuid' },
|
|
153
|
-
xml: { name: 'xml' }
|
|
157
|
+
xml: { name: 'xml' },
|
|
158
|
+
enum: {} # special type https://www.postgresql.org/docs/current/datatype-enum.html
|
|
154
159
|
}
|
|
155
160
|
|
|
156
|
-
def native_database_types
|
|
157
|
-
NATIVE_DATABASE_TYPES
|
|
158
|
-
end
|
|
159
|
-
|
|
160
|
-
def valid_type?(type)
|
|
161
|
-
!native_database_types[type].nil?
|
|
162
|
-
end
|
|
163
|
-
|
|
164
161
|
def set_standard_conforming_strings
|
|
165
162
|
execute("SET standard_conforming_strings = on", "SCHEMA")
|
|
166
163
|
end
|
|
@@ -232,10 +229,18 @@ module ArJdbc
|
|
|
232
229
|
alias supports_insert_on_duplicate_update? supports_insert_on_conflict?
|
|
233
230
|
alias supports_insert_conflict_target? supports_insert_on_conflict?
|
|
234
231
|
|
|
232
|
+
def supports_virtual_columns?
|
|
233
|
+
database_version >= 12_00_00 # >= 12.0
|
|
234
|
+
end
|
|
235
|
+
|
|
235
236
|
def supports_identity_columns? # :nodoc:
|
|
236
237
|
database_version >= 10_00_00 # >= 10.0
|
|
237
238
|
end
|
|
238
239
|
|
|
240
|
+
def supports_nulls_not_distinct?
|
|
241
|
+
database_version >= 15_00_00 # >= 15.0
|
|
242
|
+
end
|
|
243
|
+
|
|
239
244
|
def index_algorithms
|
|
240
245
|
{ concurrently: 'CONCURRENTLY' }
|
|
241
246
|
end
|
|
@@ -335,33 +340,100 @@ module ArJdbc
|
|
|
335
340
|
# Returns a list of defined enum types, and their values.
|
|
336
341
|
def enum_types
|
|
337
342
|
query = <<~SQL
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
343
|
+
SELECT
|
|
344
|
+
type.typname AS name,
|
|
345
|
+
type.OID AS oid,
|
|
346
|
+
n.nspname AS schema,
|
|
347
|
+
string_agg(enum.enumlabel, ',' ORDER BY enum.enumsortorder) AS value
|
|
348
|
+
FROM pg_enum AS enum
|
|
349
|
+
JOIN pg_type AS type ON (type.oid = enum.enumtypid)
|
|
350
|
+
JOIN pg_namespace n ON type.typnamespace = n.oid
|
|
351
|
+
WHERE n.nspname = ANY (current_schemas(false))
|
|
352
|
+
GROUP BY type.OID, n.nspname, type.typname;
|
|
345
353
|
SQL
|
|
346
|
-
|
|
354
|
+
|
|
355
|
+
internal_exec_query(query, "SCHEMA", allow_retry: true, materialize_transactions: false).cast_values.each_with_object({}) do |row, memo|
|
|
356
|
+
name, schema = row[0], row[2]
|
|
357
|
+
schema = nil if schema == current_schema
|
|
358
|
+
full_name = [schema, name].compact.join(".")
|
|
359
|
+
memo[full_name] = row.last
|
|
360
|
+
end.to_a
|
|
347
361
|
end
|
|
348
362
|
|
|
349
363
|
# Given a name and an array of values, creates an enum type.
|
|
350
|
-
def create_enum(name, values)
|
|
351
|
-
sql_values = values.map { |s|
|
|
364
|
+
def create_enum(name, values, **options)
|
|
365
|
+
sql_values = values.map { |s| quote(s) }.join(", ")
|
|
366
|
+
scope = quoted_scope(name)
|
|
352
367
|
query = <<~SQL
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
368
|
+
DO $$
|
|
369
|
+
BEGIN
|
|
370
|
+
IF NOT EXISTS (
|
|
371
|
+
SELECT 1
|
|
372
|
+
FROM pg_type t
|
|
373
|
+
JOIN pg_namespace n ON t.typnamespace = n.oid
|
|
374
|
+
WHERE t.typname = #{scope[:name]}
|
|
375
|
+
AND n.nspname = #{scope[:schema]}
|
|
376
|
+
) THEN
|
|
377
|
+
CREATE TYPE #{quote_table_name(name)} AS ENUM (#{sql_values});
|
|
378
|
+
END IF;
|
|
379
|
+
END
|
|
380
|
+
$$;
|
|
363
381
|
SQL
|
|
364
|
-
|
|
382
|
+
|
|
383
|
+
internal_exec_query(query).tap { reload_type_map }
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
# Drops an enum type.
|
|
387
|
+
#
|
|
388
|
+
# If the <tt>if_exists: true</tt> option is provided, the enum is dropped
|
|
389
|
+
# only if it exists. Otherwise, if the enum doesn't exist, an error is
|
|
390
|
+
# raised.
|
|
391
|
+
#
|
|
392
|
+
# The +values+ parameter will be ignored if present. It can be helpful
|
|
393
|
+
# to provide this in a migration's +change+ method so it can be reverted.
|
|
394
|
+
# In that case, +values+ will be used by #create_enum.
|
|
395
|
+
def drop_enum(name, values = nil, **options)
|
|
396
|
+
query = <<~SQL
|
|
397
|
+
DROP TYPE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(name)};
|
|
398
|
+
SQL
|
|
399
|
+
internal_exec_query(query).tap { reload_type_map }
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
# Rename an existing enum type to something else.
|
|
403
|
+
def rename_enum(name, options = {})
|
|
404
|
+
to = options.fetch(:to) { raise ArgumentError, ":to is required" }
|
|
405
|
+
|
|
406
|
+
exec_query("ALTER TYPE #{quote_table_name(name)} RENAME TO #{to}").tap { reload_type_map }
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
# Add enum value to an existing enum type.
|
|
410
|
+
def add_enum_value(type_name, value, options = {})
|
|
411
|
+
before, after = options.values_at(:before, :after)
|
|
412
|
+
sql = +"ALTER TYPE #{quote_table_name(type_name)} ADD VALUE '#{value}'"
|
|
413
|
+
|
|
414
|
+
if before && after
|
|
415
|
+
raise ArgumentError, "Cannot have both :before and :after at the same time"
|
|
416
|
+
elsif before
|
|
417
|
+
sql << " BEFORE '#{before}'"
|
|
418
|
+
elsif after
|
|
419
|
+
sql << " AFTER '#{after}'"
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
execute(sql).tap { reload_type_map }
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
# Rename enum value on an existing enum type.
|
|
426
|
+
def rename_enum_value(type_name, options = {})
|
|
427
|
+
unless database_version >= 10_00_00 # >= 10.0
|
|
428
|
+
raise ArgumentError, "Renaming enum values is only supported in PostgreSQL 10 or later"
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
from = options.fetch(:from) { raise ArgumentError, ":from is required" }
|
|
432
|
+
to = options.fetch(:to) { raise ArgumentError, ":to is required" }
|
|
433
|
+
|
|
434
|
+
execute("ALTER TYPE #{quote_table_name(type_name)} RENAME VALUE '#{from}' TO '#{to}'").tap {
|
|
435
|
+
reload_type_map
|
|
436
|
+
}
|
|
365
437
|
end
|
|
366
438
|
|
|
367
439
|
# Returns the configured supported identifier length supported by PostgreSQL
|
|
@@ -455,11 +527,6 @@ module ArJdbc
|
|
|
455
527
|
execute(combine_multi_statements(statements), name)
|
|
456
528
|
end
|
|
457
529
|
|
|
458
|
-
def explain(arel, binds = [])
|
|
459
|
-
sql, binds = to_sql_and_binds(arel, binds)
|
|
460
|
-
ActiveRecord::ConnectionAdapters::PostgreSQL::ExplainPrettyPrinter.new.pp(exec_query("EXPLAIN #{sql}", 'EXPLAIN', binds))
|
|
461
|
-
end
|
|
462
|
-
|
|
463
530
|
# from ActiveRecord::ConnectionAdapters::PostgreSQL::DatabaseStatements
|
|
464
531
|
READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
|
|
465
532
|
:close, :declare, :fetch, :move, :set, :show
|
|
@@ -493,6 +560,16 @@ module ArJdbc
|
|
|
493
560
|
end
|
|
494
561
|
end
|
|
495
562
|
|
|
563
|
+
# Disconnects from the database if already connected. Otherwise, this
|
|
564
|
+
# method does nothing.
|
|
565
|
+
def disconnect!
|
|
566
|
+
@lock.synchronize do
|
|
567
|
+
super
|
|
568
|
+
@raw_connection&.close
|
|
569
|
+
@raw_connection = nil
|
|
570
|
+
end
|
|
571
|
+
end
|
|
572
|
+
|
|
496
573
|
def default_sequence_name(table_name, pk = "id") #:nodoc:
|
|
497
574
|
serial_sequence(table_name, pk)
|
|
498
575
|
rescue ActiveRecord::StatementInvalid
|
|
@@ -608,17 +685,19 @@ module ArJdbc
|
|
|
608
685
|
# - format_type includes the column size constraint, e.g. varchar(50)
|
|
609
686
|
# - ::regclass is a function that gives the id for a table name
|
|
610
687
|
def column_definitions(table_name)
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
688
|
+
query(<<~SQL, "SCHEMA")
|
|
689
|
+
SELECT a.attname, format_type(a.atttypid, a.atttypmod),
|
|
690
|
+
pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
|
|
691
|
+
c.collname, col_description(a.attrelid, a.attnum) AS comment,
|
|
692
|
+
#{supports_identity_columns? ? 'attidentity' : quote('')} AS identity,
|
|
693
|
+
#{supports_virtual_columns? ? 'attgenerated' : quote('')} as attgenerated
|
|
694
|
+
FROM pg_attribute a
|
|
695
|
+
LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum
|
|
696
|
+
LEFT JOIN pg_type t ON a.atttypid = t.oid
|
|
697
|
+
LEFT JOIN pg_collation c ON a.attcollation = c.oid AND a.attcollation <> t.typcollation
|
|
698
|
+
WHERE a.attrelid = #{quote(quote_table_name(table_name))}::regclass
|
|
699
|
+
AND a.attnum > 0 AND NOT a.attisdropped
|
|
700
|
+
ORDER BY a.attnum
|
|
622
701
|
SQL
|
|
623
702
|
end
|
|
624
703
|
|
|
@@ -633,22 +712,27 @@ module ArJdbc
|
|
|
633
712
|
|
|
634
713
|
# Pulled from ActiveRecord's Postgres adapter and modified to use execute
|
|
635
714
|
def can_perform_case_insensitive_comparison_for?(column)
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
715
|
+
# NOTE: citext is an exception. It is possible to perform a
|
|
716
|
+
# case-insensitive comparison using `LOWER()`, but it is
|
|
717
|
+
# unnecessary, as `citext` is case-insensitive by definition.
|
|
718
|
+
@case_insensitive_cache ||= { "citext" => false }
|
|
719
|
+
@case_insensitive_cache.fetch(column.sql_type) do
|
|
720
|
+
@case_insensitive_cache[column.sql_type] = begin
|
|
721
|
+
sql = <<~SQL
|
|
722
|
+
SELECT exists(
|
|
723
|
+
SELECT * FROM pg_proc
|
|
724
|
+
WHERE proname = 'lower'
|
|
725
|
+
AND proargtypes = ARRAY[#{quote column.sql_type}::regtype]::oidvector
|
|
726
|
+
) OR exists(
|
|
727
|
+
SELECT * FROM pg_proc
|
|
728
|
+
INNER JOIN pg_cast
|
|
729
|
+
ON ARRAY[casttarget]::oidvector = proargtypes
|
|
730
|
+
WHERE proname = 'lower'
|
|
731
|
+
AND castsource = #{quote column.sql_type}::regtype
|
|
732
|
+
)
|
|
733
|
+
SQL
|
|
734
|
+
select_value(sql, 'SCHEMA')
|
|
735
|
+
end
|
|
652
736
|
end
|
|
653
737
|
end
|
|
654
738
|
|
|
@@ -657,6 +741,8 @@ module ArJdbc
|
|
|
657
741
|
|
|
658
742
|
# TODO: Can we base these on an error code of some kind?
|
|
659
743
|
case exception.message
|
|
744
|
+
when /could not create unique index/
|
|
745
|
+
::ActiveRecord::RecordNotUnique.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
660
746
|
when /duplicate key value violates unique constraint/
|
|
661
747
|
::ActiveRecord::RecordNotUnique.new(message, sql: sql, binds: binds)
|
|
662
748
|
when /violates not-null constraint/
|
|
@@ -675,7 +761,9 @@ module ArJdbc
|
|
|
675
761
|
::ActiveRecord::LockWaitTimeout.new(message, sql: sql, binds: binds)
|
|
676
762
|
when /canceling statement/ # This needs to come after lock timeout because the lock timeout message also contains "canceling statement"
|
|
677
763
|
::ActiveRecord::QueryCanceled.new(message, sql: sql, binds: binds)
|
|
678
|
-
when /relation
|
|
764
|
+
when /relation .* does not exist/i
|
|
765
|
+
::ActiveRecord::StatementInvalid.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
766
|
+
when /syntax error at or near/i
|
|
679
767
|
::ActiveRecord::StatementInvalid.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
680
768
|
else
|
|
681
769
|
super
|
|
@@ -770,6 +858,7 @@ module ActiveRecord::ConnectionAdapters
|
|
|
770
858
|
|
|
771
859
|
require 'arjdbc/postgresql/oid_types'
|
|
772
860
|
include ::ArJdbc::PostgreSQL::OIDTypes
|
|
861
|
+
include ::ArJdbc::PostgreSQL::DatabaseStatements
|
|
773
862
|
include ::ArJdbc::PostgreSQL::SchemaStatements
|
|
774
863
|
|
|
775
864
|
include ::ArJdbc::PostgreSQL::ColumnHelpers
|
|
@@ -787,6 +876,25 @@ module ActiveRecord::ConnectionAdapters
|
|
|
787
876
|
def new_client(conn_params, adapter_instance)
|
|
788
877
|
jdbc_connection_class.new(conn_params, adapter_instance)
|
|
789
878
|
end
|
|
879
|
+
|
|
880
|
+
def dbconsole(config, options = {})
|
|
881
|
+
pg_config = config.configuration_hash
|
|
882
|
+
|
|
883
|
+
ENV["PGUSER"] = pg_config[:username] if pg_config[:username]
|
|
884
|
+
ENV["PGHOST"] = pg_config[:host] if pg_config[:host]
|
|
885
|
+
ENV["PGPORT"] = pg_config[:port].to_s if pg_config[:port]
|
|
886
|
+
ENV["PGPASSWORD"] = pg_config[:password].to_s if pg_config[:password] && options[:include_password]
|
|
887
|
+
ENV["PGSSLMODE"] = pg_config[:sslmode].to_s if pg_config[:sslmode]
|
|
888
|
+
ENV["PGSSLCERT"] = pg_config[:sslcert].to_s if pg_config[:sslcert]
|
|
889
|
+
ENV["PGSSLKEY"] = pg_config[:sslkey].to_s if pg_config[:sslkey]
|
|
890
|
+
ENV["PGSSLROOTCERT"] = pg_config[:sslrootcert].to_s if pg_config[:sslrootcert]
|
|
891
|
+
if pg_config[:variables]
|
|
892
|
+
ENV["PGOPTIONS"] = pg_config[:variables].filter_map do |name, value|
|
|
893
|
+
"-c #{name}=#{value.to_s.gsub(/[ \\]/, '\\\\\0')}" unless value == ":default" || value == :default
|
|
894
|
+
end.join(" ")
|
|
895
|
+
end
|
|
896
|
+
find_cmd_and_exec("psql", config.database)
|
|
897
|
+
end
|
|
790
898
|
end
|
|
791
899
|
|
|
792
900
|
def initialize(...)
|
|
@@ -822,6 +930,18 @@ module ActiveRecord::ConnectionAdapters
|
|
|
822
930
|
public :sql_for_insert
|
|
823
931
|
alias :postgresql_version :database_version
|
|
824
932
|
|
|
933
|
+
def native_database_types # :nodoc:
|
|
934
|
+
self.class.native_database_types
|
|
935
|
+
end
|
|
936
|
+
|
|
937
|
+
def self.native_database_types # :nodoc:
|
|
938
|
+
@native_database_types ||= begin
|
|
939
|
+
types = NATIVE_DATABASE_TYPES.dup
|
|
940
|
+
types[:datetime] = types[datetime_type]
|
|
941
|
+
types
|
|
942
|
+
end
|
|
943
|
+
end
|
|
944
|
+
|
|
825
945
|
private
|
|
826
946
|
|
|
827
947
|
FEATURE_NOT_SUPPORTED = "0A000" # :nodoc:
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ArJdbc
|
|
4
|
+
module PostgreSQL
|
|
5
|
+
module DatabaseStatements
|
|
6
|
+
def explain(arel, binds = [], options = [])
|
|
7
|
+
sql = build_explain_clause(options) + " " + to_sql(arel, binds)
|
|
8
|
+
|
|
9
|
+
result = internal_exec_query(sql, "EXPLAIN", binds)
|
|
10
|
+
ActiveRecord::ConnectionAdapters::PostgreSQL::ExplainPrettyPrinter.new.pp(result)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def build_explain_clause(options = [])
|
|
14
|
+
return "EXPLAIN" if options.empty?
|
|
15
|
+
|
|
16
|
+
"EXPLAIN (#{options.join(", ").upcase})"
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -18,6 +18,8 @@ require "active_record/connection_adapters/sqlite3/schema_statements"
|
|
|
18
18
|
require "active_support/core_ext/class/attribute"
|
|
19
19
|
require "arjdbc/sqlite3/column"
|
|
20
20
|
|
|
21
|
+
require "arjdbc/abstract/relation_query_attribute_monkey_patch"
|
|
22
|
+
|
|
21
23
|
module SQLite3
|
|
22
24
|
module Constants
|
|
23
25
|
module Open
|
|
@@ -669,6 +671,14 @@ module ArJdbc
|
|
|
669
671
|
StatementPool.new(self.class.type_cast_config_to_integer(@config[:statement_limit]))
|
|
670
672
|
end
|
|
671
673
|
|
|
674
|
+
def reconnect
|
|
675
|
+
if active?
|
|
676
|
+
@raw_connection.rollback rescue nil
|
|
677
|
+
else
|
|
678
|
+
connect
|
|
679
|
+
end
|
|
680
|
+
end
|
|
681
|
+
|
|
672
682
|
def configure_connection
|
|
673
683
|
if @config[:timeout] && @config[:retries]
|
|
674
684
|
raise ArgumentError, "Cannot specify both timeout and retries arguments"
|
data/lib/arjdbc/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: activerecord-jdbc-alt-adapter
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 71.0.0
|
|
4
|
+
version: 71.0.0
|
|
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: 2025-01-26 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -78,6 +78,7 @@ files:
|
|
|
78
78
|
- lib/arjdbc/abstract/connection_management.rb
|
|
79
79
|
- lib/arjdbc/abstract/core.rb
|
|
80
80
|
- lib/arjdbc/abstract/database_statements.rb
|
|
81
|
+
- lib/arjdbc/abstract/relation_query_attribute_monkey_patch.rb
|
|
81
82
|
- lib/arjdbc/abstract/statement_cache.rb
|
|
82
83
|
- lib/arjdbc/abstract/transaction_support.rb
|
|
83
84
|
- lib/arjdbc/discover.rb
|
|
@@ -143,6 +144,7 @@ files:
|
|
|
143
144
|
- lib/arjdbc/postgresql/base/pgconn.rb
|
|
144
145
|
- lib/arjdbc/postgresql/column.rb
|
|
145
146
|
- lib/arjdbc/postgresql/connection_methods.rb
|
|
147
|
+
- lib/arjdbc/postgresql/database_statements.rb
|
|
146
148
|
- lib/arjdbc/postgresql/name.rb
|
|
147
149
|
- lib/arjdbc/postgresql/oid_types.rb
|
|
148
150
|
- lib/arjdbc/postgresql/schema_statements.rb
|
|
@@ -229,9 +231,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
229
231
|
version: '0'
|
|
230
232
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
231
233
|
requirements:
|
|
232
|
-
- - "
|
|
234
|
+
- - ">="
|
|
233
235
|
- !ruby/object:Gem::Version
|
|
234
|
-
version:
|
|
236
|
+
version: '0'
|
|
235
237
|
requirements: []
|
|
236
238
|
rubygems_version: 3.3.26
|
|
237
239
|
signing_key:
|