Использование параметров с запросом ADO (mysql / MyConnector) - PullRequest
3 голосов
/ 30 сентября 2010

Сегодня я скачал и установил MyConnector, чтобы я мог использовать Mysql с ADO, все установлено, хорошо !, я могу установить соединение с ODBC и установить соединение из среды delphi.

когда я строю свой запрос во время выполнения, я получаю сообщение об ошибке:

Project Project1.exe поднял класс исключения EOleException с сообщением «Аргументы имеют неправильный тип, находятся вне допустимого диапазона или конфликтуют друг с другом». Процесс остановлен. Для продолжения используйте Step или Run.

function TForm1.CreateSQL : TADOQuery;
begin
  result := TADOQuery.create(self);
  with Result do
  begin
    Connection     := MainConnection;
    CursorLocation := clUseServer;
    CursorType     := ctStatic;
    CacheSize      := 50;
    AutoCalcFields := true;
    ParamCheck     := true;
    Prepared       := true;
  end;
end;

procedure TForm1.login();
begin
  with CreateSQL do
  try
    with SQL do
    begin
      add('SELECT                       ');
      add('  *                          ');
      add('FROM                         ');
      add('  LisenswebUsers             ');
      add('WHERE                        ');
      add('  UserName     = :MyUsername '); // debugger exception here
      add('AND                          ');
      add('  UserPassword = :MyPassword '); // debugger exception here
      with Parameters do
      begin
        ParamByName('MyUsername').value := txtLogin.text;
        ParamByName('MyPassword').value := strmd5(txtPassword.text);
      end;
      Open;

      if Recordcount <> 1 then
      begin
        lblLoggedinAs.Text := format('Du er logget inn som: %s (%s)',[FieldByName('Username').AsString,FieldByName('UserEmailaddress').AsString]);
        MainPageControl.ActivePageIndex := 1;
      end else
      begin
        txtPassword.Text := '';
        txtPassword.SetFocus;
      end;
    end;
  finally
   free;
  end;
end;

Самое странное, что это работает, если я отключаю отладку в delphi.

Ответы [ 4 ]

9 голосов
/ 30 сентября 2010

Я бы попробовал добавить SQL.BeginUpdate / SQL.EndUpdate вокруг дополнений, иначе текст SQL будет анализироваться каждый раз, когда вы вызываете «Добавить».

Как правило, это хорошая идея, поскольку ADOQuery.SQL - это TStringList, у которого есть событие OnChange, которое устанавливает CommandText. Затем текст SetCommandText в конечном итоге вызывает TADOCommand.AssignCommandText, который выполняет значительный объем работы при разборе параметров, и устанавливает CommandObject.CommandText Иногда драйверы не работают с частичными операторами SQL, но все выглядит хорошо.

У меня была похожая проблема много лет назад - вот почему я узнал об этом материале!

procedure TForm1.login();
var
  Qry : TADOQuery;
begin
  Qry := CreateSQL;
  try
    Qry.SQL.BeginUpdate;

    Qry.SQL.Add('SELECT');
    Qry.SQL.Add('  *');
    Qry.SQL.Add('FROM');
    Qry.SQL.Add('  LisenswebUsers');
    Qry.SQL.Add('WHERE UserName = :MyUsername '); // debugger exception here
    Qry.SQL.Add('  AND UserPassword = :MyPassword '); // debugger exception here

    Qry.SQL.EndUpdate;
    Qry.Parameters.ParamByName('MyUsername').value := txtLogin.text;
    Qry.Parameters.ParamByName('MyPassword').value := strmd5(txtPassword.text);
    Qry.Open;

    if Qry.Recordcount <> 1 then
    begin
      lblLoggedinAs.Text := format('Du er logget inn som: %s (%s)',[FieldByName('Username').AsString,FieldByName('UserEmailaddress').AsString]);
      MainPageControl.ActivePageIndex := 1;
    end
    else
    begin
      txtPassword.Text := '';
      txtPassword.SetFocus;
    end;
  finally
    Qry.Free;
  end;
end;

Кстати, вложенные with действительно ужасны (пусть начнется священная война)

Я иногда буду использовать with, но никогда не буду вкладывать три уровня! Если да, по крайней мере, уменьшите область действия с SQL, чтобы он заканчивался ранее параметрами.

2 голосов
/ 22 октября 2014

В моем случае, определение параметров и назначение строки запроса перед назначением соединения решило проблему.Запрос выполняется в обоих случаях успешно, но компонент TADOQuery внутренне вызывает (и впоследствии глотает) значение EOleException, указанное в OP, если соединение назначено до параметризованного запроса.

