activerecord-jdbc-adapter 70.2-java → 72.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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +26 -26
  3. data/.gitignore +8 -0
  4. data/Gemfile +17 -4
  5. data/README.md +10 -5
  6. data/RUNNING_TESTS.md +36 -0
  7. data/activerecord-jdbc-adapter.gemspec +2 -2
  8. data/lib/arjdbc/abstract/connection_management.rb +25 -10
  9. data/lib/arjdbc/abstract/core.rb +15 -13
  10. data/lib/arjdbc/abstract/database_statements.rb +36 -36
  11. data/lib/arjdbc/abstract/relation_query_attribute_monkey_patch.rb +24 -0
  12. data/lib/arjdbc/abstract/statement_cache.rb +2 -7
  13. data/lib/arjdbc/abstract/transaction_support.rb +39 -22
  14. data/lib/arjdbc/jdbc/adapter.rb +0 -1
  15. data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
  16. data/lib/arjdbc/jdbc/column.rb +0 -34
  17. data/lib/arjdbc/jdbc/connection_methods.rb +1 -1
  18. data/lib/arjdbc/mysql/adapter.rb +108 -32
  19. data/lib/arjdbc/mysql/adapter_hash_config.rb +159 -0
  20. data/lib/arjdbc/mysql.rb +1 -1
  21. data/lib/arjdbc/postgresql/adapter.rb +267 -114
  22. data/lib/arjdbc/postgresql/adapter_hash_config.rb +98 -0
  23. data/lib/arjdbc/postgresql/base/array_encoder.rb +3 -1
  24. data/lib/arjdbc/postgresql/database_statements.rb +20 -0
  25. data/lib/arjdbc/postgresql/oid_types.rb +10 -29
  26. data/lib/arjdbc/postgresql/schema_statements.rb +57 -0
  27. data/lib/arjdbc/postgresql.rb +1 -1
  28. data/lib/arjdbc/sqlite3/adapter.rb +343 -172
  29. data/lib/arjdbc/sqlite3/adapter_hash_config.rb +91 -0
  30. data/lib/arjdbc/sqlite3/column.rb +117 -0
  31. data/lib/arjdbc/sqlite3/connection_methods.rb +7 -2
  32. data/lib/arjdbc/sqlite3/pragmas.rb +105 -0
  33. data/lib/arjdbc/sqlite3.rb +1 -1
  34. data/lib/arjdbc/version.rb +1 -1
  35. data/lib/arjdbc.rb +13 -1
  36. data/rakelib/02-test.rake +2 -2
  37. data/rakelib/rails.rake +2 -0
  38. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +9 -2
  39. data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +12 -5
  40. data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +14 -3
  41. metadata +15 -11
  42. data/lib/arjdbc/jdbc/base_ext.rb +0 -17
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ArJdbc
4
+ module PostgreSQLConfig
5
+ def build_connection_config(config)
6
+ config = config.deep_dup
7
+
8
+ load_jdbc_driver
9
+
10
+ config[:driver] ||= database_driver_name
11
+
12
+ host = (config[:host] ||= config[:hostaddr] || ENV["PGHOST"] || "localhost")
13
+ port = (config[:port] ||= ENV["PGPORT"] || 5432)
14
+ database = config[:database] || config[:dbname] || ENV["PGDATABASE"]
15
+
16
+ app = config[:application_name] || config[:appname] || config[:application]
17
+
18
+ config[:url] ||= if app
19
+ "jdbc:postgresql://#{host}:#{port}/#{database}?ApplicationName=#{app}"
20
+ else
21
+ "jdbc:postgresql://#{host}:#{port}/#{database}"
22
+ end
23
+
24
+ config[:url] << config[:pg_params] if config[:pg_params]
25
+
26
+ config[:username] ||= config[:user] || ENV["PGUSER"] || ENV_JAVA["user.name"]
27
+ config[:password] ||= ENV["PGPASSWORD"] unless config.key?(:password)
28
+
29
+ config[:properties] = build_properties(config)
30
+
31
+ config
32
+ end
33
+
34
+ private
35
+
36
+ def load_jdbc_driver
37
+ require "jdbc/postgres"
38
+
39
+ ::Jdbc::Postgres.load_driver(:require) if defined?(::Jdbc::Postgres.load_driver)
40
+ rescue LoadError
41
+ # assuming driver.jar is on the class-path
42
+ end
43
+
44
+ def database_driver_name
45
+ return ::Jdbc::Postgres.driver_name if defined?(::Jdbc::Postgres.driver_name)
46
+
47
+ "org.postgresql.Driver"
48
+ end
49
+
50
+ def build_properties(config)
51
+ properties = config[:properties] || {}
52
+
53
+ # PG :connect_timeout - maximum time to wait for connection to succeed
54
+ connect_timeout = config[:connect_timeout] || ENV["PGCONNECT_TIMEOUT"]
55
+
56
+ properties["socketTimeout"] ||= connect_timeout if connect_timeout
57
+
58
+ login_timeout = config[:login_timeout]
59
+
60
+ properties["loginTimeout"] ||= login_timeout if login_timeout
61
+
62
+ sslmode = config.key?(:sslmode) ? config[:sslmode] : config[:requiressl]
63
+ # NOTE: makes not much sense since this needs some JVM options :
64
+ sslmode = ENV["PGSSLMODE"] || ENV["PGREQUIRESSL"] if sslmode.nil?
65
+
66
+ # PG :sslmode - disable|allow|prefer|require
67
+ unless sslmode.nil? || !(sslmode == true || sslmode.to_s == "require")
68
+ # JRuby/JVM needs to be started with :
69
+ # -Djavax.net.ssl.trustStore=mystore -Djavax.net.ssl.trustStorePassword=...
70
+ # or a non-validating connection might be used (for testing) :
71
+ # :sslfactory = 'org.postgresql.ssl.NonValidatingFactory'
72
+
73
+ if config[:driver].start_with?("org.postgresql.")
74
+ properties["sslfactory"] ||= "org.postgresql.ssl.NonValidatingFactory"
75
+ end
76
+
77
+ properties["ssl"] ||= "true"
78
+ end
79
+
80
+ properties["tcpKeepAlive"] ||= config[:keepalives] if config.key?(:keepalives)
81
+ properties["kerberosServerName"] ||= config[:krbsrvname] if config[:krbsrvname]
82
+
83
+ prepared_statements = config.fetch(:prepared_statements, true)
84
+
85
+ prepared_statements = false if prepared_statements == "false"
86
+
87
+ if prepared_statements
88
+ # this makes the pgjdbc driver handle hot compatibility internally
89
+ properties["autosave"] ||= "conservative"
90
+ else
91
+ # If prepared statements are off, lets make sure they are really *off*
92
+ properties["prepareThreshold"] = 0
93
+ end
94
+
95
+ properties
96
+ end
97
+ end
98
+ end
@@ -12,7 +12,9 @@ module ActiveRecord::ConnectionAdapters::PostgreSQL::OID
12
12
  'text'.freeze
