2026-04-15 12:47:10 +08:00
|
|
|
|
package dbtool
|
2026-03-18 20:58:41 +08:00
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"context"
|
2026-04-28 22:37:10 +08:00
|
|
|
|
"fmt"
|
2026-03-18 20:58:41 +08:00
|
|
|
|
|
2026-04-28 22:37:10 +08:00
|
|
|
|
"mayfly-go/internal/ai/imsg"
|
2026-04-15 12:47:10 +08:00
|
|
|
|
"mayfly-go/internal/ai/tools"
|
2026-03-18 20:58:41 +08:00
|
|
|
|
"mayfly-go/internal/db/application"
|
|
|
|
|
|
"mayfly-go/internal/db/dbm/dbi"
|
2026-04-28 22:37:10 +08:00
|
|
|
|
"mayfly-go/pkg/i18n"
|
2026-03-18 20:58:41 +08:00
|
|
|
|
|
|
|
|
|
|
"github.com/cloudwego/eino/components/tool"
|
|
|
|
|
|
"github.com/cloudwego/eino/components/tool/utils"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
type QueryDataParam struct {
|
2026-05-13 20:01:05 +08:00
|
|
|
|
DbId int64 `json:"dbId" jsonschema_description:"数据库ID。取值逻辑:1. 用户本次明确指定;2. 从前序工具的输入输出中继承已选定的数据库ID;3. 若均无,传0以触发参数补全。禁止凭空猜测。"`
|
|
|
|
|
|
DbName string `json:"dbName" jsonschema_description:"数据库名称。取值逻辑:1. 用户本次明确指定;2. 从前序工具的输入输出中继承已选定的数据库名称;3. 若均无,留空以触发参数补全。禁止凭空猜测。"`
|
|
|
|
|
|
SQLs []string `json:"sqls" jsonschema_description:"SQL语句数组,支持一次性查询多条SQL" jsonschema:"required" `
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type SingleQueryResult struct {
|
|
|
|
|
|
SQL string `json:"sql" jsonschema_description:"执行的SQL语句"`
|
|
|
|
|
|
Columns []*dbi.QueryColumn `json:"columns" jsonschema_description:"查询结果列信息"`
|
|
|
|
|
|
Rows []map[string]any `json:"rows" jsonschema_description:"查询结果数据"`
|
|
|
|
|
|
Error string `json:"error,omitempty" jsonschema_description:"执行错误信息"`
|
2026-03-18 20:58:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type QueryDataOutput struct {
|
2026-05-13 20:01:05 +08:00
|
|
|
|
DbId int64 `json:"dbId" jsonschema_description:"数据库ID"`
|
|
|
|
|
|
DbName string `json:"dbName" jsonschema_description:"数据库名称"`
|
|
|
|
|
|
DbType string `json:"dbType" jsonschema_description:"数据库类型,如mysql、postgresql等"`
|
|
|
|
|
|
Results []SingleQueryResult `json:"results" jsonschema_description:"多条SQL查询结果"`
|
2026-03-18 20:58:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func GetQueryData() (tool.InvokableTool, error) {
|
|
|
|
|
|
return utils.InferTool("DbQueryData",
|
2026-04-28 22:37:10 +08:00
|
|
|
|
i18n.T(imsg.DbQueryDataToolInfo),
|
2026-03-18 20:58:41 +08:00
|
|
|
|
func(ctx context.Context, param *QueryDataParam) (*QueryDataOutput, error) {
|
2026-04-28 22:37:10 +08:00
|
|
|
|
toolDesc := i18n.TC(ctx, imsg.DbQueryDataToolDesc)
|
|
|
|
|
|
// 检查必要参数,触发参数完善
|
|
|
|
|
|
if param.DbId == 0 || param.DbName == "" {
|
|
|
|
|
|
if err := tools.InterruptOrResumeParamCompletion(ctx, toolDesc, param, i18n.TC(ctx, imsg.DbInfoIncomplete), "db", []tools.CompletionParamInfo{
|
2026-05-08 20:45:13 +08:00
|
|
|
|
{Param: "dbId", Name: "数据库ID"},
|
|
|
|
|
|
{Param: "dbName", Name: "数据库名称"},
|
2026-04-28 22:37:10 +08:00
|
|
|
|
}); err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-13 20:01:05 +08:00
|
|
|
|
if len(param.SQLs) == 0 {
|
|
|
|
|
|
return nil, fmt.Errorf("sqls parameter is required")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if len(param.SQLs) > 10 {
|
|
|
|
|
|
return nil, fmt.Errorf("too many SQL statements, maximum allowed is 10, got %d", len(param.SQLs))
|
2026-04-28 22:37:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
conn, err := application.GetDbApp().GetDbConn(ctx, uint64(param.DbId), param.DbName)
|
2026-03-18 20:58:41 +08:00
|
|
|
|
if err != nil {
|
2026-04-15 12:47:10 +08:00
|
|
|
|
return nil, tools.NewToolError(err, tools.RecoverRetry)
|
2026-03-18 20:58:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-13 20:01:05 +08:00
|
|
|
|
results := make([]SingleQueryResult, 0, len(param.SQLs))
|
|
|
|
|
|
for _, sql := range param.SQLs {
|
|
|
|
|
|
if sql == "" {
|
|
|
|
|
|
continue
|
2026-03-18 20:58:41 +08:00
|
|
|
|
}
|
2026-05-13 20:01:05 +08:00
|
|
|
|
|
|
|
|
|
|
result := SingleQueryResult{SQL: sql}
|
|
|
|
|
|
rows := make([]map[string]any, 0)
|
|
|
|
|
|
columns, err := conn.WalkQueryRows(ctx, sql, func(row map[string]any, columns []*dbi.QueryColumn) error {
|
|
|
|
|
|
rows = append(rows, row)
|
|
|
|
|
|
if len(rows) > 1000 {
|
|
|
|
|
|
return dbi.NewStopWalkQueryError("The maximum number of query rows is exceeded: 1000")
|
|
|
|
|
|
}
|
|
|
|
|
|
return nil
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
result.Error = err.Error()
|
|
|
|
|
|
} else {
|
|
|
|
|
|
result.Columns = columns
|
|
|
|
|
|
result.Rows = rows
|
|
|
|
|
|
}
|
|
|
|
|
|
results = append(results, result)
|
2026-03-18 20:58:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-08 20:45:13 +08:00
|
|
|
|
output := &QueryDataOutput{
|
|
|
|
|
|
DbId: param.DbId,
|
|
|
|
|
|
DbName: param.DbName,
|
|
|
|
|
|
DbType: string(conn.Info.Type),
|
2026-05-13 20:01:05 +08:00
|
|
|
|
Results: results,
|
2026-05-08 20:45:13 +08:00
|
|
|
|
}
|
2026-03-18 20:58:41 +08:00
|
|
|
|
return output, nil
|
|
|
|
|
|
},
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|