From 2e7c32c8934be6a6ecdf0f1b014c8ae26fe53f1c Mon Sep 17 00:00:00 2001 From: Evgeny Date: Sun, 19 Jul 2026 11:16:26 +0300 Subject: [PATCH] fix(db): use INSERT ... ON CONFLICT instead of INSERT OR REPLACE for nodes table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit INSERT OR REPLACE deletes the old row and inserts a new one, resetting unspecified columns (online, update_ts) to DEFAULT 0. This was wiping online=1 set by cs_on_peer_status_changed/member_sync_set_online. Replaced 5 INSERT OR REPLACE INTO nodes with INSERT INTO ... ON CONFLICT DO UPDATE SET — only updates the specified columns, preserving online status. Files: - chat_core.c:638 (invite flow) - chat_sync.c:1045 (CHANNEL_INFO_RESP), 1193 (JOIN), 1449 (PEER_UPSERT) - topo_node_sqlite.c:121 (BGP node_put) --- src/topo_node_sqlite.c | 8 ++++++-- tools/chatgui/transport/chat_core.c | 2 +- tools/chatgui/transport/chat_sync.c | 18 +++++++++++++++--- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/topo_node_sqlite.c b/src/topo_node_sqlite.c index 6baac6ff..5f886ecb 100644 --- a/src/topo_node_sqlite.c +++ b/src/topo_node_sqlite.c @@ -118,8 +118,12 @@ int topo_node_sqlite_node_put(sqlite3* db, struct TOPO_NODEQ* nq) { sqlite3_stmt* stmt = NULL; if (sqlite3_prepare_v2(db, - "INSERT OR REPLACE INTO nodes(node_id, name, x25519_pubkey, ed25519_pubkey, last_seen_at)" - " VALUES(?,?,?,?,unixepoch())", -1, &stmt, NULL) == SQLITE_OK) { + "INSERT INTO nodes(node_id, name, x25519_pubkey, ed25519_pubkey, last_seen_at)" + " VALUES(?,?,?,?,unixepoch())" + " ON CONFLICT(node_id) DO UPDATE SET" + " name=excluded.name, x25519_pubkey=excluded.x25519_pubkey," + " ed25519_pubkey=excluded.ed25519_pubkey, last_seen_at=excluded.last_seen_at", + -1, &stmt, NULL) == SQLITE_OK) { sqlite3_bind_int64(stmt, 1, (sqlite3_int64)ni->node_id); sqlite3_bind_text(stmt, 2, ni->node_name ? ni->node_name : "", -1, SQLITE_STATIC); sqlite3_bind_blob(stmt, 3, ni->public_key, 32, SQLITE_STATIC); diff --git a/tools/chatgui/transport/chat_core.c b/tools/chatgui/transport/chat_core.c index 1170d7a7..f12fe872 100644 --- a/tools/chatgui/transport/chat_core.c +++ b/tools/chatgui/transport/chat_core.c @@ -635,7 +635,7 @@ void chat_core_connect_from_invite(struct chat_invite* inv) { /* save pubkey to nodes table */ sqlite3_stmt* st = NULL; if (sqlite3_prepare_v2(g_cc.db, - "INSERT OR REPLACE INTO nodes(node_id, x25519_pubkey) VALUES(?,?)", + "INSERT INTO nodes(node_id, x25519_pubkey) VALUES(?,?) ON CONFLICT(node_id) DO UPDATE SET x25519_pubkey=excluded.x25519_pubkey", -1, &st, NULL) == SQLITE_OK) { sqlite3_bind_int64(st, 1, (sqlite3_int64)node_id); sqlite3_bind_blob(st, 2, inv->pubkey, 32, SQLITE_STATIC); diff --git a/tools/chatgui/transport/chat_sync.c b/tools/chatgui/transport/chat_sync.c index dd81c8ae..6c4b26a5 100644 --- a/tools/chatgui/transport/chat_sync.c +++ b/tools/chatgui/transport/chat_sync.c @@ -1042,7 +1042,11 @@ static void cs_handle_channel_info_resp(struct chat_sync* cs, uint64_t peer, sqlite3* vdb = cs->inst->topo_sqlite_db; if (vdb && inv_name[0]) { sqlite3_stmt* ns = NULL; - sqlite3_prepare_v2(vdb, "INSERT OR REPLACE INTO nodes(node_id,name,x25519_pubkey,ed25519_pubkey) VALUES(?,?,?,?)", -1, &ns, NULL); + sqlite3_prepare_v2(vdb, + "INSERT INTO nodes(node_id,name,x25519_pubkey,ed25519_pubkey) VALUES(?,?,?,?)" + " ON CONFLICT(node_id) DO UPDATE SET" + " name=excluded.name, x25519_pubkey=excluded.x25519_pubkey, ed25519_pubkey=excluded.ed25519_pubkey", + -1, &ns, NULL); if (ns) { sqlite3_bind_int64(ns, 1, (sqlite3_int64)peer); sqlite3_bind_text(ns, 2, inv_name, -1, SQLITE_STATIC); sqlite3_bind_blob(ns, 3, inv_x25519, 32, SQLITE_STATIC); @@ -1190,7 +1194,11 @@ static void cs_handle_channel_join(struct chat_sync* cs, uint64_t peer, /* save joiner node_info to local DB */ if (db && joiner_name[0]) { sqlite3_stmt* ns = NULL; - sqlite3_prepare_v2(db, "INSERT OR REPLACE INTO nodes(node_id,name,x25519_pubkey,ed25519_pubkey) VALUES(?,?,?,?)", -1, &ns, NULL); + sqlite3_prepare_v2(db, + "INSERT INTO nodes(node_id,name,x25519_pubkey,ed25519_pubkey) VALUES(?,?,?,?)" + " ON CONFLICT(node_id) DO UPDATE SET" + " name=excluded.name, x25519_pubkey=excluded.x25519_pubkey, ed25519_pubkey=excluded.ed25519_pubkey", + -1, &ns, NULL); if (ns) { sqlite3_bind_int64(ns, 1, (sqlite3_int64)node_id); sqlite3_bind_text(ns, 2, joiner_name, -1, SQLITE_STATIC); sqlite3_bind_blob(ns, 3, x25519, 32, SQLITE_STATIC); @@ -1446,7 +1454,11 @@ static void cs_handle_peer_upsert(struct chat_sync* cs, uint64_t peer, topo_node_sqlite_node_update_verified(db, node_id, peer_name, x25519, ed_pub, join_ts); if (db && peer_name[0]) { sqlite3_stmt* ns = NULL; - sqlite3_prepare_v2(db, "INSERT OR REPLACE INTO nodes(node_id,name,x25519_pubkey,ed25519_pubkey) VALUES(?,?,?,?)", -1, &ns, NULL); + sqlite3_prepare_v2(db, + "INSERT INTO nodes(node_id,name,x25519_pubkey,ed25519_pubkey) VALUES(?,?,?,?)" + " ON CONFLICT(node_id) DO UPDATE SET" + " name=excluded.name, x25519_pubkey=excluded.x25519_pubkey, ed25519_pubkey=excluded.ed25519_pubkey", + -1, &ns, NULL); if (ns) { sqlite3_bind_int64(ns, 1, (sqlite3_int64)node_id); sqlite3_bind_text(ns, 2, peer_name, -1, SQLITE_STATIC); sqlite3_bind_blob(ns, 3, x25519, 32, SQLITE_STATIC);