このコミットが含まれているのは:
2026-11-01 04:22:26 +09:00
コミット 29002d5393
20個のファイルの変更、419行の追加、102行の削除
+1 -1
ファイルの表示
@@ -340,7 +340,7 @@ class CountsCondition
return @definition.alias_source(root) if root.start_with?('aliases_')
return [nil, @definition.name_expression(root)]
end
return [nil, "(#{ @population.latest_sql })"] if root == 'latest'
return [nil, "(#{ @population.current_latest_sql })"] if root == 'latest'
if root == 'user' && parts.any?
expression = parts.first == 'id' ? 'v.created_by_user_id' :
'(SELECT actor.name FROM users actor WHERE actor.id = v.created_by_user_id)'
+1 -1
ファイルの表示
@@ -20,7 +20,7 @@ class CountsDefaults
details = details.transform_values do |value|
value.split(' ').flat_map do |token|
if resource == 'tags' && ['name', 'parents.name'].include?(token)
token == 'name' ? name : ["parents.#{ name }", "parents.#{ aliases }"]
token == 'name' ? name : "parents.#{ name }"
elsif resource == 'tags' && token == 'aliases'
aliases
elsif resource == 'tags' && token.start_with?('aliases.')
+10 -3
ファイルの表示
@@ -41,8 +41,7 @@ class CountsPopulation
raise ArgumentError
end
def latest_sql(row = 'v', cutoff = nil)
cutoff ||= history ? at : timestamp(params['at']) || at
def latest_at_sql(row, cutoff)
keys = definition.keys.map { "newer.#{ _1 } = #{ row }.#{ _1 }" }.join(' AND ')
bound = definition.model.connection.quote(cutoff)
<<~SQL.squish
@@ -52,6 +51,14 @@ class CountsPopulation
SQL
end
def current_latest_sql(row = 'v')
keys = definition.keys.map { "newer.#{ _1 } = #{ row }.#{ _1 }" }.join(' AND ')
<<~SQL.squish
NOT EXISTS (SELECT 1 FROM #{ definition.table } newer
WHERE #{ keys } AND newer.version_no > #{ row }.version_no)
SQL
end
def changed_sql(key)
column = definition.column(key)
"(previous.id IS NOT NULL AND NOT (v.#{ column } <=> previous.#{ column }))"
@@ -125,7 +132,7 @@ class CountsPopulation
raise ArgumentError if point > at
@scope = @scope.where("v.#{ definition.time_column } <= ?", point)
.where(Arel.sql(latest_sql('v', point))).where.not('v.event_type' => 'discard')
.where(Arel.sql(latest_at_sql('v', point))).where.not('v.event_type' => 'discard')
return
end
first = timestamp(params['from'])
+10 -8
ファイルの表示
@@ -1,5 +1,7 @@
# Common entrypoint for six version resources; legacy endpoints keep their contracts.
class CountsTableQuery
SQL_HINTS = ['MAX_EXECUTION_TIME(10000)',
"SET_VAR(optimizer_switch='semijoin=off')"].freeze
MAX_COLUMNS = 100
class TooManyColumns < ArgumentError; end
@@ -127,7 +129,7 @@ class CountsTableQuery
numbered AS (SELECT row_groups.*,
ROW_NUMBER() OVER (ORDER BY #{ order_rows.join(', ') }) AS position FROM row_groups),
group_totals AS (SELECT COUNT(*) AS group_count FROM row_groups)
SELECT /*+ MAX_EXECUTION_TIME(10000) */ cells.*,
SELECT /*+ #{ SQL_HINTS.join(' ') } */ cells.*,
page_rows.position AS counts_position, group_totals.group_count AS counts_group_count
FROM group_totals LEFT JOIN numbered page_rows
ON page_rows.position > #{ (page - 1) * limit }
@@ -175,7 +177,7 @@ class CountsTableQuery
def details
query = population.scope.select(Arel.sql(
"(#{ population.latest_sql }) AS counts_latest"))
"(#{ population.current_latest_sql }) AS counts_latest"))
order = sort_sql { detail_expression(_1) }
query = query.order(Arel.sql((order + ['v.id ASC']).join(', ')))
.limit(limit).offset((page - 1) * limit)
@@ -253,11 +255,11 @@ class CountsTableQuery
if HistoryAccess.admin? || mode == 'summary'
total = population.scope.except(:select)
.optimizer_hints('MAX_EXECUTION_TIME(10000)').count
.optimizer_hints(*SQL_HINTS).count
return @record_counts = { total:, visible: total, denied: 0 }
end
total, denied = unrestricted_population.scope.except(:select)
.optimizer_hints('MAX_EXECUTION_TIME(10000)').pick(Arel.sql('COUNT(*)'),
.optimizer_hints(*SQL_HINTS).pick(Arel.sql('COUNT(*)'),
Arel.sql("COALESCE(SUM(CASE WHEN #{ HistoryAccess.sql(@definition.model, 'v') } " +
'THEN 0 ELSE 1 END), 0)'))
# Related/previous-version predicates may differ under public authority.
@@ -267,7 +269,7 @@ class CountsTableQuery
total.to_i - denied.to_i
else
population.scope.except(:select)
.optimizer_hints('MAX_EXECUTION_TIME(10000)').count
.optimizer_hints(*SQL_HINTS).count
end
@record_counts = { total: total.to_i, denied: denied.to_i, visible: }
end
@@ -309,7 +311,7 @@ class CountsTableQuery
prefix = "WITH cells AS (#{ sql })"
@connection.select_value(<<~SQL).to_i
#{ prefix }
SELECT /*+ MAX_EXECUTION_TIME(10000) */ COUNT(*) FROM (
SELECT /*+ #{ SQL_HINTS.join(' ') } */ COUNT(*) FROM (
SELECT #{ keys.join(', ') } FROM cells GROUP BY #{ keys.join(', ') }
) output_groups
SQL
@@ -335,7 +337,7 @@ class CountsTableQuery
end
values = @connection.select_rows(<<~SQL)
#{ prefix }
SELECT /*+ MAX_EXECUTION_TIME(10000) */ DISTINCT #{ keys.join(', ') } FROM cells
SELECT /*+ #{ SQL_HINTS.join(' ') } */ DISTINCT #{ keys.join(', ') } FROM cells
ORDER BY #{ order } LIMIT #{ MAX_COLUMNS + 1 }
SQL
raise TooManyColumns if values.length > MAX_COLUMNS
@@ -395,7 +397,7 @@ class CountsTableQuery
end
def detail_expression(key)
return "(#{ population.latest_sql })" if key == 'latest'
return "(#{ population.current_latest_sql })" if key == 'latest'
return @definition.name_expression(key) if @definition.resource == 'tags' &&
@definition.name_column(key)
aliases = { 'tags' => 'tags_json', 'parents' => @definition.resource == 'posts' ?