actiontech / sqle

一个支持多种不同类型数据库,覆盖事前控制、事后监督、标准发布场景,帮助您建立质量规范的SQL全生命周期质量管理平台
Mozilla Public License 2.0
1.45k stars 185 forks source link

SQL操作记录:强制类型转换失败导致Panic,页面无法访问 #2594

Closed winfredLIN closed 1 month ago

winfredLIN commented 2 months ago

版本信息(Version)

latest

问题描述(Describe)

点击SQL操作记录,页面无法访问 问题诉求: 需要查明原因

截图或日志(Log)

现象: 点击SQL操作记录,页面无法访问

image 接口响应502 image

Panic信息

echo: http: panic serving 127.0.0.1:45068: interface conversion: interface {} is nil, not []uint8
goroutine 24 [running]:
net/http.(*conn).serve.func1()
        /usr/local/go/src/net/http/server.go:1850 +0x148
panic({0x2451000, 0xc00163eed0})
        /usr/local/go/src/runtime/panic.go:890 +0x267
github.com/actiontech/sqle/sqle/pkg/i18nPkg.(*I18nStr).Scan(0xc0016552b0, {0x0, 0x0})
        /root/ee/sqle/sqle/pkg/i18nPkg/i18nStr.go:86 +0xd4
database/sql.convertAssignRows({0x254bd40, 0xc0016552b0}, {0x0, 0x0}, 0xc000504200)
        /usr/local/go/src/database/sql/convert.go:385 +0x1ef9
database/sql.(*Rows).Scan(0xc000504200, {0xc00082e280, 0xa, 0xa})
        /usr/local/go/src/database/sql/sql.go:3287 +0x4ae
github.com/jmoiron/sqlx.scanAll({0x2a57a00, 0xc00162e140}, {0x22ae960, 0xc000ddeab0}, 0x0)
        /root/ee/sqle/vendor/github.com/jmoiron/sqlx/sqlx.go:961 +0xb0c
github.com/jmoiron/sqlx.(*NamedStmt).Select(0xc001128ea0, {0x22ae960, 0xc000ddeab0}, {0x241ff20, 0xc000e136e0})
        /root/ee/sqle/vendor/github.com/jmoiron/sqlx/named.go:108 +0x1b1
github.com/actiontech/sqle/sqle/model.(*Storage).getListResult(0xc0008701e8, {0x2806e20, 0x2c6}, {0x27fd1a7, 0x183}, 0xc000e136e0, {0x22ae960, 0xc000ddeab0})
        /root/ee/sqle/sqle/model/role_list.go:121 +0x28a
github.com/actiontech/sqle/sqle/model.(*Storage).GetOperationRecordList(0xc0008701e8, 0xc000e136e0)
        /root/ee/sqle/sqle/model/operation_record_ee.go:135 +0x99
github.com/actiontech/sqle/sqle/api/controller/v1.getOperationRecordList({0x2a80868, 0xc0001760a0})
        /root/ee/sqle/sqle/api/controller/v1/operation_record_ee.go:391 +0x69d
github.com/actiontech/sqle/sqle/api/controller/v1.GetOperationRecordListV1({0x2a80868, 0xc0001760a0})
        /root/ee/sqle/sqle/api/controller/v1/operation_record.go:105 +0x33
github.com/actiontech/sqle/sqle/api/middleware.AdminUserAllowed.func1.1({0x2a80868, 0xc0001760a0})
        /root/ee/sqle/sqle/api/middleware/permission.go:26 +0x216
github.com/actiontech/dms/pkg/dms-common/api/accesstoken.CheckLatestAccessToken.func1.1({0x2a80868, 0xc0001760a0})
        /root/ee/sqle/vendor/github.com/actiontech/dms/pkg/dms-common/api/accesstoken/access_token.go:31 +0x364
github.com/actiontech/sqle/sqle/api/middleware.OperationLogRecord.func1.1({0x2a80868, 0xc0001760a0})
        /root/ee/sqle/sqle/api/middleware/operation_record_ee.go:111 +0x12a
github.com/actiontech/sqle/sqle/pkg/i18nPkg.(*Bundle).EchoMiddlewareByAcceptLanguage.func1.1({0x2a80868, 0xc0001760a0})
        /root/ee/sqle/sqle/pkg/i18nPkg/bundle.go:143 +0x35f
github.com/actiontech/sqle/sqle/api/middleware.VerifyUserIsDisabled.func1.1({0x2a80868, 0xc0001760a0})
        /root/ee/sqle/sqle/api/middleware/verify_user.go:26 +0x4bf
github.com/labstack/echo/v4/middleware.JWTWithConfig.func1.1({0x2a80868, 0xc0001760a0})
        /root/ee/sqle/vendor/github.com/labstack/echo/v4/middleware/jwt.go:238 +0x60c
github.com/actiontech/sqle/sqle/api/middleware.JWTTokenAdapter.func1.1({0x2a80868, 0xc0001760a0})
        /root/ee/sqle/sqle/api/middleware/jwt.go:33 +0x3a6
github.com/labstack/echo/v4.(*Echo).add.func1({0x2a80868, 0xc0001760a0})
        /root/ee/sqle/vendor/github.com/labstack/echo/v4/echo.go:552 +0x88
github.com/labstack/echo/v4/middleware.LoggerWithConfig.func2.1({0x2a80868, 0xc0001760a0})
        /root/ee/sqle/vendor/github.com/labstack/echo/v4/middleware/logger.go:117 +0x164
