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

Ответить