101 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Ruby
		
	
	
	
			
		
		
	
	
			101 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Ruby
		
	
	
	
| # frozen_string_literal: true
 | |
| 
 | |
| module Gitlab
 | |
|   module Database
 | |
|     class AlterCellSequencesRange
 | |
|       MISSING_LIMIT_MSG = 'minval and maxval are required to alter sequence range'
 | |
| 
 | |
|       attr_reader :minval, :maxval, :connection, :logger
 | |
| 
 | |
|       def initialize(minval, maxval, connection, logger: Gitlab::AppLogger)
 | |
|         raise MISSING_LIMIT_MSG unless minval.present? && maxval.present?
 | |
| 
 | |
|         @minval = minval
 | |
|         @maxval = maxval
 | |
|         @connection = connection
 | |
|         @logger = logger
 | |
|       end
 | |
| 
 | |
|       def execute
 | |
|         logger.info("Altering existing sequences with minval: #{minval}, maxval: #{maxval}")
 | |
| 
 | |
|         sequences.each do |sequence|
 | |
|           with_lock_retries do
 | |
|             alter_sequence_query = <<~SQL
 | |
|               ALTER SEQUENCE #{sequence.seq_name}
 | |
|               START #{minval} RESTART #{minval} MINVALUE #{minval} MAXVALUE #{maxval}
 | |
|             SQL
 | |
| 
 | |
|             connection.execute(alter_sequence_query)
 | |
|           end
 | |
|         end
 | |
| 
 | |
|         logger.info("Altered all existing sequences range.")
 | |
| 
 | |
|         connection.execute(alter_new_sequences_range_function)
 | |
|         connection.execute(alter_new_sequences_range_trigger)
 | |
|       end
 | |
| 
 | |
|       private
 | |
| 
 | |
|       def sequences
 | |
|         Gitlab::Database::PostgresSequence.all
 | |
|       end
 | |
| 
 | |
|       def with_lock_retries(&)
 | |
|         Gitlab::Database::WithLockRetries.new(
 | |
|           connection: connection,
 | |
|           logger: logger
 | |
|         ).run(raise_on_exhaustion: false, &)
 | |
|       end
 | |
| 
 | |
|       def alter_new_sequences_range_function
 | |
|         <<~SQL
 | |
|           CREATE OR REPLACE FUNCTION alter_new_sequences_range()
 | |
|             RETURNS event_trigger
 | |
|           AS $$
 | |
|           DECLARE
 | |
|             command_record RECORD;
 | |
|             sequence_name text;
 | |
|             current_minval BIGINT;
 | |
|             current_maxval BIGINT;
 | |
|           BEGIN
 | |
|             FOR command_record IN SELECT * FROM pg_event_trigger_ddl_commands () LOOP
 | |
|               -- CREATE TABLE, ALTER TABLE will fire ALTER SEQUENCE event when SERIAL, BIGSERIAL IDs are used.
 | |
|               IF command_record.command_tag IN ('CREATE SEQUENCE', 'ALTER SEQUENCE') THEN
 | |
|                 sequence_name := substring(command_record.object_identity FROM '([^.]+)$');
 | |
| 
 | |
|                 SELECT min_value, max_value INTO current_minval, current_maxval FROM pg_sequences
 | |
|                 WHERE sequencename = sequence_name;
 | |
| 
 | |
|                 IF current_minval != #{minval} OR current_maxval != #{maxval} THEN
 | |
|                   RAISE NOTICE 'Altering sequence "%" with range [%, %]', sequence_name, #{minval}, #{maxval};
 | |
| 
 | |
|                   EXECUTE FORMAT('ALTER SEQUENCE %I START %s RESTART %s MINVALUE %s MAXVALUE %s',
 | |
|                     sequence_name,
 | |
|                     #{minval},
 | |
|                     #{minval},
 | |
|                     #{minval},
 | |
|                     #{maxval}
 | |
|                   );
 | |
|                 END IF;
 | |
|               END IF;
 | |
|             END LOOP;
 | |
|           END;
 | |
|           $$ LANGUAGE plpgsql;
 | |
|         SQL
 | |
|       end
 | |
| 
 | |
|       def alter_new_sequences_range_trigger
 | |
|         <<~SQL
 | |
|           DROP EVENT TRIGGER IF EXISTS alter_new_sequences_range;
 | |
| 
 | |
|           CREATE EVENT TRIGGER alter_new_sequences_range ON ddl_command_end
 | |
|             WHEN TAG IN ('CREATE TABLE', 'ALTER TABLE', 'CREATE SEQUENCE', 'ALTER SEQUENCE')
 | |
|           EXECUTE FUNCTION alter_new_sequences_range();
 | |
|         SQL
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| end
 |