activerecord-jdbc-alt-adapter 61.2.0-java → 70.0.0.rc2-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 +118 -0
- data/.github/workflows/ruby.yml +273 -0
- data/.gitignore +1 -0
- data/.travis.yml +3 -4
- data/Gemfile +9 -7
- data/README.md +5 -1
- data/Rakefile +1 -1
- data/activerecord-jdbc-adapter.gemspec +2 -2
- data/activerecord-jdbc-alt-adapter.gemspec +2 -2
- 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/core.rb +8 -9
- data/lib/arjdbc/abstract/database_statements.rb +4 -4
- data/lib/arjdbc/discover.rb +0 -67
- data/lib/arjdbc/hsqldb/adapter.rb +2 -2
- data/lib/arjdbc/jdbc/adapter.rb +3 -3
- data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
- data/lib/arjdbc/jdbc/adapter_require.rb +3 -1
- data/lib/arjdbc/jdbc/column.rb +1 -26
- data/lib/arjdbc/jdbc/type_cast.rb +2 -2
- data/lib/arjdbc/jdbc.rb +0 -7
- data/lib/arjdbc/mssql/adapter.rb +138 -108
- data/lib/arjdbc/mssql/quoting.rb +26 -27
- data/lib/arjdbc/mssql/schema_creation.rb +1 -1
- data/lib/arjdbc/mssql/schema_definitions.rb +32 -17
- data/lib/arjdbc/mssql/schema_dumper.rb +13 -1
- data/lib/arjdbc/mssql/schema_statements.rb +61 -36
- data/lib/arjdbc/mssql/transaction.rb +2 -2
- data/lib/arjdbc/mssql/types/date_and_time_types.rb +6 -6
- data/lib/arjdbc/mssql/types/numeric_types.rb +2 -2
- data/lib/arjdbc/mssql.rb +1 -1
- data/lib/arjdbc/mysql/adapter.rb +2 -1
- data/lib/arjdbc/oracle/adapter.rb +4 -23
- data/lib/arjdbc/postgresql/adapter.rb +152 -4
- data/lib/arjdbc/postgresql/oid_types.rb +142 -106
- data/lib/arjdbc/sqlite3/adapter.rb +132 -88
- data/lib/arjdbc/tasks/database_tasks.rb +0 -12
- data/lib/arjdbc/util/serialized_attributes.rb +0 -22
- data/lib/arjdbc/util/table_copier.rb +2 -1
- data/lib/arjdbc/version.rb +1 -1
- data/rakelib/02-test.rake +3 -18
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +17 -2
- data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +5 -0
- data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +33 -0
- metadata +9 -40
- 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
@@ -27,10 +27,10 @@ module ActiveRecord
|
|
27
27
|
module RealTransactionExt
|
28
28
|
attr_reader :initial_transaction_isolation
|
29
29
|
|
30
|
-
def initialize(connection,
|
30
|
+
def initialize(connection, isolation: nil, joinable: true, run_commit_callbacks: false)
|
31
31
|
@connection = connection
|
32
32
|
|
33
|
-
if
|
33
|
+
if isolation
|
34
34
|
@initial_transaction_isolation = current_transaction_isolation
|
35
35
|
end
|
36
36
|
|
@@ -13,9 +13,9 @@ module ActiveRecord
|
|
13
13
|
return %("#{value}") if value.acts_like?(:string)
|
14
14
|
|
15
15
|
if value.usec > 0
|
16
|
-
%("#{value.
|
16
|
+
%("#{value.to_fs(:db)}.#{value.usec.to_s.remove(/0+$/)}")
|
17
17
|
else
|
18
|
-
%("#{value.
|
18
|
+
%("#{value.to_fs(:db)}")
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
@@ -54,9 +54,9 @@ module ActiveRecord
|
|
54
54
|
return %("#{value}") if value.acts_like?(:string)
|
55
55
|
|
56
56
|
if value.usec > 0
|
57
|
-
%("#{value.
|
57
|
+
%("#{value.to_fs(:db)}.#{value.usec.to_s.remove(/0+$/)}")
|
58
58
|
else
|
59
|
-
%("#{value.
|
59
|
+
%("#{value.to_fs(:db)}")
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
@@ -100,9 +100,9 @@ module ActiveRecord
|
|
100
100
|
return %("#{value}") if value.acts_like?(:string)
|
101
101
|
|
102
102
|
if value.usec > 0
|
103
|
-
%("#{value.
|
103
|
+
%("#{value.to_fs(:db)}.#{value.usec.to_s.remove(/0+$/)}")
|
104
104
|
else
|
105
|
-
%("#{value.
|
105
|
+
%("#{value.to_fs(:db)}")
|
106
106
|
end
|
107
107
|
end
|
108
108
|
|
@@ -35,7 +35,7 @@ module ActiveRecord
|
|
35
35
|
end
|
36
36
|
|
37
37
|
class Money < Decimal
|
38
|
-
def initialize(
|
38
|
+
def initialize(precision: nil, limit: nil, scale: nil)
|
39
39
|
super
|
40
40
|
@precision = 19
|
41
41
|
@scale = 4
|
@@ -46,7 +46,7 @@ module ActiveRecord
|
|
46
46
|
end
|
47
47
|
|
48
48
|
class SmallMoney < Decimal
|
49
|
-
def initialize(
|
49
|
+
def initialize(precision: nil, limit: nil, scale: nil)
|
50
50
|
super
|
51
51
|
@precision = 10
|
52
52
|
@scale = 4
|
data/lib/arjdbc/mssql.rb
CHANGED
data/lib/arjdbc/mysql/adapter.rb
CHANGED
@@ -40,7 +40,7 @@ module ArJdbc
|
|
40
40
|
return if @@_initialized; @@_initialized = true
|
41
41
|
|
42
42
|
require 'arjdbc/util/serialized_attributes'
|
43
|
-
Util::SerializedAttributes.setup
|
43
|
+
Util::SerializedAttributes.setup %r{LOB\(|LOB$}i, 'after_save_with_oracle_lob'
|
44
44
|
|
45
45
|
unless ActiveRecord::ConnectionAdapters::AbstractAdapter.
|
46
46
|
instance_methods(false).detect { |m| m.to_s == "prefetch_primary_key?" }
|
@@ -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
|
@@ -81,7 +81,7 @@ module ArJdbc
|
|
81
81
|
# If using Active Record's time zone support configure the connection to return
|
82
82
|
# TIMESTAMP WITH ZONE types in UTC.
|
83
83
|
# (SET TIME ZONE does not use an equals sign like other SET variables)
|
84
|
-
if ActiveRecord
|
84
|
+
if ActiveRecord.default_timezone == :utc
|
85
85
|
execute("SET time zone 'UTC'", 'SCHEMA')
|
86
86
|
elsif tz = local_tz
|
87
87
|
execute("SET time zone '#{tz}'", 'SCHEMA')
|
@@ -320,6 +320,38 @@ module ArJdbc
|
|
320
320
|
exec_query("SELECT extname FROM pg_extension", "SCHEMA").cast_values
|
321
321
|
end
|
322
322
|
|
323
|
+
# Returns a list of defined enum types, and their values.
|
324
|
+
def enum_types
|
325
|
+
query = <<~SQL
|
326
|
+
SELECT
|
327
|
+
type.typname AS name,
|
328
|
+
string_agg(enum.enumlabel, ',' ORDER BY enum.enumsortorder) AS value
|
329
|
+
FROM pg_enum AS enum
|
330
|
+
JOIN pg_type AS type
|
331
|
+
ON (type.oid = enum.enumtypid)
|
332
|
+
GROUP BY type.typname;
|
333
|
+
SQL
|
334
|
+
exec_query(query, "SCHEMA").cast_values
|
335
|
+
end
|
336
|
+
|
337
|
+
# Given a name and an array of values, creates an enum type.
|
338
|
+
def create_enum(name, values)
|
339
|
+
sql_values = values.map { |s| "'#{s}'" }.join(", ")
|
340
|
+
query = <<~SQL
|
341
|
+
DO $$
|
342
|
+
BEGIN
|
343
|
+
IF NOT EXISTS (
|
344
|
+
SELECT 1 FROM pg_type t
|
345
|
+
WHERE t.typname = '#{name}'
|
346
|
+
) THEN
|
347
|
+
CREATE TYPE \"#{name}\" AS ENUM (#{sql_values});
|
348
|
+
END IF;
|
349
|
+
END
|
350
|
+
$$;
|
351
|
+
SQL
|
352
|
+
exec_query(query)
|
353
|
+
end
|
354
|
+
|
323
355
|
# Returns the configured supported identifier length supported by PostgreSQL
|
324
356
|
def max_identifier_length
|
325
357
|
@max_identifier_length ||= query_value("SHOW max_identifier_length", "SCHEMA").to_i
|
@@ -672,6 +704,37 @@ module ActiveRecord::ConnectionAdapters
|
|
672
704
|
class PostgreSQLAdapter < AbstractAdapter
|
673
705
|
class_attribute :create_unlogged_tables, default: false
|
674
706
|
|
707
|
+
##
|
708
|
+
# :singleton-method:
|
709
|
+
# PostgreSQL allows the creation of "unlogged" tables, which do not record
|
710
|
+
# data in the PostgreSQL Write-Ahead Log. This can make the tables faster,
|
711
|
+
# but significantly increases the risk of data loss if the database
|
712
|
+
# crashes. As a result, this should not be used in production
|
713
|
+
# environments. If you would like all created tables to be unlogged in
|
714
|
+
# the test environment you can add the following line to your test.rb
|
715
|
+
# file:
|
716
|
+
#
|
717
|
+
# ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.create_unlogged_tables = true
|
718
|
+
class_attribute :create_unlogged_tables, default: false
|
719
|
+
|
720
|
+
##
|
721
|
+
# :singleton-method:
|
722
|
+
# PostgreSQL supports multiple types for DateTimes. By default, if you use +datetime+
|
723
|
+
# in migrations, Rails will translate this to a PostgreSQL "timestamp without time zone".
|
724
|
+
# Change this in an initializer to use another NATIVE_DATABASE_TYPES. For example, to
|
725
|
+
# store DateTimes as "timestamp with time zone":
|
726
|
+
#
|
727
|
+
# ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.datetime_type = :timestamptz
|
728
|
+
#
|
729
|
+
# Or if you are adding a custom type:
|
730
|
+
#
|
731
|
+
# ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::NATIVE_DATABASE_TYPES[:my_custom_type] = { name: "my_custom_type_name" }
|
732
|
+
# ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.datetime_type = :my_custom_type
|
733
|
+
#
|
734
|
+
# If you're using +:ruby+ as your +config.active_record.schema_format+ and you change this
|
735
|
+
# setting, you should immediately run <tt>bin/rails db:migrate</tt> to update the types in your schema.rb.
|
736
|
+
class_attribute :datetime_type, default: :timestamp
|
737
|
+
|
675
738
|
# Try to use as much of the built in postgres logic as possible
|
676
739
|
# maybe someday we can extend the actual adapter
|
677
740
|
include ActiveRecord::ConnectionAdapters::PostgreSQL::ReferentialIntegrity
|
@@ -735,11 +798,96 @@ module ActiveRecord::ConnectionAdapters
|
|
735
798
|
|
736
799
|
private
|
737
800
|
|
738
|
-
|
739
|
-
|
801
|
+
FEATURE_NOT_SUPPORTED = "0A000" # :nodoc:
|
802
|
+
|
803
|
+
def execute_and_clear(sql, name, binds, prepare: false, async: false)
|
804
|
+
sql = transform_query(sql)
|
805
|
+
check_if_write_query(sql)
|
806
|
+
|
807
|
+
if !prepare || without_prepared_statement?(binds)
|
808
|
+
result = exec_no_cache(sql, name, binds, async: async)
|
809
|
+
else
|
810
|
+
result = exec_cache(sql, name, binds, async: async)
|
811
|
+
end
|
812
|
+
begin
|
813
|
+
ret = yield result
|
814
|
+
ensure
|
815
|
+
# Is this really result in AR PG?
|
816
|
+
# result.clear
|
817
|
+
end
|
818
|
+
ret
|
819
|
+
end
|
820
|
+
|
821
|
+
def exec_no_cache(sql, name, binds, async: false)
|
822
|
+
materialize_transactions
|
823
|
+
mark_transaction_written_if_write(sql)
|
824
|
+
|
825
|
+
# make sure we carry over any changes to ActiveRecord.default_timezone that have been
|
826
|
+
# made since we established the connection
|
827
|
+
update_typemap_for_default_timezone
|
828
|
+
|
829
|
+
type_casted_binds = type_casted_binds(binds)
|
830
|
+
log(sql, name, binds, type_casted_binds, async: async) do
|
831
|
+
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
832
|
+
@connection.exec_params(sql, type_casted_binds)
|
833
|
+
end
|
834
|
+
end
|
835
|
+
end
|
836
|
+
|
837
|
+
def exec_cache(sql, name, binds, async: false)
|
838
|
+
materialize_transactions
|
839
|
+
mark_transaction_written_if_write(sql)
|
840
|
+
update_typemap_for_default_timezone
|
841
|
+
|
842
|
+
stmt_key = prepare_statement(sql, binds)
|
843
|
+
type_casted_binds = type_casted_binds(binds)
|
844
|
+
|
845
|
+
log(sql, name, binds, type_casted_binds, stmt_key, async: async) do
|
846
|
+
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
847
|
+
@connection.exec_prepared(stmt_key, type_casted_binds)
|
848
|
+
end
|
849
|
+
end
|
850
|
+
rescue ActiveRecord::StatementInvalid => e
|
851
|
+
raise unless is_cached_plan_failure?(e)
|
852
|
+
|
853
|
+
# Nothing we can do if we are in a transaction because all commands
|
854
|
+
# will raise InFailedSQLTransaction
|
855
|
+
if in_transaction?
|
856
|
+
raise ActiveRecord::PreparedStatementCacheExpired.new(e.cause.message)
|
857
|
+
else
|
858
|
+
@lock.synchronize do
|
859
|
+
# outside of transactions we can simply flush this query and retry
|
860
|
+
@statements.delete sql_key(sql)
|
861
|
+
end
|
862
|
+
retry
|
863
|
+
end
|
864
|
+
end
|
865
|
+
|
866
|
+
# Annoyingly, the code for prepared statements whose return value may
|
867
|
+
# have changed is FEATURE_NOT_SUPPORTED.
|
868
|
+
#
|
869
|
+
# This covers various different error types so we need to do additional
|
870
|
+
# work to classify the exception definitively as a
|
871
|
+
# ActiveRecord::PreparedStatementCacheExpired
|
872
|
+
#
|
873
|
+
# Check here for more details:
|
874
|
+
# https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/backend/utils/cache/plancache.c#l573
|
875
|
+
def is_cached_plan_failure?(e)
|
876
|
+
pgerror = e.cause
|
877
|
+
pgerror.result.result_error_field(PG::PG_DIAG_SQLSTATE) == FEATURE_NOT_SUPPORTED &&
|
878
|
+
pgerror.result.result_error_field(PG::PG_DIAG_SOURCE_FUNCTION) == "RevalidateCachedQuery"
|
879
|
+
rescue
|
880
|
+
false
|
881
|
+
end
|
882
|
+
|
883
|
+
def in_transaction?
|
884
|
+
open_transactions > 0
|
885
|
+
end
|
886
|
+
|
887
|
+
# Returns the statement identifier for the client side cache
|
888
|
+
# of statements
|
740
889
|
def sql_key(sql)
|
741
890
|
"#{schema_search_path}-#{sql}"
|
742
891
|
end
|
743
|
-
|
744
892
|
end
|
745
893
|
end
|
@@ -92,7 +92,7 @@ module ArJdbc
|
|
92
92
|
|
93
93
|
def get_oid_type(oid, fmod, column_name, sql_type = '') # :nodoc:
|
94
94
|
if !type_map.key?(oid)
|
95
|
-
load_additional_types(
|
95
|
+
load_additional_types([oid])
|
96
96
|
end
|
97
97
|
|
98
98
|
type_map.fetch(oid, fmod, sql_type) {
|
@@ -103,132 +103,168 @@ module ArJdbc
|
|
103
103
|
}
|
104
104
|
end
|
105
105
|
|
106
|
+
def reload_type_map
|
107
|
+
type_map.clear
|
108
|
+
initialize_type_map
|
109
|
+
end
|
110
|
+
|
111
|
+
def initialize_type_map_inner(m)
|
112
|
+
m.register_type "int2", Type::Integer.new(limit: 2)
|
113
|
+
m.register_type "int4", Type::Integer.new(limit: 4)
|
114
|
+
m.register_type "int8", Type::Integer.new(limit: 8)
|
115
|
+
m.register_type "oid", OID::Oid.new
|
116
|
+
m.register_type "float4", Type::Float.new
|
117
|
+
m.alias_type "float8", "float4"
|
118
|
+
m.register_type "text", Type::Text.new
|
119
|
+
register_class_with_limit m, "varchar", Type::String
|
120
|
+
m.alias_type "char", "varchar"
|
121
|
+
m.alias_type "name", "varchar"
|
122
|
+
m.alias_type "bpchar", "varchar"
|
123
|
+
m.register_type "bool", Type::Boolean.new
|
124
|
+
register_class_with_limit m, "bit", OID::Bit
|
125
|
+
register_class_with_limit m, "varbit", OID::BitVarying
|
126
|
+
m.register_type "date", OID::Date.new
|
127
|
+
|
128
|
+
m.register_type "money", OID::Money.new
|
129
|
+
m.register_type "bytea", OID::Bytea.new
|
130
|
+
m.register_type "point", OID::Point.new
|
131
|
+
m.register_type "hstore", OID::Hstore.new
|
132
|
+
m.register_type "json", Type::Json.new
|
133
|
+
m.register_type "jsonb", OID::Jsonb.new
|
134
|
+
m.register_type "cidr", OID::Cidr.new
|
135
|
+
m.register_type "inet", OID::Inet.new
|
136
|
+
m.register_type "uuid", OID::Uuid.new
|
137
|
+
m.register_type "xml", OID::Xml.new
|
138
|
+
m.register_type "tsvector", OID::SpecializedString.new(:tsvector)
|
139
|
+
m.register_type "macaddr", OID::Macaddr.new
|
140
|
+
m.register_type "citext", OID::SpecializedString.new(:citext)
|
141
|
+
m.register_type "ltree", OID::SpecializedString.new(:ltree)
|
142
|
+
m.register_type "line", OID::SpecializedString.new(:line)
|
143
|
+
m.register_type "lseg", OID::SpecializedString.new(:lseg)
|
144
|
+
m.register_type "box", OID::SpecializedString.new(:box)
|
145
|
+
m.register_type "path", OID::SpecializedString.new(:path)
|
146
|
+
m.register_type "polygon", OID::SpecializedString.new(:polygon)
|
147
|
+
m.register_type "circle", OID::SpecializedString.new(:circle)
|
148
|
+
m.register_type "regproc", OID::Enum.new
|
149
|
+
# FIXME: adding this vector type leads to quoting not handlign Array data in quoting.
|
150
|
+
#m.register_type "_int4", OID::Vector.new(",", m.lookup("int4"))
|
151
|
+
register_class_with_precision m, "time", Type::Time
|
152
|
+
register_class_with_precision m, "timestamp", OID::Timestamp
|
153
|
+
register_class_with_precision m, "timestamptz", OID::TimestampWithTimeZone
|
154
|
+
|
155
|
+
m.register_type "numeric" do |_, fmod, sql_type|
|
156
|
+
precision = extract_precision(sql_type)
|
157
|
+
scale = extract_scale(sql_type)
|
158
|
+
|
159
|
+
# The type for the numeric depends on the width of the field,
|
160
|
+
# so we'll do something special here.
|
161
|
+
#
|
162
|
+
# When dealing with decimal columns:
|
163
|
+
#
|
164
|
+
# places after decimal = fmod - 4 & 0xffff
|
165
|
+
# places before decimal = (fmod - 4) >> 16 & 0xffff
|
166
|
+
if fmod && (fmod - 4 & 0xffff).zero?
|
167
|
+
# FIXME: Remove this class, and the second argument to
|
168
|
+
# lookups on PG
|
169
|
+
Type::DecimalWithoutScale.new(precision: precision)
|
170
|
+
else
|
171
|
+
OID::Decimal.new(precision: precision, scale: scale)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
m.register_type "interval" do |*args, sql_type|
|
176
|
+
precision = extract_precision(sql_type)
|
177
|
+
OID::Interval.new(precision: precision)
|
178
|
+
end
|
179
|
+
|
180
|
+
# pgjdbc returns these if the column is auto-incrmenting
|
181
|
+
m.alias_type 'serial', 'int4'
|
182
|
+
m.alias_type 'bigserial', 'int8'
|
183
|
+
end
|
184
|
+
|
185
|
+
|
186
|
+
# We differ from AR here because we will initialize type_map when adapter initializes
|
106
187
|
def type_map
|
107
188
|
@type_map
|
108
189
|
end
|
109
190
|
|
110
|
-
def
|
111
|
-
|
112
|
-
|
113
|
-
initialize_type_map(@type_map)
|
114
|
-
end
|
191
|
+
def initialize_type_map(m = type_map)
|
192
|
+
initialize_type_map_inner(m)
|
193
|
+
load_additional_types
|
115
194
|
end
|
116
195
|
|
117
196
|
private
|
118
197
|
|
119
|
-
def
|
120
|
-
register_class_with_limit
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
m.alias_type 'timestamptz', 'timestamp'
|
135
|
-
m.register_type 'date', OID::Date.new
|
136
|
-
|
137
|
-
m.register_type 'money', OID::Money.new
|
138
|
-
m.register_type 'bytea', OID::Bytea.new
|
139
|
-
m.register_type 'point', OID::Point.new
|
140
|
-
m.register_type 'hstore', OID::Hstore.new
|
141
|
-
m.register_type 'json', Type::Json.new
|
142
|
-
m.register_type 'jsonb', OID::Jsonb.new
|
143
|
-
m.register_type 'cidr', OID::Cidr.new
|
144
|
-
m.register_type 'inet', OID::Inet.new
|
145
|
-
m.register_type 'uuid', OID::Uuid.new
|
146
|
-
m.register_type 'xml', OID::Xml.new
|
147
|
-
m.register_type 'tsvector', OID::SpecializedString.new(:tsvector)
|
148
|
-
m.register_type 'macaddr', OID::Macaddr.new
|
149
|
-
m.register_type 'citext', OID::SpecializedString.new(:citext)
|
150
|
-
m.register_type 'ltree', OID::SpecializedString.new(:ltree)
|
151
|
-
m.register_type 'line', OID::SpecializedString.new(:line)
|
152
|
-
m.register_type 'lseg', OID::SpecializedString.new(:lseg)
|
153
|
-
m.register_type 'box', OID::SpecializedString.new(:box)
|
154
|
-
m.register_type 'path', OID::SpecializedString.new(:path)
|
155
|
-
m.register_type 'polygon', OID::SpecializedString.new(:polygon)
|
156
|
-
m.register_type 'circle', OID::SpecializedString.new(:circle)
|
157
|
-
|
158
|
-
m.register_type 'interval' do |*args, sql_type|
|
159
|
-
precision = extract_precision(sql_type)
|
160
|
-
OID::Interval.new(precision: precision)
|
198
|
+
def register_class_with_limit(...)
|
199
|
+
::ActiveRecord::ConnectionAdapters::AbstractAdapter.send(:register_class_with_limit, ...)
|
200
|
+
end
|
201
|
+
|
202
|
+
def register_class_with_precision(...)
|
203
|
+
::ActiveRecord::ConnectionAdapters::AbstractAdapter.send(:register_class_with_precision, ...)
|
204
|
+
end
|
205
|
+
|
206
|
+
def load_additional_types(oids = nil) # :nodoc:
|
207
|
+
initializer = ArjdbcTypeMapInitializer.new(type_map)
|
208
|
+
load_types_queries(initializer, oids) do |query|
|
209
|
+
execute_and_clear(query, "SCHEMA", []) do |records|
|
210
|
+
#puts "RECORDS: #{records.to_a}"
|
211
|
+
initializer.run(records)
|
212
|
+
end
|
161
213
|
end
|
214
|
+
end
|
162
215
|
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
#
|
173
|
-
# When dealing with decimal columns:
|
174
|
-
#
|
175
|
-
# places after decimal = fmod - 4 & 0xffff
|
176
|
-
# places before decimal = (fmod - 4) >> 16 & 0xffff
|
177
|
-
if fmod && (fmod - 4 & 0xffff).zero?
|
178
|
-
# FIXME: Remove this class, and the second argument to
|
179
|
-
# lookups on PG
|
180
|
-
Type::DecimalWithoutScale.new(precision: precision)
|
216
|
+
def load_types_queries(initializer, oids)
|
217
|
+
query = <<~SQL
|
218
|
+
SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype, t.typtype, t.typbasetype
|
219
|
+
FROM pg_type as t
|
220
|
+
LEFT JOIN pg_range as r ON oid = rngtypid
|
221
|
+
SQL
|
222
|
+
if oids
|
223
|
+
if oids.all? { |e| e.kind_of? Numeric }
|
224
|
+
yield query + "WHERE t.oid IN (%s)" % oids.join(", ")
|
181
225
|
else
|
182
|
-
|
226
|
+
in_list = oids.map { |e| %Q{'#{e}'} }.join(", ")
|
227
|
+
#puts caller[0..40]
|
228
|
+
puts "IN_LIST = #{in_list}"
|
229
|
+
yield query + "WHERE t.typname IN (%s)" % in_list
|
183
230
|
end
|
231
|
+
else
|
232
|
+
yield query + initializer.query_conditions_for_known_type_names
|
233
|
+
yield query + initializer.query_conditions_for_known_type_types
|
234
|
+
yield query + initializer.query_conditions_for_array_types
|
184
235
|
end
|
185
|
-
|
186
|
-
load_additional_types(m)
|
187
|
-
|
188
|
-
# pgjdbc returns these if the column is auto-incrmenting
|
189
|
-
m.alias_type 'serial', 'int4'
|
190
|
-
m.alias_type 'bigserial', 'int8'
|
191
236
|
end
|
192
237
|
|
193
|
-
def
|
194
|
-
|
238
|
+
def update_typemap_for_default_timezone
|
239
|
+
if @default_timezone != ActiveRecord.default_timezone && @timestamp_decoder
|
240
|
+
decoder_class = ActiveRecord.default_timezone == :utc ?
|
241
|
+
PG::TextDecoder::TimestampUtc :
|
242
|
+
PG::TextDecoder::TimestampWithoutTimeZone
|
195
243
|
|
196
|
-
|
197
|
-
|
198
|
-
SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype, t.typtype, t.typbasetype,
|
199
|
-
ns.nspname, ns.nspname = ANY(current_schemas(true)) in_ns
|
200
|
-
FROM pg_type as t
|
201
|
-
LEFT JOIN pg_range as r ON oid = rngtypid
|
202
|
-
JOIN pg_namespace AS ns ON t.typnamespace = ns.oid
|
203
|
-
SQL
|
204
|
-
else
|
205
|
-
query = <<-SQL
|
206
|
-
SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, t.typtype, t.typbasetype,
|
207
|
-
ns.nspname, ns.nspname = ANY(current_schemas(true)) in_ns
|
208
|
-
FROM pg_type as t
|
209
|
-
JOIN pg_namespace AS ns ON t.typnamespace = ns.oid
|
210
|
-
SQL
|
211
|
-
end
|
244
|
+
@timestamp_decoder = decoder_class.new(@timestamp_decoder.to_h)
|
245
|
+
@connection.type_map_for_results.add_coder(@timestamp_decoder)
|
212
246
|
|
213
|
-
|
214
|
-
if oid.is_a? Numeric || oid.match(/^\d+$/)
|
215
|
-
# numeric OID
|
216
|
-
query += "WHERE t.oid = %s" % oid
|
247
|
+
@default_timezone = ActiveRecord.default_timezone
|
217
248
|
|
218
|
-
|
219
|
-
|
220
|
-
|
249
|
+
# if default timezone has changed, we need to reconfigure the connection
|
250
|
+
# (specifically, the session time zone)
|
251
|
+
configure_connection
|
252
|
+
end
|
253
|
+
end
|
221
254
|
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
else
|
227
|
-
query += initializer.query_conditions_for_initial_load
|
255
|
+
def extract_scale(sql_type)
|
256
|
+
case sql_type
|
257
|
+
when /\((\d+)\)/ then 0
|
258
|
+
when /\((\d+)(,(\d+))\)/ then $3.to_i
|
228
259
|
end
|
260
|
+
end
|
261
|
+
|
262
|
+
def extract_precision(sql_type)
|
263
|
+
$1.to_i if sql_type =~ /\((\d+)(,\d+)?\)/
|
264
|
+
end
|
229
265
|
|
230
|
-
|
231
|
-
|
266
|
+
def extract_limit(sql_type)
|
267
|
+
$1.to_i if sql_type =~ /\((.*)\)/
|
232
268
|
end
|
233
269
|
|
234
270
|
# Support arrays/ranges for defining attributes that don't exist in the db
|