13
13
  else
14
14
  base_type = name.chomp('[]').to_sym
15
- ActiveRecord::Base.connection.native_database_types[base_type][:name]
15
+ ActiveRecord::Base.with_connection do |connection|
16
+ connection.native_database_types[base_type][:name]
17
+ end
16
18
  end
17
19
  end
18
20
 
@@ -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
@@ -67,28 +67,6 @@ module ArJdbc
67
67
 
68
68
  # @private
69
69
  module OIDTypes
70
-
71
- # @override
72
- def enable_extension(name)
73
- result = super(name)
74
- @extensions = nil
75
- reload_type_map
76
- result
77
- end
78
-
79
- # @override
80
- def disable_extension(name)
81
- result = super(name)
82
- @extensions = nil
83
- reload_type_map
84
- result
85
- end
86
-
87
- # @override
88
- def extensions
89
- @extensions ||= super
90
- end
91
-
92
70
  def get_oid_type(oid, fmod, column_name, sql_type = '') # :nodoc:
93
71
  # Note: type_map is storing a bunch of oid type prefixed with a namespace even
94
72
  # if they are not namespaced (e.g. ""."oidvector"). builtin types which are
@@ -118,8 +96,15 @@ module ArJdbc
118
96
  end
119
97
 
120
98
  def reload_type_map
121
- type_map.clear
99
+ @lock.synchronize do
100
+ if @type_map
101
+ type_map.clear
102
+ else
103
+ @type_map = Type::HashLookupTypeMap.new
104
+ end
105
+
122
106
  initialize_type_map
107
+ end
123
108
  end
