Alexey Popov пишет:
Это не пользы ради, а исскуства для.
Напрягает писать минипарсер с учётом всяких кавычек и коментариев.
Не напрягайся особо:
procedure TibcCustomStatement.ParseSQL;
var
ch, qc: char;
stmt: string;
ip, op, paramStart: PChar;
function Advance: boolean;
begin
ch := ip^;
inc(ip);
result := ord(ch) <> 0;
end;
procedure apnd(chr: char = #0);
begin
if chr = #0 then
chr := ch;
op^ := chr;
inc(op);
end;
procedure AddParam(paramName: string);
var
i: integer;
isOld: boolean;
begin
isOld := false;
if (length(paramName) > 4) then
begin
if StrLIComp(@paramName[1], 'OLD.', 4) = 0 then
begin
isOld := true;
paramName := copy(paramName, 5, 10000);
fHasOldParams := true;
end
else if StrLIComp(@paramName[1], 'NEW.', 4) = 0 then
paramName := copy(paramName, 5, 10000);
end;
i := 0;
while i < fNamedParamCount do
begin
if (AnsiCompareText(paramName, fNamedParams[i].Name) = 0)
and (fNamedParams[i].IsOld = isOld) then
break;
inc(i);
end;
if i = fNamedParamCount then
begin
inc(fNamedParamCount);
ReallocMem(fNamedParams, fNamedParamCount * sizeof(TParamRec));
fNamedParams[i].SqlVarCount := 0;
fNamedParams[i].SqlInd := nil;
fNamedParams[i].SqlData := nil;
fNamedParams[i].SqlVarOffsets := nil;
fNamedParams[i].Name := paramName;
fNamedParams[i].IsOld := isOld;
end;
with fNamedParams[i] do
begin
inc(SqlVarCount);
ReallocMem(SqlVarOffsets, SqlVarCount * sizeof(word));
if fIDA.sqln < fIDA.sqld then
ReallocXDA(fIDA, fIDA.sqld);
SqlVarOffsets^[SqlVarCount-1] := fIDA.sqld - 1;
end;
end;
function AtBOL(p: pchar): boolean;
begin
while (p <> @fSQL[1]) and (p^ < ' ') do
begin
if (p^ = #$0A) or (p^ = #$0D) then
begin
result := true;
exit;
end;
dec(p);
end;
result := p = @fSQL[1];
end;
begin
fProcessedText := '';
FreeParams;
fHasOldParams := false;
fHasUnnamedParams := false;
if (pos(':', fSQL) = 0) and (pos('?', fSQL) = 0) and (pos('.', fSQL)
= 0) then
begin
fProcessedText := fSQL;
exit;
end;
// Extract parameters
stmt := '';
SetLength(stmt, length(fSQL) + 1);
ip := @fSQL[1];
op := @stmt[1];
while Advance do
case ch of
'''', '"': begin
qc := ch;
Apnd;
while Advance and (ch <> qc) do
Apnd;
if ch = #0 then
DatabaseError('Unfinished string in query', self);
Apnd; // final quote
end;
'/': begin
if ip^ = '*' then
begin
// skip comment
Advance;
while ch <> #0 do
begin
while Advance and (ch <> '*') do
;
if (ch = '*') and (ip^ = '/') then
begin
advance; // skip /
break;
end;
end;
if ch = #0 then
DatabaseError('Unfinished comment in query', self);
end
else
Apnd;
end;
'-': begin
if (ip^ = '-') and AtBOL(ip - 2) then
begin
while Advance and (ch <> #$0D) and (ch <> #$0A) do
;
if (ch = #$0D) and (ip^ = #$0A) then
Advance;
end
else
Apnd;
end;
':', '?': begin
if not (ip^ in ['a'..'z', 'A'..'Z', '_', '"']) then
begin
if ch = '?' then
begin
Apnd;
inc(fIDA.sqld);
fHasUnnamedParams := true;
end
else
DatabaseError('Invalid parameter name', self);
end
else
begin
Apnd('?');
inc(fIDA.sqld);
if ip^ = '"' then
begin
qc := '"';
Advance;
paramStart := ip;
while Advance and (ip^ <> '"') do
;
if ip^ <> '"' then
DatabaseError('Unfinished quoted parameter name', self);
end
else
begin
qc := #0;
paramStart := ip;
while Advance and (ip^ in ['a'..'z', 'A'..'Z', '_',
'0'..'9', '$']) do
;
end;
AddParam(copy(fSQL, integer(paramStart) - integer(@fSQL[1]) +
1, integer(ip) - integer(paramStart)));
if qc = '"' then
Advance; // skip final quote
end;
end
else
Apnd;
end;
SetLength(stmt, integer(op) - integer(@stmt[1]));
fProcessedText := stmt;
ReallocXDA(fIDA, fIDA.sqld);
end;
--
wbr, ps
ps-at-azs-ru