//LADOQuery.Connection := LADOConnection;  // Exception @ LADOQuery.Text:=...

Param := LADOQuery.Parameters.AddParameter;
Param.Name := 'rid';
Param.DataType := ftFixedChar;
Param := LADOQuery.Parameters.AddParameter;
Param.Name := 'qd';
Param.DataType := ftLongWord;

LADOQuery.SQL.Clear;
LADOQuery.SQL.Text:='SELECT Val FROM table WHERE v1=:rid AND v2=:qd';

LADOQuery.Connection := LADOConnection;  // OK!

Я открыт для объяснений, почему это так - ничто в документации, похоже, не указывает на необходимость такого порядка операций.

Исключение возникает в файле ADODB.pas в TADOCommand.AssignCommandText здесь

 try
   // Retrieve additional parameter info from the server if supported 
   Parameters.InternalRefresh; 

, где эта ветвь используется только в том случае, если TADOQuery присоединено к действующему соединению.InternalRefresh выполняет:

if OLEDBParameters.GetParameterInfo(ParamCount, 
                                    PDBPARAMINFO(ParamInfo), 
                                    @NamesBuffer) = S_OK then
  for I := 0 to ParamCount - 1 do
    with ParamInfo[I] do
    begin
      // When no default name, fabricate one like ADO does 
      if pwszName = nil then
      Name := 'Param' + IntToStr(I+1) else // Do not localize 
      Name := pwszName;
      // ADO maps DBTYPE_BYTES to adVarBinary 
      if wType = DBTYPE_BYTES then wType := adVarBinary;
      // ADO maps DBTYPE_STR to adVarChar 
      if wType = DBTYPE_STR then wType := adVarChar;
      // ADO maps DBTYPE_WSTR to adVarWChar 
      if wType = DBTYPE_WSTR then wType := adVarWChar;
      Direction := dwFlags and $F;
      // Verify that the Direction is initialized 
      if Direction = adParamUnknown then Direction := adParamInput;
      Parameter := Command.CommandObject.CreateParameter(Name, wType, Direction, ulParamSize, EmptyParam);
      Parameter.Precision := bPrecision;
      Parameter.NumericScale := ParamInfo[I].bScale;
      // EOleException raised here  vvvvvvvvv
      Parameter.Attributes := dwFlags and $FFFFFFF0; //Mask out Input/Output flags 
      AddParameter.FParameter := Parameter;
    end;

Проблема определенно возникает на уровне OLE, возможно, из-за того, что драйвер MySQL ODBC не поддерживает возврат этой информации (или возвращает неверную информацию).Исключение возникает за интерфейсом _Parameter при настройке

 Parameter.Attributes := dwFlags and $FFFFFFF0; 

с использованием, как представляется, недопустимых значений (dwFlags = 320 -> биты, установленные выше DBPARAMFLAGSENUM определенной длины), возвращаемых из GetParameterInfo,Обработка исключений для управления потоком кажется единственной возможностью, учитывая, что интерфейс не предоставляет какого-либо механизма для проверки значений перед их установкой (и инициированием исключений).


Обновление:

Оказывается, есть открытый QC по этому поводу: http://qc.embarcadero.com/wc/qcmain.aspx?d=107267

2 голосов
/ 30 сентября 2010

Попробуйте установить явный тип данных:

CreateSql.Parameters.ParamByName('MyUserName').DataType := ftString;
1 голос
/ 15 апреля 2011

Пара BeginUpdate / EndUpdate не подходит. Используйте AddParameter, чтобы добавить параметры чистоты перед назначением команды sql. Как:

var
  Qry : TADOQuery;
begin
  Qry := CreateSQL;
  try
    with Qry.Parameters.AddParameter do
    begin
      Name := 'MyUsername';
      DataType := ftString; 
    end;
    with Qry.Parameters.AddParameter do
    begin
      Name := 'MyPassword';
      DataType := ftString; 
    end;

    Qry.SQL.BeginUpdate;

    Qry.SQL.Add('SELECT');
    Qry.SQL.Add('  *');
    Qry.SQL.Add('FROM');
    Qry.SQL.Add('  LisenswebUsers');
    Qry.SQL.Add('WHERE UserName = :MyUsername '); // debugger exception here
    Qry.SQL.Add('  AND UserPassword = :MyPassword '); // debugger exception here

    Qry.SQL.EndUpdate;
...
...