8#include "ProgressTask.hpp"
9#include "SqlConnection.hpp"
10#include "SqlError.hpp"
11#include "SqlMigration.hpp"
12#include "SqlQueryFormatter.hpp"
13#include "SqlSchema.hpp"
14#include "SqlStatement.hpp"
26namespace Lightweight::detail
30struct UnicodeUpgradeTableProgress
33 std::uint64_t rows = 0;
34 std::size_t columns = 0;
44class UnicodeUpgradeProgress
48 static constexpr std::string_view PlanningTitle =
"Plan the Unicode upgrade";
50 static constexpr std::string_view OverallTitle =
"Upgrade text columns to Unicode";
53 explicit UnicodeUpgradeProgress(ProgressTask& parent):
55 _planning { parent.BeginSubTask(PlanningTitle, 0) }
59 UnicodeUpgradeProgress(UnicodeUpgradeProgress
const&) =
delete;
60 UnicodeUpgradeProgress(UnicodeUpgradeProgress&&) =
delete;
61 UnicodeUpgradeProgress& operator=(UnicodeUpgradeProgress
const&) =
delete;
62 UnicodeUpgradeProgress& operator=(UnicodeUpgradeProgress&&) =
delete;
65 ~UnicodeUpgradeProgress()
79 _units = std::move(units);
80 auto tables = std::size_t {};
81 auto columns = std::size_t {};
82 auto rows = std::uint64_t {};
83 for (
auto const& unit: _units)
84 for (auto const& table: unit)
87 columns += table.columns;
92 _parent.Log(ProgressTask::LogLevel::Info,
"No text columns to upgrade.");
98 ProgressTask::LogLevel::Info,
99 std::format(
"Would upgrade {} column(s) across {} table(s) in {} unit(s).", columns, tables, _units.size()));
102 _weightByRows = rows > 0;
103 _overall = _parent.BeginSubTask(OverallTitle, _weightByRows ? rows : tables);
107 void BeginUnit(std::size_t index)
110 auto const& unit = _units.at(index);
111 _unit = _overall->BeginSubTask(std::format(
"Unit {} of {}", index + 1, _units.size()), unit.size());
112 for (
auto const& table: unit)
113 _tables.push_back(_unit->BeginSubTask(table.name, table.rows));
117 void UnitStep(std::string_view detail)
119 for (
auto const& table: _tables)
120 table->Advance(0, detail);
124 void TableAltering(std::size_t tableIndex)
126 _runningTable = tableIndex;
127 _tables.at(tableIndex)->Advance(0, std::format(
"alter {} column(s)", _units.at(_unitIndex).at(tableIndex).columns));
131 void TableAltered(std::size_t tableIndex)
133 auto const& table = _units.at(_unitIndex).at(tableIndex);
134 _tables.at(tableIndex)->Advance(table.rows,
"done");
136 _overall->Advance(_weightByRows ? table.rows : 1);
137 _runningTable.reset();
143 _runningTable.reset();
151 void Failed(std::string_view reason)
155 _planning->Fail(reason);
159 _tables.at(*_runningTable)->Fail(reason);
163 _overall->Fail(reason);
167 [[nodiscard]]
bool IsCancellationRequested()
const
169 return _parent.IsCancellationRequested();
175 while (!_tables.empty())
179 ProgressTask& _parent;
180 std::unique_ptr<ProgressTask> _planning;
181 std::unique_ptr<ProgressTask> _overall;
182 std::unique_ptr<ProgressTask> _unit;
183 std::vector<std::unique_ptr<ProgressTask>> _tables;
184 std::vector<std::vector<UnicodeUpgradeTableProgress>> _units;
185 std::size_t _unitIndex = 0;
186 std::optional<std::size_t> _runningTable;
187 bool _weightByRows =
false;
193[[nodiscard]]
inline std::uint64_t RowCountForProgress(SqlConnection& connection,
194 SqlSchema::FullyQualifiedTableName
const& table)
198 auto const& formatter = connection.QueryFormatter();
199 auto stmt = SqlStatement { connection };
200 auto const estimate = formatter.TableRowCountEstimateQuery();
201 if (estimate.empty() || table.schema.empty())
203 auto const rows = stmt.ExecuteDirectScalar<std::int64_t>(
204 std::format(
"SELECT COUNT(*) FROM {}", formatter.QualifiedTableName(table.schema, table.table)));
205 return static_cast<std::uint64_t
>(std::max<std::int64_t>(rows.value_or(0), 0));
207 stmt.Prepare(estimate);
208 auto cursor = stmt.Execute(table.schema, table.table);
209 if (!cursor.FetchRow())
211 return static_cast<std::uint64_t
>(std::max<std::int64_t>(cursor.GetNullableColumn<std::int64_t>(1).value_or(0), 0));
213 catch (SqlException
const&)
@ DryRun
Report the plan and change nothing.