github.com/labstack/echo/v4.(*Echo).ServeHTTP(0xc0010b26c0, {0x2a53af0, 0xc0015b0460}, 0xc000f8c000)
        /root/ee/sqle/vendor/github.com/labstack/echo/v4/echo.go:662 +0x2ae
net/http.serverHandler.ServeHTTP({0xc000a240f0}, {0x2a53af0, 0xc0015b0460}, 0xc000f8c000)
        /usr/local/go/src/net/http/server.go:2947 +0x474
net/http.(*conn).serve(0xc00021e5a0, {0x2a55170, 0xc000c68000})
        /usr/local/go/src/net/http/server.go:1991 +0x195c
created by net/http.(*Server).Serve
        /usr/local/go/src/net/http/server.go:3102 +0x9e5

AI分析

这段 panic 信息表明在使用 Go 语言的 echo 框架时,程序在处理 HTTP 请求时遇到了一个 panic。根据提供的堆栈跟踪,我们可以逐步分析 panic 的发生位置和原因。

  1. Panic 描述:

    • interface conversion: interface {} is nil, not []uint8 表示在尝试将一个 nil 接口值转换为 []byte 类型时发生了 panic。这通常发生在试图对一个 nil 值进行类型断言或类型转换时。
  2. Panic 发生的位置:

    • 根据堆栈跟踪,panic 最初发生在 github.com/actiontech/sqle/sqle/pkg/i18nPkg.(*I18nStr).Scan 方法中。这是在尝试扫描(可能是数据库查询结果)时发生的。
  3. 可能的原因:

    • 这个 panic 可能是由于 Scan 方法期望接收一个 []byte 类型的参数,但实际上接收到了一个 nil 值。这可能是因为数据库查询没有返回预期的结果,或者在处理结果时出现了错误。
  4. 进一步的分析:

    • 从堆栈跟踪中可以看出,Scan 方法是被 database/sql.(*Rows).Scan 调用的,这表明可能是在处理数据库查询结果时出现了问题。
    • 进一步的调用链显示,Scan 方法是在 github.com/actiontech/sqle/sqle/model.(*Storage).getListResult 方法中被调用的,这可能是在获取某个列表结果时出现问题。
  5. 建议的解决方案:

    • 检查 github.com/actiontech/sqle/sqle/pkg/i18nPkg.(*I18nStr).Scan 方法的实现,确保在处理 nil 值时有适当的错误处理逻辑。
    • 检查数据库查询逻辑,确保查询能够正确返回预期的结果,并且在处理结果时有适当的错误检查。
    • 可能需要添加日志记录,以便在发生 panic 时能够记录更多的上下文信息,帮助定位问题。
  6. 总结:

    • 这个 panic 指出了在处理数据库查询结果时的一个潜在问题,需要检查相关的数据库查询和结果处理逻辑,确保在处理 nil 值时有适当的错误处理和日志记录。

引发panic的代码

在文件sqle/pkg/i18nPkg/i18nStr.go中有这么一段代码,这里对输入的input进行了强制类型断言,当input为nil时,强制类型断言失败,引发panic

// Scan impl sql.Scanner interface
func (s *I18nStr) Scan(input interface{}) error {
    return json.Unmarshal(input.([]byte), s)
}

AI 分析

根据您提供的 Scan 方法的实现,我们可以更详细地分析为什么在输入为 nil 时会导致 panic。

方法实现分析

func (s *I18nStr) Scan(input interface{}) error {
    return json.Unmarshal(input.([]byte), s)
}

这个方法尝试将输入的 interface{} 类型断言为 []byte 类型,并使用 json.Unmarshal 来解析 JSON 数据。这里的关键点在于类型断言 input.([]byte)

为什么发生 Panic

  1. 类型断言失败: 当 inputnil 时,尝试将其断言为 []byte 类型将失败。在 Go 语言中,如果类型断言失败,程序会触发 panic。
  2. nil 值处理: 在 Scan 方法中,没有对 input 是否为 nil 进行检查。如果 inputnil,直接进行类型断言将导致程序 panic。

解决方案

为了避免这种 panic,可以在类型断言之前添加对 input 是否为 nil 的检查。这样可以安全地处理 nil 输入,而不会导致程序崩溃。

func (s *I18nStr) Scan(input interface{}) error {
    if input == nil {
        return nil // 或者返回一个错误,根据具体需求决定
    }
    if bytes, ok := input.([]byte); ok {
        return json.Unmarshal(bytes, s)
    } else {
        return fmt.Errorf("expected []byte, got %T", input)
    }
}

修改后的代码解释

通过这种方式,可以确保即使在面对 nil 输入时,Scan 方法也能稳定运行,不会引发 panic。

根据ai建议修改后页面能够正常访问,但该界面在英文版本中,存在中文

image image

如何复现(To Reproduce)

问题原因

解决方案

变更影响面

受影响的模块或功能

外部引用的潜在问题或风险

版本兼容性

测试建议

BugsGuru commented 2 months ago

原因是:在旧版本的sqle数据的数据库上跑的该国际化版本的sqle,新增字段自动迁移,值为null导致Scan方法input为nil

winfredLIN commented 4 weeks ago

测试版本

commit ef106ffc11ba8644bebbd6bb224656aa5dc5100a

测试步骤与结果:均可正常访问,未触发该问题

  1. 打开中文页面,结果:可正常访问 image
  2. 打开英文页面,结果:可正常访问 image