Skip to content

Commit 3af76d9

Browse files
committed
Issue #1326: ignore semicolon between double-dollar quoted strings when separating SQL queries by semicolon, e.g. $$ foo; bar $$
1 parent 036e967 commit 3af76d9

File tree

1 file changed

+33
-16
lines changed

1 file changed

+33
-16
lines changed

source/apphelpers.pas

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ interface
1414
System.Win.Registry, System.DateUtils, System.Generics.Collections, System.Contnrs, System.StrUtils, System.AnsiStrings, Winapi.TlHelp32, System.Types,
1515
dbconnection, dbstructures, dbstructures.mysql, SynMemo, Vcl.Menus, Winapi.WinInet, gnugettext, Vcl.Themes,
1616
System.Character, Vcl.ImgList, System.UITypes, Vcl.ActnList, Winapi.WinSock, System.IOUtils, Vcl.StdCtrls, Vcl.ComCtrls,
17-
Winapi.CommCtrl, Winapi.KnownFolders, SynUnicode, SynEdit;
17+
Winapi.CommCtrl, Winapi.KnownFolders, SynUnicode, SynEdit, System.IniFiles;
1818

1919
type
2020

@@ -3361,13 +3361,13 @@ function TSQLBatch.GetSize: Integer;
33613361
procedure TSQLBatch.SetSQL(Value: String);
33623362
var
33633363
i, AllLen, DelimLen, DelimStart, LastLeftOffset, RightOffset: Integer;
3364-
c, n, LastStringEncloser: Char;
3365-
Delim, DelimTest, QueryTest: String;
3364+
c, n: Char;
3365+
Delim, DelimTest, QueryTest, LastQuote, cn: String;
33663366
InString, InComment, InBigComment, InEscape: Boolean;
33673367
Marker: TSQLSentence;
33683368
rx: TRegExpr;
3369+
Quotes: THashedStringList;
33693370
const
3370-
StringEnclosers = ['"', '''', '`'];
33713371
NewLines = [#13, #10];
33723372
WhiteSpaces = NewLines + [#9, ' '];
33733373
begin
@@ -3378,11 +3378,19 @@ procedure TSQLBatch.SetSQL(Value: String);
33783378
i := 0;
33793379
LastLeftOffset := 1;
33803380
Delim := Mainform.Delimiter;
3381-
InString := False; // Loop in "enclosed string" or `identifier`
3382-
InComment := False; // Loop in one-line comment (# or --)
3383-
InBigComment := False; // Loop in /* multi-line */ or /*! condictional comment */
3384-
InEscape := False; // Previous char was backslash
3385-
LastStringEncloser := #0;
3381+
Quotes := THashedStringList.Create;
3382+
Quotes.CaseSensitive := True;
3383+
Quotes.Sorted := True;
3384+
Quotes.Add('"');
3385+
Quotes.Add('''');
3386+
Quotes.Add('`'); // MySQL/MariaDB only
3387+
Quotes.Add('$$'); // PostgreSQL only ($abc$ unsupported)
3388+
3389+
InString := False; // c is in "enclosed string" or `identifier`
3390+
InComment := False; // c is in one-line comment (# or --)
3391+
InBigComment := False; // c is in /* multi-line */ or /*! condictional comment */
3392+
InEscape := False; // Previous char was backslash
3393+
LastQuote := #0;
33863394
DelimLen := Length(Delim);
33873395
rx := TRegExpr.Create;
33883396
rx.Expression := '^\s*DELIMITER\s+(\S+)';
@@ -3393,20 +3401,27 @@ procedure TSQLBatch.SetSQL(Value: String);
33933401
Inc(i);
33943402
// Current and next char
33953403
c := FSQL[i];
3396-
if i < AllLen then n := FSQL[i+1]
3397-
else n := #0;
3404+
if i < AllLen then
3405+
n := FSQL[i+1]
3406+
else
3407+
n := #0;
3408+
cn := c + n;
33983409

3399-
// Check for comment syntax and for enclosed literals, so a query delimiter can be ignored
3410+
// Check for comment syntax, so a query delimiter can be ignored
34003411
if (not InComment) and (not InBigComment) and (not InString) and ((c + n = '--') or (c = '#')) then
34013412
InComment := True;
34023413
if (not InComment) and (not InBigComment) and (not InString) and (c + n = '/*') then
34033414
InBigComment := True;
34043415
if InBigComment and (not InComment) and (not InString) and (c + n = '*/') then
34053416
InBigComment := False;
3406-
if (not InEscape) and (not InComment) and (not InBigComment) and CharInSet(c, StringEnclosers) then begin
3407-
if (not InString) or (InString and (c = LastStringEncloser)) then begin
3408-
InString := not InString;
3409-
LastStringEncloser := c;
3417+
// Check for enclosed literals, so a query delimiter can be ignored
3418+
if (not InEscape) and (not InComment) and (not InBigComment) and (Quotes.Contains(c) or Quotes.Contains(cn)) then begin
3419+
if not InString then begin
3420+
InString := True;
3421+
LastQuote := IfThen(Quotes.Contains(c), c, cn);
3422+
end
3423+
else if (c = LastQuote) or (cn = LastQuote) then begin
3424+
InString := False;
34103425
end;
34113426
end;
34123427
if (CharInSet(c, NewLines) and (not CharInSet(n, NewLines))) or (i = 1) then begin
@@ -3449,6 +3464,8 @@ procedure TSQLBatch.SetSQL(Value: String);
34493464
end;
34503465
end;
34513466
end;
3467+
3468+
Quotes.Free;
34523469
end;
34533470

34543471
function TSQLBatch.GetSQLWithoutComments: String;

0 commit comments

Comments
 (0)