diff --git a/packages/server-utils/src/utils/sql.ts b/packages/server-utils/src/utils/sql.ts index 25caaa4df01f..f8ecdb4a9078 100644 --- a/packages/server-utils/src/utils/sql.ts +++ b/packages/server-utils/src/utils/sql.ts @@ -28,7 +28,7 @@ const UPDATE_RE = new RegExp( ); const DELETE_RE = new RegExp(`^\\s*(?DELETE)\\s+FROM\\s+(?${TABLE_NAME})`, 'i'); -const SELECT_RE = /^\s*\(?\s*(?SELECT)\b/i; +const SELECT_RE = /^\s*(?:\(\s*)?(?SELECT)\b/i; const PRAGMA_RE = /^\s*(?PRAGMA)\s+(?\S+)/i; diff --git a/packages/server-utils/test/utils/sql.test.ts b/packages/server-utils/test/utils/sql.test.ts index 500644753568..50ed62d4a50e 100644 --- a/packages/server-utils/test/utils/sql.test.ts +++ b/packages/server-utils/test/utils/sql.test.ts @@ -12,6 +12,8 @@ describe('getSqlQuerySummary', () => { ['select count(*) from orders', 'select orders'], ['SELECT DISTINCT email FROM subscribers WHERE active = ?', 'SELECT subscribers'], [' SELECT * FROM users', 'SELECT users'], + ['(SELECT * FROM users)', 'SELECT users'], + [' \t( \nselect * from users)', 'select users'], ])('%j => %j', (input, expected) => { expect(getSqlQuerySummary(input)).toBe(expected); }); @@ -165,6 +167,17 @@ describe('getSqlQuerySummary', () => { it('handles leading whitespace in fallback', () => { expect(getSqlQuerySummary(' VACUUM')).toBe('VACUUM'); }); + + it('handles long leading whitespace without excessive backtracking', () => { + const query = `${' '.repeat(100_000)}VACUUM`; + const start = performance.now(); + + const summary = getSqlQuerySummary(query); + const duration = performance.now() - start; + + expect(summary).toBe('VACUUM'); + expect(duration).toBeLessThan(1_000); + }); }); describe('set operations', () => {