activerecord-jdbc-alt-adapter 71.0.0.alpha2-java → 71.0.0-java
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|