summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/javascripts/notes/components/discussion_filter.vue2
-rw-r--r--app/controllers/concerns/issuable_collections.rb4
-rw-r--r--app/finders/issuable_finder.rb8
-rw-r--r--app/graphql/resolvers/work_item_resolver.rb2
-rw-r--r--app/graphql/types/work_item_type.rb2
-rw-r--r--app/models/concerns/pg_full_text_searchable.rb111
-rw-r--r--app/models/issue.rb14
-rw-r--r--app/models/issues/search_data.rb11
-rw-r--r--app/models/note.rb1
-rw-r--r--app/policies/project_policy.rb2
-rw-r--r--app/policies/work_item_policy.rb11
-rw-r--r--config/feature_flags/development/display_outdated_line_diff.yml8
-rw-r--r--config/feature_flags/development/issues_full_text_search.yml8
-rw-r--r--db/migrate/20211007090229_create_issue_search_table.rb29
-rw-r--r--db/post_migrate/20211026070408_backfill_issue_search_data.rb22
-rw-r--r--db/schema_migrations/202110070902291
-rw-r--r--db/schema_migrations/202110260704081
-rw-r--r--db/structure.sql1430
-rw-r--r--lib/gitlab/background_migration/backfill_issue_search_data.rb63
-rw-r--r--lib/gitlab/database/gitlab_schemas.yml1
-rw-r--r--lib/gitlab/issuables_count_for_state.rb2
-rw-r--r--qa/qa/resource/protected_branch.rb10
-rw-r--r--spec/controllers/dashboard_controller_spec.rb17
-rw-r--r--spec/controllers/projects/issues_controller_spec.rb16
-rw-r--r--spec/features/issues/filtered_search/filter_issues_spec.rb2
-rw-r--r--spec/finders/issues_finder_spec.rb23
-rw-r--r--spec/graphql/types/work_item_type_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/backfill_issue_search_data_spec.rb57
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml3
-rw-r--r--spec/models/concerns/pg_full_text_searchable_spec.rb162
-rw-r--r--spec/policies/work_item_policy_spec.rb94
31 files changed, 2094 insertions, 25 deletions
diff --git a/app/assets/javascripts/notes/components/discussion_filter.vue b/app/assets/javascripts/notes/components/discussion_filter.vue
index 102afaf308f..d5a7fc36ace 100644
--- a/app/assets/javascripts/notes/components/discussion_filter.vue
+++ b/app/assets/javascripts/notes/components/discussion_filter.vue
@@ -116,7 +116,7 @@ export default {
<gl-dropdown
v-if="displayFilters"
id="discussion-filter-dropdown"
- class="gl-mr-3 full-width-mobile discussion-filter-container js-discussion-filter-container"
+ class="full-width-mobile discussion-filter-container js-discussion-filter-container"
data-qa-selector="discussion_filter_dropdown"
:text="currentFilter.title"
:disabled="isLoading"
diff --git a/app/controllers/concerns/issuable_collections.rb b/app/controllers/concerns/issuable_collections.rb
index 4841225de08..63ff1390d92 100644
--- a/app/controllers/concerns/issuable_collections.rb
+++ b/app/controllers/concerns/issuable_collections.rb
@@ -117,6 +117,10 @@ module IssuableCollections
options[:attempt_group_search_optimizations] = true
end
+ if collection_type == 'Issue' && Feature.enabled?(:issues_full_text_search, @project || @group, default_enabled: :yaml)
+ options[:attempt_full_text_search] = true
+ end
+
params.permit(finder_type.valid_params).merge(options)
end
end
diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb
index 3e436f30971..416db1c9c7d 100644
--- a/app/finders/issuable_finder.rb
+++ b/app/finders/issuable_finder.rb
@@ -37,6 +37,7 @@
# attempt_project_search_optimizations: boolean
# crm_contact_id: integer
# crm_organization_id: integer
+# attempt_full_text_search: boolean
#
class IssuableFinder
prepend FinderWithCrossProjectAccess
@@ -46,6 +47,7 @@ class IssuableFinder
requires_cross_project_access unless: -> { params.project? }
+ FULL_TEXT_SEARCH_TERM_REGEX = /\A[\p{ASCII}|\p{Latin}]+\z/.freeze
NEGATABLE_PARAMS_HELPER_KEYS = %i[project_id scope status include_subgroups].freeze
attr_accessor :current_user, :params
@@ -331,6 +333,8 @@ class IssuableFinder
return items if items.is_a?(ActiveRecord::NullRelation)
return items if Feature.enabled?(:disable_anonymous_search, type: :ops) && current_user.nil?
+ return items.pg_full_text_search(search) if use_full_text_search?
+
if use_cte_for_search?
cte = Gitlab::SQL::CTE.new(klass.table_name, items)
@@ -341,6 +345,10 @@ class IssuableFinder
end
# rubocop: enable CodeReuse/ActiveRecord
+ def use_full_text_search?
+ params[:attempt_full_text_search] && params[:search] =~ FULL_TEXT_SEARCH_TERM_REGEX
+ end
+
# rubocop: disable CodeReuse/ActiveRecord
def by_iids(items)
params[:iids].present? ? items.where(iid: params[:iids]) : items
diff --git a/app/graphql/resolvers/work_item_resolver.rb b/app/graphql/resolvers/work_item_resolver.rb
index b1733d657e4..6eb23916d83 100644
--- a/app/graphql/resolvers/work_item_resolver.rb
+++ b/app/graphql/resolvers/work_item_resolver.rb
@@ -4,7 +4,7 @@ module Resolvers
class WorkItemResolver < BaseResolver
include Gitlab::Graphql::Authorize::AuthorizeResource
- authorize :read_issue
+ authorize :read_work_item
type Types::WorkItemType, null: true
diff --git a/app/graphql/types/work_item_type.rb b/app/graphql/types/work_item_type.rb
index 78cef150b11..512b9ef64d2 100644
--- a/app/graphql/types/work_item_type.rb
+++ b/app/graphql/types/work_item_type.rb
@@ -4,7 +4,7 @@ module Types
class WorkItemType < BaseObject
graphql_name 'WorkItem'
- authorize :read_issue
+ authorize :read_work_item
field :description, GraphQL::Types::String, null: true,
description: 'Description of the work item.'
diff --git a/app/models/concerns/pg_full_text_searchable.rb b/app/models/concerns/pg_full_text_searchable.rb
new file mode 100644
index 00000000000..612a9c5908b
--- /dev/null
+++ b/app/models/concerns/pg_full_text_searchable.rb
@@ -0,0 +1,111 @@
+# frozen_string_literal: true
+
+# This module adds PG full-text search capabilities to a model.
+# A `search_data` association with a `search_vector` column is required.
+#
+# Declare the fields that will be part of the search vector with their
+# corresponding weights. Possible values for weight are A, B, C, or D.
+# For example:
+#
+# include PgFullTextSearchable
+# pg_full_text_searchable columns: [{ name: 'title', weight: 'A' }, { name: 'description', weight: 'B' }]
+#
+# This module sets up an after_commit hook that updates the search data
+# when the searchable columns are changed. You will need to implement the
+# `#persist_pg_full_text_search_vector` method that does the actual insert or update.
+#
+# This also adds a `pg_full_text_search` scope so you can do:
+#
+# Model.pg_full_text_search("some search term")
+
+module PgFullTextSearchable
+ extend ActiveSupport::Concern
+
+ LONG_WORDS_REGEX = %r([A-Za-z0-9+/]{50,}).freeze
+ TSVECTOR_MAX_LENGTH = 1.megabyte.freeze
+ TEXT_SEARCH_DICTIONARY = 'english'
+
+ def update_search_data!
+ tsvector_sql_nodes = self.class.pg_full_text_searchable_columns.map do |column, weight|
+ tsvector_arel_node(column, weight)&.to_sql
+ end
+
+ persist_pg_full_text_search_vector(Arel.sql(tsvector_sql_nodes.compact.join(' || ')))
+ rescue ActiveRecord::StatementInvalid => e
+ raise unless e.cause.is_a?(PG::ProgramLimitExceeded) && e.message.include?('string is too long for tsvector')
+
+ Gitlab::AppJsonLogger.error(
+ message: 'Error updating search data: string is too long for tsvector',
+ class: self.class.name,
+ model_id: self.id
+ )
+ end
+
+ private
+
+ def persist_pg_full_text_search_vector(search_vector)
+ raise NotImplementedError
+ end
+
+ def tsvector_arel_node(column, weight)
+ return if self[column].blank?
+
+ column_text = self[column].gsub(LONG_WORDS_REGEX, ' ')
+ column_text = column_text[0..(TSVECTOR_MAX_LENGTH - 1)]
+ column_text = ActiveSupport::Inflector.transliterate(column_text)
+
+ Arel::Nodes::NamedFunction.new(
+ 'setweight',
+ [
+ Arel::Nodes::NamedFunction.new(
+ 'to_tsvector',
+ [Arel::Nodes.build_quoted(TEXT_SEARCH_DICTIONARY), Arel::Nodes.build_quoted(column_text)]
+ ),
+ Arel::Nodes.build_quoted(weight)
+ ]
+ )
+ end
+
+ included do
+ cattr_reader :pg_full_text_searchable_columns do
+ {}
+ end
+ end
+
+ class_methods do
+ def pg_full_text_searchable(columns:)
+ raise 'Full text search columns already defined!' if pg_full_text_searchable_columns.present?
+
+ columns.each do |column|
+ pg_full_text_searchable_columns[column[:name]] = column[:weight]
+ end
+
+ # We update this outside the transaction because this could raise an error if the resulting tsvector
+ # is too long. When that happens, we still persist the create / update but the model will not have a
+ # search data record. This is fine in most cases because this is a very rare occurrence and only happens
+ # with strings that are most likely unsearchable anyway.
+ #
+ # We also do not want to use a subtransaction here due to: https://gitlab.com/groups/gitlab-org/-/epics/6540
+ after_save_commit do
+ next unless pg_full_text_searchable_columns.keys.any? { |f| saved_changes.has_key?(f) }
+
+ update_search_data!
+ end
+ end
+
+ def pg_full_text_search(search_term)
+ search_data_table = reflect_on_association(:search_data).klass.arel_table
+
+ joins(:search_data).where(
+ Arel::Nodes::InfixOperation.new(
+ '@@',
+ search_data_table[:search_vector],
+ Arel::Nodes::NamedFunction.new(
+ 'websearch_to_tsquery',
+ [Arel::Nodes.build_quoted(TEXT_SEARCH_DICTIONARY), Arel::Nodes.build_quoted(search_term)]
+ )
+ )
+ )
+ end
+ end
+end
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 68ea6cb3abc..75727fff2cd 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -24,6 +24,7 @@ class Issue < ApplicationRecord
include Todoable
include FromUnion
include EachBatch
+ include PgFullTextSearchable
extend ::Gitlab::Utils::Override
@@ -77,6 +78,7 @@ class Issue < ApplicationRecord
end
end
+ has_one :search_data, class_name: 'Issues::SearchData'
has_one :issuable_severity
has_one :sentry_issue
has_one :alert_management_alert, class_name: 'AlertManagement::Alert'
@@ -102,6 +104,8 @@ class Issue < ApplicationRecord
alias_attribute :external_author, :service_desk_reply_to
+ pg_full_text_searchable columns: [{ name: 'title', weight: 'A' }, { name: 'description', weight: 'B' }]
+
scope :in_projects, ->(project_ids) { where(project_id: project_ids) }
scope :not_in_projects, ->(project_ids) { where.not(project_id: project_ids) }
@@ -233,6 +237,11 @@ class Issue < ApplicationRecord
def order_upvotes_asc
reorder(upvotes_count: :asc)
end
+
+ override :pg_full_text_search
+ def pg_full_text_search(search_term)
+ super.where('issue_search_data.project_id = issues.project_id')
+ end
end
def next_object_by_relative_position(ignoring: nil, order: :asc)
@@ -611,6 +620,11 @@ class Issue < ApplicationRecord
private
+ override :persist_pg_full_text_search_vector
+ def persist_pg_full_text_search_vector(search_vector)
+ Issues::SearchData.upsert({ project_id: project_id, issue_id: id, search_vector: search_vector }, unique_by: %i(project_id issue_id))
+ end
+
def spammable_attribute_changed?
title_changed? ||
description_changed? ||
diff --git a/app/models/issues/search_data.rb b/app/models/issues/search_data.rb
new file mode 100644
index 00000000000..0eda292796d
--- /dev/null
+++ b/app/models/issues/search_data.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module Issues
+ class SearchData < ApplicationRecord
+ extend SuppressCompositePrimaryKeyWarning
+
+ self.table_name = 'issue_search_data'
+
+ belongs_to :issue
+ end
+end
diff --git a/app/models/note.rb b/app/models/note.rb
index 3f3fa968393..1d661367599 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -609,7 +609,6 @@ class Note < ApplicationRecord
def show_outdated_changes?
return false unless for_merge_request?
- return false unless Feature.enabled?(:display_outdated_line_diff, noteable.source_project, default_enabled: :yaml)
return false unless system?
return false unless change_position&.line_range
diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb
index 4cc5ed06d61..147ca9c9881 100644
--- a/app/policies/project_policy.rb
+++ b/app/policies/project_policy.rb
@@ -264,8 +264,6 @@ class ProjectPolicy < BasePolicy
enable :create_work_item
end
- rule { can?(:update_issue) }.enable :update_work_item
-
# These abilities are not allowed to admins that are not members of the project,
# that's why they are defined separately.
rule { guest & can?(:download_code) }.enable :build_download_code
diff --git a/app/policies/work_item_policy.rb b/app/policies/work_item_policy.rb
index 7ba5102a406..b4723bc7ed8 100644
--- a/app/policies/work_item_policy.rb
+++ b/app/policies/work_item_policy.rb
@@ -1,12 +1,9 @@
# frozen_string_literal: true
-class WorkItemPolicy < BasePolicy
- delegate { @subject.project }
+class WorkItemPolicy < IssuePolicy
+ rule { can?(:owner_access) | is_author }.enable :delete_work_item
- desc 'User is author of the work item'
- condition(:author) do
- @user && @user == @subject.author
- end
+ rule { can?(:update_issue) }.enable :update_work_item
- rule { can?(:owner_access) | author }.enable :delete_work_item
+ rule { can?(:read_issue) }.enable :read_work_item
end
diff --git a/config/feature_flags/development/display_outdated_line_diff.yml b/config/feature_flags/development/display_outdated_line_diff.yml
deleted file mode 100644
index 979575da381..00000000000
--- a/config/feature_flags/development/display_outdated_line_diff.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: display_outdated_line_diff
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72597
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/345491
-milestone: '14.5'
-type: development
-group: group::code review
-default_enabled: true
diff --git a/config/feature_flags/development/issues_full_text_search.yml b/config/feature_flags/development/issues_full_text_search.yml
new file mode 100644
index 00000000000..35af801e3ab
--- /dev/null
+++ b/config/feature_flags/development/issues_full_text_search.yml
@@ -0,0 +1,8 @@
+---
+name: issues_full_text_search
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/71913
+rollout_issue_url:
+milestone: '14.5'
+type: development
+group: group::project management
+default_enabled: false
diff --git a/db/migrate/20211007090229_create_issue_search_table.rb b/db/migrate/20211007090229_create_issue_search_table.rb
new file mode 100644
index 00000000000..1fc15d20bd0
--- /dev/null
+++ b/db/migrate/20211007090229_create_issue_search_table.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+class CreateIssueSearchTable < Gitlab::Database::Migration[1.0]
+ include Gitlab::Database::PartitioningMigrationHelpers::TableManagementHelpers
+
+ def up
+ execute <<~SQL
+ CREATE TABLE issue_search_data (
+ project_id bigint NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
+ issue_id bigint NOT NULL REFERENCES issues(id) ON DELETE CASCADE,
+ created_at timestamp with time zone DEFAULT NOW() NOT NULL,
+ updated_at timestamp with time zone DEFAULT NOW() NOT NULL,
+ search_vector tsvector,
+ PRIMARY KEY (project_id, issue_id)
+ ) PARTITION BY HASH (project_id)
+ SQL
+
+ # rubocop: disable Migration/AddIndex
+ add_index :issue_search_data, :issue_id
+ add_index :issue_search_data, :search_vector, using: :gin, name: 'index_issue_search_data_on_search_vector'
+ # rubocop: enable Migration/AddIndex
+
+ create_hash_partitions :issue_search_data, 64
+ end
+
+ def down
+ drop_table :issue_search_data
+ end
+end
diff --git a/db/post_migrate/20211026070408_backfill_issue_search_data.rb b/db/post_migrate/20211026070408_backfill_issue_search_data.rb
new file mode 100644
index 00000000000..a840adcb991
--- /dev/null
+++ b/db/post_migrate/20211026070408_backfill_issue_search_data.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+class BackfillIssueSearchData < Gitlab::Database::Migration[1.0]
+ MIGRATION = 'BackfillIssueSearchData'
+
+ def up
+ queue_batched_background_migration(
+ MIGRATION,
+ :issues,
+ :id,
+ batch_size: 100_000,
+ sub_batch_size: 1_000,
+ job_interval: 5.minutes
+ )
+ end
+
+ def down
+ Gitlab::Database::BackgroundMigration::BatchedMigration
+ .for_configuration(MIGRATION, :issues, :id, [])
+ .delete_all
+ end
+end
diff --git a/db/schema_migrations/20211007090229 b/db/schema_migrations/20211007090229
new file mode 100644
index 00000000000..9302c958709
--- /dev/null
+++ b/db/schema_migrations/20211007090229
@@ -0,0 +1 @@
+9d87052305a552ce380e81a33c690496c44e332eb86869ea6882f5cd4856ab93 \ No newline at end of file
diff --git a/db/schema_migrations/20211026070408 b/db/schema_migrations/20211026070408
new file mode 100644
index 00000000000..e48db972388
--- /dev/null
+++ b/db/schema_migrations/20211026070408
@@ -0,0 +1 @@
+630899d5a7f833ce0533ae553de89e70bd03fad9b438fd367e3a568261b08b00 \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index cebe5aef9a5..111cb4ca521 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -1169,6 +1169,591 @@ CREATE TABLE gitlab_partitions_static.analytics_cycle_analytics_merge_request_st
);
ALTER TABLE ONLY analytics_cycle_analytics_merge_request_stage_events ATTACH PARTITION gitlab_partitions_static.analytics_cycle_analytics_merge_request_stage_events_31 FOR VALUES WITH (modulus 32, remainder 31);
+CREATE TABLE issue_search_data (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+)
+PARTITION BY HASH (project_id);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_00 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_00 FOR VALUES WITH (modulus 64, remainder 0);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_01 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_01 FOR VALUES WITH (modulus 64, remainder 1);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_02 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_02 FOR VALUES WITH (modulus 64, remainder 2);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_03 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_03 FOR VALUES WITH (modulus 64, remainder 3);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_04 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_04 FOR VALUES WITH (modulus 64, remainder 4);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_05 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_05 FOR VALUES WITH (modulus 64, remainder 5);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_06 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_06 FOR VALUES WITH (modulus 64, remainder 6);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_07 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_07 FOR VALUES WITH (modulus 64, remainder 7);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_08 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_08 FOR VALUES WITH (modulus 64, remainder 8);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_09 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_09 FOR VALUES WITH (modulus 64, remainder 9);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_10 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_10 FOR VALUES WITH (modulus 64, remainder 10);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_11 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_11 FOR VALUES WITH (modulus 64, remainder 11);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_12 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_12 FOR VALUES WITH (modulus 64, remainder 12);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_13 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_13 FOR VALUES WITH (modulus 64, remainder 13);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_14 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_14 FOR VALUES WITH (modulus 64, remainder 14);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_15 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_15 FOR VALUES WITH (modulus 64, remainder 15);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_16 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_16 FOR VALUES WITH (modulus 64, remainder 16);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_17 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_17 FOR VALUES WITH (modulus 64, remainder 17);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_18 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_18 FOR VALUES WITH (modulus 64, remainder 18);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_19 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_19 FOR VALUES WITH (modulus 64, remainder 19);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_20 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_20 FOR VALUES WITH (modulus 64, remainder 20);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_21 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_21 FOR VALUES WITH (modulus 64, remainder 21);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_22 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_22 FOR VALUES WITH (modulus 64, remainder 22);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_23 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_23 FOR VALUES WITH (modulus 64, remainder 23);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_24 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_24 FOR VALUES WITH (modulus 64, remainder 24);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_25 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_25 FOR VALUES WITH (modulus 64, remainder 25);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_26 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_26 FOR VALUES WITH (modulus 64, remainder 26);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_27 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_27 FOR VALUES WITH (modulus 64, remainder 27);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_28 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_28 FOR VALUES WITH (modulus 64, remainder 28);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_29 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_29 FOR VALUES WITH (modulus 64, remainder 29);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_30 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_30 FOR VALUES WITH (modulus 64, remainder 30);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_31 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_31 FOR VALUES WITH (modulus 64, remainder 31);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_32 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_32 FOR VALUES WITH (modulus 64, remainder 32);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_33 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_33 FOR VALUES WITH (modulus 64, remainder 33);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_34 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_34 FOR VALUES WITH (modulus 64, remainder 34);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_35 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_35 FOR VALUES WITH (modulus 64, remainder 35);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_36 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_36 FOR VALUES WITH (modulus 64, remainder 36);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_37 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_37 FOR VALUES WITH (modulus 64, remainder 37);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_38 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_38 FOR VALUES WITH (modulus 64, remainder 38);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_39 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_39 FOR VALUES WITH (modulus 64, remainder 39);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_40 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_40 FOR VALUES WITH (modulus 64, remainder 40);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_41 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_41 FOR VALUES WITH (modulus 64, remainder 41);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_42 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_42 FOR VALUES WITH (modulus 64, remainder 42);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_43 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_43 FOR VALUES WITH (modulus 64, remainder 43);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_44 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_44 FOR VALUES WITH (modulus 64, remainder 44);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_45 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_45 FOR VALUES WITH (modulus 64, remainder 45);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_46 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_46 FOR VALUES WITH (modulus 64, remainder 46);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_47 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_47 FOR VALUES WITH (modulus 64, remainder 47);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_48 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_48 FOR VALUES WITH (modulus 64, remainder 48);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_49 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_49 FOR VALUES WITH (modulus 64, remainder 49);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_50 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_50 FOR VALUES WITH (modulus 64, remainder 50);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_51 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_51 FOR VALUES WITH (modulus 64, remainder 51);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_52 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_52 FOR VALUES WITH (modulus 64, remainder 52);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_53 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_53 FOR VALUES WITH (modulus 64, remainder 53);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_54 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_54 FOR VALUES WITH (modulus 64, remainder 54);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_55 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_55 FOR VALUES WITH (modulus 64, remainder 55);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_56 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_56 FOR VALUES WITH (modulus 64, remainder 56);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_57 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_57 FOR VALUES WITH (modulus 64, remainder 57);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_58 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_58 FOR VALUES WITH (modulus 64, remainder 58);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_59 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_59 FOR VALUES WITH (modulus 64, remainder 59);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_60 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_60 FOR VALUES WITH (modulus 64, remainder 60);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_61 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_61 FOR VALUES WITH (modulus 64, remainder 61);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_62 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_62 FOR VALUES WITH (modulus 64, remainder 62);
+
+CREATE TABLE gitlab_partitions_static.issue_search_data_63 (
+ project_id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ search_vector tsvector
+);
+ALTER TABLE ONLY issue_search_data ATTACH PARTITION gitlab_partitions_static.issue_search_data_63 FOR VALUES WITH (modulus 64, remainder 63);
+
CREATE TABLE product_analytics_events_experimental (
id bigint NOT NULL,
project_id integer NOT NULL,
@@ -22749,6 +23334,201 @@ ALTER TABLE ONLY gitlab_partitions_static.analytics_cycle_analytics_merge_reques
ALTER TABLE ONLY gitlab_partitions_static.analytics_cycle_analytics_merge_request_stage_events_31
ADD CONSTRAINT analytics_cycle_analytics_merge_request_stage_events_31_pkey PRIMARY KEY (stage_event_hash_id, merge_request_id);
+ALTER TABLE ONLY issue_search_data
+ ADD CONSTRAINT issue_search_data_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_00
+ ADD CONSTRAINT issue_search_data_00_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_01
+ ADD CONSTRAINT issue_search_data_01_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_02
+ ADD CONSTRAINT issue_search_data_02_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_03
+ ADD CONSTRAINT issue_search_data_03_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_04
+ ADD CONSTRAINT issue_search_data_04_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_05
+ ADD CONSTRAINT issue_search_data_05_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_06
+ ADD CONSTRAINT issue_search_data_06_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_07
+ ADD CONSTRAINT issue_search_data_07_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_08
+ ADD CONSTRAINT issue_search_data_08_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_09
+ ADD CONSTRAINT issue_search_data_09_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_10
+ ADD CONSTRAINT issue_search_data_10_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_11
+ ADD CONSTRAINT issue_search_data_11_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_12
+ ADD CONSTRAINT issue_search_data_12_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_13
+ ADD CONSTRAINT issue_search_data_13_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_14
+ ADD CONSTRAINT issue_search_data_14_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_15
+ ADD CONSTRAINT issue_search_data_15_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_16
+ ADD CONSTRAINT issue_search_data_16_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_17
+ ADD CONSTRAINT issue_search_data_17_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_18
+ ADD CONSTRAINT issue_search_data_18_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_19
+ ADD CONSTRAINT issue_search_data_19_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_20
+ ADD CONSTRAINT issue_search_data_20_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_21
+ ADD CONSTRAINT issue_search_data_21_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_22
+ ADD CONSTRAINT issue_search_data_22_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_23
+ ADD CONSTRAINT issue_search_data_23_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_24
+ ADD CONSTRAINT issue_search_data_24_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_25
+ ADD CONSTRAINT issue_search_data_25_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_26
+ ADD CONSTRAINT issue_search_data_26_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_27
+ ADD CONSTRAINT issue_search_data_27_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_28
+ ADD CONSTRAINT issue_search_data_28_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_29
+ ADD CONSTRAINT issue_search_data_29_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_30
+ ADD CONSTRAINT issue_search_data_30_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_31
+ ADD CONSTRAINT issue_search_data_31_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_32
+ ADD CONSTRAINT issue_search_data_32_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_33
+ ADD CONSTRAINT issue_search_data_33_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_34
+ ADD CONSTRAINT issue_search_data_34_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_35
+ ADD CONSTRAINT issue_search_data_35_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_36
+ ADD CONSTRAINT issue_search_data_36_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_37
+ ADD CONSTRAINT issue_search_data_37_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_38
+ ADD CONSTRAINT issue_search_data_38_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_39
+ ADD CONSTRAINT issue_search_data_39_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_40
+ ADD CONSTRAINT issue_search_data_40_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_41
+ ADD CONSTRAINT issue_search_data_41_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_42
+ ADD CONSTRAINT issue_search_data_42_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_43
+ ADD CONSTRAINT issue_search_data_43_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_44
+ ADD CONSTRAINT issue_search_data_44_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_45
+ ADD CONSTRAINT issue_search_data_45_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_46
+ ADD CONSTRAINT issue_search_data_46_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_47
+ ADD CONSTRAINT issue_search_data_47_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_48
+ ADD CONSTRAINT issue_search_data_48_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_49
+ ADD CONSTRAINT issue_search_data_49_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_50
+ ADD CONSTRAINT issue_search_data_50_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_51
+ ADD CONSTRAINT issue_search_data_51_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_52
+ ADD CONSTRAINT issue_search_data_52_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_53
+ ADD CONSTRAINT issue_search_data_53_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_54
+ ADD CONSTRAINT issue_search_data_54_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_55
+ ADD CONSTRAINT issue_search_data_55_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_56
+ ADD CONSTRAINT issue_search_data_56_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_57
+ ADD CONSTRAINT issue_search_data_57_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_58
+ ADD CONSTRAINT issue_search_data_58_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_59
+ ADD CONSTRAINT issue_search_data_59_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_60
+ ADD CONSTRAINT issue_search_data_60_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_61
+ ADD CONSTRAINT issue_search_data_61_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_62
+ ADD CONSTRAINT issue_search_data_62_pkey PRIMARY KEY (project_id, issue_id);
+
+ALTER TABLE ONLY gitlab_partitions_static.issue_search_data_63
+ ADD CONSTRAINT issue_search_data_63_pkey PRIMARY KEY (project_id, issue_id);
+
ALTER TABLE ONLY product_analytics_events_experimental
ADD CONSTRAINT product_analytics_events_experimental_pkey PRIMARY KEY (id, project_id);
@@ -25149,6 +25929,266 @@ CREATE INDEX index_ff39be5400 ON gitlab_partitions_static.analytics_cycle_analyt
CREATE INDEX index_ff8741d8d7 ON gitlab_partitions_static.analytics_cycle_analytics_issue_stage_events_28 USING btree (stage_event_hash_id, group_id, start_event_timestamp, issue_id) WHERE ((end_event_timestamp IS NULL) AND (state_id = 1));
+CREATE INDEX index_issue_search_data_on_issue_id ON ONLY issue_search_data USING btree (issue_id);
+
+CREATE INDEX issue_search_data_00_issue_id_idx ON gitlab_partitions_static.issue_search_data_00 USING btree (issue_id);
+
+CREATE INDEX index_issue_search_data_on_search_vector ON ONLY issue_search_data USING gin (search_vector);
+
+CREATE INDEX issue_search_data_00_search_vector_idx ON gitlab_partitions_static.issue_search_data_00 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_01_issue_id_idx ON gitlab_partitions_static.issue_search_data_01 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_01_search_vector_idx ON gitlab_partitions_static.issue_search_data_01 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_02_issue_id_idx ON gitlab_partitions_static.issue_search_data_02 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_02_search_vector_idx ON gitlab_partitions_static.issue_search_data_02 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_03_issue_id_idx ON gitlab_partitions_static.issue_search_data_03 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_03_search_vector_idx ON gitlab_partitions_static.issue_search_data_03 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_04_issue_id_idx ON gitlab_partitions_static.issue_search_data_04 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_04_search_vector_idx ON gitlab_partitions_static.issue_search_data_04 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_05_issue_id_idx ON gitlab_partitions_static.issue_search_data_05 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_05_search_vector_idx ON gitlab_partitions_static.issue_search_data_05 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_06_issue_id_idx ON gitlab_partitions_static.issue_search_data_06 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_06_search_vector_idx ON gitlab_partitions_static.issue_search_data_06 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_07_issue_id_idx ON gitlab_partitions_static.issue_search_data_07 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_07_search_vector_idx ON gitlab_partitions_static.issue_search_data_07 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_08_issue_id_idx ON gitlab_partitions_static.issue_search_data_08 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_08_search_vector_idx ON gitlab_partitions_static.issue_search_data_08 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_09_issue_id_idx ON gitlab_partitions_static.issue_search_data_09 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_09_search_vector_idx ON gitlab_partitions_static.issue_search_data_09 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_10_issue_id_idx ON gitlab_partitions_static.issue_search_data_10 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_10_search_vector_idx ON gitlab_partitions_static.issue_search_data_10 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_11_issue_id_idx ON gitlab_partitions_static.issue_search_data_11 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_11_search_vector_idx ON gitlab_partitions_static.issue_search_data_11 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_12_issue_id_idx ON gitlab_partitions_static.issue_search_data_12 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_12_search_vector_idx ON gitlab_partitions_static.issue_search_data_12 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_13_issue_id_idx ON gitlab_partitions_static.issue_search_data_13 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_13_search_vector_idx ON gitlab_partitions_static.issue_search_data_13 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_14_issue_id_idx ON gitlab_partitions_static.issue_search_data_14 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_14_search_vector_idx ON gitlab_partitions_static.issue_search_data_14 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_15_issue_id_idx ON gitlab_partitions_static.issue_search_data_15 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_15_search_vector_idx ON gitlab_partitions_static.issue_search_data_15 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_16_issue_id_idx ON gitlab_partitions_static.issue_search_data_16 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_16_search_vector_idx ON gitlab_partitions_static.issue_search_data_16 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_17_issue_id_idx ON gitlab_partitions_static.issue_search_data_17 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_17_search_vector_idx ON gitlab_partitions_static.issue_search_data_17 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_18_issue_id_idx ON gitlab_partitions_static.issue_search_data_18 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_18_search_vector_idx ON gitlab_partitions_static.issue_search_data_18 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_19_issue_id_idx ON gitlab_partitions_static.issue_search_data_19 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_19_search_vector_idx ON gitlab_partitions_static.issue_search_data_19 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_20_issue_id_idx ON gitlab_partitions_static.issue_search_data_20 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_20_search_vector_idx ON gitlab_partitions_static.issue_search_data_20 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_21_issue_id_idx ON gitlab_partitions_static.issue_search_data_21 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_21_search_vector_idx ON gitlab_partitions_static.issue_search_data_21 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_22_issue_id_idx ON gitlab_partitions_static.issue_search_data_22 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_22_search_vector_idx ON gitlab_partitions_static.issue_search_data_22 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_23_issue_id_idx ON gitlab_partitions_static.issue_search_data_23 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_23_search_vector_idx ON gitlab_partitions_static.issue_search_data_23 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_24_issue_id_idx ON gitlab_partitions_static.issue_search_data_24 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_24_search_vector_idx ON gitlab_partitions_static.issue_search_data_24 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_25_issue_id_idx ON gitlab_partitions_static.issue_search_data_25 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_25_search_vector_idx ON gitlab_partitions_static.issue_search_data_25 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_26_issue_id_idx ON gitlab_partitions_static.issue_search_data_26 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_26_search_vector_idx ON gitlab_partitions_static.issue_search_data_26 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_27_issue_id_idx ON gitlab_partitions_static.issue_search_data_27 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_27_search_vector_idx ON gitlab_partitions_static.issue_search_data_27 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_28_issue_id_idx ON gitlab_partitions_static.issue_search_data_28 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_28_search_vector_idx ON gitlab_partitions_static.issue_search_data_28 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_29_issue_id_idx ON gitlab_partitions_static.issue_search_data_29 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_29_search_vector_idx ON gitlab_partitions_static.issue_search_data_29 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_30_issue_id_idx ON gitlab_partitions_static.issue_search_data_30 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_30_search_vector_idx ON gitlab_partitions_static.issue_search_data_30 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_31_issue_id_idx ON gitlab_partitions_static.issue_search_data_31 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_31_search_vector_idx ON gitlab_partitions_static.issue_search_data_31 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_32_issue_id_idx ON gitlab_partitions_static.issue_search_data_32 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_32_search_vector_idx ON gitlab_partitions_static.issue_search_data_32 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_33_issue_id_idx ON gitlab_partitions_static.issue_search_data_33 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_33_search_vector_idx ON gitlab_partitions_static.issue_search_data_33 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_34_issue_id_idx ON gitlab_partitions_static.issue_search_data_34 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_34_search_vector_idx ON gitlab_partitions_static.issue_search_data_34 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_35_issue_id_idx ON gitlab_partitions_static.issue_search_data_35 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_35_search_vector_idx ON gitlab_partitions_static.issue_search_data_35 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_36_issue_id_idx ON gitlab_partitions_static.issue_search_data_36 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_36_search_vector_idx ON gitlab_partitions_static.issue_search_data_36 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_37_issue_id_idx ON gitlab_partitions_static.issue_search_data_37 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_37_search_vector_idx ON gitlab_partitions_static.issue_search_data_37 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_38_issue_id_idx ON gitlab_partitions_static.issue_search_data_38 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_38_search_vector_idx ON gitlab_partitions_static.issue_search_data_38 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_39_issue_id_idx ON gitlab_partitions_static.issue_search_data_39 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_39_search_vector_idx ON gitlab_partitions_static.issue_search_data_39 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_40_issue_id_idx ON gitlab_partitions_static.issue_search_data_40 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_40_search_vector_idx ON gitlab_partitions_static.issue_search_data_40 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_41_issue_id_idx ON gitlab_partitions_static.issue_search_data_41 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_41_search_vector_idx ON gitlab_partitions_static.issue_search_data_41 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_42_issue_id_idx ON gitlab_partitions_static.issue_search_data_42 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_42_search_vector_idx ON gitlab_partitions_static.issue_search_data_42 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_43_issue_id_idx ON gitlab_partitions_static.issue_search_data_43 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_43_search_vector_idx ON gitlab_partitions_static.issue_search_data_43 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_44_issue_id_idx ON gitlab_partitions_static.issue_search_data_44 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_44_search_vector_idx ON gitlab_partitions_static.issue_search_data_44 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_45_issue_id_idx ON gitlab_partitions_static.issue_search_data_45 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_45_search_vector_idx ON gitlab_partitions_static.issue_search_data_45 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_46_issue_id_idx ON gitlab_partitions_static.issue_search_data_46 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_46_search_vector_idx ON gitlab_partitions_static.issue_search_data_46 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_47_issue_id_idx ON gitlab_partitions_static.issue_search_data_47 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_47_search_vector_idx ON gitlab_partitions_static.issue_search_data_47 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_48_issue_id_idx ON gitlab_partitions_static.issue_search_data_48 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_48_search_vector_idx ON gitlab_partitions_static.issue_search_data_48 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_49_issue_id_idx ON gitlab_partitions_static.issue_search_data_49 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_49_search_vector_idx ON gitlab_partitions_static.issue_search_data_49 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_50_issue_id_idx ON gitlab_partitions_static.issue_search_data_50 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_50_search_vector_idx ON gitlab_partitions_static.issue_search_data_50 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_51_issue_id_idx ON gitlab_partitions_static.issue_search_data_51 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_51_search_vector_idx ON gitlab_partitions_static.issue_search_data_51 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_52_issue_id_idx ON gitlab_partitions_static.issue_search_data_52 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_52_search_vector_idx ON gitlab_partitions_static.issue_search_data_52 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_53_issue_id_idx ON gitlab_partitions_static.issue_search_data_53 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_53_search_vector_idx ON gitlab_partitions_static.issue_search_data_53 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_54_issue_id_idx ON gitlab_partitions_static.issue_search_data_54 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_54_search_vector_idx ON gitlab_partitions_static.issue_search_data_54 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_55_issue_id_idx ON gitlab_partitions_static.issue_search_data_55 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_55_search_vector_idx ON gitlab_partitions_static.issue_search_data_55 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_56_issue_id_idx ON gitlab_partitions_static.issue_search_data_56 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_56_search_vector_idx ON gitlab_partitions_static.issue_search_data_56 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_57_issue_id_idx ON gitlab_partitions_static.issue_search_data_57 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_57_search_vector_idx ON gitlab_partitions_static.issue_search_data_57 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_58_issue_id_idx ON gitlab_partitions_static.issue_search_data_58 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_58_search_vector_idx ON gitlab_partitions_static.issue_search_data_58 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_59_issue_id_idx ON gitlab_partitions_static.issue_search_data_59 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_59_search_vector_idx ON gitlab_partitions_static.issue_search_data_59 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_60_issue_id_idx ON gitlab_partitions_static.issue_search_data_60 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_60_search_vector_idx ON gitlab_partitions_static.issue_search_data_60 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_61_issue_id_idx ON gitlab_partitions_static.issue_search_data_61 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_61_search_vector_idx ON gitlab_partitions_static.issue_search_data_61 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_62_issue_id_idx ON gitlab_partitions_static.issue_search_data_62 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_62_search_vector_idx ON gitlab_partitions_static.issue_search_data_62 USING gin (search_vector);
+
+CREATE INDEX issue_search_data_63_issue_id_idx ON gitlab_partitions_static.issue_search_data_63 USING btree (issue_id);
+
+CREATE INDEX issue_search_data_63_search_vector_idx ON gitlab_partitions_static.issue_search_data_63 USING gin (search_vector);
+
CREATE INDEX index_product_analytics_events_experimental_project_and_time ON ONLY product_analytics_events_experimental USING btree (project_id, collector_tstamp);
CREATE INDEX product_analytics_events_expe_project_id_collector_tstamp_idx10 ON gitlab_partitions_static.product_analytics_events_experimental_10 USING btree (project_id, collector_tstamp);
@@ -29157,6 +30197,390 @@ ALTER INDEX index_issue_stage_events_project_duration ATTACH PARTITION gitlab_pa
ALTER INDEX index_issue_stage_events_group_in_progress_duration ATTACH PARTITION gitlab_partitions_static.index_ff8741d8d7;
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_00_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_00_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_00_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_01_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_01_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_01_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_02_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_02_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_02_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_03_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_03_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_03_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_04_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_04_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_04_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_05_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_05_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_05_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_06_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_06_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_06_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_07_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_07_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_07_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_08_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_08_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_08_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_09_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_09_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_09_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_10_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_10_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_10_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_11_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_11_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_11_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_12_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_12_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_12_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_13_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_13_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_13_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_14_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_14_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_14_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_15_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_15_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_15_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_16_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_16_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_16_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_17_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_17_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_17_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_18_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_18_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_18_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_19_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_19_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_19_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_20_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_20_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_20_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_21_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_21_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_21_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_22_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_22_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_22_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_23_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_23_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_23_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_24_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_24_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_24_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_25_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_25_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_25_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_26_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_26_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_26_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_27_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_27_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_27_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_28_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_28_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_28_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_29_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_29_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_29_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_30_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_30_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_30_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_31_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_31_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_31_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_32_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_32_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_32_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_33_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_33_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_33_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_34_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_34_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_34_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_35_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_35_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_35_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_36_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_36_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_36_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_37_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_37_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_37_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_38_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_38_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_38_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_39_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_39_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_39_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_40_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_40_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_40_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_41_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_41_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_41_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_42_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_42_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_42_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_43_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_43_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_43_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_44_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_44_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_44_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_45_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_45_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_45_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_46_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_46_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_46_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_47_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_47_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_47_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_48_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_48_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_48_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_49_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_49_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_49_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_50_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_50_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_50_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_51_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_51_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_51_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_52_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_52_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_52_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_53_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_53_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_53_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_54_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_54_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_54_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_55_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_55_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_55_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_56_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_56_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_56_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_57_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_57_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_57_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_58_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_58_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_58_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_59_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_59_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_59_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_60_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_60_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_60_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_61_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_61_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_61_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_62_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_62_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_62_search_vector_idx;
+
+ALTER INDEX index_issue_search_data_on_issue_id ATTACH PARTITION gitlab_partitions_static.issue_search_data_63_issue_id_idx;
+
+ALTER INDEX issue_search_data_pkey ATTACH PARTITION gitlab_partitions_static.issue_search_data_63_pkey;
+
+ALTER INDEX index_issue_search_data_on_search_vector ATTACH PARTITION gitlab_partitions_static.issue_search_data_63_search_vector_idx;
+
ALTER INDEX index_product_analytics_events_experimental_project_and_time ATTACH PARTITION gitlab_partitions_static.product_analytics_events_expe_project_id_collector_tstamp_idx10;
ALTER INDEX index_product_analytics_events_experimental_project_and_time ATTACH PARTITION gitlab_partitions_static.product_analytics_events_expe_project_id_collector_tstamp_idx11;
@@ -31884,6 +33308,12 @@ ALTER TABLE ONLY timelogs
ALTER TABLE ONLY u2f_registrations
ADD CONSTRAINT fk_u2f_registrations_user_id FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
+ALTER TABLE issue_search_data
+ ADD CONSTRAINT issue_search_data_issue_id_fkey FOREIGN KEY (issue_id) REFERENCES issues(id) ON DELETE CASCADE;
+
+ALTER TABLE issue_search_data
+ ADD CONSTRAINT issue_search_data_project_id_fkey FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
+
ALTER TABLE product_analytics_events_experimental
ADD CONSTRAINT product_analytics_events_experimental_project_id_fkey FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
diff --git a/lib/gitlab/background_migration/backfill_issue_search_data.rb b/lib/gitlab/background_migration/backfill_issue_search_data.rb
new file mode 100644
index 00000000000..82722fe1dc3
--- /dev/null
+++ b/lib/gitlab/background_migration/backfill_issue_search_data.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+# rubocop:disable Style/Documentation
+
+module Gitlab
+ module BackgroundMigration
+ # Backfills the new `issue_search_data` table, which contains
+ # the tsvector from the issue title and description.
+ class BackfillIssueSearchData
+ include Gitlab::Database::DynamicModelHelpers
+
+ def perform(start_id, stop_id, batch_table, batch_column, sub_batch_size, pause_ms)
+ define_batchable_model(batch_table, connection: ActiveRecord::Base.connection).where(batch_column => start_id..stop_id).each_batch(of: sub_batch_size) do |sub_batch|
+ update_search_data(sub_batch)
+
+ sleep(pause_ms * 0.001)
+ rescue ActiveRecord::StatementInvalid => e
+ raise unless e.cause.is_a?(PG::ProgramLimitExceeded) && e.message.include?('string is too long for tsvector')
+
+ update_search_data_individually(sub_batch, pause_ms)
+ end
+ end
+
+ private
+
+ def update_search_data(relation)
+ relation.klass.connection.execute(
+ <<~SQL
+ INSERT INTO issue_search_data (project_id, issue_id, search_vector, created_at, updated_at)
+ SELECT
+ project_id,
+ id,
+ setweight(to_tsvector('english', LEFT(title, 255)), 'A') || setweight(to_tsvector('english', LEFT(REGEXP_REPLACE(description, '[A-Za-z0-9+/]{50,}', ' ', 'g'), 1048576)), 'B'),
+ NOW(),
+ NOW()
+ FROM issues
+ WHERE issues.id IN (#{relation.select(:id).to_sql})
+ ON CONFLICT DO NOTHING
+ SQL
+ )
+ end
+
+ def update_search_data_individually(relation, pause_ms)
+ relation.pluck(:id).each do |issue_id|
+ update_search_data(relation.klass.where(id: issue_id))
+
+ sleep(pause_ms * 0.001)
+ rescue ActiveRecord::StatementInvalid => e
+ raise unless e.cause.is_a?(PG::ProgramLimitExceeded) && e.message.include?('string is too long for tsvector')
+
+ logger.error(
+ message: 'Error updating search data: string is too long for tsvector',
+ class: relation.klass.name,
+ model_id: issue_id
+ )
+ end
+ end
+
+ def logger
+ @logger ||= Gitlab::BackgroundMigration::Logger.build
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/gitlab_schemas.yml b/lib/gitlab/database/gitlab_schemas.yml
index 04b35a32b9d..95005871194 100644
--- a/lib/gitlab/database/gitlab_schemas.yml
+++ b/lib/gitlab/database/gitlab_schemas.yml
@@ -274,6 +274,7 @@ issue_emails: :gitlab_main
issue_email_participants: :gitlab_main
issue_links: :gitlab_main
issue_metrics: :gitlab_main
+issue_search_data: :gitlab_main
issues: :gitlab_main
issues_prometheus_alert_events: :gitlab_main
issues_self_managed_prometheus_alert_events: :gitlab_main
diff --git a/lib/gitlab/issuables_count_for_state.rb b/lib/gitlab/issuables_count_for_state.rb
index f11dd520d2d..42b549cf127 100644
--- a/lib/gitlab/issuables_count_for_state.rb
+++ b/lib/gitlab/issuables_count_for_state.rb
@@ -144,7 +144,7 @@ module Gitlab
def params_include_filters?
non_filtering_params = %i[
scope state sort group_id include_subgroups
- attempt_group_search_optimizations non_archived issue_types
+ attempt_group_search_optimizations attempt_full_text_search non_archived issue_types
]
finder.params.except(*non_filtering_params).values.any?
diff --git a/qa/qa/resource/protected_branch.rb b/qa/qa/resource/protected_branch.rb
index 062d4e9f3d8..55ad6edb3c1 100644
--- a/qa/qa/resource/protected_branch.rb
+++ b/qa/qa/resource/protected_branch.rb
@@ -72,6 +72,16 @@ module QA
self.remove_via_api!(&block)
end
+ # Remove the branch protection after confirming that it exists
+ def remove_via_api!
+ Support::Retrier.retry_until(max_duration: 60, sleep_interval: 1, message: "Waiting for branch #{branch_name} to be protected") do
+ # We confirm it exists before removal because there's no creation event when the default branch is automatically protected by GitLab itself, and there's a slight delay between creating the repo and protecting the default branch
+ exists?
+ end
+
+ super
+ end
+
def api_get_path
"/projects/#{project.id}/protected_branches/#{branch_name}"
end
diff --git a/spec/controllers/dashboard_controller_spec.rb b/spec/controllers/dashboard_controller_spec.rb
index 8fae617ea65..dbeac9fd240 100644
--- a/spec/controllers/dashboard_controller_spec.rb
+++ b/spec/controllers/dashboard_controller_spec.rb
@@ -13,7 +13,22 @@ RSpec.describe DashboardController do
end
describe 'GET issues' do
- it_behaves_like 'issuables list meta-data', :issue, :issues
+ context 'when issues_full_text_search is disabled' do
+ before do
+ stub_feature_flags(issues_full_text_search: false)
+ end
+
+ it_behaves_like 'issuables list meta-data', :issue, :issues
+ end
+
+ context 'when issues_full_text_search is enabled' do
+ before do
+ stub_feature_flags(issues_full_text_search: true)
+ end
+
+ it_behaves_like 'issuables list meta-data', :issue, :issues
+ end
+
it_behaves_like 'issuables requiring filter', :issues
end
diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb
index bf0b833b311..c159768690e 100644
--- a/spec/controllers/projects/issues_controller_spec.rb
+++ b/spec/controllers/projects/issues_controller_spec.rb
@@ -72,7 +72,21 @@ RSpec.describe Projects::IssuesController do
project.add_developer(user)
end
- it_behaves_like "issuables list meta-data", :issue
+ context 'when issues_full_text_search is disabled' do
+ before do
+ stub_feature_flags(issues_full_text_search: false)
+ end
+
+ it_behaves_like 'issuables list meta-data', :issue
+ end
+
+ context 'when issues_full_text_search is enabled' do
+ before do
+ stub_feature_flags(issues_full_text_search: true)
+ end
+
+ it_behaves_like 'issuables list meta-data', :issue
+ end
it_behaves_like 'set sort order from user preference' do
let(:sorting_param) { 'updated_asc' }
diff --git a/spec/features/issues/filtered_search/filter_issues_spec.rb b/spec/features/issues/filtered_search/filter_issues_spec.rb
index edf3df7c16e..2883030e9ac 100644
--- a/spec/features/issues/filtered_search/filter_issues_spec.rb
+++ b/spec/features/issues/filtered_search/filter_issues_spec.rb
@@ -497,6 +497,8 @@ RSpec.describe 'Filter issues', :js do
end
it 'filters issues by searched text containing special characters' do
+ stub_feature_flags(issues_full_text_search: false)
+
issue = create(:issue, project: project, author: user, title: "issue with !@\#{$%^&*()-+")
search = '!@#{$%^&*()-+'
diff --git a/spec/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb
index c22e56c3b9e..b00cdca3423 100644
--- a/spec/finders/issues_finder_spec.rb
+++ b/spec/finders/issues_finder_spec.rb
@@ -632,6 +632,29 @@ RSpec.describe IssuesFinder do
end
end
+ context 'filtering by issue term using full-text search' do
+ let(:params) { { search: search_term, attempt_full_text_search: true } }
+
+ let_it_be(:english) { create(:issue, project: project1, title: 'title', description: 'something english') }
+ let_it_be(:japanese) { create(:issue, project: project1, title: '日本語 title', description: 'another english description') }
+
+ context 'with latin search term' do
+ let(:search_term) { 'title english' }
+
+ it 'returns matching issues' do
+ expect(issues).to contain_exactly(english, japanese)
+ end
+ end
+
+ context 'with non-latin search term' do
+ let(:search_term) { '日本語' }
+
+ it 'returns matching issues' do
+ expect(issues).to contain_exactly(japanese)
+ end
+ end
+ end
+
context 'filtering by issues iids' do
let(:params) { { iids: [issue3.iid] } }
diff --git a/spec/graphql/types/work_item_type_spec.rb b/spec/graphql/types/work_item_type_spec.rb
index 4e44123d475..6a5b4a0882e 100644
--- a/spec/graphql/types/work_item_type_spec.rb
+++ b/spec/graphql/types/work_item_type_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe GitlabSchema.types['WorkItem'] do
specify { expect(described_class.graphql_name).to eq('WorkItem') }
- specify { expect(described_class).to require_graphql_authorizations(:read_issue) }
+ specify { expect(described_class).to require_graphql_authorizations(:read_work_item) }
it 'has specific fields' do
fields = %i[description description_html id iid lock_version state title title_html work_item_type]
diff --git a/spec/lib/gitlab/background_migration/backfill_issue_search_data_spec.rb b/spec/lib/gitlab/background_migration/backfill_issue_search_data_spec.rb
new file mode 100644
index 00000000000..b29d4c3583b
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/backfill_issue_search_data_spec.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BackgroundMigration::BackfillIssueSearchData do
+ let(:namespaces_table) { table(:namespaces) }
+ let(:projects_table) { table(:projects) }
+ let(:issue_search_data_table) { table(:issue_search_data) }
+
+ let!(:namespace) { namespaces_table.create!(name: 'gitlab-org', path: 'gitlab-org') }
+ let!(:project) { projects_table.create!(name: 'gitlab', path: 'gitlab-org/gitlab-ce', namespace_id: namespace.id) }
+ let!(:issues) { Array.new(10) { table(:issues).create!(project_id: project.id, title: 'test title', description: 'test description') } }
+
+ let(:migration) { described_class.new }
+
+ before do
+ allow(migration).to receive(:sleep)
+ end
+
+ it 'backfills search data for the specified records' do
+ # sleeps for every sub-batch
+ expect(migration).to receive(:sleep).with(0.05).exactly(3).times
+
+ migration.perform(issues[0].id, issues[5].id, :issues, :id, 2, 50)
+
+ expect(issue_search_data_table.count).to eq(6)
+ end
+
+ it 'skips issues that already have search data' do
+ old_time = Time.new(2019, 1, 1).in_time_zone
+ issue_search_data_table.create!(project_id: project.id, issue_id: issues[0].id, updated_at: old_time)
+
+ migration.perform(issues[0].id, issues[5].id, :issues, :id, 2, 50)
+
+ expect(issue_search_data_table.count).to eq(6)
+ expect(issue_search_data_table.find_by_issue_id(issues[0].id).updated_at).to be_like_time(old_time)
+ end
+
+ it 'rescues batch with bad data and inserts other rows' do
+ issues[1].update!(description: Array.new(30_000) { SecureRandom.hex }.join(' '))
+
+ expect_next_instance_of(Gitlab::BackgroundMigration::Logger) do |logger|
+ expect(logger).to receive(:error).with(a_hash_including(message: /string is too long for tsvector/, model_id: issues[1].id))
+ end
+
+ expect { migration.perform(issues[0].id, issues[5].id, :issues, :id, 2, 50) }.not_to raise_error
+
+ expect(issue_search_data_table.count).to eq(5)
+ expect(issue_search_data_table.find_by_issue_id(issues[1].id)).to eq(nil)
+ end
+
+ it 're-raises other errors' do
+ allow(migration).to receive(:update_search_data).and_raise(ActiveRecord::StatementTimeout)
+
+ expect { migration.perform(issues[0].id, issues[5].id, :issues, :id, 2, 50) }.to raise_error(ActiveRecord::StatementTimeout)
+ end
+end
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index ce13f405459..ae3aafffe56 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -34,6 +34,7 @@ issues:
- issuable_severity
- issuable_sla
- issue_assignees
+- search_data
- closed_by
- epic_issue
- epic
@@ -627,6 +628,8 @@ issuable_severity:
issue_assignees:
- issue
- assignee
+search_data:
+- issue
merge_request_assignees:
- merge_request
- assignee
diff --git a/spec/models/concerns/pg_full_text_searchable_spec.rb b/spec/models/concerns/pg_full_text_searchable_spec.rb
new file mode 100644
index 00000000000..50a97e873a5
--- /dev/null
+++ b/spec/models/concerns/pg_full_text_searchable_spec.rb
@@ -0,0 +1,162 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe PgFullTextSearchable do
+ let(:project) { create(:project) }
+
+ let(:model_class) do
+ Class.new(ActiveRecord::Base) do
+ include PgFullTextSearchable
+
+ self.table_name = 'issues'
+
+ belongs_to :project
+ has_one :search_data, class_name: 'Issues::SearchData'
+
+ def persist_pg_full_text_search_vector(search_vector)
+ Issues::SearchData.upsert({ project_id: project_id, issue_id: id, search_vector: search_vector }, unique_by: %i(project_id issue_id))
+ end
+
+ def self.name
+ 'Issue'
+ end
+ end
+ end
+
+ describe '.pg_full_text_searchable' do
+ it 'sets pg_full_text_searchable_columns' do
+ model_class.pg_full_text_searchable columns: [{ name: 'title', weight: 'A' }]
+
+ expect(model_class.pg_full_text_searchable_columns).to eq({ 'title' => 'A' })
+ end
+
+ it 'raises an error when called twice' do
+ model_class.pg_full_text_searchable columns: [{ name: 'title', weight: 'A' }]
+
+ expect { model_class.pg_full_text_searchable columns: [{ name: 'title', weight: 'A' }] }.to raise_error('Full text search columns already defined!')
+ end
+ end
+
+ describe 'after commit hook' do
+ let(:model) { model_class.create!(project: project) }
+
+ before do
+ model_class.pg_full_text_searchable columns: [{ name: 'title', weight: 'A' }]
+ end
+
+ context 'when specified columns are changed' do
+ it 'calls update_search_data!' do
+ expect(model).to receive(:update_search_data!)
+
+ model.update!(title: 'A new title')
+ end
+ end
+
+ context 'when specified columns are not changed' do
+ it 'does not enqueue worker' do
+ expect(model).not_to receive(:update_search_data!)
+
+ model.update!(description: 'A new description')
+ end
+ end
+ end
+
+ describe '.pg_full_text_search' do
+ let(:english) { model_class.create!(project: project, title: 'title', description: 'something english') }
+ let(:with_accent) { model_class.create!(project: project, title: 'Jürgen', description: 'Ærøskøbing') }
+ let(:japanese) { model_class.create!(project: project, title: '日本語 title', description: 'another english description') }
+
+ before do
+ model_class.pg_full_text_searchable columns: [{ name: 'title', weight: 'A' }, { name: 'description', weight: 'B' }]
+
+ [english, with_accent, japanese].each(&:update_search_data!)
+ end
+
+ it 'searches across all fields' do
+ expect(model_class.pg_full_text_search('title english')).to contain_exactly(english, japanese)
+ end
+
+ it 'searches for exact term with quotes' do
+ expect(model_class.pg_full_text_search('"something english"')).to contain_exactly(english)
+ end
+
+ it 'ignores accents' do
+ expect(model_class.pg_full_text_search('jurgen')).to contain_exactly(with_accent)
+ end
+
+ it 'does not support searching by non-Latin characters' do
+ expect(model_class.pg_full_text_search('日本')).to be_empty
+ end
+ end
+
+ describe '#update_search_data!' do
+ let(:model) { model_class.create!(project: project, title: 'title', description: 'description') }
+
+ before do
+ model_class.pg_full_text_searchable columns: [{ name: 'title', weight: 'A' }, { name: 'description', weight: 'B' }]
+ end
+
+ it 'sets the correct weights' do
+ model.update_search_data!
+
+ expect(model.search_data.search_vector).to match(/'titl':1A/)
+ expect(model.search_data.search_vector).to match(/'descript':2B/)
+ end
+
+ context 'with accented and non-Latin characters' do
+ let(:model) { model_class.create!(project: project, title: '日本語', description: 'Jürgen') }
+
+ it 'transliterates accented characters and removes non-Latin ones' do
+ model.update_search_data!
+
+ expect(model.search_data.search_vector).not_to match(/日本語/)
+ expect(model.search_data.search_vector).to match(/jurgen/)
+ end
+ end
+
+ context 'when upsert times out' do
+ it 're-raises the exception' do
+ expect(Issues::SearchData).to receive(:upsert).once.and_raise(ActiveRecord::StatementTimeout)
+
+ expect { model.update_search_data! }.to raise_error(ActiveRecord::StatementTimeout)
+ end
+ end
+
+ context 'with strings that go over tsvector limit', :delete do
+ let(:long_string) { Array.new(30_000) { SecureRandom.hex }.join(' ') }
+ let(:model) { model_class.create!(project: project, title: 'title', description: long_string) }
+
+ it 'does not raise an exception' do
+ expect(Gitlab::AppJsonLogger).to receive(:error).with(
+ a_hash_including(class: model_class.name, model_id: model.id)
+ )
+
+ expect { model.update_search_data! }.not_to raise_error
+
+ expect(model.search_data).to eq(nil)
+ end
+ end
+
+ context 'when model class does not implement persist_pg_full_text_search_vector' do
+ let(:model_class) do
+ Class.new(ActiveRecord::Base) do
+ include PgFullTextSearchable
+
+ self.table_name = 'issues'
+
+ belongs_to :project
+ has_one :search_data, class_name: 'Issues::SearchData'
+
+ def self.name
+ 'Issue'
+ end
+ end
+ end
+
+ it 'raises an error' do
+ expect { model.update_search_data! }.to raise_error(NotImplementedError)
+ end
+ end
+ end
+end
diff --git a/spec/policies/work_item_policy_spec.rb b/spec/policies/work_item_policy_spec.rb
new file mode 100644
index 00000000000..08a22a95540
--- /dev/null
+++ b/spec/policies/work_item_policy_spec.rb
@@ -0,0 +1,94 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe WorkItemPolicy do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:public_project) { create(:project, :public) }
+ let_it_be(:guest) { create(:user).tap { |user| project.add_guest(user) } }
+ let_it_be(:guest_author) { create(:user).tap { |user| project.add_guest(user) } }
+ let_it_be(:reporter) { create(:user).tap { |user| project.add_reporter(user) } }
+ let_it_be(:non_member_user) { create(:user) }
+ let_it_be(:work_item) { create(:work_item, project: project) }
+ let_it_be(:authored_work_item) { create(:work_item, project: project, author: guest_author) }
+ let_it_be(:public_work_item) { create(:work_item, project: public_project) }
+
+ let(:work_item_subject) { work_item }
+
+ subject { described_class.new(current_user, work_item_subject) }
+
+ before_all do
+ public_project.add_developer(guest_author)
+ end
+
+ describe 'read_work_item' do
+ context 'when project is public' do
+ let(:work_item_subject) { public_work_item }
+
+ context 'when user is not a member of the project' do
+ let(:current_user) { non_member_user }
+
+ it { is_expected.to be_allowed(:read_work_item) }
+ end
+
+ context 'when user is a member of the project' do
+ let(:current_user) { guest_author }
+
+ it { is_expected.to be_allowed(:read_work_item) }
+ end
+ end
+
+ context 'when project is private' do
+ let(:work_item_subject) { work_item }
+
+ context 'when user is not a member of the project' do
+ let(:current_user) { non_member_user }
+
+ it { is_expected.to be_disallowed(:read_work_item) }
+ end
+
+ context 'when user is a member of the project' do
+ let(:current_user) { guest_author }
+
+ it { is_expected.to be_allowed(:read_work_item) }
+ end
+ end
+ end
+
+ describe 'update_work_item' do
+ context 'when user is reporter' do
+ let(:current_user) { reporter }
+
+ it { is_expected.to be_allowed(:update_work_item) }
+ end
+
+ context 'when user is guest' do
+ let(:current_user) { guest }
+
+ it { is_expected.to be_disallowed(:update_work_item) }
+
+ context 'when guest authored the work item' do
+ let(:work_item_subject) { authored_work_item }
+ let(:current_user) { guest_author }
+
+ it { is_expected.to be_allowed(:update_work_item) }
+ end
+ end
+ end
+
+ describe 'delete_work_item' do
+ context 'when user is a member of the project' do
+ let(:work_item_subject) { work_item }
+ let(:current_user) { reporter }
+
+ it { is_expected.to be_disallowed(:delete_work_item) }
+
+ context 'when guest authored the work item' do
+ let(:work_item_subject) { authored_work_item }
+ let(:current_user) { guest_author }
+
+ it { is_expected.to be_allowed(:delete_work_item) }
+ end
+ end
+ end
+end