Skip to content

Commit 28d4516

Browse files
committed
fix(clickhouse): reject chained statements in read-only query operation
1 parent 1535da1 commit 28d4516

1 file changed

Lines changed: 38 additions & 0 deletions

File tree

  • apps/sim/app/api/tools/clickhouse

apps/sim/app/api/tools/clickhouse/utils.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,39 @@ function ensureJsonFormat(query: string): string {
149149
return trimmed
150150
}
151151

152+
/**
153+
* Detects whether a statement chains a second statement after a `;` that is not
154+
* inside a string ('...'), quoted identifier ("..." / `...`) span. A trailing
155+
* semicolon with nothing after it is allowed.
156+
*/
157+
function hasChainedStatement(sql: string): boolean {
158+
let inSingle = false
159+
let inDouble = false
160+
let inBacktick = false
161+
for (let i = 0; i < sql.length; i++) {
162+
const ch = sql[i]
163+
if (inSingle) {
164+
if (ch === '\\') i++
165+
else if (ch === "'") inSingle = false
166+
continue
167+
}
168+
if (inDouble) {
169+
if (ch === '\\') i++
170+
else if (ch === '"') inDouble = false
171+
continue
172+
}
173+
if (inBacktick) {
174+
if (ch === '`') inBacktick = false
175+
continue
176+
}
177+
if (ch === "'") inSingle = true
178+
else if (ch === '"') inDouble = true
179+
else if (ch === '`') inBacktick = true
180+
else if (ch === ';' && sql.slice(i + 1).trim().length > 0) return true
181+
}
182+
return false
183+
}
184+
152185
export async function executeClickHouseQuery(
153186
config: ClickHouseConnectionConfig,
154187
query: string,
@@ -162,6 +195,11 @@ export async function executeClickHouseQuery(
162195
'The query operation only allows read-only statements (SELECT, WITH, SHOW, DESCRIBE, EXPLAIN, EXISTS). Use the Execute Raw SQL operation to run writes or DDL.'
163196
)
164197
}
198+
if (hasChainedStatement(query)) {
199+
throw new Error(
200+
'The query operation only allows a single statement; chained statements separated by ";" are not allowed. Use the Execute Raw SQL operation to run multiple statements.'
201+
)
202+
}
165203
}
166204
const result = await clickhouseRequest(config, ensureJsonFormat(query))
167205
return parseRowsResult(result)

0 commit comments

Comments
 (0)