今天我下载并安装了MyConnector,所以我可以将Mysql与ADO一起使用,一切安装完毕,OK!,我可以与ODBC建立连接并从我的delphi环境进行连接。
当我在runetime构建我的查询时,我收到一条错误说:
项目Project1.exe引发异常类EOleException,消息'参数类型错误,超出可接受的范围,或者彼此冲突'。流程停止了。使用步骤或运行继续。
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中关闭调试,这是有效的。
答案 0 :(得分:9)
我会尝试在Adds周围添加SQL.BeginUpdate / SQL.EndUpdate,否则每次调用“Add”时都会解析SQL文本。
这通常是个好主意,因为ADOQuery.SQL是一个TStringList,它有一个设置CommandText的OnChange事件。 SetCommandText文本然后最终调用TADOCommand.AssignCommandText,它执行相当多的工作来解析params,并设置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的范围,以便它在使用Parameters之前结束。
答案 1 :(得分:2)
尝试设置显式数据类型:
CreateSql.Parameters.ParamByName('MyUserName').DataType := ftString;
答案 2 :(得分:2)
在我的例子中,定义参数并在分配连接之前分配查询字符串纠正了问题。查询在两种情况下都成功执行,但如果在参数化查询之前分配了连接,TADOQuery
组件会在内部引发(并随后吞下)OP中记录的EOleException
。
//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!
我愿意解释为什么会出现这种情况 - 文档中没有任何内容似乎表明需要这种操作顺序。
在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
返回的似乎无效的值(DBPARAMFLAGSENUM
= 320 - >设置在GetParameterInfo
定义长度以上的位)。流控制的异常处理似乎是唯一的选择,因为接口在设置它们(和触发异常)之前不提供任何检查值的机制。
更新:
事实证明,有一个关于此问题的公开质询:http://qc.embarcadero.com/wc/qcmain.aspx?d=107267
答案 3 :(得分:1)
BeginUpdate / EndUpdate对不够用。在分配sql命令之前,使用AddParameter添加参数表达式。像:
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;
...