124
109
 
125
110
  def initialize_type_map_inner(m)
@@ -127,8 +112,8 @@ module ArJdbc
127
112
  m.register_type "int4", Type::Integer.new(limit: 4)
128
113
  m.register_type "int8", Type::Integer.new(limit: 8)
129
114
  m.register_type "oid", OID::Oid.new
130
- m.register_type "float4", Type::Float.new
131
- m.alias_type "float8", "float4"
115
+ m.register_type "float4", Type::Float.new(limit: 24)
116
+ m.register_type "float8", Type::Float.new
132
117
  m.register_type "text", Type::Text.new
133
118
  register_class_with_limit m, "varchar", Type::String
134
119
  m.alias_type "char", "varchar"
@@ -274,10 +259,6 @@ module ArJdbc
274
259
  $1.to_i if sql_type =~ /\((\d+)(,\d+)?\)/
275
260
  end
276
261
 
277
- def extract_limit(sql_type)
278
- $1.to_i if sql_type =~ /\((.*)\)/
279
- end
280
-
281
262
  # Support arrays/ranges for defining attributes that don't exist in the db
282
263
  ActiveRecord::Type.add_modifier({ array: true }, OID::Array, adapter: :postgresql)
283
264
  ActiveRecord::Type.add_modifier({ range: true }, OID::Range, adapter: :postgresql)
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ArJdbc
4
+ module PostgreSQL
5
+ module SchemaStatements
6
+ ForeignKeyDefinition = ActiveRecord::ConnectionAdapters::ForeignKeyDefinition
7
+ Utils = ActiveRecord::ConnectionAdapters::PostgreSQL::Utils
8
+
9
+ def foreign_keys(table_name)
10
+ scope = quoted_scope(table_name)
11
+ fk_info = internal_exec_query(<<~SQL, "SCHEMA", allow_retry: true, materialize_transactions: false)
12
+ SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete, c.convalidated AS valid, c.condeferrable AS deferrable, c.condeferred AS deferred, c.conkey, c.confkey, c.conrelid, c.confrelid
13
+ FROM pg_constraint c
14
+ JOIN pg_class t1 ON c.conrelid = t1.oid
15
+ JOIN pg_class t2 ON c.confrelid = t2.oid
16
+ JOIN pg_attribute a1 ON a1.attnum = c.conkey[1] AND a1.attrelid = t1.oid
17
+ JOIN pg_attribute a2 ON a2.attnum = c.confkey[1] AND a2.attrelid = t2.oid
18
+ JOIN pg_namespace t3 ON c.connamespace = t3.oid
19
+ WHERE c.contype = 'f'
20
+ AND t1.relname = #{scope[:name]}
21
+ AND t3.nspname = #{scope[:schema]}
22
+ ORDER BY c.conname
23
+ SQL
24
+
25
+ fk_info.map do |row|
26
+ to_table = Utils.unquote_identifier(row["to_table"])
27
+ # conkey = row["conkey"].scan(/\d+/).map(&:to_i)
28
+ # confkey = row["confkey"].scan(/\d+/).map(&:to_i)
29
+ conkey = row["conkey"]
30
+ confkey = row["confkey"]
31
+
32
+ if conkey.size > 1
33
+ column = column_names_from_column_numbers(row["conrelid"], conkey)
34
+ primary_key = column_names_from_column_numbers(row["confrelid"], confkey)
35
+ else
36
+ column = Utils.unquote_identifier(row["column"])
37
+ primary_key = row["primary_key"]
38
+ end
39
+
40
+ options = {
41
+ column: column,
42
+ name: row["name"],
43
+ primary_key: primary_key
44
+ }
45
+
46
+ options[:on_delete] = extract_foreign_key_action(row["on_delete"])
47
+ options[:on_update] = extract_foreign_key_action(row["on_update"])
48
+ options[:deferrable] = extract_constraint_deferrable(row["deferrable"], row["deferred"])
49
+
50
+ options[:validate] = row["valid"]
51
+
52
+ ForeignKeyDefinition.new(table_name, to_table, options)
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -1,3 +1,3 @@
1
1
  require 'arjdbc'
2
2
  require 'arjdbc/postgresql/adapter'
3
- require 'arjdbc/postgresql/connection_methods'
3
+ # require 'arjdbc/postgresql/connection_methods'