Переглянути джерело

fix(nodes): use GREATEST for last_online merge on PostgreSQL

setRemoteTrafficLocked merged last_online with MAX(last_online, ?), which
is SQLite's two-argument scalar max. PostgreSQL's MAX() is aggregate-only,
so node traffic sync failed every cycle with "function max(bigint, unknown)
does not exist (SQLSTATE 42883)", flooding the logs.

Add a dialect-aware database.GreatestExpr helper (GREATEST on Postgres,
MAX on SQLite) and use it for the last_online merge. last_online is a
non-null int64, so the two functions are semantically identical here.

Closes #4633
MHSanaei 18 годин тому
батько
коміт
8a28373a01
2 змінених файлів з 15 додано та 10 видалено
  1. 8 6
      database/dialect.go
  2. 7 4
      web/service/inbound.go

+ 8 - 6
database/dialect.go

@@ -12,15 +12,17 @@ func JSONClientsFromInbound() string {
 	return "FROM inbounds, JSON_EACH(JSON_EXTRACT(inbounds.settings, '$.clients')) AS client"
 }
 
-// JSONFieldText returns a SQL expression that extracts the textual value of <key>
-// from a JSON expression. On both backends the result is the raw (unquoted) string,
-// so callers do NOT need to trim surrounding quotes.
 func JSONFieldText(expr, key string) string {
 	if IsPostgres() {
 		return fmt.Sprintf("(%s ->> '%s')", expr, key)
 	}
-	// SQLite's JSON_EXTRACT on a text value returns the JSON-encoded form
-	// (with surrounding quotes). Wrap it in json_extract(json_quote(...)) trick
-	// is fragile; simpler: unwrap quotes with TRIM(BOTH '"').
+
 	return fmt.Sprintf("TRIM(JSON_EXTRACT(%s, '$.%s'), '\"')", expr, key)
 }
+
+func GreatestExpr(a, b string) string {
+	if IsPostgres() {
+		return fmt.Sprintf("GREATEST(%s, %s)", a, b)
+	}
+	return fmt.Sprintf("MAX(%s, %s)", a, b)
+}

+ 7 - 4
web/service/inbound.go

@@ -1503,10 +1503,13 @@ func (s *InboundService) setRemoteTrafficLocked(nodeID int, snap *runtime.Traffi
 			}
 
 			if err := tx.Exec(
-				`UPDATE client_traffics
-				 SET up = ?, down = ?, enable = ?, total = ?, expiry_time = ?, reset = ?,
-				     last_online = MAX(last_online, ?)
-				 WHERE email = ?`,
+				fmt.Sprintf(
+					`UPDATE client_traffics
+					 SET up = ?, down = ?, enable = ?, total = ?, expiry_time = ?, reset = ?,
+					     last_online = %s
+					 WHERE email = ?`,
+					database.GreatestExpr("last_online", "?"),
+				),
 				cs.Up, cs.Down, cs.Enable, cs.Total, cs.ExpiryTime, cs.Reset,
 				cs.LastOnline, cs.Email,
 			).Error; err != nil {