mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-05-31 10:14:15 +00:00
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
This commit is contained in:
parent
df777c12d3
commit
8a28373a01
2 changed files with 15 additions and 10 deletions
|
|
@ -12,15 +12,17 @@ func JSONClientsFromInbound() string {
|
||||||
return "FROM inbounds, JSON_EACH(JSON_EXTRACT(inbounds.settings, '$.clients')) AS client"
|
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 {
|
func JSONFieldText(expr, key string) string {
|
||||||
if IsPostgres() {
|
if IsPostgres() {
|
||||||
return fmt.Sprintf("(%s ->> '%s')", expr, key)
|
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)
|
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)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1503,10 +1503,13 @@ func (s *InboundService) setRemoteTrafficLocked(nodeID int, snap *runtime.Traffi
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := tx.Exec(
|
if err := tx.Exec(
|
||||||
|
fmt.Sprintf(
|
||||||
`UPDATE client_traffics
|
`UPDATE client_traffics
|
||||||
SET up = ?, down = ?, enable = ?, total = ?, expiry_time = ?, reset = ?,
|
SET up = ?, down = ?, enable = ?, total = ?, expiry_time = ?, reset = ?,
|
||||||
last_online = MAX(last_online, ?)
|
last_online = %s
|
||||||
WHERE email = ?`,
|
WHERE email = ?`,
|
||||||
|
database.GreatestExpr("last_online", "?"),
|
||||||
|
),
|
||||||
cs.Up, cs.Down, cs.Enable, cs.Total, cs.ExpiryTime, cs.Reset,
|
cs.Up, cs.Down, cs.Enable, cs.Total, cs.ExpiryTime, cs.Reset,
|
||||||
cs.LastOnline, cs.Email,
|
cs.LastOnline, cs.Email,
|
||||||
).Error; err != nil {
|
).Error; err != nil {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue