diff --git a/PHASE25-26-NOTES.md b/PHASE25-26-NOTES.md
new file mode 100644
index 0000000..aa54490
--- /dev/null
+++ b/PHASE25-26-NOTES.md
@@ -0,0 +1,14 @@
+# Phase 25–26 — Performance sampling and diagnostics
+
+- Samples the Slow Query Analysis, Connection Statistics, InnoDB Metrics, Dashboard, and Server Status screens on successful refresh.
+- `View Trends…` compares current and previous counter values, reporting changes per second when values are monotonic.
+- Tracks up to 60 snapshots per open administration screen in memory; `Clear Samples` removes them.
+- Slow-query snapshots compare execution counts by Performance Schema SQL digest text.
+- No new server privileges, schema modifications, third-party dependencies or external MySQL binaries.
+
+## Limitations
+- Samples are not persisted, and are discarded when the screen is closed.
+- Slow query analysis is limited to the top 100 digests returned by the existing SQL; digests dropping out of the top 100 will not be comparable.
+- For cumulative counters, server restarts or Performance Schema resets can invalidate deltas; negative deltas are suppressed.
+- A counter rate is not the same as query latency, and the SQL digest data may be truncated.
+- Not compiled with Xcode or tested on a live MySQL server in this environment.
diff --git a/WorkbenchReplacement/MainView.swift b/WorkbenchReplacement/MainView.swift
index 82bd9e2..fb92b0d 100644
--- a/WorkbenchReplacement/MainView.swift
+++ b/WorkbenchReplacement/MainView.swift
@@ -2211,6 +2211,14 @@ struct WorkbenchAdministrationView: View {
@State private var processActionError: String? = nil
@State private var processActionStatus: String? = nil
@State private var terminatingProcess = false
+ // Phase 25/26: bounded, in-session samples. No credentials or SQL persisted.
+ @State private var diagnosticSamples: [DiagnosticSample] = []
+ @State private var showingTrends = false
+
+ private var supportsTrends: Bool {
+ page == .slowQueries || page == .connectionStatistics ||
+ page == .innodbMetrics || page == .dashboard || page == .serverStatus
+ }
private var diagnosticGuidance: String? {
switch page {
@@ -2284,6 +2292,20 @@ struct WorkbenchAdministrationView: View {
.padding(.vertical, 8)
}
+ if supportsTrends && !diagnosticSamples.isEmpty {
+ HStack(spacing: 12) {
+ Label("\(diagnosticSamples.count) samples", systemImage: "chart.xyaxis.line")
+ .foregroundStyle(.secondary)
+ Button("View Trends…") { showingTrends = true }
+ Button("Clear Samples") { diagnosticSamples.removeAll() }
+ Spacer()
+ Text("Samples are kept in memory for this screen only")
+ .font(.caption).foregroundStyle(.secondary)
+ }
+ .padding(.horizontal, 16)
+ .padding(.vertical, 6)
+ }
+
if page == .clientConnections {
processControls
}
@@ -2361,6 +2383,9 @@ struct WorkbenchAdministrationView: View {
)
}
}
+ .sheet(isPresented: $showingTrends) {
+ WorkbenchDiagnosticTrendsView(page: page, samples: diagnosticSamples)
+ }
.sheet(isPresented: $showingGrants) {
VStack(alignment: .leading, spacing: 12) {
Text("Grants: \(selectedAccount ?? "")")
@@ -2626,6 +2651,12 @@ struct WorkbenchAdministrationView: View {
)
result = response
+ if supportsTrends {
+ diagnosticSamples.append(DiagnosticSample(at: Date(), columns: response.columns, rows: response.rows))
+ if diagnosticSamples.count > 60 {
+ diagnosticSamples.removeFirst(diagnosticSamples.count - 60)
+ }
+ }
if page == .clientConnections,
let selectedProcessID,
!processIDs.contains(selectedProcessID) {
@@ -4055,3 +4086,93 @@ private struct WorkbenchAccountManagerView: View {
}
}
}
+
+
+// MARK: - Phase 25/26: Live performance samples and counter rates
+
+private struct DiagnosticSample: Identifiable {
+ let id = UUID()
+ let at: Date
+ let columns: [String]
+ let rows: [[String]]
+}
+
+private struct WorkbenchDiagnosticTrendsView: View {
+ let page: WorkbenchAdminPage
+ let samples: [DiagnosticSample]
+ @Environment(\.dismiss) private var dismiss
+
+ private func metricMap(_ sample: DiagnosticSample) -> [String: Double] {
+ var values: [String: Double] = [:]
+ if page == .slowQueries {
+ guard let name = sample.columns.firstIndex(of: "DIGEST_TEXT"),
+ let count = sample.columns.firstIndex(of: "COUNT_STAR") else { return values }
+ for row in sample.rows where row.indices.contains(name) && row.indices.contains(count) {
+ if let value = Double(row[count]) { values[row[name]] = value }
+ }
+ } else {
+ for row in sample.rows where row.count >= 2 {
+ if let value = Double(row[1]) { values[row[0]] = value }
+ }
+ }
+ return values
+ }
+
+ private var comparisons: [(String, Double, Double, Double?)] {
+ guard let latest = samples.last else { return [] }
+ let current = metricMap(latest)
+ let prior = samples.count > 1 ? metricMap(samples[samples.count - 2]) : [:]
+ let seconds = samples.count > 1
+ ? latest.at.timeIntervalSince(samples[samples.count - 2].at) : 0
+ return current.keys.sorted().map { key in
+ let value = current[key] ?? 0
+ let before = prior[key] ?? value
+ let rate: Double? = seconds > 0 && prior[key] != nil && value >= before
+ ? (value - before) / seconds : nil
+ return (key, value, before, rate)
+ }
+ }
+
+ var body: some View {
+ VStack(alignment: .leading, spacing: 12) {
+ HStack {
+ Text("\(page.rawValue) — Trends").font(.title2.bold())
+ Spacer()
+ Button("Close") { dismiss() }
+ }
+ Text("\(samples.count) samples. Rates compare the two latest successful refreshes; cumulative counters can reset when MySQL restarts or statistics are cleared.")
+ .font(.caption).foregroundStyle(.secondary)
+ if samples.count < 2 {
+ ContentUnavailableView("More samples needed", systemImage: "chart.xyaxis.line",
+ description: Text("Refresh this screen twice, or enable auto-refresh."))
+ } else {
+ ScrollView {
+ LazyVStack(alignment: .leading, spacing: 8) {
+ HStack {
+ Text("Metric").frame(maxWidth: .infinity, alignment: .leading)
+ Text("Current").frame(width: 110, alignment: .trailing)
+ Text("Previous").frame(width: 110, alignment: .trailing)
+ Text("Change/sec").frame(width: 110, alignment: .trailing)
+ }.font(.headline)
+ Divider()
+ ForEach(comparisons.indices, id: \.self) { index in
+ let item = comparisons[index]
+ HStack {
+ Text(item.0).lineLimit(2).frame(maxWidth: .infinity, alignment: .leading)
+ Text(item.1.formatted()).frame(width: 110, alignment: .trailing)
+ Text(item.2.formatted()).frame(width: 110, alignment: .trailing)
+ Text(item.3.map { $0.formatted(.number.precision(.fractionLength(2))) } ?? "—")
+ .frame(width: 110, alignment: .trailing)
+ }.font(.system(.caption, design: .monospaced))
+ Divider()
+ }
+ }
+ }
+ }
+ Text("Query digest counts are grouped by SQL fingerprint. This is a sampled comparison, not a durable monitoring database.")
+ .font(.caption).foregroundStyle(.secondary)
+ }
+ .padding(20)
+ .frame(minWidth: 820, minHeight: 480)
+ }
+}
diff --git a/build/Build/Intermediates.noindex/WorkbenchReplacement.build/Debug/WorkbenchReplacement.build/Objects-normal/arm64/MainView.o b/build/Build/Intermediates.noindex/WorkbenchReplacement.build/Debug/WorkbenchReplacement.build/Objects-normal/arm64/MainView.o
index 730c3b2..3ad2e63 100644
Binary files a/build/Build/Intermediates.noindex/WorkbenchReplacement.build/Debug/WorkbenchReplacement.build/Objects-normal/arm64/MainView.o and b/build/Build/Intermediates.noindex/WorkbenchReplacement.build/Debug/WorkbenchReplacement.build/Objects-normal/arm64/MainView.o differ
diff --git a/build/Build/Intermediates.noindex/WorkbenchReplacement.build/Debug/WorkbenchReplacement.build/Objects-normal/arm64/MainView.stringsdata b/build/Build/Intermediates.noindex/WorkbenchReplacement.build/Debug/WorkbenchReplacement.build/Objects-normal/arm64/MainView.stringsdata
index fbc7baa..babd39b 100644
--- a/build/Build/Intermediates.noindex/WorkbenchReplacement.build/Debug/WorkbenchReplacement.build/Objects-normal/arm64/MainView.stringsdata
+++ b/build/Build/Intermediates.noindex/WorkbenchReplacement.build/Debug/WorkbenchReplacement.build/Objects-normal/arm64/MainView.stringsdata
@@ -719,7 +719,7 @@
"key": "Terminate MySQL session?",
"location": {
"startingColumn": 13,
- "startingLine": 2337
+ "startingLine": 2359
}
},
{
@@ -727,7 +727,7 @@
"key": "The server did not return any columns.",
"location": {
"startingColumn": 25,
- "startingLine": 2270
+ "startingLine": 2278
}
},
{
@@ -735,7 +735,7 @@
"key": "Loading %@…",
"location": {
"startingColumn": 30,
- "startingLine": 2248
+ "startingLine": 2256
}
},
{
@@ -743,7 +743,7 @@
"key": "No Data",
"location": {
"startingColumn": 21,
- "startingLine": 2267
+ "startingLine": 2275
}
},
{
@@ -751,7 +751,7 @@
"key": "Unable to Load %@",
"location": {
"startingColumn": 25,
- "startingLine": 2254
+ "startingLine": 2262
}
},
{
@@ -759,7 +759,39 @@
"key": "Retry",
"location": {
"startingColumn": 28,
- "startingLine": 2260
+ "startingLine": 2268
+ }
+ },
+ {
+ "comment": "",
+ "key": "Samples are kept in memory for this screen only",
+ "location": {
+ "startingColumn": 26,
+ "startingLine": 2302
+ }
+ },
+ {
+ "comment": "",
+ "key": "%lld samples",
+ "location": {
+ "startingColumn": 27,
+ "startingLine": 2297
+ }
+ },
+ {
+ "comment": "",
+ "key": "View Trends…",
+ "location": {
+ "startingColumn": 28,
+ "startingLine": 2299
+ }
+ },
+ {
+ "comment": "",
+ "key": "Clear Samples",
+ "location": {
+ "startingColumn": 28,
+ "startingLine": 2300
}
},
{
@@ -767,7 +799,7 @@
"key": "Changes require confirmation",
"location": {
"startingColumn": 26,
- "startingLine": 2314
+ "startingLine": 2336
}
},
{
@@ -775,7 +807,7 @@
"key": "Account",
"location": {
"startingColumn": 28,
- "startingLine": 2293
+ "startingLine": 2315
}
},
{
@@ -783,7 +815,7 @@
"key": "Show Grants",
"location": {
"startingColumn": 28,
- "startingLine": 2304
+ "startingLine": 2326
}
},
{
@@ -791,7 +823,7 @@
"key": "Manage Accounts…",
"location": {
"startingColumn": 28,
- "startingLine": 2308
+ "startingLine": 2330
}
},
{
@@ -799,7 +831,7 @@
"key": "Select account",
"location": {
"startingColumn": 30,
- "startingLine": 2294
+ "startingLine": 2316
}
},
{
@@ -807,7 +839,7 @@
"key": "%@@%@",
"location": {
"startingColumn": 38,
- "startingLine": 2298
+ "startingLine": 2320
}
},
{
@@ -815,7 +847,7 @@
"key": "%@ session %@",
"location": {
"startingColumn": 24,
- "startingLine": 2345
+ "startingLine": 2367
}
},
{
@@ -823,7 +855,7 @@
"key": "Cancel",
"location": {
"startingColumn": 20,
- "startingLine": 2350
+ "startingLine": 2372
}
},
{
@@ -831,7 +863,7 @@
"key": "This operation affects a live MySQL session. Terminating a connection can interrupt transactions and roll back uncommitted work. Verify the session ID before proceeding.",
"location": {
"startingColumn": 18,
- "startingLine": 2352
+ "startingLine": 2374
}
},
{
@@ -839,7 +871,7 @@
"key": "Grants: %@",
"location": {
"startingColumn": 22,
- "startingLine": 2366
+ "startingLine": 2391
}
},
{
@@ -847,7 +879,7 @@
"key": "Close",
"location": {
"startingColumn": 24,
- "startingLine": 2378
+ "startingLine": 2403
}
},
{
@@ -855,7 +887,7 @@
"key": "Requires PROCESS privilege to see other users' sessions and appropriate privileges to terminate them.",
"location": {
"startingColumn": 18,
- "startingLine": 2408
+ "startingLine": 2433
}
},
{
@@ -863,7 +895,7 @@
"key": "Session",
"location": {
"startingColumn": 24,
- "startingLine": 2388
+ "startingLine": 2413
}
},
{
@@ -871,7 +903,7 @@
"key": "Stop Query",
"location": {
"startingColumn": 24,
- "startingLine": 2395
+ "startingLine": 2420
}
},
{
@@ -879,7 +911,7 @@
"key": "Disconnect Session",
"location": {
"startingColumn": 24,
- "startingLine": 2397
+ "startingLine": 2422
}
},
{
@@ -887,7 +919,7 @@
"key": "Select a session",
"location": {
"startingColumn": 26,
- "startingLine": 2389
+ "startingLine": 2414
}
},
{
@@ -895,7 +927,7 @@
"key": "ID %@",
"location": {
"startingColumn": 30,
- "startingLine": 2391
+ "startingLine": 2416
}
},
{
@@ -903,7 +935,7 @@
"key": "Filter results",
"location": {
"startingColumn": 27,
- "startingLine": 2473
+ "startingLine": 2498
}
},
{
@@ -911,7 +943,7 @@
"key": "Auto-refresh",
"location": {
"startingColumn": 20,
- "startingLine": 2478
+ "startingLine": 2503
}
},
{
@@ -919,7 +951,7 @@
"key": "Refresh every five seconds",
"location": {
"startingColumn": 23,
- "startingLine": 2480
+ "startingLine": 2505
}
},
{
@@ -927,7 +959,7 @@
"key": "Refresh",
"location": {
"startingColumn": 23,
- "startingLine": 2485
+ "startingLine": 2510
}
},
{
@@ -935,7 +967,7 @@
"key": "SQL Editor",
"location": {
"startingColumn": 23,
- "startingLine": 2492
+ "startingLine": 2517
}
},
{
@@ -943,7 +975,7 @@
"key": "Not loaded",
"location": {
"startingColumn": 22,
- "startingLine": 2570
+ "startingLine": 2595
}
},
{
@@ -951,7 +983,7 @@
"key": "Updated %@",
"location": {
"startingColumn": 21,
- "startingLine": 2567
+ "startingLine": 2592
}
},
{
@@ -959,7 +991,7 @@
"key": "%lld rows",
"location": {
"startingColumn": 18,
- "startingLine": 2575
+ "startingLine": 2600
}
},
{
@@ -967,7 +999,7 @@
"key": "Import SQL into %@?",
"location": {
"startingColumn": 13,
- "startingLine": 2882
+ "startingLine": 2913
}
},
{
@@ -975,7 +1007,7 @@
"key": "Operation",
"location": {
"startingColumn": 20,
- "startingLine": 2685
+ "startingLine": 2716
}
},
{
@@ -983,7 +1015,7 @@
"key": "Data Export",
"location": {
"startingColumn": 22,
- "startingLine": 2686
+ "startingLine": 2717
}
},
{
@@ -991,7 +1023,7 @@
"key": "Data Import / Restore",
"location": {
"startingColumn": 22,
- "startingLine": 2687
+ "startingLine": 2718
}
},
{
@@ -999,7 +1031,7 @@
"key": "MySQL Connection",
"location": {
"startingColumn": 26,
- "startingLine": 2694
+ "startingLine": 2725
}
},
{
@@ -1007,7 +1039,7 @@
"key": "Export Options",
"location": {
"startingColumn": 30,
- "startingLine": 2718
+ "startingLine": 2749
}
},
{
@@ -1015,7 +1047,7 @@
"key": "Import Options",
"location": {
"startingColumn": 30,
- "startingLine": 2774
+ "startingLine": 2805
}
},
{
@@ -1023,7 +1055,7 @@
"key": "Progress",
"location": {
"startingColumn": 26,
- "startingLine": 2786
+ "startingLine": 2817
}
},
{
@@ -1031,7 +1063,7 @@
"key": "Connection",
"location": {
"startingColumn": 36,
- "startingLine": 2696
+ "startingLine": 2727
}
},
{
@@ -1039,7 +1071,7 @@
"key": "Database",
"location": {
"startingColumn": 28,
- "startingLine": 2700
+ "startingLine": 2731
}
},
{
@@ -1047,7 +1079,7 @@
"key": "Select Database",
"location": {
"startingColumn": 30,
- "startingLine": 2701
+ "startingLine": 2732
}
},
{
@@ -1055,7 +1087,7 @@
"key": "Refresh Databases",
"location": {
"startingColumn": 32,
- "startingLine": 2709
+ "startingLine": 2740
}
},
{
@@ -1063,7 +1095,7 @@
"key": "No tables found. Select a database or refresh the list.",
"location": {
"startingColumn": 34,
- "startingLine": 2740
+ "startingLine": 2771
}
},
{
@@ -1071,7 +1103,7 @@
"key": "InnoDB data is exported using a consistent snapshot and a single streamed query per table. Tables without unique indexes are supported.",
"location": {
"startingColumn": 30,
- "startingLine": 2769
+ "startingLine": 2800
}
},
{
@@ -1079,7 +1111,7 @@
"key": "Table structure",
"location": {
"startingColumn": 32,
- "startingLine": 2720
+ "startingLine": 2751
}
},
{
@@ -1087,7 +1119,7 @@
"key": "Table data",
"location": {
"startingColumn": 32,
- "startingLine": 2721
+ "startingLine": 2752
}
},
{
@@ -1095,7 +1127,7 @@
"key": "Add DROP TABLE IF EXISTS",
"location": {
"startingColumn": 32,
- "startingLine": 2722
+ "startingLine": 2753
}
},
{
@@ -1103,7 +1135,7 @@
"key": "Include views (definitions)",
"location": {
"startingColumn": 32,
- "startingLine": 2724
+ "startingLine": 2755
}
},
{
@@ -1111,7 +1143,7 @@
"key": "Include triggers",
"location": {
"startingColumn": 32,
- "startingLine": 2726
+ "startingLine": 2757
}
},
{
@@ -1119,7 +1151,7 @@
"key": "Include stored procedures and functions",
"location": {
"startingColumn": 32,
- "startingLine": 2728
+ "startingLine": 2759
}
},
{
@@ -1127,7 +1159,7 @@
"key": "Loading tables…",
"location": {
"startingColumn": 57,
- "startingLine": 2738
+ "startingLine": 2769
}
},
{
@@ -1135,7 +1167,7 @@
"key": "Tables (%lld selected)",
"location": {
"startingColumn": 34,
- "startingLine": 2731
+ "startingLine": 2762
}
},
{
@@ -1143,7 +1175,7 @@
"key": "All",
"location": {
"startingColumn": 36,
- "startingLine": 2733
+ "startingLine": 2764
}
},
{
@@ -1151,7 +1183,7 @@
"key": "None",
"location": {
"startingColumn": 36,
- "startingLine": 2734
+ "startingLine": 2765
}
},
{
@@ -1159,7 +1191,7 @@
"key": "Refresh",
"location": {
"startingColumn": 36,
- "startingLine": 2735
+ "startingLine": 2766
}
},
{
@@ -1167,7 +1199,7 @@
"key": "Views (%lld selected)",
"location": {
"startingColumn": 38,
- "startingLine": 2754
+ "startingLine": 2785
}
},
{
@@ -1175,7 +1207,7 @@
"key": "All",
"location": {
"startingColumn": 40,
- "startingLine": 2756
+ "startingLine": 2787
}
},
{
@@ -1183,7 +1215,7 @@
"key": "None",
"location": {
"startingColumn": 40,
- "startingLine": 2757
+ "startingLine": 2788
}
},
{
@@ -1191,7 +1223,7 @@
"key": "Import SQL statements into the selected database.",
"location": {
"startingColumn": 30,
- "startingLine": 2776
+ "startingLine": 2807
}
},
{
@@ -1199,7 +1231,7 @@
"key": "Supports MySQL DELIMITER directives, triggers and stored routines. Import is not transactional; use a verified backup before restoring.",
"location": {
"startingColumn": 30,
- "startingLine": 2779
+ "startingLine": 2810
}
},
{
@@ -1207,7 +1239,7 @@
"key": "Current table: %@ / %@ rows · Total exported: %@",
"location": {
"startingColumn": 30,
- "startingLine": 2803
+ "startingLine": 2834
}
},
{
@@ -1215,7 +1247,7 @@
"key": "Close",
"location": {
"startingColumn": 24,
- "startingLine": 2817
+ "startingLine": 2848
}
},
{
@@ -1223,7 +1255,7 @@
"key": "Verify Backup…",
"location": {
"startingColumn": 28,
- "startingLine": 2825
+ "startingLine": 2856
}
},
{
@@ -1231,7 +1263,7 @@
"key": "Verify an SQL file against its SHA-256 checksum sidecar",
"location": {
"startingColumn": 27,
- "startingLine": 2828
+ "startingLine": 2859
}
},
{
@@ -1239,7 +1271,7 @@
"key": "Verify Restored Database…",
"location": {
"startingColumn": 28,
- "startingLine": 2829
+ "startingLine": 2860
}
},
{
@@ -1247,7 +1279,7 @@
"key": "Compare restored table row counts and object names with the export manifest",
"location": {
"startingColumn": 27,
- "startingLine": 2833
+ "startingLine": 2864
}
},
{
@@ -1255,7 +1287,7 @@
"key": "Cancel",
"location": {
"startingColumn": 28,
- "startingLine": 2837
+ "startingLine": 2868
}
},
{
@@ -1263,7 +1295,7 @@
"key": "Export SQL…",
"location": {
"startingColumn": 31,
- "startingLine": 2844
+ "startingLine": 2875
}
},
{
@@ -1271,7 +1303,7 @@
"key": "Import SQL…",
"location": {
"startingColumn": 31,
- "startingLine": 2845
+ "startingLine": 2876
}
},
{
@@ -1279,7 +1311,7 @@
"key": "Import SQL",
"location": {
"startingColumn": 20,
- "startingLine": 2885
+ "startingLine": 2916
}
},
{
@@ -1287,7 +1319,7 @@
"key": "Cancel",
"location": {
"startingColumn": 20,
- "startingLine": 2893
+ "startingLine": 2924
}
},
{
@@ -1295,7 +1327,7 @@
"key": "SQL files can modify or delete existing database objects and data. Ensure you have a backup before continuing.",
"location": {
"startingColumn": 17,
- "startingLine": 2898
+ "startingLine": 2929
}
},
{
@@ -1303,7 +1335,7 @@
"key": "Database Import / Export",
"location": {
"startingColumn": 22,
- "startingLine": 2910
+ "startingLine": 2941
}
},
{
@@ -1311,7 +1343,7 @@
"key": "Built-in native MySQL database tools",
"location": {
"startingColumn": 22,
- "startingLine": 2913
+ "startingLine": 2944
}
},
{
@@ -1319,7 +1351,7 @@
"key": "Confirm %@",
"location": {
"startingColumn": 16,
- "startingLine": 3964
+ "startingLine": 3995
}
},
{
@@ -1327,7 +1359,7 @@
"key": "Manage MySQL Accounts",
"location": {
"startingColumn": 18,
- "startingLine": 3914
+ "startingLine": 3945
}
},
{
@@ -1335,7 +1367,7 @@
"key": "Account changes run on %@. Review the SQL before applying it.",
"location": {
"startingColumn": 18,
- "startingLine": 3915
+ "startingLine": 3946
}
},
{
@@ -1343,7 +1375,7 @@
"key": "Operation",
"location": {
"startingColumn": 24,
- "startingLine": 3918
+ "startingLine": 3949
}
},
{
@@ -1351,7 +1383,7 @@
"key": "Username",
"location": {
"startingColumn": 27,
- "startingLine": 3923
+ "startingLine": 3954
}
},
{
@@ -1359,7 +1391,7 @@
"key": "Host",
"location": {
"startingColumn": 27,
- "startingLine": 3925
+ "startingLine": 3956
}
},
{
@@ -1367,7 +1399,7 @@
"key": "Password",
"location": {
"startingColumn": 33,
- "startingLine": 3927
+ "startingLine": 3958
}
},
{
@@ -1375,7 +1407,7 @@
"key": "Database",
"location": {
"startingColumn": 31,
- "startingLine": 3930
+ "startingLine": 3961
}
},
{
@@ -1383,7 +1415,7 @@
"key": "Privilege",
"location": {
"startingColumn": 28,
- "startingLine": 3931
+ "startingLine": 3962
}
},
{
@@ -1391,7 +1423,7 @@
"key": "Close",
"location": {
"startingColumn": 24,
- "startingLine": 3946
+ "startingLine": 3977
}
},
{
@@ -1399,7 +1431,7 @@
"key": "Review SQL…",
"location": {
"startingColumn": 24,
- "startingLine": 3948
+ "startingLine": 3979
}
},
{
@@ -1407,7 +1439,7 @@
"key": "Cancel",
"location": {
"startingColumn": 20,
- "startingLine": 3965
+ "startingLine": 3996
}
},
{
@@ -1415,7 +1447,7 @@
"key": "Apply Change",
"location": {
"startingColumn": 20,
- "startingLine": 3966
+ "startingLine": 3997
}
},
{
@@ -1423,7 +1455,87 @@
"key": "Run this operation against %@?\n\n%@",
"location": {
"startingColumn": 18,
- "startingLine": 3971
+ "startingLine": 4002
+ }
+ },
+ {
+ "comment": "",
+ "key": "%lld samples. Rates compare the two latest successful refreshes; cumulative counters can reset when MySQL restarts or statistics are cleared.",
+ "location": {
+ "startingColumn": 18,
+ "startingLine": 4143
+ }
+ },
+ {
+ "comment": "",
+ "key": "Refresh this screen twice, or enable auto-refresh.",
+ "location": {
+ "startingColumn": 58,
+ "startingLine": 4147
+ }
+ },
+ {
+ "comment": "",
+ "key": "Query digest counts are grouped by SQL fingerprint. This is a sampled comparison, not a durable monitoring database.",
+ "location": {
+ "startingColumn": 18,
+ "startingLine": 4172
+ }
+ },
+ {
+ "comment": "",
+ "key": "More samples needed",
+ "location": {
+ "startingColumn": 40,
+ "startingLine": 4146
+ }
+ },
+ {
+ "comment": "",
+ "key": "%@ — Trends",
+ "location": {
+ "startingColumn": 22,
+ "startingLine": 4139
+ }
+ },
+ {
+ "comment": "",
+ "key": "Close",
+ "location": {
+ "startingColumn": 24,
+ "startingLine": 4141
+ }
+ },
+ {
+ "comment": "",
+ "key": "Metric",
+ "location": {
+ "startingColumn": 34,
+ "startingLine": 4152
+ }
+ },
+ {
+ "comment": "",
+ "key": "Current",
+ "location": {
+ "startingColumn": 34,
+ "startingLine": 4153
+ }
+ },
+ {
+ "comment": "",
+ "key": "Previous",
+ "location": {
+ "startingColumn": 34,
+ "startingLine": 4154
+ }
+ },
+ {
+ "comment": "",
+ "key": "Change/sec",
+ "location": {
+ "startingColumn": 34,
+ "startingLine": 4155
}
}
]
diff --git a/build/Build/Intermediates.noindex/WorkbenchReplacement.build/Debug/WorkbenchReplacement.build/Objects-normal/arm64/MainView.swiftdeps b/build/Build/Intermediates.noindex/WorkbenchReplacement.build/Debug/WorkbenchReplacement.build/Objects-normal/arm64/MainView.swiftdeps
index 7904cfd..2796245 100644
Binary files a/build/Build/Intermediates.noindex/WorkbenchReplacement.build/Debug/WorkbenchReplacement.build/Objects-normal/arm64/MainView.swiftdeps and b/build/Build/Intermediates.noindex/WorkbenchReplacement.build/Debug/WorkbenchReplacement.build/Objects-normal/arm64/MainView.swiftdeps differ
diff --git a/build/Build/Intermediates.noindex/WorkbenchReplacement.build/Debug/WorkbenchReplacement.build/Objects-normal/arm64/WorkbenchReplacement-primary.priors b/build/Build/Intermediates.noindex/WorkbenchReplacement.build/Debug/WorkbenchReplacement.build/Objects-normal/arm64/WorkbenchReplacement-primary.priors
index 4e23019..a4eab7b 100644
Binary files a/build/Build/Intermediates.noindex/WorkbenchReplacement.build/Debug/WorkbenchReplacement.build/Objects-normal/arm64/WorkbenchReplacement-primary.priors and b/build/Build/Intermediates.noindex/WorkbenchReplacement.build/Debug/WorkbenchReplacement.build/Objects-normal/arm64/WorkbenchReplacement-primary.priors differ
diff --git a/build/Build/Intermediates.noindex/WorkbenchReplacement.build/Debug/WorkbenchReplacement.build/Objects-normal/arm64/WorkbenchReplacement.swiftmodule b/build/Build/Intermediates.noindex/WorkbenchReplacement.build/Debug/WorkbenchReplacement.build/Objects-normal/arm64/WorkbenchReplacement.swiftmodule
index 5690d6b..34b656c 100644
Binary files a/build/Build/Intermediates.noindex/WorkbenchReplacement.build/Debug/WorkbenchReplacement.build/Objects-normal/arm64/WorkbenchReplacement.swiftmodule and b/build/Build/Intermediates.noindex/WorkbenchReplacement.build/Debug/WorkbenchReplacement.build/Objects-normal/arm64/WorkbenchReplacement.swiftmodule differ
diff --git a/build/Build/Intermediates.noindex/WorkbenchReplacement.build/Debug/WorkbenchReplacement.build/Objects-normal/arm64/WorkbenchReplacement.swiftsourceinfo b/build/Build/Intermediates.noindex/WorkbenchReplacement.build/Debug/WorkbenchReplacement.build/Objects-normal/arm64/WorkbenchReplacement.swiftsourceinfo
index 0b56cdc..e066dc1 100644
Binary files a/build/Build/Intermediates.noindex/WorkbenchReplacement.build/Debug/WorkbenchReplacement.build/Objects-normal/arm64/WorkbenchReplacement.swiftsourceinfo and b/build/Build/Intermediates.noindex/WorkbenchReplacement.build/Debug/WorkbenchReplacement.build/Objects-normal/arm64/WorkbenchReplacement.swiftsourceinfo differ
diff --git a/build/Build/Intermediates.noindex/XCBuildData/build.db b/build/Build/Intermediates.noindex/XCBuildData/build.db
index ae994cc..4716024 100644
Binary files a/build/Build/Intermediates.noindex/XCBuildData/build.db and b/build/Build/Intermediates.noindex/XCBuildData/build.db differ
diff --git a/build/Build/Intermediates.noindex/XCBuildData/registered-launchservices.txt b/build/Build/Intermediates.noindex/XCBuildData/registered-launchservices.txt
index 1dd82f4..6addbb6 100644
--- a/build/Build/Intermediates.noindex/XCBuildData/registered-launchservices.txt
+++ b/build/Build/Intermediates.noindex/XCBuildData/registered-launchservices.txt
@@ -30,3 +30,4 @@
/Volumes/Developer/Applications/WorkbenchReplacement/build/Build/Products/Debug/WorkbenchReplacement.app
/Volumes/Developer/Applications/WorkbenchReplacement/build/Build/Products/Debug/WorkbenchReplacement.app
/Volumes/Developer/Applications/WorkbenchReplacement/build/Build/Products/Debug/WorkbenchReplacement.app
+/Volumes/Developer/Applications/WorkbenchReplacement/build/Build/Products/Debug/WorkbenchReplacement.app
diff --git a/build/Build/Products/Debug/WorkbenchReplacement.app/Contents/MacOS/WorkbenchReplacement b/build/Build/Products/Debug/WorkbenchReplacement.app/Contents/MacOS/WorkbenchReplacement
index cf38929..28cb370 100755
Binary files a/build/Build/Products/Debug/WorkbenchReplacement.app/Contents/MacOS/WorkbenchReplacement and b/build/Build/Products/Debug/WorkbenchReplacement.app/Contents/MacOS/WorkbenchReplacement differ
diff --git a/build/Build/Products/Debug/WorkbenchReplacement.app/Contents/MacOS/WorkbenchReplacement.debug.dylib b/build/Build/Products/Debug/WorkbenchReplacement.app/Contents/MacOS/WorkbenchReplacement.debug.dylib
index e3f65ca..dbbdca6 100755
Binary files a/build/Build/Products/Debug/WorkbenchReplacement.app/Contents/MacOS/WorkbenchReplacement.debug.dylib and b/build/Build/Products/Debug/WorkbenchReplacement.app/Contents/MacOS/WorkbenchReplacement.debug.dylib differ
diff --git a/build/Build/Products/Debug/WorkbenchReplacement.app/Contents/MacOS/__preview.dylib b/build/Build/Products/Debug/WorkbenchReplacement.app/Contents/MacOS/__preview.dylib
index 8560fd8..738f882 100755
Binary files a/build/Build/Products/Debug/WorkbenchReplacement.app/Contents/MacOS/__preview.dylib and b/build/Build/Products/Debug/WorkbenchReplacement.app/Contents/MacOS/__preview.dylib differ
diff --git a/build/Build/Products/Debug/WorkbenchReplacement.app/Contents/_CodeSignature/CodeResources b/build/Build/Products/Debug/WorkbenchReplacement.app/Contents/_CodeSignature/CodeResources
index 9e990a2..68311f8 100644
--- a/build/Build/Products/Debug/WorkbenchReplacement.app/Contents/_CodeSignature/CodeResources
+++ b/build/Build/Products/Debug/WorkbenchReplacement.app/Contents/_CodeSignature/CodeResources
@@ -19,7 +19,7 @@
cdhash
- s+RLc8/qmsHJTbP/vbm0kuQhxbA=
+ Fuz3gDgwkgMS+lEzJ6OSoxSzPqo=
requirement
identifier "WorkbenchReplacement.debug" and anchor apple generic and certificate leaf[subject.CN] = "Apple Development: Mark Gregory (FLBRJ3BYDD)" and certificate 1[field.1.2.840.113635.100.6.2.1] /* exists */
diff --git a/build/Build/Products/Debug/WorkbenchReplacement.swiftmodule/Project/arm64-apple-macos.swiftsourceinfo b/build/Build/Products/Debug/WorkbenchReplacement.swiftmodule/Project/arm64-apple-macos.swiftsourceinfo
index 0b56cdc..e066dc1 100644
Binary files a/build/Build/Products/Debug/WorkbenchReplacement.swiftmodule/Project/arm64-apple-macos.swiftsourceinfo and b/build/Build/Products/Debug/WorkbenchReplacement.swiftmodule/Project/arm64-apple-macos.swiftsourceinfo differ
diff --git a/build/Build/Products/Debug/WorkbenchReplacement.swiftmodule/arm64-apple-macos.swiftmodule b/build/Build/Products/Debug/WorkbenchReplacement.swiftmodule/arm64-apple-macos.swiftmodule
index 5690d6b..34b656c 100644
Binary files a/build/Build/Products/Debug/WorkbenchReplacement.swiftmodule/arm64-apple-macos.swiftmodule and b/build/Build/Products/Debug/WorkbenchReplacement.swiftmodule/arm64-apple-macos.swiftmodule differ
diff --git a/build/Index.noindex/DataStore/v5/units/MainView.o-CNVK7PE7JUX3 b/build/Index.noindex/DataStore/v5/units/MainView.o-CNVK7PE7JUX3
index c229536..277b5ce 100644
Binary files a/build/Index.noindex/DataStore/v5/units/MainView.o-CNVK7PE7JUX3 and b/build/Index.noindex/DataStore/v5/units/MainView.o-CNVK7PE7JUX3 differ
diff --git a/build/Logs/Build/LogStoreManifest.plist b/build/Logs/Build/LogStoreManifest.plist
index facb46a..689f1f8 100644
--- a/build/Logs/Build/LogStoreManifest.plist
+++ b/build/Logs/Build/LogStoreManifest.plist
@@ -6,48 +6,6 @@
13
logs
- 0D84D8B7-4EBD-46B6-9E1E-5318CA005DB1
-
- className
- IDECommandLineBuildLog
- documentTypeString
- <nil>
- domainType
- Xcode.IDEActivityLogDomainType.BuildLog
- fileName
- 0D84D8B7-4EBD-46B6-9E1E-5318CA005DB1.xcactivitylog
- hasPrimaryLog
-
- primaryObservable
-
- highLevelStatus
- S
- totalNumberOfAnalyzerIssues
- 0
- totalNumberOfErrors
- 0
- totalNumberOfTestFailures
- 0
- totalNumberOfWarnings
- 0
-
- schemeIdentifier-containerName
- WorkbenchReplacement project
- schemeIdentifier-schemeName
- WorkbenchReplacement
- schemeIdentifier-sharedScheme
- 1
- signature
- Building project WorkbenchReplacement with scheme WorkbenchReplacement and configuration Debug
- timeStartedRecording
- 813880069.98529804
- timeStoppedRecording
- 813880086.21717203
- title
- Building project WorkbenchReplacement with scheme WorkbenchReplacement and configuration Debug
- uniqueIdentifier
- 0D84D8B7-4EBD-46B6-9E1E-5318CA005DB1
-
64DBE2F7-41EB-44D3-A0AB-CCC5468F4E72
className
@@ -90,7 +48,7 @@
uniqueIdentifier
64DBE2F7-41EB-44D3-A0AB-CCC5468F4E72
- 9B404BEF-D5CC-4B4B-93CF-3A0C95C748D2
+ F4C8C8BA-B9A7-46F3-8FF6-180215A4D5E4
className
IDECommandLineBuildLog
@@ -99,7 +57,7 @@
domainType
Xcode.IDEActivityLogDomainType.BuildLog
fileName
- 9B404BEF-D5CC-4B4B-93CF-3A0C95C748D2.xcactivitylog
+ F4C8C8BA-B9A7-46F3-8FF6-180215A4D5E4.xcactivitylog
hasPrimaryLog
primaryObservable
@@ -124,55 +82,13 @@
signature
Building project WorkbenchReplacement with scheme WorkbenchReplacement and configuration Debug
timeStartedRecording
- 813879702.54720795
+ 813918930.91679394
timeStoppedRecording
- 813879718.93544304
+ 813918948.64702797
title
Building project WorkbenchReplacement with scheme WorkbenchReplacement and configuration Debug
uniqueIdentifier
- 9B404BEF-D5CC-4B4B-93CF-3A0C95C748D2
-
- FE752EBA-0994-486D-9A0C-1DA5C49E3451
-
- className
- IDECommandLineBuildLog
- documentTypeString
- <nil>
- domainType
- Xcode.IDEActivityLogDomainType.BuildLog
- fileName
- FE752EBA-0994-486D-9A0C-1DA5C49E3451.xcactivitylog
- hasPrimaryLog
-
- primaryObservable
-
- highLevelStatus
- S
- totalNumberOfAnalyzerIssues
- 0
- totalNumberOfErrors
- 0
- totalNumberOfTestFailures
- 0
- totalNumberOfWarnings
- 0
-
- schemeIdentifier-containerName
- WorkbenchReplacement project
- schemeIdentifier-schemeName
- WorkbenchReplacement
- schemeIdentifier-sharedScheme
- 1
- signature
- Building project WorkbenchReplacement with scheme WorkbenchReplacement and configuration Debug
- timeStartedRecording
- 813879926.65620303
- timeStoppedRecording
- 813879942.82261503
- title
- Building project WorkbenchReplacement with scheme WorkbenchReplacement and configuration Debug
- uniqueIdentifier
- FE752EBA-0994-486D-9A0C-1DA5C49E3451
+ F4C8C8BA-B9A7-46F3-8FF6-180215A4D5E4
diff --git a/build/ModuleCache.noindex/Session.modulevalidation b/build/ModuleCache.noindex/Session.modulevalidation
index 529aeff..aa50651 100644
--- a/build/ModuleCache.noindex/Session.modulevalidation
+++ b/build/ModuleCache.noindex/Session.modulevalidation
@@ -1 +1 @@
-1792187454.770874: Module build session file for module cache at Path(str: "/Volumes/Developer/Applications/WorkbenchReplacement/build/ModuleCache.noindex")
+1792226131.7427912: Module build session file for module cache at Path(str: "/Volumes/Developer/Applications/WorkbenchReplacement/build/ModuleCache.noindex")
diff --git a/build/SDKStatCaches.noindex/macosx27.0-26A425-e829b21a6f8c9b70876ba0858053c0447231f6df4def33e022ae2eb8f782df1a.sdkstatcache b/build/SDKStatCaches.noindex/macosx27.0-26A425-e829b21a6f8c9b70876ba0858053c0447231f6df4def33e022ae2eb8f782df1a.sdkstatcache
index 9b8e1f6..e06d269 100644
Binary files a/build/SDKStatCaches.noindex/macosx27.0-26A425-e829b21a6f8c9b70876ba0858053c0447231f6df4def33e022ae2eb8f782df1a.sdkstatcache and b/build/SDKStatCaches.noindex/macosx27.0-26A425-e829b21a6f8c9b70876ba0858053c0447231f6df4def33e022ae2eb8f782df1a.sdkstatcache differ
diff --git a/build/info.plist b/build/info.plist
index 90f17fa..eebbe38 100644
--- a/build/info.plist
+++ b/build/info.plist
@@ -3,7 +3,7 @@
LastAccessedDate
- 2026-10-16T21:50:54Z
+ 2026-10-17T08:35:31Z
WorkspacePath
/Volumes/Developer/Applications/WorkbenchReplacement/WorkbenchReplacement.xcodeproj