From 213d145f3aa093f8fe1eb26ca38dfcfc10eb397c Mon Sep 17 00:00:00 2001 From: rosenfield Date: Fri, 5 Oct 2007 20:17:11 +0000 Subject: [PATCH] * Add code comments. * Add helpful (hopefully) delimiter syntax checking. * Protect the backslash-in-string-literal parsing a bit more by only activating it inside string literals. Also move it towards the string literal handler to improve readability. * Fix regression: choose characters for secchar and thdchar that are really unused by the parser logic. --- source/helpers.pas | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/source/helpers.pas b/source/helpers.pas index 0099abd4..af377a66 100644 --- a/source/helpers.pas +++ b/source/helpers.pas @@ -327,12 +327,22 @@ begin result := ''; s := Trim(s); // Test for empty delimiter. - if s = '' then result := 'DELIMITER must be followed by a character or string'; + if s = '' then result := 'DELIMITER must be followed by a non-comment character or string'; // Disallow backslash, because the MySQL CLI does so for some reason. // Then again, is there any reason to be bug-per-bug compatible with some random SQL parser? - if Pos('\', s) > 0 then result := 'Backslash disallowed in DELIMITER because the MySQL CLI does not accept it'; - // Disallow using DELIMITER, so we don't have to deal with it in code. - if UpperCase(s) = 'DELIMITER' then result := '"DELIMITER" is disallowed as a SQL delimiter'; + if Pos('\', s) > 0 then result := 'Backslash disallowed in DELIMITER (because the MySQL CLI does not accept it)'; + // Disallow stuff which would be negated by the comment parsing logic. + if + (Pos('/*', s) > 0) or + (Pos('--', s) > 0) or + (Pos('#', s) > 0) + then result := 'Start-of-comment tokens disallowed in DELIMITER (because it would be ignored)'; + // Disallow stuff which would be negated by the SQL parser (and could slightly confuse it, if at end-of-string). + if + (Pos('''', s) > 0) or + (Pos('`', s) > 0) or + (Pos('"', s) > 0) + then result := 'String literal markers disallowed in DELIMITER (because it would be ignored)'; end; @@ -468,11 +478,12 @@ begin i := i + 1; // Helpers for multi-character tests, avoids testing for string length. - secchar := '-'; - thdchar := '-'; + secchar := '+'; + thdchar := '+'; if i < length(sql) then secchar := sql[i + 1]; if i + 1 < length(sql) then thdchar := sql[i + 2]; + // Turn comments into whitespace. if (sql[i] = '#') and (not instring) and (not inbigcomment) then begin incomment := true; end; @@ -510,6 +521,7 @@ begin if i < len then continue; end; + // Avoid parsing stuff inside string literals. if (sql[i] in ['''', '"', '`']) and (not (backslash and instring)) and (not incomment) then begin if instring and (sql[i] = encloser) then begin if secchar = encloser then @@ -524,6 +536,9 @@ begin if i < len then continue; end; + if (instring and (sql[i] = '\')) or backslash then + backslash := not backslash; + // Allow a DELIMITER command in middle of SQL, like the MySQL CLI does. if (not instring) and (not incomment) and (not inbigcomment) and (not inconditional) and (not indelimiter) and (start + 8 = i) and scanReverse(sql, i, 'delimiter', true) then begin // The allowed DELIMITER format is: @@ -552,6 +567,7 @@ begin if i < len then continue; end; + // Handle conditional comments. if (not instring) and (not incomment) and (sql[i] + secchar + thdchar = '/*!') then begin inconditional := true; condterminated := false; @@ -584,7 +600,7 @@ begin start := i + 1; end else begin tmp := '/*!' + conditional + ' '; - Move(tmp[1], sql[start - length(tmp)], length(tmp)); + move(tmp[1], sql[start - length(tmp)], length(tmp)); start := start - length(tmp); end; condterminated := false; @@ -595,10 +611,7 @@ begin if i < len then continue; end; - if (sql[i] = '\') or backslash then - backslash := not backslash; - - // add sql sentence + // Add sql sentence. if ((not instring) and (scanReverse(sql, i, delimiter, false)) or (i = len)) then begin if (i < len) then j := delimiter_length else begin // end of string, add sql sentence but only remove delimiter if it's there