From 60912c882d3d085fc73732116b5daecfeec120af Mon Sep 17 00:00:00 2001 From: jim Date: Wed, 29 Jul 2026 16:26:08 -0500 Subject: [PATCH] fix: stop AddAPICount from throwing on missing DateCreated column The INSERT named a DateCreated column that DailyAPICount (Date, APICount) never had, so every call threw "no such column: DateCreated" into an empty catch block. Today's row was never created and the tally sat idle since 2026-04-13. Drop the column from the INSERT, and report the three silent failure points (insert error, missing row after insert, update matching zero rows) instead of swallowing them. --- URLNotesGrabberCORE/DataAccess.cs | 46 +++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/URLNotesGrabberCORE/DataAccess.cs b/URLNotesGrabberCORE/DataAccess.cs index ed1ffc4..9c479bf 100644 --- a/URLNotesGrabberCORE/DataAccess.cs +++ b/URLNotesGrabberCORE/DataAccess.cs @@ -80,6 +80,10 @@ namespace URLNotesGrabberCORE private static SQLiteConnection? _importConnection; private static HashSet? _importBlogCache; private static readonly object _importSessionLock = new object(); + // AddAPICount/UpdateAPICount run once per API call. A schema-level failure there repeats + // identically every time, so log each distinct message once instead of per call. + private static readonly HashSet _apiCountFailuresLogged = new HashSet(); + private static readonly object _apiCountFailureLock = new object(); static DataAccess() { @@ -566,21 +570,40 @@ namespace URLNotesGrabberCORE // Use INSERT OR IGNORE to avoid UNIQUE constraint errors when the date row already exists. // Also explicitly initialize APICount to 0 in case the table has no default. - string sql = "INSERT OR IGNORE INTO DailyAPICount (Date, APICount, DateCreated) values(@date, 0, @DateCreated)"; + // + // DailyAPICount is (Date TEXT PK, APICount INTEGER) — the crawler never creates or + // migrates this table, and no code reads a creation timestamp off it, so the insert + // names only those two columns. Naming a DateCreated column here used to throw + // "no such column: DateCreated" into a silent catch, which meant the day's row was + // never created and the tally sat at 0 for months. + string sql = "INSERT OR IGNORE INTO DailyAPICount (Date, APICount) values(@date, 0)"; using (SQLiteCommand command = new SQLiteCommand(sql, connection)) { command.Parameters.AddWithValue("@date", DateTime.Today.ToShortDateString()); - command.Parameters.AddWithValue("@DateCreated", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); command.ExecuteNonQuery(); } } catch (Exception ex) { // Breakpoint here - //Console.WriteLine(ex.Message); + ReportAPICountFailure($"Error creating the row for {DateTime.Today.ToShortDateString()}: {ex.Message}"); } } + // Bookkeeping writes that fail identically on every API call would flood the console, but + // swallowing them entirely is what hid the DateCreated bug. Log each distinct message once. + // Messages embed today's date, so a date rollover reports afresh. + private static void ReportAPICountFailure(string message) + { + lock (_apiCountFailureLock) + { + if (!_apiCountFailuresLogged.Add(message)) + return; + } + + Console.WriteLine($"[DailyAPICount] {message}"); + } + public static bool AddNote(string rootBlogName, string noteBlogName, long postID, long timestamp, string type, string? DBPath = null) { DBPath ??= GetDefaultDbPath(); @@ -993,7 +1016,9 @@ namespace URLNotesGrabberCORE using SQLiteConnection connection = new SQLiteConnection("Data Source=" + DBPath); int count = 0; - try { AddAPICount(); } catch { } + // AddAPICount reports its own failures; this guard only stops a connection-level + // problem from taking down the read below. + try { AddAPICount(); } catch (Exception ex) { ReportAPICountFailure($"AddAPICount failed: {ex.Message}"); } try { @@ -1001,6 +1026,7 @@ namespace URLNotesGrabberCORE string sql = "SELECT APICount FROM DailyAPICount WHERE [Date] = @date"; + bool rowFound = false; using (SQLiteCommand command = new SQLiteCommand(sql, connection)) { command.Parameters.AddWithValue("@date", DateTime.Today.ToShortDateString()); @@ -1008,10 +1034,16 @@ namespace URLNotesGrabberCORE { while (reader.Read()) { + rowFound = true; count = reader.GetInt32(0); // Assuming Id is the first column } } } + + // A missing row means AddAPICount did not take. Returning a silent 0 here is what + // made the tally look merely idle rather than broken. + if (!rowFound) + ReportAPICountFailure($"No row for {DateTime.Today.ToShortDateString()} after AddAPICount - reported count of 0 is not a real tally."); } catch (Exception ex) { @@ -1654,7 +1686,11 @@ namespace URLNotesGrabberCORE { command.Parameters.AddWithValue("@APICount", APICount); command.Parameters.AddWithValue("@date", DateTime.Today.ToShortDateString()); - command.ExecuteNonQuery(); + + // No row for today means this UPDATE matched nothing and the increment was + // thrown away, while the value returned below still looks like a real count. + if (command.ExecuteNonQuery() == 0) + ReportAPICountFailure($"UPDATE matched no row for {DateTime.Today.ToShortDateString()} - the count of {APICount} was not persisted."); } } catch (Exception ex)