Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion full/src/wasm_wrapper.c
Original file line number Diff line number Diff line change
Expand Up @@ -379,8 +379,19 @@ static char* build_scan_json(PgQuery__ScanResult *scan_result, const char* origi
char c = token_text[j];
if (c == '"' || c == '\\') {
escaped_text[escaped_pos++] = '\\';
escaped_text[escaped_pos++] = c;
} else if (c == '\n') {
escaped_text[escaped_pos++] = '\\';
escaped_text[escaped_pos++] = 'n';
} else if (c == '\r') {
escaped_text[escaped_pos++] = '\\';
escaped_text[escaped_pos++] = 'r';
} else if (c == '\t') {
escaped_text[escaped_pos++] = '\\';
escaped_text[escaped_pos++] = 't';
} else {
escaped_text[escaped_pos++] = c;
}
escaped_text[escaped_pos++] = c;
}
escaped_text[escaped_pos] = '\0';

Expand Down
52 changes: 51 additions & 1 deletion full/test/scan.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -225,5 +225,55 @@ describe("Query Scanning", () => {
assert.equal(typeof result1.version, "number");
assert.ok(result1.version > 0);
});

it("should handle multi-line dollar-quoted strings without JSON errors", () => {
// Without the fix, scanSync throws:
// "Bad control character in string literal"
// because build_scan_json() doesn't escape \n in the token text.
const sql = `CREATE FUNCTION test() RETURNS void AS $$
BEGIN
RAISE NOTICE 'hello';
END;
$$ LANGUAGE plpgsql`;

const result = query.scanSync(sql);
assert.equal(typeof result, "object");
assert.ok(Array.isArray(result.tokens));
assert.ok(result.tokens.length > 0);

// The dollar-quoted body spans multiple lines
const dollarToken = result.tokens.find(t => t.text.includes('BEGIN'));
assert.ok(dollarToken, "should have a token containing the function body");
assert.ok(dollarToken.text.includes('\n'), "token text should preserve newlines");
});

it("should handle dollar-quoted tokens with tabs", () => {
// Tab characters also break JSON.parse when unescaped.
const sql = `SELECT $$line1
indented
line3$$`;

const result = query.scanSync(sql);
assert.equal(typeof result, "object");
assert.ok(Array.isArray(result.tokens));

const dollarToken = result.tokens.find(t => t.text.includes('indented'));
assert.ok(dollarToken, "should have a token containing the tabbed content");
});

it("should handle multi-line block comments", () => {
// C-style block comments spanning multiple lines hit the same bug.
const sql = `SELECT 1; /* multi
line
comment */ SELECT 2`;

const result = query.scanSync(sql);
assert.equal(typeof result, "object");
assert.ok(Array.isArray(result.tokens));

const commentToken = result.tokens.find(t => t.tokenName === "C_COMMENT");
assert.ok(commentToken, "should have a C_COMMENT token");
assert.ok(commentToken.text.includes('\n'), "comment text should preserve newlines");
});
});
});
});
Loading