ovirt_metrics 3.0.0 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/lib/active_record/connection_adapters/ovirt_postgresql_adapter.rb +30 -0
  3. data/lib/ovirt_metrics.rb +4 -1
  4. data/lib/ovirt_metrics/version.rb +1 -1
  5. metadata +3 -35
  6. data/lib/active_record/connection_adapters/ovirt_legacy_postgresql/column.rb +0 -15
  7. data/lib/active_record/connection_adapters/ovirt_legacy_postgresql/database_statements.rb +0 -170
  8. data/lib/active_record/connection_adapters/ovirt_legacy_postgresql/explain_pretty_printer.rb +0 -42
  9. data/lib/active_record/connection_adapters/ovirt_legacy_postgresql/oid.rb +0 -31
  10. data/lib/active_record/connection_adapters/ovirt_legacy_postgresql/oid/array.rb +0 -70
  11. data/lib/active_record/connection_adapters/ovirt_legacy_postgresql/oid/bit.rb +0 -52
  12. data/lib/active_record/connection_adapters/ovirt_legacy_postgresql/oid/bit_varying.rb +0 -13
  13. data/lib/active_record/connection_adapters/ovirt_legacy_postgresql/oid/bytea.rb +0 -15
  14. data/lib/active_record/connection_adapters/ovirt_legacy_postgresql/oid/cidr.rb +0 -48
  15. data/lib/active_record/connection_adapters/ovirt_legacy_postgresql/oid/date_time.rb +0 -21
  16. data/lib/active_record/connection_adapters/ovirt_legacy_postgresql/oid/decimal.rb +0 -13
  17. data/lib/active_record/connection_adapters/ovirt_legacy_postgresql/oid/enum.rb +0 -19
  18. data/lib/active_record/connection_adapters/ovirt_legacy_postgresql/oid/hstore.rb +0 -59
  19. data/lib/active_record/connection_adapters/ovirt_legacy_postgresql/oid/inet.rb +0 -13
  20. data/lib/active_record/connection_adapters/ovirt_legacy_postgresql/oid/json.rb +0 -10
  21. data/lib/active_record/connection_adapters/ovirt_legacy_postgresql/oid/jsonb.rb +0 -23
  22. data/lib/active_record/connection_adapters/ovirt_legacy_postgresql/oid/money.rb +0 -39
  23. data/lib/active_record/connection_adapters/ovirt_legacy_postgresql/oid/point.rb +0 -43
  24. data/lib/active_record/connection_adapters/ovirt_legacy_postgresql/oid/rails_5_1_point.rb +0 -50
  25. data/lib/active_record/connection_adapters/ovirt_legacy_postgresql/oid/range.rb +0 -93
  26. data/lib/active_record/connection_adapters/ovirt_legacy_postgresql/oid/specialized_string.rb +0 -15
  27. data/lib/active_record/connection_adapters/ovirt_legacy_postgresql/oid/type_map_initializer.rb +0 -109
  28. data/lib/active_record/connection_adapters/ovirt_legacy_postgresql/oid/uuid.rb +0 -21
  29. data/lib/active_record/connection_adapters/ovirt_legacy_postgresql/oid/vector.rb +0 -26
  30. data/lib/active_record/connection_adapters/ovirt_legacy_postgresql/oid/xml.rb +0 -28
  31. data/lib/active_record/connection_adapters/ovirt_legacy_postgresql/quoting.rb +0 -116
  32. data/lib/active_record/connection_adapters/ovirt_legacy_postgresql/referential_integrity.rb +0 -49
  33. data/lib/active_record/connection_adapters/ovirt_legacy_postgresql/schema_definitions.rb +0 -180
  34. data/lib/active_record/connection_adapters/ovirt_legacy_postgresql/schema_dumper.rb +0 -47
  35. data/lib/active_record/connection_adapters/ovirt_legacy_postgresql/schema_statements.rb +0 -682
  36. data/lib/active_record/connection_adapters/ovirt_legacy_postgresql/type_metadata.rb +0 -35
  37. data/lib/active_record/connection_adapters/ovirt_legacy_postgresql/utils.rb +0 -77
  38. data/lib/active_record/connection_adapters/ovirt_legacy_postgresql_adapter.rb +0 -856
