(ctx context.Context, args *QuerySQLArgs)
| 52 | } |
| 53 | |
| 54 | func (t *QuerySQL) Handler(ctx context.Context, args *QuerySQLArgs) (*QuerySQLResult, error) { |
| 55 | if args.SQL == "" { |
| 56 | return nil, fmt.Errorf("sql query is required") |
| 57 | } |
| 58 | |
| 59 | s := GetSession(ctx) |
| 60 | |
| 61 | // Apply timeout default |
| 62 | timeoutSeconds := args.TimeoutSeconds |
| 63 | if timeoutSeconds <= 0 { |
| 64 | timeoutSeconds = 30 |
| 65 | } |
| 66 | |
| 67 | // Apply a hard limit to prevent large results that bloat the context |
| 68 | instance, err := t.Runtime.Instance(ctx, s.InstanceID()) |
| 69 | if err != nil { |
| 70 | return nil, fmt.Errorf("failed to get instance: %w", err) |
| 71 | } |
| 72 | cfg, err := instance.Config() |
| 73 | if err != nil { |
| 74 | return nil, fmt.Errorf("failed to get instance config: %w", err) |
| 75 | } |
| 76 | hardLimit := cfg.AIMaxQueryLimit |
| 77 | |
| 78 | // Apply timeout |
| 79 | ctx, cancel := context.WithTimeout(ctx, time.Duration(timeoutSeconds)*time.Second) |
| 80 | defer cancel() |
| 81 | |
| 82 | // Build resolver properties with system limit |
| 83 | props := map[string]any{ |
| 84 | "sql": args.SQL, |
| 85 | "limit": hardLimit, |
| 86 | } |
| 87 | if args.Connector != "" { |
| 88 | props["connector"] = args.Connector |
| 89 | } |
| 90 | |
| 91 | // Execute via the SQL resolver |
| 92 | res, _, err := t.Runtime.Resolve(ctx, &runtime.ResolveOptions{ |
| 93 | InstanceID: s.InstanceID(), |
| 94 | Resolver: "sql", |
| 95 | ResolverProperties: props, |
| 96 | Claims: s.Claims(), |
| 97 | }) |
| 98 | if err != nil { |
| 99 | return nil, err |
| 100 | } |
| 101 | defer res.Close() |
| 102 | |
| 103 | // Collect results in tabular format |
| 104 | schema, data, err := resolverResultToTabular(res) |
| 105 | if err != nil { |
| 106 | return nil, err |
| 107 | } |
| 108 | |
| 109 | result := &QuerySQLResult{ |
| 110 | Schema: schema, |
| 111 | Data: data, |
nothing calls this directly
no test coverage detected