activerecord-yugabytedb-adapter 7.0.4.1 → 7.1.3.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3db689c384694018413781b6b103d41fe67fa1f01e9e26e7e628b4bb2bb07535
4
- data.tar.gz: '008122cddcd6ff3d30c3527c67d4455f91298a7822242f8de51d4abc8add98eb'
3
+ metadata.gz: f2cc03a2de664cf174a7f51d10d8a7d466a1746a2a664e65c84a063b1690c176
4
+ data.tar.gz: 81ca6a9131426b34378264ffac4495387b1351c5c23cf476ab32334f07676696
5
5
  SHA512:
6
- metadata.gz: c23aaf43a62c4a84848678204dd9cf54184bff185e0998955a0c13e6c7bd2cd84ba1c966567a31236678abe128cd91937c3fcbe51c55c8cbc866bfff2837dc11
7
- data.tar.gz: f87027546cb7cdb1cb732bc0b880eda9eb20e599f87af2f4bd3e21f51d769503bc820ac4e99c7c44e255f8aea0dd60e686b827f17a5c0f974f460e69969f1a9e
6
+ metadata.gz: 0ffc610ae76a0d049e8bd35eeea4b5c7ef557c5774768be0b7d28c78da446893813fd2342b339d91b11363ccd3fbfcefda0514b7ed1976d87088ec85b12a82e8
7
+ data.tar.gz: d2a122f7b7af63ab3434ae6dfbfa7d05993a6f3aeb7fc6ae6149196857f7125aa3b712babd67ce18b963076ea52ae9362c93fd8fa2f7a7a083c1dc66e8f0f294
data/Gemfile.lock CHANGED
@@ -2,29 +2,40 @@ PATH
2
2
  remote: .
3
3
  specs:
4
4
  activerecord-yugabytedb-adapter (7.0.4.1)
5
- activerecord (= 7.0.4)
6
- yugabyte_ysql (~> 0.3)
5
+ activerecord (= 7.1.3.4)
6
+ yugabytedb-ysql (~> 0.3)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- activemodel (7.0.4)
12
- activesupport (= 7.0.4)
13
- activerecord (7.0.4)
14
- activemodel (= 7.0.4)
15
- activesupport (= 7.0.4)
16
- activesupport (7.0.4)
11
+ activemodel (7.1.3.4)
12
+ activesupport (= 7.1.3.4)
13
+ activerecord (7.1.3.4)
14
+ activemodel (= 7.1.3.4)
15
+ activesupport (= 7.1.3.4)
16
+ timeout (>= 0.4.0)
17
+ activesupport (7.1.3.4)
18
+ base64
19
+ bigdecimal
17
20
  concurrent-ruby (~> 1.0, >= 1.0.2)
21
+ connection_pool (>= 2.2.5)
22
+ drb
18
23
  i18n (>= 1.6, < 2)
19
24
  minitest (>= 5.1)
25
+ mutex_m
20
26
  tzinfo (~> 2.0)
21
27
  ast (2.4.2)
28
+ base64 (0.2.0)
29
+ bigdecimal (3.1.8)
22
30
  concurrent-ruby (1.3.3)
31
+ connection_pool (2.4.1)
32
+ drb (2.2.1)
23
33
  i18n (1.14.5)
24
34
  concurrent-ruby (~> 1.0)
25
35
  json (2.7.2)
26
36
  language_server-protocol (3.17.0.3)
27
37
  minitest (5.24.0)
38
+ mutex_m (0.2.0)
28
39
  parallel (1.25.1)
29
40
  parser (3.3.3.0)
30
41
  ast (~> 2.4.1)
@@ -50,10 +61,11 @@ GEM
50
61
  parser (>= 3.3.1.0)
51
62
  ruby-progressbar (1.13.0)
52
63
  strscan (3.1.0)
64
+ timeout (0.4.1)
53
65
  tzinfo (2.0.6)
54
66
  concurrent-ruby (~> 1.0)
55
67
  unicode-display_width (2.5.0)
56
- yugabyte_ysql (0.3)
68
+ yugabytedb-ysql (0.3)
57
69
 
58
70
  PLATFORMS
