pg_saurus 4.0.3 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|