@@ -1,47 +0,0 @@
1
- module ActiveRecord
2
- module ConnectionAdapters
3
- module OvirtLegacyPostgreSQL
4
- module ColumnDumper
5
- def column_spec_for_primary_key(column)
6
- spec = super
7
- if schema_type(column) == :uuid
8
- spec[:default] ||= 'nil'
9
- end
10
- spec
11
- end
12
-
13
- # Adds +:array+ option to the default set
14
- def prepare_column_options(column)
15
- spec = super
16
- spec[:array] = 'true' if column.array?
17
- spec
18
- end
19
-
20
- # Adds +:array+ as a valid migration key
21
- def migration_keys
22
- super + [:array]
23
- end
24
-
25
- private
26
-
27
- def default_primary_key?(column)
28
- schema_type(column) == :serial
29
- end
30
-
31
- def schema_type(column)
32
- return super unless column.serial?
33
-
34
- if column.bigint?
35
- :bigserial
36
- else
37
- :serial
38
- end
39
- end
40
-
41
- def schema_expression(column)
42
- super unless column.serial?
43
- end
44
- end
45
- end
46
- end
47
- end
@@ -1,682 +0,0 @@
1
- require 'active_support/core_ext/string/strip'
2
-
3
- module ActiveRecord
4
- module ConnectionAdapters
5
- module OvirtLegacyPostgreSQL
6
- class SchemaCreation < AbstractAdapter::SchemaCreation
7
- private
8
-
9
- def visit_ColumnDefinition(o)
10
- o.sql_type = type_to_sql(o.type, o.limit, o.precision, o.scale, o.array)
11
- super
12
- end
13
-
14
- def add_column_options!(sql, options)
15
- if options[:collation]
16
- sql << " COLLATE \"#{options[:collation]}\""
17
- end
18
- super
19
- end
20
- end
21
-
22
- module SchemaStatements
23
- # Drops the database specified on the +name+ attribute
24
- # and creates it again using the provided +options+.
25
- def recreate_database(name, options = {}) #:nodoc:
26
- drop_database(name)
27
- create_database(name, options)
28
- end
29
-
30
- # Create a new PostgreSQL database. Options include <tt>:owner</tt>, <tt>:template</tt>,
31
- # <tt>:encoding</tt> (defaults to utf8), <tt>:collation</tt>, <tt>:ctype</tt>,
32
- # <tt>:tablespace</tt>, and <tt>:connection_limit</tt> (note that MySQL uses
33
- # <tt>:charset</tt> while PostgreSQL uses <tt>:encoding</tt>).
34
- #
35
- # Example:
36
- # create_database config[:database], config
37
- # create_database 'foo_development', encoding: 'unicode'
38
- def create_database(name, options = {})
39
- options = { encoding: 'utf8' }.merge!(options.symbolize_keys)
40
-
41
- option_string = options.inject("") do |memo, (key, value)|
42
- memo += case key
43
- when :owner
44
- " OWNER = \"#{value}\""
45
- when :template
46
- " TEMPLATE = \"#{value}\""
47
- when :encoding
48
- " ENCODING = '#{value}'"
49
- when :collation
50
- " LC_COLLATE = '#{value}'"
51
- when :ctype
52
- " LC_CTYPE = '#{value}'"
53
- when :tablespace
54
- " TABLESPACE = \"#{value}\""
55
- when :connection_limit
56
- " CONNECTION LIMIT = #{value}"
57
- else
58
- ""
59
- end
60
- end
61
-
62
- execute "CREATE DATABASE #{quote_table_name(name)}#{option_string}"
63
- end
64
-
65
- # Drops a PostgreSQL database.
66
- #
67
- # Example:
68
- # drop_database 'matt_development'
69
- def drop_database(name) #:nodoc:
70
- execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}"
71
- end
72
-
73
- # Returns the list of all tables in the schema search path.
74
- def tables(name = nil)
75
- if name
76
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
77
- Passing arguments to #tables is deprecated without replacement.
78
- MSG
79
- end
80
-
81
- select_values("SELECT tablename FROM pg_tables WHERE schemaname = ANY(current_schemas(false))", 'SCHEMA')
82
- end
83
-
84
- def data_sources # :nodoc
85
- select_values(<<-SQL, 'SCHEMA')
86
- SELECT c.relname
87
- FROM pg_class c
88
- LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
89
- WHERE c.relkind IN ('r', 'v','m') -- (r)elation/table, (v)iew, (m)aterialized view
90
- AND n.nspname = ANY (current_schemas(false))
91
- SQL
92
- end
93
-
94
- # Returns true if table exists.
95
- # If the schema is not specified as part of +name+ then it will only find tables within
96
- # the current schema search path (regardless of permissions to access tables in other schemas)
97
- def table_exists?(name)
98
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
99
- #table_exists? currently checks both tables and views.
100
- This behavior is deprecated and will be changed with Rails 5.1 to only check tables.
101
- Use #data_source_exists? instead.
102
- MSG
103
-
104
- data_source_exists?(name)
105
- end
106
-
107
- def data_source_exists?(name)
108
- name = Utils.extract_schema_qualified_name(name.to_s)
109
- return false unless name.identifier
110
-
111
- select_value(<<-SQL, 'SCHEMA').to_i > 0
112
- SELECT COUNT(*)
113
- FROM pg_class c
114
- LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
115
- WHERE c.relkind IN ('r','v','m') -- (r)elation/table, (v)iew, (m)aterialized view
116
- AND c.relname = '#{name.identifier}'
117
- AND n.nspname = #{name.schema ? "'#{name.schema}'" : 'ANY (current_schemas(false))'}
118
- SQL
119
- end
120
-
121
- def views # :nodoc:
122
- select_values(<<-SQL, 'SCHEMA')
123
- SELECT c.relname
124
- FROM pg_class c
125
- LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
126
- WHERE c.relkind IN ('v','m') -- (v)iew, (m)aterialized view
127
- AND n.nspname = ANY (current_schemas(false))
128
- SQL
129
- end
130
-
131
- def view_exists?(view_name) # :nodoc:
132
- name = Utils.extract_schema_qualified_name(view_name.to_s)
133
- return false unless name.identifier
134
-
135
- select_values(<<-SQL, 'SCHEMA').any?
136
- SELECT c.relname
137
- FROM pg_class c
138
- LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
139
- WHERE c.relkind IN ('v','m') -- (v)iew, (m)aterialized view
140
- AND c.relname = '#{name.identifier}'
141
- AND n.nspname = #{name.schema ? "'#{name.schema}'" : 'ANY (current_schemas(false))'}
142
- SQL
143
- end
144
-
145
- def drop_table(table_name, options = {}) # :nodoc:
146
- execute "DROP TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}#{' CASCADE' if options[:force] == :cascade}"
147
- end
148
-
149
- # Returns true if schema exists.
150
- def schema_exists?(name)
151
- select_value("SELECT COUNT(*) FROM pg_namespace WHERE nspname = '#{name}'", 'SCHEMA').to_i > 0
152
- end
153
-
154
- # Verifies existence of an index with a given name.
155
- def index_name_exists?(table_name, index_name, default)
156
- table = Utils.extract_schema_qualified_name(table_name.to_s)
157
- index = Utils.extract_schema_qualified_name(index_name.to_s)
158
-
159
- select_value(<<-SQL, 'SCHEMA').to_i > 0
160
- SELECT COUNT(*)
161
- FROM pg_class t
162
- INNER JOIN pg_index d ON t.oid = d.indrelid
163
- INNER JOIN pg_class i ON d.indexrelid = i.oid
164
- LEFT JOIN pg_namespace n ON n.oid = i.relnamespace
165
- WHERE i.relkind = 'i'
166
- AND i.relname = '#{index.identifier}'
167
- AND t.relname = '#{table.identifier}'
168
- AND n.nspname = #{index.schema ? "'#{index.schema}'" : 'ANY (current_schemas(false))'}
169
- SQL
170
- end
171
-
172
- # Returns an array of indexes for the given table.
173
- def indexes(table_name, name = nil)
174
- table = Utils.extract_schema_qualified_name(table_name.to_s)
175
-
176
- result = query(<<-SQL, 'SCHEMA')
177
- SELECT distinct i.relname, d.indisunique, d.indkey, pg_get_indexdef(d.indexrelid), t.oid,
178
- pg_catalog.obj_description(i.oid, 'pg_class') AS comment,
179
- (SELECT COUNT(*) FROM pg_opclass o
180
- JOIN (SELECT unnest(string_to_array(d.indclass::text, ' '))::int oid) c
181
- ON o.oid = c.oid WHERE o.opcdefault = 'f')
182
- FROM pg_class t
183
- INNER JOIN pg_index d ON t.oid = d.indrelid
184
- INNER JOIN pg_class i ON d.indexrelid = i.oid
185
- LEFT JOIN pg_namespace n ON n.oid = i.relnamespace
186
- WHERE i.relkind = 'i'
187
- AND d.indisprimary = 'f'
188
- AND t.relname = '#{table.identifier}'
189
- AND n.nspname = #{table.schema ? "'#{table.schema}'" : 'ANY (current_schemas(false))'}
190
- ORDER BY i.relname
191
- SQL
192
-
193
- result.map do |row|
194
- index_name = row[0]
195
- unique = row[1]
196
- indkey = row[2].split(" ").map(&:to_i)
197
- inddef = row[3]
198
- oid = row[4]
199
- comment = row[5]
200
- opclass = row[6]
201
-
202
- using, expressions, where = inddef.scan(/ USING (\w+?) \((.+?)\)(?: WHERE (.+))?\z/).flatten
203
-
204
- if indkey.include?(0) || opclass > 0
205
- columns = expressions
206
- else
207
- columns = Hash[query(<<-SQL.strip_heredoc, "SCHEMA")].values_at(*indkey).compact
208
- SELECT a.attnum, a.attname
209
- FROM pg_attribute a
210
- WHERE a.attrelid = #{oid}
211
- AND a.attnum IN (#{indkey.join(",")})
212
- SQL
213
-
214
- # add info on sort order for columns (only desc order is explicitly specified, asc is the default)
215
- orders = Hash[
216
- expressions.scan(/(\w+) DESC/).flatten.map { |order_column| [order_column, :desc] }
217
- ]
218
- end
219
-
220
- IndexDefinition.new(table_name, index_name, unique, columns, [], orders, where, nil, using.to_sym, comment)
221
- end.compact
222
- end
223
-
224
- # Returns the list of all column definitions for a table.
225
- def columns(table_name) # :nodoc:
226
- table_name = table_name.to_s
227
- column_definitions(table_name).map do |column_name, type, default, notnull, oid, fmod, collation, comment|
228
- oid = oid.to_i
229
- fmod = fmod.to_i
230
- type_metadata = fetch_type_metadata(column_name, type, oid, fmod)
231
- default_value = extract_value_from_default(default)
232
- default_function = extract_default_function(default_value, default)
233
- new_column(column_name, default_value, type_metadata, !notnull, table_name, default_function, collation, comment: comment.presence)
234
- end
235
- end
236
-
237
- def new_column(*args) # :nodoc:
238
- OvirtLegacyPostgreSQLColumn.new(*args)
239
- end
240
-
241
- # Returns a comment stored in database for given table
242
- def table_comment(table_name) # :nodoc:
243
- name = Utils.extract_schema_qualified_name(table_name.to_s)
244
- if name.identifier
245
- select_value(<<-SQL.strip_heredoc, 'SCHEMA')
246
- SELECT pg_catalog.obj_description(c.oid, 'pg_class')
247
- FROM pg_catalog.pg_class c
248
- LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
249
- WHERE c.relname = #{quote(name.identifier)}
250
- AND c.relkind IN ('r') -- (r)elation/table
251
- AND n.nspname = #{name.schema ? quote(name.schema) : 'ANY (current_schemas(false))'}
252
- SQL
253
- end
254
- end
255
-
256
- # Returns the current database name.
257
- def current_database
258
- select_value('select current_database()', 'SCHEMA')
259
- end
260
-
261
- # Returns the current schema name.
262
- def current_schema
263
- select_value('SELECT current_schema', 'SCHEMA')
264
- end
265
-
266
- # Returns the current database encoding format.
267
- def encoding
268
- select_value("SELECT pg_encoding_to_char(encoding) FROM pg_database WHERE datname LIKE '#{current_database}'", 'SCHEMA')
269
- end
270
-
271
- # Returns the current database collation.
272
- def collation
273
- select_value("SELECT datcollate FROM pg_database WHERE datname LIKE '#{current_database}'", 'SCHEMA')
274
- end
275
-
276
- # Returns the current database ctype.
277
- def ctype
278
- select_value("SELECT datctype FROM pg_database WHERE datname LIKE '#{current_database}'", 'SCHEMA')
279
- end
280
-
281
- # Returns an array of schema names.
282
- def schema_names
283
- select_values(<<-SQL, 'SCHEMA')
284
- SELECT nspname
285
- FROM pg_namespace
286
- WHERE nspname !~ '^pg_.*'
287
- AND nspname NOT IN ('information_schema')
288
- ORDER by nspname;
289
- SQL
290
- end
291
-
292
- # Creates a schema for the given schema name.
293
- def create_schema schema_name
294
- execute "CREATE SCHEMA #{quote_schema_name(schema_name)}"
295
- end
296
-
297
- # Drops the schema for the given schema name.
298
- def drop_schema(schema_name, options = {})
299
- execute "DROP SCHEMA#{' IF EXISTS' if options[:if_exists]} #{quote_schema_name(schema_name)} CASCADE"
300
- end
301
-
302
- # Sets the schema search path to a string of comma-separated schema names.
303
- # Names beginning with $ have to be quoted (e.g. $user => '$user').
304
- # See: http://www.postgresql.org/docs/current/static/ddl-schemas.html
305
- #
306
- # This should be not be called manually but set in database.yml.
307
- def schema_search_path=(schema_csv)
308
- if schema_csv
309
- execute("SET search_path TO #{schema_csv}", 'SCHEMA')
310
- @schema_search_path = schema_csv
311
- end
312
- end
313
-
314
- # Returns the active schema search path.
315
- def schema_search_path
316
- @schema_search_path ||= select_value('SHOW search_path', 'SCHEMA')
317
- end
318
-
319
- # Returns the current client message level.
320
- def client_min_messages
321
- select_value('SHOW client_min_messages', 'SCHEMA')
322
- end
323
-
324
- # Set the client message level.
325
- def client_min_messages=(level)
326
- execute("SET client_min_messages TO '#{level}'", 'SCHEMA')
327
- end
328
-
329
- # Returns the sequence name for a table's primary key or some other specified key.
330
- def default_sequence_name(table_name, pk = nil) #:nodoc:
331
- result = serial_sequence(table_name, pk || 'id')
332
- return nil unless result
333
- Utils.extract_schema_qualified_name(result).to_s
334
- rescue ActiveRecord::StatementInvalid
335
- OvirtLegacyPostgreSQL::Name.new(nil, "#{table_name}_#{pk || 'id'}_seq").to_s
336
- end
337
-
338
- def serial_sequence(table, column)
339
- select_value("SELECT pg_get_serial_sequence('#{table}', '#{column}')", 'SCHEMA')
340
- end
341
-
342
- # Sets the sequence of a table's primary key to the specified value.
343
- def set_pk_sequence!(table, value) #:nodoc:
344
- pk, sequence = pk_and_sequence_for(table)
345
-
346
- if pk
347
- if sequence
348
- quoted_sequence = quote_table_name(sequence)
349
-
350
- select_value("SELECT setval('#{quoted_sequence}', #{value})", 'SCHEMA')
351
- else
352
- @logger.warn "#{table} has primary key #{pk} with no default sequence." if @logger
353
- end
354
- end
355
- end
356
-
357
- # Resets the sequence of a table's primary key to the maximum value.
358
- def reset_pk_sequence!(table, pk = nil, sequence = nil) #:nodoc:
359
- unless pk and sequence
360
- default_pk, default_sequence = pk_and_sequence_for(table)
361
-
362
- pk ||= default_pk
363
- sequence ||= default_sequence
364
- end
365
-
366
- if @logger && pk && !sequence
367
- @logger.warn "#{table} has primary key #{pk} with no default sequence."
368
- end
369
-
370
- if pk && sequence
371
- quoted_sequence = quote_table_name(sequence)
372
-
373
- select_value(<<-end_sql, 'SCHEMA')
374
- SELECT setval('#{quoted_sequence}', (SELECT COALESCE(MAX(#{quote_column_name pk})+(SELECT increment_by FROM #{quoted_sequence}), (SELECT min_value FROM #{quoted_sequence})) FROM #{quote_table_name(table)}), false)
375
- end_sql
376
- end
377
- end
378
-
379
- # Returns a table's primary key and belonging sequence.
380
- def pk_and_sequence_for(table) #:nodoc:
381
- # First try looking for a sequence with a dependency on the
382
- # given table's primary key.
383
- result = query(<<-end_sql, 'SCHEMA')[0]
384
- SELECT attr.attname, nsp.nspname, seq.relname
385
- FROM pg_class seq,
386
- pg_attribute attr,
387
- pg_depend dep,
388
- pg_constraint cons,
389
- pg_namespace nsp
390
- WHERE seq.oid = dep.objid
391
- AND seq.relkind = 'S'
392
- AND attr.attrelid = dep.refobjid
393
- AND attr.attnum = dep.refobjsubid
394
- AND attr.attrelid = cons.conrelid
395
- AND attr.attnum = cons.conkey[1]
396
- AND seq.relnamespace = nsp.oid
397
- AND cons.contype = 'p'
398
- AND dep.classid = 'pg_class'::regclass
399
- AND dep.refobjid = '#{quote_table_name(table)}'::regclass
400
- end_sql
401
-
402
- if result.nil? or result.empty?
403
- result = query(<<-end_sql, 'SCHEMA')[0]
404
- SELECT attr.attname, nsp.nspname,
405
- CASE
406
- WHEN pg_get_expr(def.adbin, def.adrelid) !~* 'nextval' THEN NULL
407
- WHEN split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2) ~ '.' THEN
408
- substr(split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2),
409
- strpos(split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2), '.')+1)
410
- ELSE split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2)
411
- END
412
- FROM pg_class t
413
- JOIN pg_attribute attr ON (t.oid = attrelid)
414
- JOIN pg_attrdef def ON (adrelid = attrelid AND adnum = attnum)
415
- JOIN pg_constraint cons ON (conrelid = adrelid AND adnum = conkey[1])
416
- JOIN pg_namespace nsp ON (t.relnamespace = nsp.oid)
417
- WHERE t.oid = '#{quote_table_name(table)}'::regclass
418
- AND cons.contype = 'p'
419
- AND pg_get_expr(def.adbin, def.adrelid) ~* 'nextval|uuid_generate'
420
- end_sql
421
- end
422
-
423
- pk = result.shift
424
- if result.last
425
- [pk, OvirtLegacyPostgreSQL::Name.new(*result)]
426
- else
427
- [pk, nil]
428
- end
429
- rescue
430
- nil
431
- end
432
-
433
- def primary_keys(table_name) # :nodoc:
434
- select_values(<<-SQL.strip_heredoc, 'SCHEMA')
435
- WITH pk_constraint AS (
436
- SELECT conrelid, unnest(conkey) AS connum FROM pg_constraint
437
- WHERE contype = 'p'
438
- AND conrelid = '#{quote_table_name(table_name)}'::regclass
439
- ), cons AS (
440
- SELECT conrelid, connum, row_number() OVER() AS rownum FROM pk_constraint
441
- )
442
- SELECT attr.attname FROM pg_attribute attr
443
- INNER JOIN cons ON attr.attrelid = cons.conrelid AND attr.attnum = cons.connum
444
- ORDER BY cons.rownum
445
- SQL
446
- end
447
-
448
- # Renames a table.
449
- # Also renames a table's primary key sequence if the sequence name exists and
450
- # matches the Active Record default.
451
- #
452
- # Example:
453
- # rename_table('octopuses', 'octopi')
454
- def rename_table(table_name, new_name)
455
- clear_cache!
456
- execute "ALTER TABLE #{quote_table_name(table_name)} RENAME TO #{quote_table_name(new_name)}"
457
- pk, seq = pk_and_sequence_for(new_name)
458
- if seq && seq.identifier == "#{table_name}_#{pk}_seq"
459
- new_seq = "#{new_name}_#{pk}_seq"
460
- idx = "#{table_name}_pkey"
461
- new_idx = "#{new_name}_pkey"
462
- execute "ALTER TABLE #{seq.quoted} RENAME TO #{quote_table_name(new_seq)}"
463
- execute "ALTER INDEX #{quote_table_name(idx)} RENAME TO #{quote_table_name(new_idx)}"
464
- end
465
-
466
- rename_table_indexes(table_name, new_name)
467
- end
468
-
469
- def add_column(table_name, column_name, type, options = {}) #:nodoc:
470
- clear_cache!
471
- super
472
- change_column_comment(table_name, column_name, options[:comment]) if options.key?(:comment)
473
- end
474
-
475
- def change_column(table_name, column_name, type, options = {}) #:nodoc:
476
- clear_cache!
477
- quoted_table_name = quote_table_name(table_name)
478
- quoted_column_name = quote_column_name(column_name)
479
- sql_type = type_to_sql(type, options[:limit], options[:precision], options[:scale], options[:array])
480
- sql = "ALTER TABLE #{quoted_table_name} ALTER COLUMN #{quoted_column_name} TYPE #{sql_type}"
481
- if options[:collation]
482
- sql << " COLLATE \"#{options[:collation]}\""
483
- end
484
- if options[:using]
485
- sql << " USING #{options[:using]}"
486
- elsif options[:cast_as]
487
- cast_as_type = type_to_sql(options[:cast_as], options[:limit], options[:precision], options[:scale], options[:array])
488
- sql << " USING CAST(#{quoted_column_name} AS #{cast_as_type})"
489
- end
490
- execute sql
491
-
492
- change_column_default(table_name, column_name, options[:default]) if options_include_default?(options)
493
- change_column_null(table_name, column_name, options[:null], options[:default]) if options.key?(:null)
494
- change_column_comment(table_name, column_name, options[:comment]) if options.key?(:comment)
495
- end
496
-
497
- # Changes the default value of a table column.
498
- def change_column_default(table_name, column_name, default_or_changes) # :nodoc:
499
- clear_cache!
500
- column = column_for(table_name, column_name)
501
- return unless column
502
-
503
- default = extract_new_default_value(default_or_changes)
504
- alter_column_query = "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} %s"
505
- if default.nil?
506
- # <tt>DEFAULT NULL</tt> results in the same behavior as <tt>DROP DEFAULT</tt>. However, PostgreSQL will
507
- # cast the default to the columns type, which leaves us with a default like "default NULL::character varying".
508
- execute alter_column_query % "DROP DEFAULT"
509
- else
510
- execute alter_column_query % "SET DEFAULT #{quote_default_expression(default, column)}"
511
- end
512
- end
513
-
514
- def change_column_null(table_name, column_name, null, default = nil) #:nodoc:
515
- clear_cache!
516
- unless null || default.nil?
517
- column = column_for(table_name, column_name)
518
- execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote_default_expression(default, column)} WHERE #{quote_column_name(column_name)} IS NULL") if column
519
- end
520
- execute("ALTER TABLE #{quote_table_name(table_name)} ALTER #{quote_column_name(column_name)} #{null ? 'DROP' : 'SET'} NOT NULL")
521
- end
522
-
523
- # Adds comment for given table column or drops it if +comment+ is a +nil+
524
- def change_column_comment(table_name, column_name, comment) # :nodoc:
525
- clear_cache!
526
- execute "COMMENT ON COLUMN #{quote_table_name(table_name)}.#{quote_column_name(column_name)} IS #{quote(comment)}"
527
- end
528
-
529
- # Adds comment for given table or drops it if +comment+ is a +nil+
530
- def change_table_comment(table_name, comment) # :nodoc:
531
- clear_cache!
532
- execute "COMMENT ON TABLE #{quote_table_name(table_name)} IS #{quote(comment)}"
533
- end
534
-
535
- # Renames a column in a table.
536
- def rename_column(table_name, column_name, new_column_name) #:nodoc:
537
- clear_cache!
538
- execute "ALTER TABLE #{quote_table_name(table_name)} RENAME COLUMN #{quote_column_name(column_name)} TO #{quote_column_name(new_column_name)}"
539
- rename_column_indexes(table_name, column_name, new_column_name)
540
- end
541
-
542
- def add_index(table_name, column_name, options = {}) #:nodoc:
543
- index_name, index_type, index_columns, index_options, index_algorithm, index_using, comment = add_index_options(table_name, column_name, options)
544
- execute("CREATE #{index_type} INDEX #{index_algorithm} #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} #{index_using} (#{index_columns})#{index_options}").tap do
545
- execute "COMMENT ON INDEX #{quote_column_name(index_name)} IS #{quote(comment)}" if comment
546
- end
547
- end
548
-
549
- def remove_index(table_name, options = {}) #:nodoc:
550
- table = Utils.extract_schema_qualified_name(table_name.to_s)
551
-
552
- if options.is_a?(Hash) && options.key?(:name)
553
- provided_index = Utils.extract_schema_qualified_name(options[:name].to_s)
554
-
555
- options[:name] = provided_index.identifier
556
- table = OvirtLegacyPostgreSQL::Name.new(provided_index.schema, table.identifier) unless table.schema.present?
557
-
558
- if provided_index.schema.present? && table.schema != provided_index.schema
559
- raise ArgumentError.new("Index schema '#{provided_index.schema}' does not match table schema '#{table.schema}'")
560
- end
561
- end
562
-
563
- index_to_remove = OvirtLegacyPostgreSQL::Name.new(table.schema, index_name_for_remove(table.to_s, options))
564
- algorithm =
565
- if options.is_a?(Hash) && options.key?(:algorithm)
566
- index_algorithms.fetch(options[:algorithm]) do
567
- raise ArgumentError.new("Algorithm must be one of the following: #{index_algorithms.keys.map(&:inspect).join(', ')}")
568
- end
569
- end
570
- execute "DROP INDEX #{algorithm} #{quote_table_name(index_to_remove)}"
571
- end
572
-
573
- # Renames an index of a table. Raises error if length of new
574
- # index name is greater than allowed limit.
575
- def rename_index(table_name, old_name, new_name)
576
- validate_index_length!(table_name, new_name)
577
-
578
- execute "ALTER INDEX #{quote_column_name(old_name)} RENAME TO #{quote_table_name(new_name)}"
579
- end
580
-
581
- def foreign_keys(table_name)
582
- fk_info = select_all <<-SQL.strip_heredoc
583
- 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
584
- FROM pg_constraint c
585
- JOIN pg_class t1 ON c.conrelid = t1.oid
586
- JOIN pg_class t2 ON c.confrelid = t2.oid
587
- JOIN pg_attribute a1 ON a1.attnum = c.conkey[1] AND a1.attrelid = t1.oid
588
- JOIN pg_attribute a2 ON a2.attnum = c.confkey[1] AND a2.attrelid = t2.oid
589
- JOIN pg_namespace t3 ON c.connamespace = t3.oid
590
- WHERE c.contype = 'f'
591
- AND t1.relname = #{quote(table_name)}
592
- AND t3.nspname = ANY (current_schemas(false))
593
- ORDER BY c.conname
594
- SQL
595
-
596
- fk_info.map do |row|
597
- options = {
598
- column: row['column'],
599
- name: row['name'],
600
- primary_key: row['primary_key']
601
- }
602
-
603
- options[:on_delete] = extract_foreign_key_action(row['on_delete'])
604
- options[:on_update] = extract_foreign_key_action(row['on_update'])
605
-
606
- ForeignKeyDefinition.new(table_name, row['to_table'], options)
607
- end
608
- end
609
-
610
- def extract_foreign_key_action(specifier) # :nodoc:
611
- case specifier
612
- when 'c'; :cascade
613
- when 'n'; :nullify
614
- when 'r'; :restrict
615
- end
616
- end
617
-
618
- def index_name_length
619
- 63
620
- end
621
-
622
- # Maps logical Rails types to PostgreSQL-specific data types.
623
- def type_to_sql(type, limit = nil, precision = nil, scale = nil, array = nil)
624
- sql = case type.to_s
625
- when 'binary'
626
- # PostgreSQL doesn't support limits on binary (bytea) columns.
627
- # The hard limit is 1GB, because of a 32-bit size field, and TOAST.
628
- case limit
629
- when nil, 0..0x3fffffff; super(type)
630
- else raise(ActiveRecordError, "No binary type has byte size #{limit}.")
631
- end
632
- when 'text'
633
- # PostgreSQL doesn't support limits on text columns.
634
- # The hard limit is 1GB, according to section 8.3 in the manual.
635
- case limit
636
- when nil, 0..0x3fffffff; super(type)
637
- else raise(ActiveRecordError, "The limit on text can be at most 1GB - 1byte.")
638
- end
639
- when 'integer'
640
- case limit
641
- when 1, 2; 'smallint'
642
- when nil, 3, 4; 'integer'
643
- when 5..8; 'bigint'
644
- else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with precision 0 instead.")
645
- end
646
- else
647
- super(type, limit, precision, scale)
648
- end
649
-
650
- sql << '[]' if array && type != :primary_key
651
- sql
652
- end
653
-
654
- # PostgreSQL requires the ORDER BY columns in the select list for distinct queries, and
655
- # requires that the ORDER BY include the distinct column.
656
- def columns_for_distinct(columns, orders) #:nodoc:
657
- order_columns = orders.reject(&:blank?).map{ |s|
658
- # Convert Arel node to string
659
- s = s.to_sql unless s.is_a?(String)
660
- # Remove any ASC/DESC modifiers
661
- s.gsub(/\s+(?:ASC|DESC)\b/i, '')
662
- .gsub(/\s+NULLS\s+(?:FIRST|LAST)\b/i, '')
663
- }.reject(&:blank?).map.with_index { |column, i| "#{column} AS alias_#{i}" }
664
-
665
- [super, *order_columns].join(', ')
666
- end
667
-
668
- def fetch_type_metadata(column_name, sql_type, oid, fmod)
669
- cast_type = get_oid_type(oid, fmod, column_name, sql_type)
670
- simple_type = SqlTypeMetadata.new(
671
- sql_type: sql_type,
672
- type: cast_type.type,
673
- limit: cast_type.limit,
674
- precision: cast_type.precision,
675
- scale: cast_type.scale,
676
- )
677
- OvirtLegacyPostgreSQLTypeMetadata.new(simple_type, oid: oid, fmod: fmod)
678
- end
679
- end
680
- end
681
- end
682
- end