Commit fa840067 authored by Andreas Brandl's avatar Andreas Brandl Committed by Toon Claes

Deprecate #add_column_with_default helper

With PostgreSQL 11, this helper isn't needed anymore. We're deprecating
this here and also adjust the rubocops accordingly.

See https://gitlab.com/gitlab-org/gitlab/-/issues/207820
parent e4855eb6
......@@ -7,7 +7,7 @@ class AddDefaultProjectCreationSetting < ActiveRecord::Migration[4.2]
def up
unless column_exists?(:application_settings, :default_project_creation)
add_column_with_default(:application_settings, :default_project_creation, :integer, default: 2)
add_column_with_default(:application_settings, :default_project_creation, :integer, default: 2) # rubocop:disable Migration/AddColumnWithDefault
end
end
......
......@@ -6,7 +6,7 @@ class AddAllowLocalRequestsFromHooksAndServicesToApplicationSettings < ActiveRec
disable_ddl_transaction!
def up
add_column_with_default(:application_settings, :allow_local_requests_from_hooks_and_services,
add_column_with_default(:application_settings, :allow_local_requests_from_hooks_and_services, # rubocop:disable Migration/AddColumnWithDefault
:boolean,
default: false,
allow_null: false)
......
......@@ -9,7 +9,7 @@ class AddPrivilegedToRunner < ActiveRecord::Migration[4.2]
disable_ddl_transaction!
def up
add_column_with_default :clusters_applications_runners, :privileged, :boolean, default: true, allow_null: false
add_column_with_default :clusters_applications_runners, :privileged, :boolean, default: true, allow_null: false # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -6,7 +6,9 @@ class AddMirrorAvailableToApplicationSettings < ActiveRecord::Migration[4.2]
disable_ddl_transaction!
def up
# rubocop:disable Migration/AddColumnWithDefault
add_column_with_default(:application_settings, :mirror_available, :boolean, default: true, allow_null: false) unless column_exists?(:application_settings, :mirror_available)
# rubocop:enable Migration/AddColumnWithDefault
end
def down
......
......@@ -12,7 +12,7 @@ class EnsureRemoteMirrorColumns < ActiveRecord::Migration[4.2]
add_column :remote_mirrors, :remote_name, :string unless column_exists?(:remote_mirrors, :remote_name)
unless column_exists?(:remote_mirrors, :only_protected_branches)
add_column_with_default(:remote_mirrors,
add_column_with_default(:remote_mirrors, # rubocop:disable Migration/AddColumnWithDefault
:only_protected_branches,
:boolean,
default: false,
......
......@@ -10,7 +10,7 @@ class AddDeployStrategyToProjectAutoDevops < ActiveRecord::Migration[4.2]
disable_ddl_transaction!
def up
add_column_with_default :project_auto_devops, :deploy_strategy, :integer, default: 0, allow_null: false
add_column_with_default :project_auto_devops, :deploy_strategy, :integer, default: 0, allow_null: false # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -6,7 +6,7 @@ class AddHideThirdPartyOffersToApplicationSettings < ActiveRecord::Migration[4.2
disable_ddl_transaction!
def up
add_column_with_default(:application_settings, :hide_third_party_offers,
add_column_with_default(:application_settings, :hide_third_party_offers, # rubocop:disable Migration/AddColumnWithDefault
:boolean,
default: false,
allow_null: false)
......
......@@ -8,7 +8,7 @@ class AddInstanceStatisticsVisibilityToApplicationSetting < ActiveRecord::Migrat
disable_ddl_transaction!
def up
add_column_with_default(:application_settings, :instance_statistics_visibility_private,
add_column_with_default(:application_settings, :instance_statistics_visibility_private, # rubocop:disable Migration/AddColumnWithDefault
:boolean,
default: false,
allow_null: false)
......
......@@ -8,7 +8,7 @@ class AddWebIdeClientSidePreviewEnabledToApplicationSettings < ActiveRecord::Mig
disable_ddl_transaction!
def up
add_column_with_default(:application_settings, :web_ide_clientside_preview_enabled,
add_column_with_default(:application_settings, :web_ide_clientside_preview_enabled, # rubocop:disable Migration/AddColumnWithDefault
:boolean,
default: false,
allow_null: false)
......
......@@ -10,7 +10,9 @@ class AddUserShowAddSshKeyMessageToApplicationSettings < ActiveRecord::Migration
disable_ddl_transaction!
def up
# rubocop:disable Migration/AddColumnWithDefault
add_column_with_default :application_settings, :user_show_add_ssh_key_message, :boolean, default: true, allow_null: false
# rubocop:enable Migration/AddColumnWithDefault
end
def down
......
......@@ -8,7 +8,7 @@ class AddCommonToPrometheusMetrics < ActiveRecord::Migration[4.2]
disable_ddl_transaction!
def up
add_column_with_default(:prometheus_metrics, :common, :boolean, default: false)
add_column_with_default(:prometheus_metrics, :common, :boolean, default: false) # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -8,7 +8,7 @@ class AddLegacyAbacToClusterProvidersGcp < ActiveRecord::Migration[4.2]
disable_ddl_transaction!
def up
add_column_with_default(:cluster_providers_gcp, :legacy_abac, :boolean, default: true)
add_column_with_default(:cluster_providers_gcp, :legacy_abac, :boolean, default: true) # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -12,7 +12,7 @@ class AddDiffMaxPatchBytesToApplicationSettings < ActiveRecord::Migration[4.2]
disable_ddl_transaction!
def up
add_column_with_default(:application_settings,
add_column_with_default(:application_settings, # rubocop:disable Migration/AddColumnWithDefault
:diff_max_patch_bytes,
:integer,
default: 100.kilobytes,
......
......@@ -9,7 +9,7 @@ class AddClusterTypeToClusters < ActiveRecord::Migration[4.2]
disable_ddl_transaction!
def up
add_column_with_default(:clusters, :cluster_type, :smallint, default: PROJECT_CLUSTER_TYPE)
add_column_with_default(:clusters, :cluster_type, :smallint, default: PROJECT_CLUSTER_TYPE) # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -7,7 +7,7 @@ class AddFirstDayOfWeekToApplicationSettings < ActiveRecord::Migration[5.0]
DOWNTIME = false
def up
add_column_with_default(:application_settings, :first_day_of_week, :integer, default: 0)
add_column_with_default(:application_settings, :first_day_of_week, :integer, default: 0) # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -8,7 +8,7 @@ class AddProtectedCiVariablesToApplicationSettings < ActiveRecord::Migration[5.0
disable_ddl_transaction!
def up
add_column_with_default(:application_settings, :protected_ci_variables, :boolean, default: false, allow_null: false)
add_column_with_default(:application_settings, :protected_ci_variables, :boolean, default: false, allow_null: false) # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -12,7 +12,7 @@ class AddMaskedToCiVariables < ActiveRecord::Migration[5.0]
disable_ddl_transaction!
def up
add_column_with_default :ci_variables, :masked, :boolean, default: false, allow_null: false
add_column_with_default :ci_variables, :masked, :boolean, default: false, allow_null: false # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -12,7 +12,7 @@ class AddMaskedToCiGroupVariables < ActiveRecord::Migration[5.0]
disable_ddl_transaction!
def up
add_column_with_default :ci_group_variables, :masked, :boolean, default: false, allow_null: false
add_column_with_default :ci_group_variables, :masked, :boolean, default: false, allow_null: false # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -8,7 +8,7 @@ class AddEmailHeaderAndFooterEnabledFlagToAppearancesTable < ActiveRecord::Migra
DOWNTIME = false
def up
add_column_with_default(:appearances, :email_header_and_footer_enabled, :boolean, default: false)
add_column_with_default(:appearances, :email_header_and_footer_enabled, :boolean, default: false) # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -8,9 +8,9 @@ class AddMultiLineAttributesToSuggestion < ActiveRecord::Migration[5.0]
disable_ddl_transaction!
def up
add_column_with_default :suggestions, :lines_above, :integer, default: 0, allow_null: false
add_column_with_default :suggestions, :lines_below, :integer, default: 0, allow_null: false
add_column_with_default :suggestions, :outdated, :boolean, default: false, allow_null: false
add_column_with_default :suggestions, :lines_above, :integer, default: 0, allow_null: false # rubocop:disable Migration/AddColumnWithDefault
add_column_with_default :suggestions, :lines_below, :integer, default: 0, allow_null: false # rubocop:disable Migration/AddColumnWithDefault
add_column_with_default :suggestions, :outdated, :boolean, default: false, allow_null: false # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -8,7 +8,7 @@ class AddAutoSslEnabledToPagesDomain < ActiveRecord::Migration[5.0]
disable_ddl_transaction!
def up
add_column_with_default :pages_domains, :auto_ssl_enabled, :boolean, default: false
add_column_with_default :pages_domains, :auto_ssl_enabled, :boolean, default: false # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -8,7 +8,7 @@ class AddManagedToCluster < ActiveRecord::Migration[5.0]
DOWNTIME = false
def up
add_column_with_default(:clusters, :managed, :boolean, default: true)
add_column_with_default(:clusters, :managed, :boolean, default: true) # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -12,7 +12,7 @@ class AddLetsEncryptTermsOfServiceAcceptedToApplicationSettings < ActiveRecord::
disable_ddl_transaction!
def up
add_column_with_default(:application_settings, :lets_encrypt_terms_of_service_accepted, :boolean, default: false)
add_column_with_default(:application_settings, :lets_encrypt_terms_of_service_accepted, :boolean, default: false) # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -198,7 +198,7 @@ class BackportEnterpriseSchema < ActiveRecord::Migration[5.0]
def add_column_with_default_if_not_exists(table, name, *args)
unless column_exists?(table, name)
add_column_with_default(table, name, *args)
add_column_with_default(table, name, *args) # rubocop:disable Migration/AddColumnWithDefault
end
end
......
......@@ -8,7 +8,7 @@ class AddVariableTypeToCiVariables < ActiveRecord::Migration[5.0]
ENV_VAR_VARIABLE_TYPE = 1
def up
add_column_with_default(:ci_variables, :variable_type, :smallint, default: ENV_VAR_VARIABLE_TYPE)
add_column_with_default(:ci_variables, :variable_type, :smallint, default: ENV_VAR_VARIABLE_TYPE) # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -8,7 +8,7 @@ class AddVariableTypeToCiGroupVariables < ActiveRecord::Migration[5.0]
ENV_VAR_VARIABLE_TYPE = 1
def up
add_column_with_default(:ci_group_variables, :variable_type, :smallint, default: ENV_VAR_VARIABLE_TYPE)
add_column_with_default(:ci_group_variables, :variable_type, :smallint, default: ENV_VAR_VARIABLE_TYPE) # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -8,7 +8,7 @@ class AddVariableTypeToCiPipelineScheduleVariables < ActiveRecord::Migration[5.0
ENV_VAR_VARIABLE_TYPE = 1
def up
add_column_with_default(:ci_pipeline_schedule_variables, :variable_type, :smallint, default: ENV_VAR_VARIABLE_TYPE)
add_column_with_default(:ci_pipeline_schedule_variables, :variable_type, :smallint, default: ENV_VAR_VARIABLE_TYPE) # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -12,7 +12,7 @@ class AddRuleTypeToApprovalMergeRequestApprovalRules < ActiveRecord::Migration[5
disable_ddl_transaction!
def up
add_column_with_default(:approval_merge_request_rules, :rule_type, :integer, limit: 2, default: 1)
add_column_with_default(:approval_merge_request_rules, :rule_type, :integer, limit: 2, default: 1) # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -11,7 +11,7 @@ class AddDnsRebindingProtectionEnabledToApplicationSettings < ActiveRecord::Migr
disable_ddl_transaction!
def up
add_column_with_default(:application_settings, :dns_rebinding_protection_enabled,
add_column_with_default(:application_settings, :dns_rebinding_protection_enabled, # rubocop:disable Migration/AddColumnWithDefault
:boolean,
default: true,
allow_null: false)
......
......@@ -11,7 +11,7 @@ class AddLdapMembershipLock < ActiveRecord::Migration[5.1]
disable_ddl_transaction!
def up
add_column_with_default(:application_settings, :lock_memberships_to_ldap, :boolean, default: false)
add_column_with_default(:application_settings, :lock_memberships_to_ldap, :boolean, default: false) # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -11,7 +11,9 @@ class AddDefaultProjectDeletionProtectionToApplicationSettings < ActiveRecord::M
disable_ddl_transaction!
def up
# rubocop:disable Migration/AddColumnWithDefault
add_column_with_default :application_settings, :default_project_deletion_protection, :boolean, default: false, allow_null: false
# rubocop:enable Migration/AddColumnWithDefault
end
def down
......
......@@ -12,7 +12,7 @@ class AddSourceToPagesDomains < ActiveRecord::Migration[5.1]
disable_ddl_transaction!
def up
add_column_with_default(:pages_domains, :certificate_source, :smallint, default: 0)
add_column_with_default(:pages_domains, :certificate_source, :smallint, default: 0) # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -12,7 +12,9 @@ class AddTimeTrackingLimitToHoursToApplicationSettings < ActiveRecord::Migration
disable_ddl_transaction!
def up
# rubocop:disable Migration/AddColumnWithDefault
add_column_with_default :application_settings, :time_tracking_limit_to_hours, :boolean, default: false, allow_null: false
# rubocop:enable Migration/AddColumnWithDefault
end
def down
......
......@@ -8,7 +8,7 @@ class AddGrafanaToSettings < ActiveRecord::Migration[5.1]
DOWNTIME = false
def up
add_column_with_default(:application_settings, :grafana_enabled, :boolean,
add_column_with_default(:application_settings, :grafana_enabled, :boolean, # rubocop:disable Migration/AddColumnWithDefault
default: false, allow_null: false)
end
......
......@@ -9,7 +9,7 @@ class AddGrafanaUrlToSettings < ActiveRecord::Migration[5.1]
# rubocop:disable Migration/PreventStrings
def up
add_column_with_default(:application_settings, :grafana_url, :string,
add_column_with_default(:application_settings, :grafana_url, :string, # rubocop:disable Migration/AddColumnWithDefault
default: '/-/grafana', allow_null: false)
end
# rubocop:enable Migration/PreventStrings
......
......@@ -8,7 +8,9 @@ class AddStrategiesToOperationsFeatureFlagScopes < ActiveRecord::Migration[5.1]
disable_ddl_transaction!
def up
# rubocop:disable Migration/AddColumnWithDefault
add_column_with_default :operations_feature_flag_scopes, :strategies, :jsonb, default: [{ name: "default", parameters: {} }]
# rubocop:enable Migration/AddColumnWithDefault
end
def down
......
......@@ -8,7 +8,7 @@ class AddRuleTypeToApprovalProjectRules < ActiveRecord::Migration[5.1]
disable_ddl_transaction!
def up
add_column_with_default :approval_project_rules, :rule_type, :integer, limit: 2, default: 0, allow_null: false
add_column_with_default :approval_project_rules, :rule_type, :integer, limit: 2, default: 0, allow_null: false # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -11,7 +11,7 @@ class AddNamespacePerEnvironmentFlagToClusters < ActiveRecord::Migration[5.1]
disable_ddl_transaction!
def up
add_column_with_default :clusters, :namespace_per_environment, :boolean, default: false
add_column_with_default :clusters, :namespace_per_environment, :boolean, default: false # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -10,7 +10,6 @@ class AddEventTypeToDesignManagementDesignsVersions < ActiveRecord::Migration[5.
# We disable these cops here because adding this column is safe. The table does not
# have any data in it.
# rubocop: disable Migration/AddIndex
# rubocop: disable Migration/AddColumn
def up
add_column(:design_management_designs_versions, :event, :integer,
limit: 2,
......
......@@ -12,7 +12,7 @@ class AddObjectStorageFlagToGeoNode < ActiveRecord::Migration[5.2]
disable_ddl_transaction!
def up
add_column_with_default :geo_nodes, :sync_object_storage, :boolean, default: false
add_column_with_default :geo_nodes, :sync_object_storage, :boolean, default: false # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -9,7 +9,7 @@ class AddMergeRequestsRequireCodeOwnerApprovalToProtectedBranches < ActiveRecord
disable_ddl_transaction!
def up
add_column_with_default(
add_column_with_default( # rubocop:disable Migration/AddColumnWithDefault
:protected_branches,
:code_owner_approval_required,
:boolean,
......
......@@ -14,7 +14,7 @@ class RemoveEpicIssuesDefaultRelativePosition < ActiveRecord::Migration[5.2]
change_column_null :epic_issues, :relative_position, true
change_column_default :epic_issues, :relative_position, from: 1073741823, to: nil
else
add_column_with_default(:epic_issues, :relative_position, :integer, default: nil, allow_null: true)
add_column_with_default(:epic_issues, :relative_position, :integer, default: nil, allow_null: true) # rubocop:disable Migration/AddColumnWithDefault
end
end
......
......@@ -8,7 +8,7 @@ class AddActiveJobsLimitToPlans < ActiveRecord::Migration[5.2]
disable_ddl_transaction!
def up
add_column_with_default :plans, :active_jobs_limit, :integer, default: 0
add_column_with_default :plans, :active_jobs_limit, :integer, default: 0 # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -7,7 +7,7 @@ class AddMaxIssueCountToList < ActiveRecord::Migration[4.2]
DOWNTIME = false
def up
add_column_with_default :lists, :max_issue_count, :integer, default: 0
add_column_with_default :lists, :max_issue_count, :integer, default: 0 # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -8,7 +8,7 @@ class AddCloudRunToClustersProvidersGcp < ActiveRecord::Migration[5.2]
disable_ddl_transaction!
def up
add_column_with_default(:cluster_providers_gcp, :cloud_run, :boolean, default: false)
add_column_with_default(:cluster_providers_gcp, :cloud_run, :boolean, default: false) # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -11,7 +11,7 @@ class AddShowWhitespaceInDiffsToUserPreferences < ActiveRecord::Migration[5.2]
disable_ddl_transaction!
def up
add_column_with_default :user_preferences, :show_whitespace_in_diffs, :boolean, default: true, allow_null: false
add_column_with_default :user_preferences, :show_whitespace_in_diffs, :boolean, default: true, allow_null: false # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -9,7 +9,7 @@ class AddCleanupStatusToCluster < ActiveRecord::Migration[5.2]
disable_ddl_transaction!
def up
add_column_with_default(:clusters, :cleanup_status,
add_column_with_default(:clusters, :cleanup_status, # rubocop:disable Migration/AddColumnWithDefault
:smallint,
default: 1,
allow_null: false)
......
......@@ -8,7 +8,7 @@ class AddPushEventHooksLimitToApplicationSettings < ActiveRecord::Migration[5.2]
disable_ddl_transaction!
def up
add_column_with_default(:application_settings, :push_event_hooks_limit, :integer, default: 3)
add_column_with_default(:application_settings, :push_event_hooks_limit, :integer, default: 3) # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -6,7 +6,7 @@ class AddPendoEnabledToApplicationSettings < ActiveRecord::Migration[5.2]
disable_ddl_transaction!
def up
add_column_with_default :application_settings, :pendo_enabled, :boolean, default: false, allow_null: false
add_column_with_default :application_settings, :pendo_enabled, :boolean, default: false, allow_null: false # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -8,7 +8,7 @@ class AddPushEventActivitiesLimitToApplicationSettings < ActiveRecord::Migration
disable_ddl_transaction!
def up
add_column_with_default(:application_settings, :push_event_activities_limit, :integer, default: 3)
add_column_with_default(:application_settings, :push_event_activities_limit, :integer, default: 3) # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -8,7 +8,7 @@ class AddExpireNotificationDeliveredToPersonalAccessTokens < ActiveRecord::Migra
disable_ddl_transaction!
def up
add_column_with_default :personal_access_tokens, :expire_notification_delivered, :boolean, default: false
add_column_with_default :personal_access_tokens, :expire_notification_delivered, :boolean, default: false # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -8,7 +8,7 @@ class AddMaxIssueWeightToList < ActiveRecord::Migration[5.2]
DOWNTIME = false
def up
add_column_with_default :lists, :max_issue_weight, :integer, default: 0
add_column_with_default :lists, :max_issue_weight, :integer, default: 0 # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -8,7 +8,7 @@ class AddEnabledToGrafanaIntegrations < ActiveRecord::Migration[5.2]
disable_ddl_transaction!
def up
add_column_with_default(
add_column_with_default( # rubocop:disable Migration/AddColumnWithDefault
:grafana_integrations,
:enabled,
:boolean,
......
......@@ -9,7 +9,7 @@ class AddSecretToSnippet < ActiveRecord::Migration[5.2]
def up
unless column_exists?(:snippets, :secret)
add_column_with_default :snippets, :secret, :boolean, default: false
add_column_with_default :snippets, :secret, :boolean, default: false # rubocop:disable Migration/AddColumnWithDefault
end
add_concurrent_index :snippets, [:visibility_level, :secret]
......
......@@ -9,7 +9,7 @@ class AddStateToMergeTrains < ActiveRecord::Migration[5.2]
disable_ddl_transaction!
def up
add_column_with_default :merge_trains, :status, :integer, limit: 2, default: MERGE_TRAIN_STATUS_CREATED
add_column_with_default :merge_trains, :status, :integer, limit: 2, default: MERGE_TRAIN_STATUS_CREATED # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -8,7 +8,7 @@ class AddArtifactsToCiBuildNeed < ActiveRecord::Migration[5.2]
disable_ddl_transaction!
def up
add_column_with_default(:ci_build_needs, :artifacts,
add_column_with_default(:ci_build_needs, :artifacts, # rubocop:disable Migration/AddColumnWithDefault
:boolean,
default: true,
allow_null: false)
......
......@@ -8,7 +8,7 @@ class AddIssueLinksType < ActiveRecord::Migration[5.1]
disable_ddl_transaction!
def up
add_column_with_default :issue_links, :link_type, :integer, default: 0, limit: 2
add_column_with_default :issue_links, :link_type, :integer, default: 0, limit: 2 # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -8,7 +8,7 @@ class AddConfidentialToDoorkeeperApplication < ActiveRecord::Migration[5.2]
disable_ddl_transaction!
def up
add_column_with_default(
add_column_with_default( # rubocop:disable Migration/AddColumnWithDefault
:oauth_applications,
:confidential,
:boolean,
......
......@@ -9,8 +9,8 @@ class AddWildcardAndDomainTypeToPagesDomains < ActiveRecord::Migration[5.2]
disable_ddl_transaction!
def up
add_column_with_default :pages_domains, :wildcard, :boolean, default: false
add_column_with_default :pages_domains, :domain_type, :integer, limit: 2, default: PROJECT_TYPE
add_column_with_default :pages_domains, :wildcard, :boolean, default: false # rubocop:disable Migration/AddColumnWithDefault
add_column_with_default :pages_domains, :domain_type, :integer, limit: 2, default: PROJECT_TYPE # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -10,7 +10,7 @@ class AddBroadcastTypeToBroadcastMessage < ActiveRecord::Migration[5.2]
disable_ddl_transaction!
def up
add_column_with_default(:broadcast_messages, :broadcast_type, :smallint, default: BROADCAST_MESSAGE_BANNER_TYPE)
add_column_with_default(:broadcast_messages, :broadcast_type, :smallint, default: BROADCAST_MESSAGE_BANNER_TYPE) # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -8,7 +8,7 @@ class AddSamlProviderProhibitedOuterForks < ActiveRecord::Migration[5.2]
disable_ddl_transaction!
def up
add_column_with_default :saml_providers, :prohibited_outer_forks, :boolean, default: false, allow_null: true
add_column_with_default :saml_providers, :prohibited_outer_forks, :boolean, default: false, allow_null: true # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -8,7 +8,7 @@ class AddUpdatingNameDisabledForUsersToApplicationSettings < ActiveRecord::Migra
disable_ddl_transaction!
def up
add_column_with_default(:application_settings, :updating_name_disabled_for_users,
add_column_with_default(:application_settings, :updating_name_disabled_for_users, # rubocop:disable Migration/AddColumnWithDefault
:boolean,
default: false,
allow_null: false)
......
......@@ -9,7 +9,7 @@ class AddRepositoryStorageToSnippets < ActiveRecord::Migration[5.2]
# rubocop:disable Migration/PreventStrings
def up
add_column_with_default(
add_column_with_default( # rubocop:disable Migration/AddColumnWithDefault
:snippets,
:repository_storage,
:string,
......
......@@ -8,7 +8,7 @@ class AddStorageVersionToSnippets < ActiveRecord::Migration[5.2]
disable_ddl_transaction!
def up
add_column_with_default(
add_column_with_default( # rubocop:disable Migration/AddColumnWithDefault
:snippets,
:storage_version,
:integer,
......
......@@ -8,7 +8,7 @@ class AddDeployTokenTypeToDeployTokens < ActiveRecord::Migration[5.2]
DOWNTIME = false
def up
add_column_with_default :deploy_tokens, :deploy_token_type, :integer, default: 2, limit: 2, allow_null: false
add_column_with_default :deploy_tokens, :deploy_token_type, :integer, default: 2, limit: 2, allow_null: false # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -9,7 +9,7 @@ class AddUsageToPagesDomains < ActiveRecord::Migration[5.2]
disable_ddl_transaction!
def up
add_column_with_default :pages_domains, :usage, :integer, limit: 2, default: PAGES_USAGE, allow_null: false
add_column_with_default :pages_domains, :usage, :integer, limit: 2, default: PAGES_USAGE, allow_null: false # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -8,7 +8,7 @@ class AddNpmPackageRequestsForwardingToApplicationSettings < ActiveRecord::Migra
disable_ddl_transaction!
def up
add_column_with_default(:application_settings, :npm_package_requests_forwarding,
add_column_with_default(:application_settings, :npm_package_requests_forwarding, # rubocop:disable Migration/AddColumnWithDefault
:boolean,
default: false,
allow_null: false)
......
......@@ -12,7 +12,9 @@ class AddVersionToFeatureFlagsTable < ActiveRecord::Migration[6.0]
def up
# The operations_feature_flags table is small enough that we can disable this cop.
# See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25552#note_291202882
# rubocop:disable Migration/AddColumnWithDefault
add_column_with_default(:operations_feature_flags, :version, :smallint, default: FEATURE_FLAG_LEGACY_VERSION, allow_null: false)
# rubocop:enable Migration/AddColumnWithDefault
end
def down
......
......@@ -10,7 +10,7 @@ class AddRuntimeCreatedToCiJobVariables < ActiveRecord::Migration[6.0]
DEFAULT_SOURCE = 0 # Equvalent to Ci::JobVariable.internal_source
def up
add_column_with_default(:ci_job_variables, :source, :integer, limit: 2, default: DEFAULT_SOURCE, allow_null: false)
add_column_with_default(:ci_job_variables, :source, :integer, limit: 2, default: DEFAULT_SOURCE, allow_null: false) # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -8,7 +8,7 @@ class AddCiPipelineSchedulesToPlanLimits < ActiveRecord::Migration[6.0]
DOWNTIME = false
def up
add_column_with_default(:plan_limits, :ci_pipeline_schedules, :integer, default: 0, allow_null: false)
add_column_with_default(:plan_limits, :ci_pipeline_schedules, :integer, default: 0, allow_null: false) # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -10,7 +10,7 @@ class AddModsecurityModeToIngressApplication < ActiveRecord::Migration[6.0]
disable_ddl_transaction!
def up
add_column_with_default(:clusters_applications_ingress, :modsecurity_mode, :smallint, default: 0, allow_null: false)
add_column_with_default(:clusters_applications_ingress, :modsecurity_mode, :smallint, default: 0, allow_null: false) # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -8,8 +8,8 @@ class AddCostFactorFiledsToCiRunners < ActiveRecord::Migration[6.0]
disable_ddl_transaction!
def up
add_column_with_default(:ci_runners, :public_projects_minutes_cost_factor, :float, allow_null: false, default: 0.0)
add_column_with_default(:ci_runners, :private_projects_minutes_cost_factor, :float, allow_null: false, default: 1.0)
add_column_with_default(:ci_runners, :public_projects_minutes_cost_factor, :float, allow_null: false, default: 0.0) # rubocop:disable Migration/AddColumnWithDefault
add_column_with_default(:ci_runners, :private_projects_minutes_cost_factor, :float, allow_null: false, default: 1.0) # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -11,7 +11,7 @@ class AddLetsencryptErrorsToPagesDomains < ActiveRecord::Migration[6.0]
disable_ddl_transaction!
def up
add_column_with_default :pages_domains, :auto_ssl_failed, :boolean, default: false
add_column_with_default :pages_domains, :auto_ssl_failed, :boolean, default: false # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -9,7 +9,9 @@ class AddBioToUserDetails < ActiveRecord::Migration[6.0]
# rubocop:disable Migration/PreventStrings
def up
add_column_with_default(:user_details, :bio, :string, default: '', allow_null: false, limit: 255, update_column_in_batches_args: { batch_column_name: :user_id })
# rubocop:disable Migration/AddColumnWithDefault
add_column_with_default(:user_details, :bio, :string, default: '', allow_null: false, limit: 255)
# rubocop:enable Migration/AddColumnWithDefault
end
# rubocop:enable Migration/PreventStrings
......
......@@ -7,7 +7,7 @@ class AddNamespaceStorageSizeLimitToApplicationSettings < ActiveRecord::Migratio
disable_ddl_transaction!
def up
add_column_with_default :application_settings, :namespace_storage_size_limit, :bigint, default: 0
add_column_with_default :application_settings, :namespace_storage_size_limit, :bigint, default: 0 # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -8,7 +8,7 @@ class AddSeatLinkEnabledToApplicationSettings < ActiveRecord::Migration[6.0]
disable_ddl_transaction!
def up
add_column_with_default(:application_settings, :seat_link_enabled,
add_column_with_default(:application_settings, :seat_link_enabled, # rubocop:disable Migration/AddColumnWithDefault
:boolean,
default: true,
allow_null: false)
......
......@@ -8,7 +8,7 @@ class AddConfidentialAttributeToEpics < ActiveRecord::Migration[6.0]
disable_ddl_transaction!
def up
add_column_with_default(:epics, :confidential, :boolean, default: false)
add_column_with_default(:epics, :confidential, :boolean, default: false) # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -8,7 +8,7 @@ class AddContainerExpirationPoliciesEnableHistoricEntriesToApplicationSettings <
disable_ddl_transaction!
def up
add_column_with_default(:application_settings,
add_column_with_default(:application_settings, # rubocop:disable Migration/AddColumnWithDefault
:container_expiration_policies_enable_historic_entries,
:boolean,
default: false,
......
......@@ -8,7 +8,7 @@ class AddWriteRegistryToDeployTokens < ActiveRecord::Migration[6.0]
disable_ddl_transaction!
def up
add_column_with_default(:deploy_tokens, :write_registry, :boolean, default: false, allow_null: false)
add_column_with_default(:deploy_tokens, :write_registry, :boolean, default: false, allow_null: false) # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -8,8 +8,8 @@ class AddPackageScopesToDeployTokens < ActiveRecord::Migration[6.0]
disable_ddl_transaction!
def up
add_column_with_default(:deploy_tokens, :read_package_registry, :boolean, default: false, allow_null: false)
add_column_with_default(:deploy_tokens, :write_package_registry, :boolean, default: false, allow_null: false)
add_column_with_default(:deploy_tokens, :read_package_registry, :boolean, default: false, allow_null: false) # rubocop:disable Migration/AddColumnWithDefault
add_column_with_default(:deploy_tokens, :write_package_registry, :boolean, default: false, allow_null: false) # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -7,7 +7,7 @@ class AddGroupOwnersCanManageDefaultBranchProtectionToApplicationSettings < Acti
disable_ddl_transaction!
def up
add_column_with_default(:application_settings,
add_column_with_default(:application_settings, # rubocop:disable Migration/AddColumnWithDefault
:group_owners_can_manage_default_branch_protection,
:boolean,
default: true)
......
......@@ -8,12 +8,12 @@ class AddWafAndCiliumLogsToApplicationsFluentd < ActiveRecord::Migration[6.0]
disable_ddl_transaction!
def up
add_column_with_default(:clusters_applications_fluentd,
add_column_with_default(:clusters_applications_fluentd, # rubocop:disable Migration/AddColumnWithDefault
:waf_log_enabled,
:boolean,
default: true,
allow_null: false)
add_column_with_default(:clusters_applications_fluentd,
add_column_with_default(:clusters_applications_fluentd, # rubocop:disable Migration/AddColumnWithDefault
:cilium_log_enabled,
:boolean,
default: true,
......
......@@ -9,13 +9,13 @@ class AddRegistrySettingsToApplicationSettings < ActiveRecord::Migration[6.0]
# rubocop:disable Migration/AddLimitToTextColumns
def up
add_column_with_default(:application_settings,
add_column_with_default(:application_settings, # rubocop:disable Migration/AddColumnWithDefault
:container_registry_vendor,
:text,
default: '',
allow_null: false)
add_column_with_default(:application_settings,
add_column_with_default(:application_settings, # rubocop:disable Migration/AddColumnWithDefault
:container_registry_version,
:text,
default: '',
......
......@@ -24,7 +24,9 @@ class RemoveCircuitBreaker < ActiveRecord::Migration[4.2]
def down
CIRCUIT_BREAKER_COLUMS_WITH_DEFAULT.each do |column, default|
# rubocop:disable Migration/AddColumnWithDefault
add_column_with_default(:application_settings, column, :integer, default: default) unless column_exists?(:application_settings, column)
# rubocop:enable Migration/AddColumnWithDefault
end
end
end
......@@ -28,7 +28,9 @@ class RemoveSentryFromApplicationSettings < ActiveRecord::Migration[5.0]
def down
SENTRY_ENABLED_COLUMNS.each do |column|
# rubocop:disable Migration/AddColumnWithDefault
add_column_with_default(:application_settings, column, :boolean, default: false, allow_null: false) unless column_exists?(:application_settings, column)
# rubocop:enable Migration/AddColumnWithDefault
end
SENTRY_DSN_COLUMNS.each do |column|
......
......@@ -13,7 +13,7 @@ class RemovePendoFromApplicationSettings < ActiveRecord::Migration[5.2]
end
def down
add_column_with_default :application_settings, :pendo_enabled, :boolean, default: false, allow_null: false
add_column_with_default :application_settings, :pendo_enabled, :boolean, default: false, allow_null: false # rubocop:disable Migration/AddColumnWithDefault
add_column :application_settings, :pendo_url, :string, limit: 255
end
end
......@@ -12,6 +12,8 @@ class DropProjectCiCdSettingsMergeTrainsEnabled < ActiveRecord::Migration[5.2]
end
def down
# rubocop:disable Migration/AddColumnWithDefault
add_column_with_default :project_ci_cd_settings, :merge_trains_enabled, :boolean, default: false, allow_null: true # rubocop:disable Migration/UpdateLargeTable
# rubocop:enable Migration/AddColumnWithDefault
end
end
......@@ -19,7 +19,7 @@ class RemoveStorageVersionColumnFromSnippets < ActiveRecord::Migration[5.2]
def down
return if column_exists?(:snippets, :storage_version)
add_column_with_default(
add_column_with_default( # rubocop:disable Migration/AddColumnWithDefault
:snippets,
:storage_version,
:integer,
......
......@@ -15,7 +15,7 @@ class ReaddTemplateColumnToServices < ActiveRecord::Migration[6.0]
# to production, so we should be okay to re-add it without worrying
# about doing a data migration. If we needed to restore the value
# of `template`, we would look for entries with `project_id IS NULL`.
add_column_with_default :services, :template, :boolean, default: false, allow_null: true
add_column_with_default :services, :template, :boolean, default: false, allow_null: true # rubocop:disable Migration/AddColumnWithDefault
end
# rubocop:enable Migration/UpdateLargeTable
......
......@@ -16,7 +16,7 @@ class RemoveRepositoryStorageFromSnippets < ActiveRecord::Migration[6.0]
def down
return if column_exists?(:snippets, :repository_storage)
add_column_with_default(
add_column_with_default( # rubocop:disable Migration/AddColumnWithDefault
:snippets,
:repository_storage,
:string,
......
......@@ -64,7 +64,7 @@ TARGET=12-9-stable-ee scripts/regenerate-schema
The document ["What Requires Downtime?"](what_requires_downtime.md) specifies
various database operations, such as
- [adding, dropping, and renaming columns](what_requires_downtime.md#adding-columns)
- [dropping and renaming columns](what_requires_downtime.md#dropping-columns)
- [changing column constraints and types](what_requires_downtime.md#changing-column-constraints)
- [adding and dropping indexes, tables, and foreign keys](what_requires_downtime.md#adding-indexes)
......@@ -552,34 +552,12 @@ You can read more about adding [foreign key constraints to an existing column](d
## Adding Columns With Default Values
When adding columns with default values to non-empty tables, you must use
`add_column_with_default`. This method ensures the table is updated without
requiring downtime. This method is not reversible so you must manually define
the `up` and `down` methods in your migration class.
With PostgreSQL 11 being the minimum version since GitLab 13.0, adding columns with default values has become much easier and
the standard `add_column` helper should be used in all cases.
For example, to add the column `foo` to the `projects` table with a default
value of `10` you'd write the following:
```ruby
class MyMigration < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
disable_ddl_transaction!
def up
add_column_with_default(:projects, :foo, :integer, default: 10)
end
def down
remove_column(:projects, :foo)
end
end
```
Keep in mind that this operation can easily take 10-15 minutes to complete on
larger installations (e.g. GitLab.com). As a result, you should only add
default values if absolutely necessary. There is a RuboCop cop that will fail if
this method is used on some tables that are very large on GitLab.com, which
would cause other issues.
Before PostgreSQL 11, adding a column with a default was problematic as it would
have caused a full table rewrite. The corresponding helper `add_column_with_default`
has been deprecated and will be removed in a later release.
## Changing the column default
......@@ -620,8 +598,7 @@ without requiring `disable_ddl_transaction!`.
## Updating an existing column
To update an existing column to a particular value, you can use
`update_column_in_batches` (`add_column_with_default` uses this internally to
fill in the default value). This will split the updates into batches, so we
`update_column_in_batches`. This will split the updates into batches, so we
don't update too many rows at in a single statement.
This updates the column `foo` in the `projects` table to 10, where `some_column`
......@@ -747,7 +724,7 @@ set the limit to 8-bytes. This will allow the column to hold a value up to
Rails migration example:
```ruby
add_column_with_default(:projects, :foo, :integer, default: 10, limit: 8)
add_column(:projects, :foo, :integer, default: 10, limit: 8)
```
## Timestamp column type
......
......@@ -5,38 +5,6 @@ GitLab offline, others do require a downtime period. This guide describes
various operations, their impact, and how to perform them without requiring
downtime.
## Adding Columns
You can safely add a new column to an existing table as long as it does **not**
have a default value. For example, this query would not require downtime:
```sql
ALTER TABLE projects ADD COLUMN random_value int;
```
Add a column _with_ a default however does require downtime. For example,
consider this query:
```sql
ALTER TABLE projects ADD COLUMN random_value int DEFAULT 42;
```
This requires updating every single row in the `projects` table so that
`random_value` is set to `42` by default. This requires updating all rows and
indexes in a table. This in turn acquires enough locks on the table for it to
effectively block any other queries.
Adding a column with a default value _can_ be done without requiring downtime
when using the migration helper method
`Gitlab::Database::MigrationHelpers#add_column_with_default`. This method works
similar to `add_column` except it updates existing rows in batches without
blocking access to the table being modified. See ["Adding Columns With Default
Values"](migration_style_guide.md#adding-columns-with-default-values) for more
information on how to use this method.
Note that usage of `add_column_with_default` with `allow_null: false` to also add
a `NOT NULL` constraint is [discouraged](https://gitlab.com/gitlab-org/gitlab/issues/38060).
## Dropping Columns
Removing columns is tricky because running GitLab processes may still be using
......
......@@ -6,8 +6,8 @@ class AddNeedsResyncToProjectRegistry < ActiveRecord::Migration[4.2]
disable_ddl_transaction!
def up
add_column_with_default(:project_registry, :resync_repository, :boolean, default: true)
add_column_with_default(:project_registry, :resync_wiki, :boolean, default: true)
add_column_with_default(:project_registry, :resync_repository, :boolean, default: true) # rubocop:disable Migration/AddColumnWithDefault
add_column_with_default(:project_registry, :resync_wiki, :boolean, default: true) # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -7,7 +7,7 @@ class AddFileRegistrySuccess < ActiveRecord::Migration[4.2]
def up
# Ensure existing rows are recorded as successes
add_column_with_default :file_registry, :success, :boolean, default: true, allow_null: false
add_column_with_default :file_registry, :success, :boolean, default: true, allow_null: false # rubocop:disable Migration/AddColumnWithDefault
change_column :file_registry, :success, :boolean, default: false
end
......
......@@ -3,8 +3,6 @@ class AddRepositoryVerificationToProjectRegistry < ActiveRecord::Migration[4.2]
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
# rubocop:disable Migration/AddColumn
# rubocop:disable Migration/PreventStrings
def change
add_column :project_registry, :repository_verification_checksum, :string
......@@ -18,5 +16,4 @@ class AddRepositoryVerificationToProjectRegistry < ActiveRecord::Migration[4.2]
add_column :project_registry, :last_wiki_verification_failure, :string
end
# rubocop:enable Migration/PreventStrings
# rubocop:enable Migration/AddColumn
end
......@@ -6,7 +6,7 @@ class AddMissingOnPrimaryToFileRegistry < ActiveRecord::Migration[4.2]
disable_ddl_transaction!
def up
add_column_with_default :file_registry, :missing_on_primary, :boolean, default: false, allow_null: false
add_column_with_default :file_registry, :missing_on_primary, :boolean, default: false, allow_null: false # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -6,7 +6,7 @@ class AddMissingOnPrimaryToJobArtifactRegistry < ActiveRecord::Migration[4.2]
disable_ddl_transaction!
def up
add_column_with_default :job_artifact_registry, :missing_on_primary, :boolean, default: false, allow_null: false
add_column_with_default :job_artifact_registry, :missing_on_primary, :boolean, default: false, allow_null: false # rubocop:disable Migration/AddColumnWithDefault
end
def down
......
......@@ -4,7 +4,7 @@ class AddChecksumMismatchFieldsToProjectRegistry < ActiveRecord::Migration[4.2]
DOWNTIME = false
def change
add_column :project_registry, :repository_checksum_mismatch, :boolean, null: false, default: false # rubocop:disable Migration/AddColumn
add_column :project_registry, :wiki_checksum_mismatch, :boolean, null: false, default: false # rubocop:disable Migration/AddColumn
add_column :project_registry, :repository_checksum_mismatch, :boolean, null: false, default: false
add_column :project_registry, :wiki_checksum_mismatch, :boolean, null: false, default: false
end
end
......@@ -7,7 +7,7 @@ class RemoveLastVerificationFailedColumnsFromGeoProjectRegistry < ActiveRecord::
end
def down
add_column :project_registry, :last_repository_verification_failed, :boolean, default: false, null: false # rubocop:disable Migration/AddColumn
add_column :project_registry, :last_wiki_verification_failed, :boolean, default: false, null: false # rubocop:disable Migration/AddColumn
add_column :project_registry, :last_repository_verification_failed, :boolean, default: false, null: false
add_column :project_registry, :last_wiki_verification_failed, :boolean, default: false, null: false
end
end
......@@ -451,66 +451,13 @@ module Gitlab
# Adds a column with a default value without locking an entire table.
#
# This method runs the following steps:
#
# 1. Add the column with a default value of NULL.
# 2. Change the default value of the column to the specified value.
# 3. Update all existing rows in batches.
# 4. Set a `NOT NULL` constraint on the column if desired (the default).
#
# These steps ensure a column can be added to a large and commonly used
# table without locking the entire table for the duration of the table
# modification.
#
# table - The name of the table to update.
# column - The name of the column to add.
# type - The column type (e.g. `:integer`).
# default - The default value for the column.
# limit - Sets a column limit. For example, for :integer, the default is
# 4-bytes. Set `limit: 8` to allow 8-byte integers.
# allow_null - When set to `true` the column will allow NULL values, the
# default is to not allow NULL values.
#
# This method can also take a block which is passed directly to the
# `update_column_in_batches` method.
def add_column_with_default(table, column, type, default:, limit: nil, allow_null: false, update_column_in_batches_args: {}, &block)
if transaction_open?
raise 'add_column_with_default can not be run inside a transaction, ' \
'you can disable transactions by calling disable_ddl_transaction! ' \
'in the body of your migration class'
end
disable_statement_timeout do
transaction do
if limit
add_column(table, column, type, default: nil, limit: limit)
else
add_column(table, column, type, default: nil)
end
# @deprecated With PostgreSQL 11, adding columns with a default does not lead to a table rewrite anymore.
# As such, this method is not needed anymore and the default `add_column` helper should be used.
# This helper is subject to be removed in a >13.0 release.
def add_column_with_default(table, column, type, default:, limit: nil, allow_null: false)
raise 'Deprecated: add_column_with_default does not support being passed blocks anymore' if block_given?
# Changing the default before the update ensures any newly inserted
# rows already use the proper default value.
change_column_default(table, column, default)
end
begin
default_after_type_cast = connection.type_cast(default, column_for(table, column))
if update_column_in_batches_args.any?
update_column_in_batches(table, column, default_after_type_cast, **update_column_in_batches_args, &block)
else
update_column_in_batches(table, column, default_after_type_cast, &block)
end
change_column_null(table, column, false) unless allow_null
# We want to rescue _all_ exceptions here, even those that don't inherit
# from StandardError.
rescue Exception => error # rubocop: disable all
remove_column(table, column)
raise error
end
end
add_column(table, column, type, default: default, limit: limit, null: allow_null)
end
# Renames a column without requiring downtime.
......
require_relative '../../migration_helpers'
module RuboCop
module Cop
module Migration
# Cop that checks if columns are added in a way that doesn't require
# downtime.
class AddColumn < RuboCop::Cop::Cop
include MigrationHelpers
MSG = '`add_column` with a default value requires downtime, ' \
'use `add_column_with_default` instead'.freeze
def on_send(node)
return unless in_migration?(node)
name = node.children[1]
return unless name == :add_column
# Ignore whitelisted tables.
return if table_whitelisted?(node.children[2])
opts = node.children.last
return unless opts && opts.type == :hash
opts.each_node(:pair) do |pair|
if hash_key_type(pair) == :sym && hash_key_name(pair) == :default
add_offense(node, location: :selector)
end
end
end
def table_whitelisted?(symbol)
symbol && symbol.type == :sym &&
WHITELISTED_TABLES.include?(symbol.children[0])
end
def hash_key_type(pair)
pair.children[0].type
end
def hash_key_name(pair)
pair.children[0].children[0]
end
end
end
end
end
......@@ -5,39 +5,17 @@ require_relative '../../migration_helpers'
module RuboCop
module Cop
module Migration
# Cop that checks if columns are added in a way that doesn't require
# downtime.
class AddColumnWithDefault < RuboCop::Cop::Cop
include MigrationHelpers
MSG = '`add_column_with_default` without `allow_null: true` may cause prolonged lock situations and downtime, ' \
'see https://gitlab.com/gitlab-org/gitlab/issues/38060'.freeze
def_node_matcher :add_column_with_default?, <<~PATTERN
(send _ :add_column_with_default $_ ... (hash $...))
PATTERN
MSG = '`add_column_with_default` is deprecated, use `add_column` instead'.freeze
def on_send(node)
return unless in_migration?(node)
add_column_with_default?(node) do |table, options|
add_offense(node, location: :selector) if offensive?(table, options)
end
end
private
def offensive?(table, options)
table_blacklisted?(table) && !nulls_allowed?(options)
end
def nulls_allowed?(options)
options.find { |opt| opt.key.value == :allow_null && opt.value.true_type? }
end
name = node.children[1]
def table_blacklisted?(symbol)
symbol && symbol.type == :sym &&
BLACKLISTED_TABLES.include?(symbol.children[0])
add_offense(node, location: :selector) if name == :add_column_with_default
end
end
end
......
......@@ -14,7 +14,6 @@ module RuboCop
BLACKLISTED_METHODS = %i[
add_column
add_column_with_default
add_reference
add_timestamps_with_timezone
].freeze
......
require_relative '../../migration_helpers'
module RuboCop
module Cop
module Migration
# Cop that checks if `add_column_with_default` is used with `up`/`down` methods
# and not `change`.
class ReversibleAddColumnWithDefault < RuboCop::Cop::Cop
include MigrationHelpers
def_node_matcher :add_column_with_default?, <<~PATTERN
(send nil? :add_column_with_default $...)
PATTERN
def_node_matcher :defines_change?, <<~PATTERN
(def :change ...)
PATTERN
MSG = '`add_column_with_default` is not reversible so you must manually define ' \
'the `up` and `down` methods in your migration class, using `remove_column` in `down`'.freeze
def on_send(node)
return unless in_migration?(node)
return unless add_column_with_default?(node)
node.each_ancestor(:def) do |def_node|
next unless defines_change?(def_node)
add_offense(def_node, location: :name)
end
end
end
end
end
end
......@@ -624,141 +624,13 @@ describe Gitlab::Database::MigrationHelpers do
describe '#add_column_with_default' do
let(:column) { Project.columns.find { |c| c.name == "id" } }
context 'outside of a transaction' do
context 'when a column limit is not set' do
before do
expect(model).to receive(:transaction_open?)
.and_return(false)
.at_least(:once)
expect(model).to receive(:transaction).and_yield
expect(model).to receive(:add_column)
.with(:projects, :foo, :integer, default: nil)
expect(model).to receive(:change_column_default)
.with(:projects, :foo, 10)
expect(model).to receive(:column_for)
.with(:projects, :foo).and_return(column)
end
it 'adds the column while allowing NULL values' do
expect(model).to receive(:update_column_in_batches)
.with(:projects, :foo, 10)
expect(model).not_to receive(:change_column_null)
it 'delegates to #add_column' do
expect(model).to receive(:add_column).with(:projects, :foo, :integer, default: 10, limit: nil, null: true)
model.add_column_with_default(:projects, :foo, :integer,
default: 10,
allow_null: true)
end
it 'adds the column while not allowing NULL values' do
expect(model).to receive(:update_column_in_batches)
.with(:projects, :foo, 10)
expect(model).to receive(:change_column_null)
.with(:projects, :foo, false)
model.add_column_with_default(:projects, :foo, :integer, default: 10)
end
it 'removes the added column whenever updating the rows fails' do
expect(model).to receive(:update_column_in_batches)
.with(:projects, :foo, 10)
.and_raise(RuntimeError)
expect(model).to receive(:remove_column)
.with(:projects, :foo)
expect do
model.add_column_with_default(:projects, :foo, :integer, default: 10)
end.to raise_error(RuntimeError)
end
it 'removes the added column whenever changing a column NULL constraint fails' do
expect(model).to receive(:change_column_null)
.with(:projects, :foo, false)
.and_raise(ActiveRecord::ActiveRecordError)
expect(model).to receive(:remove_column)
.with(:projects, :foo)
expect do
model.add_column_with_default(:projects, :foo, :integer, default: 10)
end.to raise_error(ActiveRecord::ActiveRecordError)
end
end
context 'when `update_column_in_batches_args` is given' do
let(:column) { UserDetail.columns.find { |c| c.name == "user_id" } }
it 'uses `user_id` for `update_column_in_batches`' do
allow(model).to receive(:transaction_open?).and_return(false)
allow(model).to receive(:transaction).and_yield
allow(model).to receive(:column_for).with(:user_details, :foo).and_return(column)
allow(model).to receive(:update_column_in_batches).with(:user_details, :foo, 10, batch_column_name: :user_id)
allow(model).to receive(:change_column_null).with(:user_details, :foo, false)
allow(model).to receive(:change_column_default).with(:user_details, :foo, 10)
expect(model).to receive(:add_column)
.with(:user_details, :foo, :integer, default: nil)
model.add_column_with_default(
:user_details,
:foo,
:integer,
default: 10,
update_column_in_batches_args: { batch_column_name: :user_id }
)
end
end
context 'when a column limit is set' do
it 'adds the column with a limit' do
allow(model).to receive(:transaction_open?).and_return(false)
allow(model).to receive(:transaction).and_yield
allow(model).to receive(:column_for).with(:projects, :foo).and_return(column)
allow(model).to receive(:update_column_in_batches).with(:projects, :foo, 10)
allow(model).to receive(:change_column_null).with(:projects, :foo, false)
allow(model).to receive(:change_column_default).with(:projects, :foo, 10)
expect(model).to receive(:add_column)
.with(:projects, :foo, :integer, default: nil, limit: 8)
model.add_column_with_default(:projects, :foo, :integer, default: 10, limit: 8)
end
end
it 'adds a column with an array default value for a jsonb type' do
create(:project)
allow(model).to receive(:transaction_open?).and_return(false)
allow(model).to receive(:transaction).and_yield
expect(model).to receive(:update_column_in_batches).with(:projects, :foo, '[{"foo":"json"}]').and_call_original
model.add_column_with_default(:projects, :foo, :jsonb, default: [{ foo: "json" }])
end
it 'adds a column with an object default value for a jsonb type' do
create(:project)
allow(model).to receive(:transaction_open?).and_return(false)
allow(model).to receive(:transaction).and_yield
expect(model).to receive(:update_column_in_batches).with(:projects, :foo, '{"foo":"json"}').and_call_original
model.add_column_with_default(:projects, :foo, :jsonb, default: { foo: "json" })
end
end
context 'inside a transaction' do
it 'raises RuntimeError' do
expect(model).to receive(:transaction_open?).and_return(true)
expect do
model.add_column_with_default(:projects, :foo, :integer, default: 10)
end.to raise_error(RuntimeError)
end
end
end
describe '#rename_column_concurrently' do
......
......@@ -27,10 +27,9 @@ describe RuboCop::Cop::Migration::AddColumnWithDefault do
allow(cop).to receive(:in_migration?).and_return(true)
end
let(:offense) { '`add_column_with_default` without `allow_null: true` may cause prolonged lock situations and downtime, see https://gitlab.com/gitlab-org/gitlab/issues/38060' }
let(:offense) { '`add_column_with_default` is deprecated, use `add_column` instead' }
context 'for blacklisted table' do
it 'registers an offense when specifying allow_null: false' do
it 'registers an offense ' do
expect_offense(<<~RUBY)
def up
add_column_with_default(:merge_request_diff_files, :artifacts, :boolean, default: true, allow_null: false)
......@@ -38,33 +37,5 @@ describe RuboCop::Cop::Migration::AddColumnWithDefault do
end
RUBY
end
it 'registers no offense when specifying allow_null: true' do
expect_no_offenses(<<~RUBY)
def up
add_column_with_default(:merge_request_diff_files, :artifacts, :boolean, default: true, allow_null: true)
end
RUBY
end
it 'registers an offense when allow_null is not specified' do
expect_offense(<<~RUBY)
def up
add_column_with_default(:merge_request_diff_files, :artifacts, :boolean, default: true)
^^^^^^^^^^^^^^^^^^^^^^^ #{offense}
end
RUBY
end
end
context 'for tables not on the blacklist' do
it 'registers no offense for application_settings (not on blacklist)' do
expect_no_offenses(<<~RUBY)
def up
add_column_with_default(:application_settings, :another_column, :boolean, default: true, allow_null: false)
end
RUBY
end
end
end
end
......@@ -42,8 +42,8 @@ describe RuboCop::Cop::Migration::AddColumnsToWideTables do
expect_offense(<<~RUBY)
def up
add_column_with_default(:users, :another_column, :boolean, default: false)
^^^^^^^^^^^^^^^^^^^^^^^ #{offense}
add_column(:users, :another_column, :boolean, default: false)
^^^^^^^^^^ #{offense}
end
RUBY
end
......
# frozen_string_literal: true
require 'spec_helper'
require 'rubocop'
require 'rubocop/rspec/support'
require_relative '../../../../rubocop/cop/migration/reversible_add_column_with_default'
describe RuboCop::Cop::Migration::ReversibleAddColumnWithDefault do
include CopHelper
subject(:cop) { described_class.new }
context 'in migration' do
before do
allow(cop).to receive(:in_migration?).and_return(true)
end
it 'registers an offense when add_column_with_default is used inside a change method' do
inspect_source('def change; add_column_with_default :table, :column, default: false; end')
aggregate_failures do
expect(cop.offenses.size).to eq(1)
expect(cop.offenses.map(&:line)).to eq([1])
end
end
it 'registers no offense when add_column_with_default is used inside an up method' do
inspect_source('def up; add_column_with_default :table, :column, default: false; end')
expect(cop.offenses.size).to eq(0)
end
end
context 'outside of migration' do
it 'registers no offense' do
inspect_source('def change; add_column_with_default :table, :column, default: false; end')
expect(cop.offenses.size).to eq(0)
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment