fix: MariaDB JSON_EACH compatibility for subscription and traffic queries

Replace SQLite-only JSON_EACH with DB-type branching (JSON_TABLE for
MariaDB) in subscription, client traffic, and migration queries.
Bump version to v1.5.1.
This commit is contained in:
root 2026-04-24 10:16:48 +08:00
parent eca9b219cf
commit 1a02ebb024
3 changed files with 76 additions and 25 deletions

View file

@ -1 +1 @@
v1.4.6-beta
v1.5.1

View file

@ -11,6 +11,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/goccy/go-json"
"github.com/mhsanaei/3x-ui/v2/config"
"github.com/mhsanaei/3x-ui/v2/database"
"github.com/mhsanaei/3x-ui/v2/database/model"
"github.com/mhsanaei/3x-ui/v2/logger"
@ -115,14 +116,29 @@ func (s *SubService) GetSubs(subId string, host string) ([]string, int64, xray.C
func (s *SubService) getInboundsBySubId(subId string) ([]*model.Inbound, error) {
db := database.GetDB()
var inbounds []*model.Inbound
err := db.Model(model.Inbound{}).Preload("ClientStats").Where(`id in (
SELECT DISTINCT inbounds.id
FROM inbounds,
JSON_EACH(JSON_EXTRACT(inbounds.settings, '$.clients')) AS client
WHERE
protocol in ('vmess','vless','trojan','shadowsocks')
AND JSON_EXTRACT(client.value, '$.subId') = ? AND enable = ?
)`, subId, true).Find(&inbounds).Error
var query string
if config.GetDBTypeFromJSON() == "mariadb" {
query = `id in (
SELECT DISTINCT inbounds.id
FROM inbounds,
JSON_TABLE(inbounds.settings, '$.clients[*]' COLUMNS(value JSON PATH '$')) AS client
WHERE
protocol in ('vmess','vless','trojan','shadowsocks')
AND JSON_EXTRACT(client.value, '$.subId') = ? AND enable = ?
)`
} else {
query = `id in (
SELECT DISTINCT inbounds.id
FROM inbounds,
JSON_EACH(JSON_EXTRACT(inbounds.settings, '$.clients')) AS client
WHERE
protocol in ('vmess','vless','trojan','shadowsocks')
AND JSON_EXTRACT(client.value, '$.subId') = ? AND enable = ?
)`
}
err := db.Model(model.Inbound{}).Preload("ClientStats").Where(query, subId, true).Find(&inbounds).Error
if err != nil {
return nil, err
}
@ -141,9 +157,17 @@ func (s *SubService) getClientTraffics(traffics []xray.ClientTraffic, email stri
func (s *SubService) getFallbackMaster(dest string, streamSettings string) (string, int, string, error) {
db := database.GetDB()
var inbound *model.Inbound
var jsonQuery string
if config.GetDBTypeFromJSON() == "mariadb" {
jsonQuery = "EXISTS (SELECT * FROM JSON_TABLE(settings, '$.fallbacks[*]' COLUMNS(value JSON PATH '$')) AS jt WHERE JSON_EXTRACT(jt.value, '$.dest') = ?)"
} else {
jsonQuery = "EXISTS (SELECT * FROM json_each(settings, '$.fallbacks') WHERE json_extract(value, '$.dest') = ?)"
}
err := db.Model(model.Inbound{}).
Where("JSON_TYPE(settings, '$.fallbacks') = 'array'").
Where("EXISTS (SELECT * FROM json_each(settings, '$.fallbacks') WHERE json_extract(value, '$.dest') = ?)", dest).
Where(jsonQuery, dest).
Find(&inbound).Error
if err != nil {
return "", 0, "", err

View file

@ -10,6 +10,7 @@ import (
"strings"
"time"
"github.com/mhsanaei/3x-ui/v2/config"
"github.com/mhsanaei/3x-ui/v2/database"
"github.com/mhsanaei/3x-ui/v2/database/model"
"github.com/mhsanaei/3x-ui/v2/logger"
@ -1525,14 +1526,27 @@ func (s *InboundService) GetInboundTags() (string, error) {
func (s *InboundService) MigrationRemoveOrphanedTraffics() {
db := database.GetDB()
db.Exec(`
DELETE FROM client_traffics
WHERE email NOT IN (
SELECT JSON_EXTRACT(client.value, '$.email')
FROM inbounds,
JSON_EACH(JSON_EXTRACT(inbounds.settings, '$.clients')) AS client
)
`)
var query string
if config.GetDBTypeFromJSON() == "mariadb" {
query = `
DELETE FROM client_traffics
WHERE email NOT IN (
SELECT JSON_EXTRACT(client.value, '$.email')
FROM inbounds,
JSON_TABLE(inbounds.settings, '$.clients[*]' COLUMNS(value JSON PATH '$')) AS client
)`
} else {
query = `
DELETE FROM client_traffics
WHERE email NOT IN (
SELECT JSON_EXTRACT(client.value, '$.email')
FROM inbounds,
JSON_EACH(JSON_EXTRACT(inbounds.settings, '$.clients')) AS client
)`
}
db.Exec(query)
}
func (s *InboundService) AddClientStat(tx *gorm.DB, inboundId int, client *model.Client) error {
@ -2327,13 +2341,26 @@ func (s *InboundService) GetClientTrafficByID(id string) ([]xray.ClientTraffic,
db := database.GetDB()
var traffics []xray.ClientTraffic
err := db.Model(xray.ClientTraffic{}).Where(`email IN(
SELECT JSON_EXTRACT(client.value, '$.email') as email
FROM inbounds,
JSON_EACH(JSON_EXTRACT(inbounds.settings, '$.clients')) AS client
WHERE
JSON_EXTRACT(client.value, '$.id') in (?)
)`, id).Find(&traffics).Error
var query string
if config.GetDBTypeFromJSON() == "mariadb" {
query = `email IN(
SELECT JSON_EXTRACT(client.value, '$.email') as email
FROM inbounds,
JSON_TABLE(inbounds.settings, '$.clients[*]' COLUMNS(value JSON PATH '$')) AS client
WHERE
JSON_EXTRACT(client.value, '$.id') in (?)
)`
} else {
query = `email IN(
SELECT JSON_EXTRACT(client.value, '$.email') as email
FROM inbounds,
JSON_EACH(JSON_EXTRACT(inbounds.settings, '$.clients')) AS client
WHERE
JSON_EXTRACT(client.value, '$.id') in (?)
)`
}
err := db.Model(xray.ClientTraffic{}).Where(query, id).Find(&traffics).Error
if err != nil {
logger.Debug(err)