@@ -225,5 +225,55 @@ describe("Query Scanning", () => {
225225 assert . equal ( typeof result1 . version , "number" ) ;
226226 assert . ok ( result1 . version > 0 ) ;
227227 } ) ;
228+
229+ it ( "should handle multi-line dollar-quoted strings without JSON errors" , ( ) => {
230+ // Without the fix, scanSync throws:
231+ // "Bad control character in string literal"
232+ // because build_scan_json() doesn't escape \n in the token text.
233+ const sql = `CREATE FUNCTION test() RETURNS void AS $$
234+ BEGIN
235+ RAISE NOTICE 'hello';
236+ END;
237+ $$ LANGUAGE plpgsql` ;
238+
239+ const result = query . scanSync ( sql ) ;
240+ assert . equal ( typeof result , "object" ) ;
241+ assert . ok ( Array . isArray ( result . tokens ) ) ;
242+ assert . ok ( result . tokens . length > 0 ) ;
243+
244+ // The dollar-quoted body spans multiple lines
245+ const dollarToken = result . tokens . find ( t => t . text . includes ( 'BEGIN' ) ) ;
246+ assert . ok ( dollarToken , "should have a token containing the function body" ) ;
247+ assert . ok ( dollarToken . text . includes ( '\n' ) , "token text should preserve newlines" ) ;
248+ } ) ;
249+
250+ it ( "should handle dollar-quoted tokens with tabs" , ( ) => {
251+ // Tab characters also break JSON.parse when unescaped.
252+ const sql = `SELECT $$line1
253+ indented
254+ line3$$` ;
255+
256+ const result = query . scanSync ( sql ) ;
257+ assert . equal ( typeof result , "object" ) ;
258+ assert . ok ( Array . isArray ( result . tokens ) ) ;
259+
260+ const dollarToken = result . tokens . find ( t => t . text . includes ( 'indented' ) ) ;
261+ assert . ok ( dollarToken , "should have a token containing the tabbed content" ) ;
262+ } ) ;
263+
264+ it ( "should handle multi-line block comments" , ( ) => {
265+ // C-style block comments spanning multiple lines hit the same bug.
266+ const sql = `SELECT 1; /* multi
267+ line
268+ comment */ SELECT 2` ;
269+
270+ const result = query . scanSync ( sql ) ;
271+ assert . equal ( typeof result , "object" ) ;
272+ assert . ok ( Array . isArray ( result . tokens ) ) ;
273+
274+ const commentToken = result . tokens . find ( t => t . tokenName === "C_COMMENT" ) ;
275+ assert . ok ( commentToken , "should have a C_COMMENT token" ) ;
276+ assert . ok ( commentToken . text . includes ( '\n' ) , "comment text should preserve newlines" ) ;
277+ } ) ;
228278 } ) ;
229- } ) ;
279+ } ) ;
0 commit comments