59
71
  x86_64-linux
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # ActiveRecord YugabyteDB Adapter
2
2
 
3
- This is an adapter for YugabyteDB for ActiveRecord. The adapter uses YugabyteDB's Ruby smart driver underneath. The adapter code is derived from the [PostgreSQL adapter v7.0.4 for ActiveRecord in the Rails repository](https://github.com/rails/rails/tree/v7.0.4/activerecord/lib/active_record/connection_adapters).
3
+ This is an adapter for YugabyteDB for ActiveRecord. The adapter uses YugabyteDB's Ruby smart driver underneath. The adapter code is derived from the [PostgreSQL adapter v7.1.3.4 for ActiveRecord in the Rails repository](https://github.com/rails/rails/tree/v7.1.3.4/activerecord/lib/active_record/connection_adapters).
4
4
 
5
5
  ## Installation
6
6
 
@@ -14,7 +14,13 @@ If bundler is not being used to manage dependencies, install the gem by executin
14
14
 
15
15
  ## Usage
16
16
 
17
- Check this [simple example](https://github.com/YugabyteDB-Samples/orm-examples/tree/ruby-smart-driver) for usage of this adapter.
17
+ Include the gem in your `Gemfile`
18
+ ```ruby
19
+ gem 'rails', '7.1.3.4'
20
+ gem 'activerecord-yugabytedb-adapter', '7.1.3.4'
21
+ ```
22
+
23
+ Check this [simple example](https://github.com/YugabyteDB-Samples/orm-examples/tree/ruby-smart-driver/ruby/ror) for usage of this adapter.
18
24
 
19
25
  ## Development
20
26
 
@@ -30,8 +30,8 @@ Gem::Specification.new do |spec|
30
30
 
31
31
  # Uncomment to register a new dependency of your gem
32
32
  # spec.add_dependency "example-gem", "~> 1.0"
33
- spec.add_dependency "activerecord", "7.0.4"
34
- spec.add_dependency "yugabyte_ysql", "~> 0.3"
33
+ spec.add_dependency "activerecord", "7.1.3.4"
34
+ spec.add_dependency "yugabytedb-ysql", "~> 0.3"
35
35
 
36
36
 
37
37
  # For more information and examples about making a new gem, check out our
@@ -1,23 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/object/blank"
4
-
5
3
  module ActiveRecord
6
4
  module ConnectionAdapters
7
5
  module YugabyteDB
8
6
  class Column < ConnectionAdapters::Column # :nodoc:
9
7
  delegate :oid, :fmod, to: :sql_type_metadata
10
8
 
11
- def initialize(*, serial: nil, generated: nil, **)
9
+ def initialize(*, serial: nil, identity: nil, generated: nil, **)
12
10
  super
13
11
  @serial = serial
12
+ @identity = identity
14
13
  @generated = generated
15
14
  end
16
15
 
16
+ def identity?
17
+ @identity
18
+ end
19
+
17
20
  def serial?
18
21
  @serial
19
22
  end
20
23
 
24
+ def auto_incremented_by_db?
25
+ serial? || identity?
26
+ end
27
+
21
28
  def virtual?
22
29
  # We assume every generated column is virtual, no matter the concrete type
23
30
  @generated.present?
@@ -42,17 +49,22 @@ module ActiveRecord
42
49
 
43
50
  def init_with(coder)
44
51
  @serial = coder["serial"]
52
+ @identity = coder["identity"]
53
+ @generated = coder["generated"]
45
54
  super
46
55
  end
47
56
 
48
57
  def encode_with(coder)
49
58
  coder["serial"] = @serial
59
+ coder["identity"] = @identity
60
+ coder["generated"] = @generated
50
61
  super
51
62
  end
52
63
 
53
64
  def ==(other)
54
65
  other.is_a?(Column) &&
55
66
  super &&
67
+ identity? == other.identity? &&
56
68
  serial? == other.serial?
57
69
  end
58
70
  alias :eql? :==
@@ -60,6 +72,7 @@ module ActiveRecord
60
72
  def hash
61
73
  Column.hash ^
62
74
  super.hash ^
75
+ identity?.hash ^
63
76
  serial?.hash
64
77
  end
65
78
  end
@@ -4,19 +4,21 @@ module ActiveRecord
4
4
  module ConnectionAdapters
5
5
  module YugabyteDB
6
6
  module DatabaseStatements
7
- def explain(arel, binds = [])
8
- sql = "EXPLAIN #{to_sql(arel, binds)}"
9
- YugabyteDB::ExplainPrettyPrinter.new.pp(exec_query(sql, "EXPLAIN", binds))
7
+ def explain(arel, binds = [], options = [])
8
+ sql = build_explain_clause(options) + " " + to_sql(arel, binds)
9
+ result = internal_exec_query(sql, "EXPLAIN", binds)
10
+ YugabyteDB::ExplainPrettyPrinter.new.pp(result)
10
11
  end
11
12
 
12
13
  # Queries the database and returns the results in an Array-like object
13
14
  def query(sql, name = nil) # :nodoc:
14
- materialize_transactions
15
15
  mark_transaction_written_if_write(sql)
16
16
 
17
17
  log(sql, name) do
18
- ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
19
- @connection.async_exec(sql).map_types!(@type_map_for_results).values
18
+ with_raw_connection do |conn|
19
+ result = conn.async_exec(sql).map_types!(@type_map_for_results).values
20
+ verified!
21
+ result
20
22
  end
21
23
  end
22
24
  end
@@ -34,34 +36,38 @@ module ActiveRecord
34
36
 
35
37
  # Executes an SQL statement, returning a PG::Result object on success
36
38
  # or raising a PG::Error exception otherwise.
39
+ #
40
+ # Setting +allow_retry+ to true causes the db to reconnect and retry
41
+ # executing the SQL statement in case of a connection-related exception.
42
+ # This option should only be enabled for known idempotent queries.
43
+ #
37
44
  # Note: the PG::Result object is manually memory managed; if you don't
38
45
  # need it specifically, you may want consider the <tt>exec_query</tt> wrapper.
39
- def execute(sql, name = nil)
40
- sql = transform_query(sql)
41
- check_if_write_query(sql)
42
-
43
- materialize_transactions
44
- mark_transaction_written_if_write(sql)
46
+ def execute(...) # :nodoc:
47
+ super
48
+ ensure
49
+ @notice_receiver_sql_warnings = []
50
+ end
45
51
 
46
- log(sql, name) do
47
- ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
48
- @connection.async_exec(sql)
52
+ def raw_execute(sql, name, async: false, allow_retry: false, materialize_transactions: true)
53
+ log(sql, name, async: async) do
54
+ with_raw_connection(allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |conn|
55
+ result = conn.async_exec(sql)
56
+ verified!
57
+ handle_warnings(result)
58
+ result
49
59
  end
50
60
  end
51
61
  end
52
62
 
53
- def exec_query(sql, name = "SQL", binds = [], prepare: false, async: false) # :nodoc:
54
- execute_and_clear(sql, name, binds, prepare: prepare, async: async) do |result|
63
+ def internal_exec_query(sql, name = "SQL", binds = [], prepare: false, async: false, allow_retry: false, materialize_transactions: true) # :nodoc:
64
+ execute_and_clear(sql, name, binds, prepare: prepare, async: async, allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |result|
55
65
  types = {}
56
66
  fields = result.fields
57
67
  fields.each_with_index do |fname, i|
58
68
  ftype = result.ftype i
59
69
  fmod = result.fmod i
60
- case type = get_oid_type(ftype, fmod, fname)
61
- when Type::Integer, Type::Float, OID::Decimal, Type::String, Type::DateTime, Type::Boolean
62
- # skip if a column has already been type casted by pg decoders
63
- else types[fname] = type
64
- end
70
+ types[fname] = types[i] = get_oid_type(ftype, fmod, fname)
65
71
  end
66
72
  build_result(columns: fields, rows: result.values, column_types: types)
67
73
  end
@@ -72,26 +78,11 @@ module ActiveRecord
72
78
  end
73
79
  alias :exec_update :exec_delete
74
80
 
75
- def sql_for_insert(sql, pk, binds) # :nodoc:
76
- if pk.nil?
77
- # Extract the table from the insert sql. Yuck.
78
- table_ref = extract_table_ref_from_insert_sql(sql)
79
- pk = primary_key(table_ref) if table_ref
80
- end
81
-
82
- if pk = suppress_composite_primary_key(pk)
83
- sql = "#{sql} RETURNING #{quote_column_name(pk)}"
84
- end
85
-
86
- super
87
- end
88
- private :sql_for_insert
89
-
90
- def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil) # :nodoc:
81
+ def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil, returning: nil) # :nodoc:
91
82
  if use_insert_returning? || pk == false
92
83
  super
93
84
  else
94
- result = exec_query(sql, name, binds)
85
+ result = internal_exec_query(sql, name, binds)
95
86
  unless sequence_name
96
87
  table_ref = extract_table_ref_from_insert_sql(sql)
97
88
  if table_ref
@@ -107,22 +98,27 @@ module ActiveRecord
107
98
 
108
99
  # Begins a transaction.
109
100
  def begin_db_transaction # :nodoc:
110
- execute("BEGIN", "TRANSACTION")
101
+ internal_execute("BEGIN", "TRANSACTION", allow_retry: true, materialize_transactions: false)
111
102
  end
112
103
 
113
104
  def begin_isolated_db_transaction(isolation) # :nodoc:
114
- begin_db_transaction
115
- execute "SET TRANSACTION ISOLATION LEVEL #{transaction_isolation_levels.fetch(isolation)}"
105
+ internal_execute("BEGIN ISOLATION LEVEL #{transaction_isolation_levels.fetch(isolation)}", "TRANSACTION", allow_retry: true, materialize_transactions: false)
116
106
  end
117
107
 
118
108
  # Commits a transaction.
119
109
  def commit_db_transaction # :nodoc:
120
- execute("COMMIT", "TRANSACTION")
110
+ internal_execute("COMMIT", "TRANSACTION", allow_retry: false, materialize_transactions: true)
121
111
  end
122
112
 
123
113
  # Aborts a transaction.
124
114
  def exec_rollback_db_transaction # :nodoc:
125
- execute("ROLLBACK", "TRANSACTION")
115
+ cancel_any_running_query
116
+ internal_execute("ROLLBACK", "TRANSACTION", allow_retry: false, materialize_transactions: true)
117
+ end
118
+
119
+ def exec_restart_db_transaction # :nodoc:
120
+ cancel_any_running_query
121
+ internal_execute("ROLLBACK AND CHAIN", "TRANSACTION", allow_retry: false, materialize_transactions: true)
126
122
  end
127
123
 
128
124
  # From https://www.postgresql.org/docs/current/functions-datetime.html#FUNCTIONS-DATETIME-CURRENT
@@ -133,7 +129,24 @@ module ActiveRecord
133
129
  HIGH_PRECISION_CURRENT_TIMESTAMP
134
130
  end
135
131
 
132
+ def build_explain_clause(options = [])
133
+ return "EXPLAIN" if options.empty?
134
+
135
+ "EXPLAIN (#{options.join(", ").upcase})"
136
+ end
137
+
136
138
  private
139
+ IDLE_TRANSACTION_STATUSES = [YSQL::PQTRANS_IDLE, YSQL::PQTRANS_INTRANS, YSQL::PQTRANS_INERROR]
140
+ private_constant :IDLE_TRANSACTION_STATUSES
141
+
142
+ def cancel_any_running_query
143
+ return if @raw_connection.nil? || IDLE_TRANSACTION_STATUSES.include?(@raw_connection.transaction_status)
144
+
145
+ @raw_connection.cancel
146
+ @raw_connection.block
147
+ rescue YSQL::Error
148
+ end
149
+
137
150
  def execute_batch(statements, name = nil)
138
151
  execute(combine_multi_statements(statements))
139
152
  end
@@ -144,12 +157,29 @@ module ActiveRecord
144
157
 
145
158
  # Returns the current ID of a table's sequence.
146
159
  def last_insert_id_result(sequence_name)
147
- exec_query("SELECT currval(#{quote(sequence_name)})", "SQL")
160
+ internal_exec_query("SELECT currval(#{quote(sequence_name)})", "SQL")
161
+ end
162
+
163
+ def returning_column_values(result)
164
+ result.rows.first
148
165
  end
149
166
 
150
167
  def suppress_composite_primary_key(pk)
151
168
  pk unless pk.is_a?(Array)
152
169
  end
170
+
171
+ def handle_warnings(sql)
172
+ @notice_receiver_sql_warnings.each do |warning|
173
+ next if warning_ignored?(warning)
174
+
175
+ warning.sql = sql
176
+ ActiveRecord.db_warnings_action.call(warning)
177
+ end
178
+ end
179
+
180
+ def warning_ignored?(warning)
181
+ ["WARNING", "ERROR", "FATAL", "PANIC"].exclude?(warning.level) || super
182
+ end
153
183
  end
154
184
  end
155
185
  end
@@ -16,8 +16,8 @@ module ActiveRecord
16
16
  @subtype = subtype
17
17
  @delimiter = delimiter
18
18
 
19
- @pg_encoder = YugabyteYSQL::TextEncoder::Array.new name: "#{type}[]", delimiter: delimiter
20
- @pg_decoder = YugabyteYSQL::TextDecoder::Array.new name: "#{type}[]", delimiter: delimiter
19
+ @pg_encoder = YSQL::TextEncoder::Array.new name: "#{type}[]", delimiter: delimiter
20
+ @pg_decoder = YSQL::TextDecoder::Array.new name: "#{type}[]", delimiter: delimiter
21
21
  end
22
22
 
23
23
  def deserialize(value)
@@ -65,7 +65,7 @@ module ActiveRecord
65
65
  end
66
66
 
67
67
  def map(value, &block)
68
- value.map(&block)
68
+ value.map { |v| subtype.map(v, &block) }
69
69
  end
70
70
 
71
71
  def changed_in_place?(raw_old_value, new_value)
@@ -8,7 +8,7 @@ module ActiveRecord
8
8
  def deserialize(value)
9
9
  return if value.nil?
10
10
  return value.to_s if value.is_a?(Type::Binary::Data)
11
- YugabyteYSQL::Connection.unescape_bytea(super)
11
+ YSQL::Connection.unescape_bytea(super)
12
12
  end
13
13
  end
14
14
  end
@@ -27,9 +27,10 @@ module ActiveRecord
27
27
  value = value.sub(/^\((.+)\)$/, '-\1') # (4)
28
28
  case value
29
29
  when /^-?\D*+[\d,]+\.\d{2}$/ # (1)
30
- value.gsub!(/[^-\d.]/, "")
30
+ value.delete!("^-0-9.")
31
31
  when /^-?\D*+[\d.]+,\d{2}$/ # (2)
32
- value.gsub!(/[^-\d,]/, "").sub!(/,/, ".")
32
+ value.delete!("^-0-9,")
33
+ value.tr!(",", ".")
33
34
  end
34
35
 
35
36
  super(value)
@@ -18,7 +18,7 @@ module ActiveRecord
18
18
  end
19
19
 
20
20
  def cast_value(value)
21
- return if value == "empty"
21
+ return if ["empty", ""].include? value
22
22
  return value unless value.is_a?(::String)
23
23
 
24
24
  extracted = extract_bounds(value)
@@ -28,7 +28,7 @@ module ActiveRecord
28
28
  if !infinity?(from) && extracted[:exclude_start]
29
29
  raise ArgumentError, "The Ruby Range object does not support excluding the beginning of a Range. (unsupported value: '#{value}')"
30
30
  end
31
- ::Range.new(from, to, extracted[:exclude_end])
31
+ ::Range.new(*sanitize_bounds(from, to), extracted[:exclude_end])
32
32
  end
33
33
 
34
34
  def serialize(value)
@@ -76,6 +76,15 @@ module ActiveRecord
76
76
  }
77
77
  end
78
78
 
79
+ INFINITE_FLOAT_RANGE = (-::Float::INFINITY)..(::Float::INFINITY) # :nodoc:
80
+
81
+ def sanitize_bounds(from, to)
82
+ [
83
+ (from == -::Float::INFINITY && !INFINITE_FLOAT_RANGE.cover?(to)) ? nil : from,
84
+ (to == ::Float::INFINITY && !INFINITE_FLOAT_RANGE.cover?(from)) ? nil : to
85
+ ]
86
+ end
87
+
79
88
  # When formatting the bound values of range types, PostgreSQL quotes
80
89
  # the bound value using double-quotes in certain conditions. Within
81
90
  # a double-quoted string, literal " and \ characters are themselves
@@ -13,9 +13,9 @@ module ActiveRecord
13
13
  return if value.blank?
14
14
 
15
15
  time = super
16
- return time if time.is_a?(ActiveSupport::TimeWithZone)
16
+ return time if time.is_a?(ActiveSupport::TimeWithZone) || !time.acts_like?(:time)
17
17
 
18
- # While in UTC mode, the PG gem may not return times back in "UTC" even if they were provided to Postgres in UTC.
18
+ # While in UTC mode, the PG gem may not return times back in "UTC" even if they were provided to PostgreSQL in UTC.
19
19
  # We prefer times always in UTC, so here we convert back.
20
20
  if is_utc?
21
21
  time.getutc
@@ -4,19 +4,48 @@ module ActiveRecord
4
4
  module ConnectionAdapters
5
5
  module YugabyteDB
6
6
  module Quoting
7
+ QUOTED_COLUMN_NAMES = Concurrent::Map.new # :nodoc:
8
+ QUOTED_TABLE_NAMES = Concurrent::Map.new # :nodoc:
9
+
10
+ class IntegerOutOf64BitRange < StandardError
11
+ def initialize(msg)
12
+ super(msg)
13
+ end
14
+ end
15
+
7
16
  # Escapes binary strings for bytea input to the database.
8
17
  def escape_bytea(value)
9
- @connection.escape_bytea(value) if value
18
+ valid_raw_connection.escape_bytea(value) if value
10
19
  end
11
20
 
12
21
  # Unescapes bytea output from a database to the binary string it represents.
13
22
  # NOTE: This is NOT an inverse of escape_bytea! This is only to be used
14
23
  # on escaped binary output from database drive.
15
24
  def unescape_bytea(value)
16
- @connection.unescape_bytea(value) if value
25
+ valid_raw_connection.unescape_bytea(value) if value
26
+ end
27
+
28
+ def check_int_in_range(value)
29
+ if value.to_int > 9223372036854775807 || value.to_int < -9223372036854775808
30
+ exception = <<~ERROR
31
+ Provided value outside of the range of a signed 64bit integer.
32
+
33
+ PostgreSQL will treat the column type in question as a numeric.
34
+ This may result in a slow sequential scan due to a comparison
35
+ being performed between an integer or bigint value and a numeric value.
36
+
37
+ To allow for this potentially unwanted behavior, set
38
+ ActiveRecord.raise_int_wider_than_64bit to false.
39
+ ERROR
40
+ raise IntegerOutOf64BitRange.new exception
41
+ end
17
42
  end
18
43
 
19
44
  def quote(value) # :nodoc:
45
+ if ActiveRecord.raise_int_wider_than_64bit && value.is_a?(Integer)
46
+ check_int_in_range(value)
47
+ end
48
+
20
49
  case value
21
50
  when OID::Xml::Data
22
51
  "xml '#{quote_string(value.to_s)}'"
@@ -43,7 +72,9 @@ module ActiveRecord
43
72
 
44
73
  # Quotes strings for use in SQL input.
45
74
  def quote_string(s) # :nodoc:
46
- @connection.escape(s)
75
+ with_raw_connection(allow_retry: true, materialize_transactions: false) do |connection|
76
+ connection.escape(s)
77
+ end
47
78
  end
48
79
 
49
80
  # Checks the following cases:
@@ -55,12 +86,12 @@ module ActiveRecord
55
86
  # - "schema.name".table_name
56
87
  # - "schema.name"."table.name"
57
88
  def quote_table_name(name) # :nodoc:
58
- self.class.quoted_table_names[name] ||= Utils.extract_schema_qualified_name(name.to_s).quoted.freeze
89
+ QUOTED_TABLE_NAMES[name] ||= Utils.extract_schema_qualified_name(name.to_s).quoted.freeze
59
90
  end
60
91
 
61
92
  # Quotes schema names for use in SQL queries.
62
93
  def quote_schema_name(name)
63
- YugabyteYSQL::Connection.quote_ident(name)
94
+ YSQL::Connection.quote_ident(name)
64
95
  end
65
96
 
66
97
  def quote_table_name_for_assignment(table, attr)
@@ -69,7 +100,7 @@ module ActiveRecord
69
100
 
70
101
  # Quotes column names for use in SQL queries.
71
102
  def quote_column_name(name) # :nodoc:
72
- self.class.quoted_column_names[name] ||= YugabyteYSQL::Connection.quote_ident(super).freeze
103
+ QUOTED_COLUMN_NAMES[name] ||= YSQL::Connection.quote_ident(super).freeze
73
104
  end
74
105
 
75
106
  # Quote date/time values for use in SQL input.
@@ -89,7 +120,7 @@ module ActiveRecord
89
120
  def quote_default_expression(value, column) # :nodoc:
90
121
  if value.is_a?(Proc)
91
122
  value.call
92
- elsif column.type == :uuid && value.is_a?(String) && /\(\)/.match?(value)
123
+ elsif column.type == :uuid && value.is_a?(String) && value.include?("()")
93
124
  value # Does not quote function default values for UUID columns
94
125
  elsif column.respond_to?(:array?)
95
126
  type = lookup_cast_type_from_column(column)
@@ -118,6 +149,7 @@ module ActiveRecord
118
149
  end
119
150
 
120
151
  def lookup_cast_type_from_column(column) # :nodoc:
152
+ verify! if type_map.nil?
121
153
  type_map.lookup(column.oid, column.fmod, column.sql_type)
122
154
  end
123
155
 
@@ -134,7 +166,7 @@ module ActiveRecord
134
166
  (
135
167
  (?:
136
168
  # "schema_name"."table_name"."column_name"::type_name | function(one or no argument)::type_name
137
- ((?:\w+\.|"\w+"\.){,2}(?:\w+|"\w+")(?:::\w+)?) | \w+\((?:|\g<2>)\)(?:::\w+)?
169
+ ((?:\w+\.|"\w+"\.){,2}(?:\w+|"\w+")(?:::\w+)? | \w+\((?:|\g<2>)\)(?:::\w+)?)
138
170
  )
139
171
  (?:(?:\s+AS)?\s+(?:\w+|"\w+"))?
140
172
  )
@@ -147,8 +179,9 @@ module ActiveRecord
147
179
  (
148
180
  (?:
149
181
  # "schema_name"."table_name"."column_name"::type_name | function(one or no argument)::type_name
150
- ((?:\w+\.|"\w+"\.){,2}(?:\w+|"\w+")(?:::\w+)?) | \w+\((?:|\g<2>)\)(?:::\w+)?
182
+ ((?:\w+\.|"\w+"\.){,2}(?:\w+|"\w+")(?:::\w+)? | \w+\((?:|\g<2>)\)(?:::\w+)?)
151
183
  )
184
+ (?:\s+COLLATE\s+"\w+")?
152
185
  (?:\s+ASC|\s+DESC)?
153
186
  (?:\s+NULLS\s+(?:FIRST|LAST))?
154
187
  )
@@ -38,7 +38,7 @@ Rails needs superuser privileges to disable referential integrity.
38
38
  end
39
39
  end
40
40
 
41
- def all_foreign_keys_valid? # :nodoc:
41
+ def check_all_foreign_keys_valid! # :nodoc:
42
42
  sql = <<~SQL
43
43
  do $$
44
44
  declare r record;
@@ -61,14 +61,8 @@ Rails needs superuser privileges to disable referential integrity.
61
61
  $$;
62
62
  SQL
63
63
 
64
- begin
65
- transaction(requires_new: true) do
66
- execute(sql)
67
- end
68
-
69
- true
70
- rescue ActiveRecord::StatementInvalid
71
- false
64
+ transaction(requires_new: true) do
65
+ execute(sql)
72
66
  end
73
67
  end
74
68
  end