Database RuboCop docs
Database/AvoidInheritanceColumn
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
|---|---|---|---|---|
| Enabled | Yes | No | - | - |
Checks for self.inheritance_column usage, which is discouraged https://docs.gitlab.com/ee/development/database/single_table_inheritance.html
Database/AvoidIntRangePartitioning
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
|---|---|---|---|---|
| Enabled | Yes | No | - | - |
Prevents new usages of the :int_range partitioning strategy.
int_range partition boundaries are derived from the ID sequence of the
partitioning key, and sequence ranges are allocated per cell. A destination
cell therefore cannot reproduce the partition topology of the source cell,
which blocks moving an organization between cells.
Use a date-range strategy (:daily, :weekly, :monthly) instead, or reach
out to @gitlab-org/database-team/triage if that does not fit the access
pattern.
Examples
# bad
partitioned_by :project_id, strategy: :int_range, partition_size: 2_000_000
# bad
partition_table_by_int_range(
'merge_request_diff_commits',
'merge_request_diff_id',
partition_size: 10_000_000,
primary_key: %w[merge_request_diff_id relative_order]
)
# good
partitioned_by :created_at, strategy: :monthly, retain_for: 3.months
Database/AvoidScopeTo
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
|---|---|---|---|---|
| Enabled | Yes | No | - | - |
Disallows the use of scope_to to avoid problematic batched background migration queries.
Examples
# bad
class CustomBatchedMigrationClass < BatchedMigrationJob
scope_to ->(relation) { relation.where( user_type: "ADMIN") }
end
# good
class CustomBatchedMigrationClass < BatchedMigrationJob
def perform
each_sub_batch do |relation|
relation.where( user_type: "ADMIN").update_all("column = 'foo'")
end
end
end
Database/AvoidUnpartitionedCiRelations
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
|---|---|---|---|---|
| Enabled | Yes | No | - | - |
Prevents calling partitioned CI relation methods on Project without partition scoping.
Partitioned CI tables require .in_partition(partition_id) to avoid expensive
cross-partition scans that can cause database lock contention.
Examples
# bad
project.all_pipelines
project.builds.where(status: :failed)
@project.job_artifacts.recent
# good
project.all_pipelines.in_partition(106)
project.builds.in_partition(106).where(status: :failed)
@project.job_artifacts.in_partition(106).recent
Database/AvoidUsingConnectionExecute
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
|---|---|---|---|---|
| Enabled | Yes | No | - | - |
Avoid using connection.execute for read-only queries.
Examples
# bad
class MyClass < ApplicationRecord
def all
connection.execute('SELECT * FROM my_table') # This goes to the primary db node
end
end
# good
class MyClass < ApplicationRecord
def all
connection.select_all('SELECT * FROM my_table') # This goes to a read replica
end
end
Database/AvoidUsingPluckWithoutLimit
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
|---|---|---|---|---|
| Enabled | Yes | No | - | - |
Checks the use of .pluck(:attribute) without setting a limit.
Examples
# bad
def all
Project.where(user_id: User.pluck(:id))
end
# good
def all(limit)
Project.where(user_id: User.limit(limit).pluck(:id))
end
Database/DisableReferentialIntegrity
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
|---|---|---|---|---|
| Enabled | Yes | No | - | - |
Cop that checks if ‘disable_referential_integrity’ method is called.
Database/EstablishConnection
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
|---|---|---|---|---|
| Enabled | Yes | No | - | - |
No documentation
Database/JsonbSizeLimit
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
|---|---|---|---|---|
| Enabled | Yes | No | - | - |
Enforces size limits on new JSONB column validations
This cop ensures that new json_schema validations include explicit size limits to prevent unbounded JSONB growth that can impact database performance at scale.
Examples
# bad - no size limit specified
validates :metadata, json_schema: { filename: "project_metadata" }
# good - explicit size limit
validates :metadata, json_schema: { filename: "project_metadata", size_limit: 64.kilobytes }
Database/MultipleDatabases
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
|---|---|---|---|---|
| Enabled | Yes | No | - | - |
Examples
# bad
ActiveRecord::Base.connection
# good
ApplicationRecord.connection
Database/NoOnDemandCellLocalBackgroundOperation
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
|---|---|---|---|---|
| Enabled | Yes | No | - | - |
Prevents on-demand enqueuing of
Gitlab::Database::BackgroundOperation::WorkerCellLocal.
Cell-local background operations are stored under the
gitlab_shared_cell_local schema and are not migrated when an
organization moves to a new cell. On-demand enqueues would therefore
be silently lost. Only recurring cron jobs may enqueue cell-local
workers, via Database::BackgroundOperation::CronEnqueueWorker.
See doc/development/database/background_operations.md for the full rationale.
Examples
# bad
Gitlab::Database::BackgroundOperation::WorkerCellLocal.enqueue(
'MyOperationClass', 'target_table', 'id'
)
# good (recurring cron)
# Register the operation in config/schedule.yml under
# Database::BackgroundOperation::CronEnqueueWorker.
Database/PreventWildcardInjection
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
|---|---|---|---|---|
| Enabled | Yes | No | - | - |
Checks for potential wildcard injection vulnerabilities in LIKE queries
This cop detects dangerous patterns where user input could be used directly in LIKE queries without proper sanitization, potentially leading to wildcard injection attacks.
Examples
# bad
where("name LIKE '%#{term}%'")
where("title LIKE ?", "#{pattern}%")
# good
where("name LIKE ?", "%#{sanitize_sql_like(term)}%")
where("title LIKE ?", sanitize_sql_like(pattern))
Database/RescueQueryCanceled
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
|---|---|---|---|---|
| Enabled | Yes | No | - | - |
Checks for rescue blocks targeting the ActiveRecord::QueryCanceled class.
Examples
# bad
begin
run_an_expensive_long_query
rescue ActiveRecord::QueryCanceled
try_something_else
end
# good
run_cheap_queries_with_each_batch
Database/RescueStatementTimeout
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
|---|---|---|---|---|
| Enabled | Yes | No | - | - |
Checks for rescue blocks targeting the ActiveRecord::StatementTimeout class.
Examples
# bad
begin
run_an_expensive_long_query
rescue ActiveRecord::StatementTimeout
try_something_else
end
# good
run_cheap_queries_with_each_batch