mirror of
https://github.com/hellodigua/ChatLab.git
synced 2026-04-23 18:19:01 +08:00
feat: SQL实验室支持导出
This commit is contained in:
@@ -5,9 +5,6 @@
|
||||
|
||||
import { openDatabase } from '../core'
|
||||
|
||||
// 最大返回行数限制
|
||||
const MAX_LIMIT = 1000
|
||||
|
||||
// 查询超时时间(毫秒)
|
||||
const QUERY_TIMEOUT_MS = 10000
|
||||
|
||||
@@ -81,41 +78,17 @@ export function getSchema(sessionId: string): TableSchema[] {
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析并强制添加 LIMIT
|
||||
* 如果 SQL 没有 LIMIT 或 LIMIT 超过最大值,强制设置为 MAX_LIMIT
|
||||
* 检查 SQL 是否包含 LIMIT 子句
|
||||
*/
|
||||
function enforceLimit(sql: string): { sql: string; limited: boolean } {
|
||||
const trimmedSQL = sql.trim()
|
||||
|
||||
// 检查是否是 SELECT 语句
|
||||
if (!trimmedSQL.toUpperCase().startsWith('SELECT')) {
|
||||
return { sql: trimmedSQL, limited: false }
|
||||
}
|
||||
|
||||
// 使用正则匹配 LIMIT 子句
|
||||
const limitMatch = trimmedSQL.match(/\bLIMIT\s+(\d+)\s*(?:,\s*\d+)?(?:\s+OFFSET\s+\d+)?/i)
|
||||
|
||||
if (limitMatch) {
|
||||
const currentLimit = parseInt(limitMatch[1], 10)
|
||||
if (currentLimit > MAX_LIMIT) {
|
||||
// 替换超出的 LIMIT
|
||||
const newSQL = trimmedSQL.replace(/\bLIMIT\s+\d+/i, `LIMIT ${MAX_LIMIT}`)
|
||||
return { sql: newSQL, limited: true }
|
||||
}
|
||||
return { sql: trimmedSQL, limited: false }
|
||||
} else {
|
||||
// 没有 LIMIT,追加
|
||||
// 需要处理可能存在的分号
|
||||
const sqlWithoutSemicolon = trimmedSQL.replace(/;\s*$/, '')
|
||||
return { sql: `${sqlWithoutSemicolon} LIMIT ${MAX_LIMIT}`, limited: true }
|
||||
}
|
||||
function hasLimit(sql: string): boolean {
|
||||
return /\bLIMIT\s+\d+/i.test(sql)
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行用户 SQL 查询
|
||||
* - 只支持 SELECT 语句
|
||||
* - 强制 LIMIT 不超过 MAX_LIMIT
|
||||
* - 带超时控制
|
||||
* - 不强制 LIMIT,由用户自行控制
|
||||
* - 带超时控制(由 Worker 管理器控制)
|
||||
*/
|
||||
export function executeRawSQL(sessionId: string, sql: string): SQLResult {
|
||||
const db = openDatabase(sessionId)
|
||||
@@ -130,16 +103,12 @@ export function executeRawSQL(sessionId: string, sql: string): SQLResult {
|
||||
throw new Error('只支持 SELECT 查询语句')
|
||||
}
|
||||
|
||||
// 强制 LIMIT
|
||||
const { sql: limitedSQL, limited } = enforceLimit(trimmedSQL)
|
||||
|
||||
// 执行查询
|
||||
const startTime = Date.now()
|
||||
|
||||
try {
|
||||
// better-sqlite3 是同步的,我们通过 Worker 实现"超时"
|
||||
// 这里先执行,超时由 Worker 管理器控制
|
||||
const stmt = db.prepare(limitedSQL)
|
||||
// better-sqlite3 是同步的,超时由 Worker 管理器控制
|
||||
const stmt = db.prepare(trimmedSQL)
|
||||
const rows = stmt.all()
|
||||
const duration = Date.now() - startTime
|
||||
|
||||
@@ -154,7 +123,7 @@ export function executeRawSQL(sessionId: string, sql: string): SQLResult {
|
||||
rows: rowData,
|
||||
rowCount: rows.length,
|
||||
duration,
|
||||
limited: limited || rows.length >= MAX_LIMIT,
|
||||
limited: false, // 不再强制限制
|
||||
}
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
|
||||
Reference in New Issue
Block a user