このコミットが含まれているのは:
@@ -1,5 +1,6 @@
|
||||
# Re-aggregate distinct membership; tag row tuples alone use additive contributions.
|
||||
class CountsPivotTotals
|
||||
class TimedOut < ActiveRecord::StatementTimeout; end
|
||||
def initialize(population, axes, row_headers, column_headers)
|
||||
@population = population
|
||||
@axes = axes
|
||||
@@ -27,20 +28,26 @@ class CountsPivotTotals
|
||||
retained = additive ? (0...@axes.rows.length).to_a | indexes : indexes
|
||||
joins = @axes.joins(retained.map { @axes.all[_1].fetch('field') })
|
||||
scope = scope.joins(joins) unless joins.empty?
|
||||
predicates = []
|
||||
if row_depth.positive?
|
||||
tuples = headers.map { _1[:values] }.uniq
|
||||
predicate = tuples.map { Array.new(row_depth) { |i|
|
||||
"(#{ expressions[i] }) <=> ?"
|
||||
"a#{ indexes[i] } <=> ?"
|
||||
}.join(' AND ') }.map { "(#{ _1 })" }.join(' OR ')
|
||||
scope = scope.where(predicate, *tuples.flatten)
|
||||
predicates << @population.definition.model.sanitize_sql_array([
|
||||
tuples.empty? ? 'FALSE' : "(#{ predicate })", *tuples.flatten])
|
||||
end
|
||||
if column_depth.positive?
|
||||
tuples = columns.map { _1[:values] }.uniq
|
||||
predicate = tuples.map { Array.new(column_depth) { |i|
|
||||
"(#{ expressions[row_depth + i] }) <=> ?"
|
||||
"a#{ indexes[row_depth + i] } <=> ?"
|
||||
}.join(' AND ') }.map { "(#{ _1 })" }.join(' OR ')
|
||||
scope = scope.where(predicate, *tuples.flatten)
|
||||
predicates << @population.definition.model.sanitize_sql_array([
|
||||
tuples.empty? ? 'FALSE' : "(#{ predicate })", *tuples.flatten])
|
||||
end
|
||||
# Filter projected coordinates, not repeated masking/time expressions.
|
||||
# Each member still participates in the complete DISTINCT population.
|
||||
selection = predicates.empty? ? '' : " WHERE #{ predicates.join(' AND ') }"
|
||||
grouped = indexes.each_with_index.map { |key, index|
|
||||
"a#{ key } AS v#{ index }"
|
||||
}
|
||||
@@ -56,19 +63,19 @@ class CountsPivotTotals
|
||||
output = ["#{ row_depth } AS row_depth", "#{ column_depth } AS column_depth"] +
|
||||
projected + padding + ['SUM(count) AS count']
|
||||
grouping = coordinates.empty? ? '' : " GROUP BY #{ coordinates.join(', ') }"
|
||||
"SELECT #{ output.join(', ') } FROM (#{ inner }) leaf#{ grouping }"
|
||||
"SELECT #{ output.join(', ') } FROM (#{ inner }) leaf#{ selection }#{ grouping }"
|
||||
else
|
||||
inner = @axes.grouped_sql(scope, indexes)
|
||||
"SELECT #{ fields.join(', ') } FROM (#{ inner }) grouped"
|
||||
"SELECT #{ fields.join(', ') } FROM (#{ inner }) grouped#{ selection }"
|
||||
end
|
||||
end
|
||||
end
|
||||
return [] if queries.empty?
|
||||
|
||||
sql = queries.map { "(#{ _1 })" }.join(' UNION ALL ')
|
||||
@population.definition.model.connection.select_all(
|
||||
"WITH population_members AS (#{ basis }) " +
|
||||
"SELECT /*+ MAX_EXECUTION_TIME(10000) */ * FROM (#{ sql }) totals").map do |record|
|
||||
statement = "WITH population_members AS (#{ basis }) " +
|
||||
"SELECT /*+ #{ CountsTableQuery::SQL_HINTS.join(' ') } */ * FROM (#{ sql }) totals"
|
||||
@population.definition.model.connection.select_all(statement).map do |record|
|
||||
row_depth = record['row_depth'].to_i
|
||||
column_depth = record['column_depth'].to_i
|
||||
{ row: (0...row_depth).map { record["v#{ _1 }"] },
|
||||
@@ -78,5 +85,7 @@ class CountsPivotTotals
|
||||
row_depth, column_depth),
|
||||
count: record['count'].to_i }
|
||||
end
|
||||
rescue ActiveRecord::StatementTimeout
|
||||
raise TimedOut, 'Counts pivot totals exceeded the query time limit'
|
||||
end
|
||||
end
|
||||
|
||||
新しいイシューから参照
ユーザーをブロックする