* 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.
This commit is contained in:
rosenfield
2007-10-05 20:17:11 +00:00
parent a3e18dc1dc
commit 213d145f3a

View File

@ -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