Skip to content

Commit 2ee73cf

Browse files
anandgupta42claude
andcommitted
fix: classify quoted remote-execute calls as writes and end DuckDB -- comments at CR
- pass `identifiers=true` to `maskSql` when detecting `postgres_execute`-style calls - treat CR as a line-comment terminator under `duckdb` - add regression tests Co-Authored-By: Claude Opus 5.5 <[email protected]>
1 parent 6aa2db4 commit 2ee73cf

3 files changed

Lines changed: 10 additions & 2 deletions

File tree

‎packages/opencode/src/altimate/tools/sql-classify.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ export function classifyAndCheck(sql: string, dialect?: string): {
198198

199199
// DuckDB scanner functions run their statement on the attached remote database, outside any local
200200
// read-only transaction, so a SELECT calling them is a write.
201-
const remoteExecute = REMOTE_EXECUTE_CALL.test(maskSql(tokenizeSql(sql, dialect).tokens))
201+
const remoteExecute = REMOTE_EXECUTE_CALL.test(maskSql(tokenizeSql(sql, dialect).tokens, true))
202202
return {
203203
queryType: !remoteExecute && otherIsReadOnly(sql, result.statements, dialect) ? "read" : "write",
204204
blocked,

‎packages/opencode/src/altimate/tools/sql-tokenize.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export function tokenizeSql(sql: string, dialect?: string): { tokens: SqlToken[]
2121
kind = "comment"
2222
// PostgreSQL also ends line comments at CR. Keep following code visible
2323
// when the dialect is unknown; other dialects retain their LF handling.
24-
const newline = !dialect || /^postgres$/i.test(dialect) ? /[\r\n]/ : /\n/
24+
const newline = !dialect || /^(postgres|duckdb)$/i.test(dialect) ? /[\r\n]/ : /\n/
2525
const end = sql.slice(i + 2).search(newline)
2626
i = end < 0 ? sql.length : i + 2 + end
2727
} else if (sql.startsWith("/*", i)) {

‎packages/opencode/test/altimate/tools/sql-classify.test.ts‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,3 +362,11 @@ describe("SQL-building aggregates are reads", () => {
362362
test.each(["postgres_execute", "mysql_execute"])("a SELECT calling %s is classified as a write", (fn) => {
363363
expect(classify(`SELECT * FROM ${fn}('remote', 'DELETE FROM orders')`, "duckdb")).toBe("write")
364364
})
365+
366+
test("a quoted remote-execute function name is still classified as a write", () => {
367+
expect(classify(`SELECT * FROM "postgres_execute"('remote', 'DELETE FROM orders')`, "duckdb")).toBe("write")
368+
})
369+
370+
test("duckdb line comments end at CR so a following DROP is blocked", () => {
371+
expect(classifyAndCheck("SELECT 1 -- x\r; DROP SCHEMA s", "duckdb").blocked).toBe(true)
372+
})

0 commit comments

Comments
 (0)