Skip to content

Commit

Permalink
Add GPT queries
Browse files Browse the repository at this point in the history
Needed to ignore start of comments when inside a literal
  • Loading branch information
hansott committed Mar 6, 2024
1 parent 08f2d7c commit 84ecb61
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,62 @@ t.test("it understands MySQL escaping rules", async (t) => {
[69, 71, "b"],
],
],
[
`SELECT * FROM users WHERE name = 'John' -- and 'Jane';`,
[[33, 38, "John"]],
],
[
`SELECT * FROM users WHERE note = 'O\\'Reilly\\'s book';`,
[[33, 51, "O\\'Reilly\\'s book"]],
],
[`SELECT * FROM users WHERE path = 'C:\\\\\\\\'Documents\\\\\\';`, []],
[
`SELECT * FROM users WHERE name = 'Doe /* John */';`,
[[33, 48, "Doe /* John */"]],
],
[
`SELECT * FROM logs WHERE message = 'Error: Invalid path \\'/home/user/docs\\'\\\\nRetry with a valid path.';`,
[
[
35,
102,
"Error: Invalid path \\'/home/user/docs\\'\\\\nRetry with a valid path.",
],
],
],
[
`SELECT * FROM files WHERE data = x'4D7953514C' AND backup = b'01010101';`,
[
[34, 45, "4D7953514C"],
[61, 70, "01010101"],
],
],
[
`SELECT * FROM messages WHERE greeting = CONCAT('Hello, ', '\\'world!\\'', ' How\\'s everything?');`,
[
[47, 55, "Hello, "],
[58, 69, "\\'world!\\'"],
[72, 92, " How\\'s everything?"],
],
],
[
`SELECT * FROM products WHERE description = 'It''s ''quoted'' text here';`,
[[43, 70, "It''s ''quoted'' text here"]],
],
[
`SELECT * FROM code_snippets WHERE snippet = 'SELECT * FROM table -- where condition = \\'value\\'';`,
[[44, 95, "SELECT * FROM table -- where condition = \\'value\\'"]],
],
[
`SELECT * FROM reviews WHERE comment = 'He said, \\"This is awesome!\\" But I think it\\'s just \\'okay\\'.';`,
[
[
38,
101,
"He said, \\\"This is awesome!\\\" But I think it\\'s just \\'okay\\'.",
],
],
],
];

for (const [input, expected] of checks) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,68 +13,77 @@ export class SQLDialectMySQL implements SQLDialect {
const char = sql[i];
const nextChar = sql[i + 1];

// Handle escaping characters
if (char === "\\" && !inSingleLineComment && !inMultiLineComment) {
// Skip processing for escaped characters, ensuring we're not in a comment
if (
char === "\\" &&
!inSingleLineComment &&
!inMultiLineComment &&
literal
) {
i++;
continue;
}

// Check for single-line comment start
// Start or end of literal processing
if (
(char === "#" || (char === "-" && nextChar === "-")) &&
escapeQuotes.includes(char) &&
!inSingleLineComment &&
!inMultiLineComment
) {
inSingleLineComment = true;
continue;
}

// Check for multi-line comment start
if (char === "/" && nextChar === "*" && !inSingleLineComment) {
inMultiLineComment = true;
i++; // Skip the '*' to avoid confusion with closing tags
continue;
}
if (literal && literal.quote === char) {
// Check for escape sequence of the quote itself
if (sql[i + 1] === char) {
i++; // Skip the next quote
continue;
}

// Handle end of single-line comment
if (inSingleLineComment && char === "\n") {
inSingleLineComment = false;
continue;
}
ranges.push([literal.start, i, sql.slice(literal.start + 1, i)]);
literal = undefined; // Exit literal
continue;
}

// Handle end of multi-line comment
if (inMultiLineComment && char === "*" && nextChar === "/") {
inMultiLineComment = false;
i++; // Move past the '/'
continue;
if (!literal) {
literal = { start: i, quote: char }; // Start a new literal
continue;
}
}

// Skip literal processing if we're inside a comment
if (inSingleLineComment || inMultiLineComment) {
continue;
}
// Only check for comments if not inside a literal
if (!literal) {
// Single-line comment start
if (
(char === "#" || (char === "-" && nextChar === "-")) &&
!inMultiLineComment
) {
inSingleLineComment = true;
continue;
}

// Literal processing
for (const quote of escapeQuotes) {
if (char === quote) {
if (literal && literal.quote === quote) {
// Double quote escape check
if (sql[i + 1] === quote) {
i++;
continue;
}
// Multi-line comment start
if (char === "/" && nextChar === "*" && !inSingleLineComment) {
inMultiLineComment = true;
i++; // Skip the '*' to avoid confusion with closing tags
continue;
}

ranges.push([literal.start, i, sql.slice(literal.start + 1, i)]);
literal = undefined;
continue;
}
// End of single-line comment
if (inSingleLineComment && char === "\n") {
inSingleLineComment = false;
continue;
}

literal = { start: i, quote: char };
// End of multi-line comment
if (inMultiLineComment && char === "*" && nextChar === "/") {
inMultiLineComment = false;
i++; // Move past the '/'
continue;
}
}
}

// If we end up with an unclosed literal, it's an error in the SQL syntax
// Check for unclosed literal as an error in SQL syntax
if (literal) {
// Unclosed literal, return an empty range or handle as an error
return [];
}

Expand Down

0 comments on commit 84ecb61

Please sign in to comment.