pg_saurus 4.0.3 → 5.0.0
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/lib/core_ext/active_record/connection_adapters/postgresql/schema_statements.rb +38 -26
- data/lib/pg_saurus/connection_adapters/abstract_adapter/schema_methods.rb +6 -4
- data/lib/pg_saurus/connection_adapters/postgresql_adapter/extension_methods.rb +1 -2
- data/lib/pg_saurus/connection_adapters/postgresql_adapter/function_methods.rb +3 -2
- data/lib/pg_saurus/connection_adapters/postgresql_adapter/translate_exception.rb +3 -2
- data/lib/pg_saurus/connection_adapters/postgresql_adapter/trigger_methods.rb +2 -2
- data/lib/pg_saurus/create_index_concurrently.rb +1 -1
- data/lib/pg_saurus/engine.rb +15 -4
- data/lib/pg_saurus/schema_dumper/extension_methods.rb +2 -2
- data/lib/pg_saurus/version.rb +1 -1
- metadata +28 -16
- data/lib/core_ext/active_record/connection_adapters/postgresql/column.rb +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7a6d057b35291dc622b20193e085fc52c5807fd8310b1d8925b9c0636d72d95b
|
4
|
+
data.tar.gz: 7f0257ad41a044c887519c844a54334172fa5e829f7c6e06c0aca6280f8f6625
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ab15973698f38c460f51ee4879913be9c6fc4d9b7c5fde71d4e597cb230b8097b1011330017da05d2b67d8fac6c7e852c21e2d2314602ecf0892a9c3ed7251e7
|
7
|
+
data.tar.gz: 680092950b8eeb8d1716edf301d14a94744ecdb352423b9550b5b84abbd59ffd323dcb226bac13707e1b4edbe4753808ccfe955cbb5f2f0890a168f1f0d3658c
|
@@ -29,7 +29,7 @@ module ActiveRecord
|
|
29
29
|
WHERE schemaname = ANY (ARRAY['public'])
|
30
30
|
SQL
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
# Returns an array of indexes for the given table.
|
34
34
|
#
|
35
35
|
# == Patch 1:
|
@@ -135,13 +135,9 @@ module ActiveRecord
|
|
135
135
|
# the column is difficult to target for quoting.
|
136
136
|
skip_column_quoting = options.delete(:skip_column_quoting) or false
|
137
137
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
index_options,
|
142
|
-
index_algorithm,
|
143
|
-
index_using,
|
144
|
-
comment = add_index_options(table_name, column_name, options)
|
138
|
+
index, algorithm, if_not_exists = add_index_options(table_name, column_name, **options)
|
139
|
+
algorithm = creation_method || algorithm
|
140
|
+
create_index = CreateIndexDefinition.new(index, algorithm, if_not_exists)
|
145
141
|
|
146
142
|
# GOTCHA:
|
147
143
|
# It ensures that there is no existing index only for the case when the index
|
@@ -156,24 +152,11 @@ module ActiveRecord
|
|
156
152
|
# -- zekefast 2012-09-25
|
157
153
|
if creation_method.present? && index_exists?(table_name, column_name, options)
|
158
154
|
raise ::PgSaurus::IndexExistsError,
|
159
|
-
"Index #{
|
155
|
+
"Index #{index.name} for `#{table_name}.#{column_name}` " \
|
160
156
|
"column can not be created concurrently, because such index already exists."
|
161
157
|
end
|
162
158
|
|
163
|
-
|
164
|
-
statements << "CREATE #{index_type} INDEX"
|
165
|
-
statements << creation_method if creation_method.present?
|
166
|
-
statements << index_algorithm if index_algorithm.present?
|
167
|
-
statements << quote_column_name(index_name)
|
168
|
-
statements << "ON"
|
169
|
-
statements << quote_table_name(table_name)
|
170
|
-
statements << index_using if index_using.present?
|
171
|
-
statements << "(#{index_columns_and_opclasses})" if index_columns_and_opclasses.present? unless skip_column_quoting
|
172
|
-
statements << "(#{column_name})" if column_name.present? and skip_column_quoting
|
173
|
-
statements << index_options if index_options.present?
|
174
|
-
|
175
|
-
sql = statements.join(' ')
|
176
|
-
execute(sql)
|
159
|
+
execute schema_creation.accept(create_index)
|
177
160
|
end
|
178
161
|
|
179
162
|
# Check to see if an index exists on a table for a given index definition.
|
@@ -250,7 +233,7 @@ module ActiveRecord
|
|
250
233
|
column_name, operator_name = split_column_name(name)
|
251
234
|
|
252
235
|
result_name = if column_name =~ FUNCTIONAL_INDEX_REGEXP
|
253
|
-
_name =
|
236
|
+
_name = column_name.gsub(/\b#{$3}\b/, quote_column_name($3))
|
254
237
|
_name += " #{operator_name}"
|
255
238
|
_name
|
256
239
|
else
|
@@ -260,9 +243,8 @@ module ActiveRecord
|
|
260
243
|
end
|
261
244
|
]
|
262
245
|
|
263
|
-
add_options_for_index_columns(quoted_columns, options).values
|
246
|
+
add_options_for_index_columns(quoted_columns, **options).values.join(", ")
|
264
247
|
end
|
265
|
-
protected :quoted_columns_for_index
|
266
248
|
|
267
249
|
# Map an expression to a name appropriate for an index.
|
268
250
|
def expression_index_name(name)
|
@@ -280,6 +262,36 @@ module ActiveRecord
|
|
280
262
|
end
|
281
263
|
private :expression_index_name
|
282
264
|
|
265
|
+
|
266
|
+
# == Patch 1:
|
267
|
+
# Remove schema name part from table name when sequence name doesn't include it.
|
268
|
+
def new_column_from_field(table_name, field)
|
269
|
+
column_name, type, default, notnull, oid, fmod, collation, comment = field
|
270
|
+
type_metadata = fetch_type_metadata(column_name, type, oid.to_i, fmod.to_i)
|
271
|
+
default_value = extract_value_from_default(default)
|
272
|
+
default_function = extract_default_function(default_value, default)
|
273
|
+
|
274
|
+
if match = default_function&.match(/\Anextval\('"?(?<sequence_name>.+_(?<suffix>seq\d*))"?'::regclass\)\z/)
|
275
|
+
sequence_name = match[:sequence_name]
|
276
|
+
is_schema_name_included = sequence_name.split(".").size > 1
|
277
|
+
_table_name = is_schema_name_included ? table_name : table_name.split(".").last
|
278
|
+
|
279
|
+
serial = sequence_name_from_parts(_table_name, column_name, match[:suffix]) == sequence_name
|
280
|
+
end
|
281
|
+
|
282
|
+
PostgreSQL::Column.new(
|
283
|
+
column_name,
|
284
|
+
default_value,
|
285
|
+
type_metadata,
|
286
|
+
!notnull,
|
287
|
+
default_function,
|
288
|
+
collation: collation,
|
289
|
+
comment: comment.presence,
|
290
|
+
serial: serial
|
291
|
+
)
|
292
|
+
end
|
293
|
+
private :new_column_from_field
|
294
|
+
|
283
295
|
# Split column name to name and operator class if possible.
|
284
296
|
def split_column_name(name)
|
285
297
|
if name =~ OPERATOR_REGEXP
|
@@ -4,17 +4,19 @@ module PgSaurus::ConnectionAdapters::AbstractAdapter::SchemaMethods
|
|
4
4
|
|
5
5
|
# Provide :schema option to +create_table+ method.
|
6
6
|
def create_table(table_name, options = {}, &block)
|
7
|
-
options
|
8
|
-
schema_name = options.delete(:schema)
|
9
|
-
table_name = "#{schema_name}.#{table_name}" if schema_name
|
7
|
+
table_name, options = extract_table_options(table_name, options)
|
10
8
|
super(table_name, options, &block)
|
11
9
|
end
|
12
10
|
|
13
11
|
# Provide :schema option to +drop_table+ method.
|
14
12
|
def drop_table(table_name, options = {})
|
13
|
+
super(*extract_table_options(table_name, options))
|
14
|
+
end
|
15
|
+
|
16
|
+
def extract_table_options(table_name, options)
|
15
17
|
options = options.dup
|
16
18
|
schema_name = options.delete(:schema)
|
17
19
|
table_name = "#{schema_name}.#{table_name}" if schema_name
|
18
|
-
|
20
|
+
[table_name, options]
|
19
21
|
end
|
20
22
|
end
|
@@ -112,8 +112,7 @@ module PgSaurus::ConnectionAdapters::PostgreSQLAdapter::ExtensionMethods
|
|
112
112
|
# @return [Hash{String => Hash{Symbol => String}}] A list of loaded extensions with their options
|
113
113
|
def pg_extensions
|
114
114
|
# Check postgresql version to not break on Postgresql < 9.1 during schema dump
|
115
|
-
|
116
|
-
return {} unless pg_version_str =~ /^PostgreSQL (\d+\.\d+.\d+)/ && ($1 >= '9.1')
|
115
|
+
return {} if (::PgSaurus::Engine.pg_server_version <=> [9, 1]) < 0
|
117
116
|
|
118
117
|
sql = <<-SQL
|
119
118
|
SELECT pge.extname AS ext_name, pgn.nspname AS schema_name, pge.extversion AS ext_version
|
@@ -11,12 +11,13 @@ module PgSaurus::ConnectionAdapters::PostgreSQLAdapter::FunctionMethods
|
|
11
11
|
|
12
12
|
# Return a list of defined DB functions. Ignore function definitions that can't be parsed.
|
13
13
|
def functions
|
14
|
+
pg_major = ::PgSaurus::Engine.pg_server_version[0]
|
14
15
|
res = select_all <<-SQL
|
15
16
|
SELECT n.nspname AS "Schema",
|
16
17
|
p.proname AS "Name",
|
17
18
|
pg_catalog.pg_get_function_result(p.oid) AS "Returning",
|
18
19
|
CASE
|
19
|
-
WHEN p.proiswindow
|
20
|
+
WHEN #{pg_major >= 11 ? "p.prokind = 'w'" : "p.proiswindow"} THEN 'window'
|
20
21
|
WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN 'trigger'
|
21
22
|
ELSE 'normal'
|
22
23
|
END AS "Type",
|
@@ -26,7 +27,7 @@ module PgSaurus::ConnectionAdapters::PostgreSQLAdapter::FunctionMethods
|
|
26
27
|
WHERE pg_catalog.pg_function_is_visible(p.oid)
|
27
28
|
AND n.nspname <> 'pg_catalog'
|
28
29
|
AND n.nspname <> 'information_schema'
|
29
|
-
AND p.proisagg <> TRUE
|
30
|
+
AND #{pg_major >= 11 ? "p.prokind <> 'a'" : "p.proisagg <> TRUE"}
|
30
31
|
ORDER BY 1, 2, 3, 4;
|
31
32
|
SQL
|
32
33
|
res.inject([]) do |buffer, row|
|
@@ -5,14 +5,15 @@ module PgSaurus::ConnectionAdapters::PostgreSQLAdapter::TranslateException
|
|
5
5
|
INSUFFICIENT_PRIVILEGE = "42501"
|
6
6
|
|
7
7
|
# Intercept insufficient privilege PG::Error and raise active_record wrapped database exception
|
8
|
-
def translate_exception(exception, message)
|
8
|
+
def translate_exception(exception, message:, sql:, binds:)
|
9
|
+
return exception unless exception.respond_to?(:result)
|
9
10
|
exception_result = exception.result
|
10
11
|
|
11
12
|
case exception_result.try(:error_field, PG::Result::PG_DIAG_SQLSTATE)
|
12
13
|
when INSUFFICIENT_PRIVILEGE
|
13
14
|
exc_message = exception_result.try(:error_field, PG::Result::PG_DIAG_MESSAGE_PRIMARY)
|
14
15
|
exc_message ||= message
|
15
|
-
::ActiveRecord::InsufficientPrivilege.new(exc_message)
|
16
|
+
::ActiveRecord::InsufficientPrivilege.new(exc_message, sql: sql, binds: binds)
|
16
17
|
else
|
17
18
|
super
|
18
19
|
end
|
@@ -95,7 +95,7 @@ module PgSaurus::ConnectionAdapters::PostgreSQLAdapter::TriggerMethods
|
|
95
95
|
|
96
96
|
# Parse the condition from the trigger definition.
|
97
97
|
def parse_condition(trigger_definition)
|
98
|
-
trigger_definition[/WHEN[\s](.*?)[\s]EXECUTE[\s]PROCEDURE/m, 1]
|
98
|
+
trigger_definition[/WHEN[\s](.*?)[\s]EXECUTE[\s](FUNCTION|PROCEDURE)/m, 1]
|
99
99
|
end
|
100
100
|
private :parse_condition
|
101
101
|
|
@@ -107,7 +107,7 @@ module PgSaurus::ConnectionAdapters::PostgreSQLAdapter::TriggerMethods
|
|
107
107
|
|
108
108
|
# Parse the procedure name from the trigger definition.
|
109
109
|
def parse_proc_name(trigger_definition)
|
110
|
-
trigger_definition[/EXECUTE[\s]PROCEDURE[\s](.*?)$/m,
|
110
|
+
trigger_definition[/EXECUTE[\s](FUNCTION|PROCEDURE)[\s](.*?)$/m, 2]
|
111
111
|
end
|
112
112
|
private :parse_proc_name
|
113
113
|
|
@@ -72,7 +72,7 @@ module PgSaurus::CreateIndexConcurrently
|
|
72
72
|
def add_index(table_name, column_name, options = {}, &block)
|
73
73
|
table_name = proper_table_name(table_name)
|
74
74
|
# GOTCHA:
|
75
|
-
# checks if index should be created
|
75
|
+
# checks if index should be created concurrently then put it into
|
76
76
|
# the queue to wait till queue processing will be called (should be
|
77
77
|
# happended after closing transaction).
|
78
78
|
# Otherwise just delegate call to PgSaurus's `add_index`.
|
data/lib/pg_saurus/engine.rb
CHANGED
@@ -2,13 +2,24 @@ module PgSaurus
|
|
2
2
|
# :nodoc:
|
3
3
|
class Engine < Rails::Engine
|
4
4
|
|
5
|
+
# Postgres server version.
|
6
|
+
#
|
7
|
+
# @return [Array<Integer>]
|
8
|
+
def self.pg_server_version
|
9
|
+
@pg_server_version ||=
|
10
|
+
::ActiveRecord::Base.connection.
|
11
|
+
select_value('SHOW SERVER_VERSION').
|
12
|
+
split('.')[0..1].map(&:to_i)
|
13
|
+
end
|
14
|
+
|
5
15
|
initializer "pg_saurus" do
|
6
16
|
ActiveSupport.on_load(:active_record) do
|
7
17
|
# load monkey patches
|
8
|
-
%w
|
9
|
-
|
10
|
-
|
11
|
-
|
18
|
+
%w[
|
19
|
+
schema_dumper
|
20
|
+
errors
|
21
|
+
connection_adapters/postgresql/schema_statements
|
22
|
+
].each do |path|
|
12
23
|
require ::PgSaurus::Engine.root + "lib/core_ext/active_record/" + path
|
13
24
|
end
|
14
25
|
|
@@ -15,8 +15,8 @@ module PgSaurus::SchemaDumper::ExtensionMethods
|
|
15
15
|
extensions = @connection.pg_extensions
|
16
16
|
commands = extensions.map do |extension_name, options|
|
17
17
|
result = [%Q|create_extension "#{extension_name}"|]
|
18
|
-
result << %Q
|
19
|
-
result << %Q
|
18
|
+
result << %Q|schema_name: "#{options[:schema_name]}"| unless options[:schema_name] == 'public'
|
19
|
+
result << %Q|version: "#{options[:version]}"|
|
20
20
|
result.join(', ')
|
21
21
|
end
|
22
22
|
|
data/lib/pg_saurus/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pg_saurus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 5.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Potapov Sergey
|
@@ -10,10 +10,10 @@ authors:
|
|
10
10
|
- Matt Dressel
|
11
11
|
- Bruce Burdick
|
12
12
|
- HornsAndHooves
|
13
|
-
autorequire:
|
13
|
+
autorequire:
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
|
-
date:
|
16
|
+
date: 2022-01-06 00:00:00.000000000 Z
|
17
17
|
dependencies:
|
18
18
|
- !ruby/object:Gem::Dependency
|
19
19
|
name: pg
|
@@ -29,62 +29,76 @@ dependencies:
|
|
29
29
|
- - ">="
|
30
30
|
- !ruby/object:Gem::Version
|
31
31
|
version: '0'
|
32
|
+
- !ruby/object:Gem::Dependency
|
33
|
+
name: psych
|
34
|
+
requirement: !ruby/object:Gem::Requirement
|
35
|
+
requirements:
|
36
|
+
- - "~>"
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '3'
|
39
|
+
type: :runtime
|
40
|
+
prerelease: false
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - "~>"
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '3'
|
32
46
|
- !ruby/object:Gem::Dependency
|
33
47
|
name: railties
|
34
48
|
requirement: !ruby/object:Gem::Requirement
|
35
49
|
requirements:
|
36
50
|
- - "~>"
|
37
51
|
- !ruby/object:Gem::Version
|
38
|
-
version:
|
52
|
+
version: '6.0'
|
39
53
|
type: :runtime
|
40
54
|
prerelease: false
|
41
55
|
version_requirements: !ruby/object:Gem::Requirement
|
42
56
|
requirements:
|
43
57
|
- - "~>"
|
44
58
|
- !ruby/object:Gem::Version
|
45
|
-
version:
|
59
|
+
version: '6.0'
|
46
60
|
- !ruby/object:Gem::Dependency
|
47
61
|
name: activemodel
|
48
62
|
requirement: !ruby/object:Gem::Requirement
|
49
63
|
requirements:
|
50
64
|
- - "~>"
|
51
65
|
- !ruby/object:Gem::Version
|
52
|
-
version:
|
66
|
+
version: '6.0'
|
53
67
|
type: :runtime
|
54
68
|
prerelease: false
|
55
69
|
version_requirements: !ruby/object:Gem::Requirement
|
56
70
|
requirements:
|
57
71
|
- - "~>"
|
58
72
|
- !ruby/object:Gem::Version
|
59
|
-
version:
|
73
|
+
version: '6.0'
|
60
74
|
- !ruby/object:Gem::Dependency
|
61
75
|
name: activerecord
|
62
76
|
requirement: !ruby/object:Gem::Requirement
|
63
77
|
requirements:
|
64
78
|
- - "~>"
|
65
79
|
- !ruby/object:Gem::Version
|
66
|
-
version:
|
80
|
+
version: '6.0'
|
67
81
|
type: :runtime
|
68
82
|
prerelease: false
|
69
83
|
version_requirements: !ruby/object:Gem::Requirement
|
70
84
|
requirements:
|
71
85
|
- - "~>"
|
72
86
|
- !ruby/object:Gem::Version
|
73
|
-
version:
|
87
|
+
version: '6.0'
|
74
88
|
- !ruby/object:Gem::Dependency
|
75
89
|
name: activesupport
|
76
90
|
requirement: !ruby/object:Gem::Requirement
|
77
91
|
requirements:
|
78
92
|
- - "~>"
|
79
93
|
- !ruby/object:Gem::Version
|
80
|
-
version:
|
94
|
+
version: '6.0'
|
81
95
|
type: :runtime
|
82
96
|
prerelease: false
|
83
97
|
version_requirements: !ruby/object:Gem::Requirement
|
84
98
|
requirements:
|
85
99
|
- - "~>"
|
86
100
|
- !ruby/object:Gem::Version
|
87
|
-
version:
|
101
|
+
version: '6.0'
|
88
102
|
- !ruby/object:Gem::Dependency
|
89
103
|
name: rspec-rails
|
90
104
|
requirement: !ruby/object:Gem::Requirement
|
@@ -212,7 +226,6 @@ extra_rdoc_files:
|
|
212
226
|
files:
|
213
227
|
- README.markdown
|
214
228
|
- lib/colorized_text.rb
|
215
|
-
- lib/core_ext/active_record/connection_adapters/postgresql/column.rb
|
216
229
|
- lib/core_ext/active_record/connection_adapters/postgresql/schema_statements.rb
|
217
230
|
- lib/core_ext/active_record/errors.rb
|
218
231
|
- lib/core_ext/active_record/schema_dumper.rb
|
@@ -270,7 +283,7 @@ homepage: https://github.com/HornsAndHooves/pg_saurus
|
|
270
283
|
licenses:
|
271
284
|
- MIT
|
272
285
|
metadata: {}
|
273
|
-
post_install_message:
|
286
|
+
post_install_message:
|
274
287
|
rdoc_options: []
|
275
288
|
require_paths:
|
276
289
|
- lib
|
@@ -285,9 +298,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
285
298
|
- !ruby/object:Gem::Version
|
286
299
|
version: '0'
|
287
300
|
requirements: []
|
288
|
-
|
289
|
-
|
290
|
-
signing_key:
|
301
|
+
rubygems_version: 3.0.8
|
302
|
+
signing_key:
|
291
303
|
specification_version: 4
|
292
304
|
summary: ActiveRecord extensions for PostgreSQL.
|
293
305
|
test_files: []
|
@@ -1,19 +0,0 @@
|
|
1
|
-
module ActiveRecord
|
2
|
-
module ConnectionAdapters
|
3
|
-
# PostgreSQL-specific extensions to column definitions in a table.
|
4
|
-
class PostgreSQLColumn < Column #:nodoc:
|
5
|
-
# == Patch 1:
|
6
|
-
# Remove schema name part from table name when sequence name doesn't include it.
|
7
|
-
def serial?
|
8
|
-
return unless default_function
|
9
|
-
|
10
|
-
if %r{\Anextval\('"?(?<sequence_name>.+_(?<suffix>seq\d*))"?'::regclass\)\z} =~ default_function
|
11
|
-
is_schema_name_included = sequence_name.split(".").size > 1
|
12
|
-
_table_name = is_schema_name_included ? table_name : table_name.split(".").last
|
13
|
-
|
14
|
-
sequence_name_from_parts(_table_name, name, suffix) == sequence_name
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|