2

好的,这是一个卷发。我正在编写一些我没有编写的 Delphi 代码,我遇到了一个非常奇怪的问题。我的存储过程的参数之一是通过 as null,即使它肯定是被发送的1

Delphi 代码使用 TADOQuery 来执行存储过程(匿名):

 ADOQuery1.SQL.Text := "exec MyStoredProcedure :Foo,:Bar,:Baz,:Qux,:Smang,:Jimmy";
 ADOQuery1.Parameters.ParamByName("Foo").Value := Integer(someFunction()); 
 // other parameters all set similarly
 ADOQuery1.ExecSQL;

Integer(SomeFunction())目前总是返回 1 - 我用调试器检查过。

但是,在我的存储过程中(出于调试目的而更改):

create procedure MyStoredProcedure (
    @Foo int, @Bar int, @Baz int,
    @Qux int, @Smang int, @Jimmy varchar(20) 
) as begin
    -- temp debug
    if ( @Foo is null ) begin
        insert into TempLog values ( "oh crap" )
    end
    -- do the rest of the stuff here..
end

TempLog确实以“哦,废话”结尾(附带问题:必须有更好的方法来调试存储的过程:它是什么?)。

以下是分析器的示例跟踪:

exec [MYDB]..sp_procedure_params_rowset N'MyStoredProcedure',1,NULL,NULL

declare @p3 int
set @p3=NULL
exec sp_executesql 
    N'exec MyStoredProcedure @P1,@P2,@P3,@P4,@P5,@P6',
    N'@P1 int OUTPUT,@P2 int,@P3 int,@P4 int,@P5 int,@P6 int',
    @p3 output,1,1,1,0,200
select @p3

这对我来说有点奇怪。请注意,它正在使用 @p3@P3 - 这会导致我的问题吗?

另一个奇怪的事情是,它似乎取决于我使用的 TADOConnection。

该项目是一个 dll,它从另一个应用程序传递了一个 TADOConnection。它使用此连接调用所有存储过程。

如果不使用此连接,我首先这样做:

ConnectionNew := TADOQuery.Create(ConnectionOld.Owner);
ConnectionNew.ConnectionString := ConnectionOld.ConnectionString;
TADOQuery1.Connection := ConnectionNew;

那么问题就不会出现了!这种情况的痕迹是这样的:

exec [MYDB]..sp_procedure_params_rowset N'MyStoredProcedure',1,NULL,NULL

declare @p1 int
set @p1=64
exec sp_prepare @p1 output,
    N'@P1 int,@P2 int,@P3 int,@P4 int,@P5 int,@P6 varchar(20)',
    N'exec MyStoredProcedure @P1,@P2,@P3,@P4,@P5,@P6',
    1
select @p1

SET FMTONLY ON exec sp_execute 64,0,0,0,0,0,' ' SET FMTONLY OFF

exec sp_unprepare 64

SET NO_BROWSETABLE OFF

exec sp_executesql 
    N'exec MyStoredProcedure @P1,@P2,@P3,@P4,@P5,@P6',
    N'@P1 int,@P2 int,@P3 int,@P4 int,@P5 int,@P6 varchar(20)',
    1,1,1,3,0,'400.00'

不幸的是,这对 lil ol' 我来说有点过分了。什么样的 TADOConnection 选项可能会影响这一点?

有没有人有任何想法?

编辑: 下面更新(不想再提出这个问题了:P)

4

8 回答 8

1

在我的程序中,我有很多与您的第一个片段非常相似的代码,我还没有遇到过这个问题。

实际上是您的代码,还是您如何表达问题以供我们理解?SQL 的文本是存储在 DFM 中还是动态填充?

我想知道查询的 Params 属性是否已经在 IDE 中获得了定义/缓存的参数列表,这可以解释为什么 P1 被视为输出(这几乎肯定会导致您的 NULL 问题)。

就在您设置 ParamByName.Value 之前,请尝试

ParamByName("Foo").ParamType=ptInput;

我不确定为什么您更改连接字符串也会解决此问题,除非它正在重置该查询参数的内部含义。

在 TSQLQuery 下,每当 SQL.Text 值更改时,查询的 Params 属性就会被重置/重新创建(我不确定 TADOQuery 是否属实),所以你的第一个片段应该导致任何现有的 Params信息已被删除。

如果上面的“ParamByname.ParamType”建议确实为您解决了问题,那么肯定在其他地方(在创建时?在表单上?)查询发生了一些事情,导致它认为 Foo 是一个输出参数......

这些帮助有用?:-)

于 2008-09-26T05:24:36.543 回答
0

警告:我不知道德尔福,但这个问题敲响了一个微弱的钟声,所以我对它感兴趣

如果您使用 TADOStoredProc 而不是 TADOQuery,您会得到相同的结果吗?请参阅 delphi 5 开发人员指南

此外,看起来第一个跟踪没有准备调用并且认为@P1 是执行中的输出参数,而第二个跟踪使用@P1 作为输出进行了准备调用,但在执行中没有将@P1 显示为输出步骤 - 这很重要吗?它确实看起来很奇怪,因此可能是一个线索

您也可以尝试用常量 1 替换函数调用

祝你好运,请告诉我们你的发现!

于 2008-09-26T03:55:13.310 回答
0

我怀疑您之前使用 ADOQuery 时遗留了一些参数不匹配。

您是否尝试在更改 SQL.Text 后重置参数:

  ADOQuery1.Parameters.Refresh;

您也可以尝试清除参数并显式重新创建它们:

  ADOQuery1.Parameters.Clear;
  ADOQuery1.Parameters.CreateParameter('Foo', ftInteger, pdInput, 0, 1);
  [...]

我认为更改连接实际上会强制参数的 InternalRefresh。

于 2008-09-30T08:37:56.677 回答
0
 ADOQuery1.Parameters.ParamByName("Foo").Value = Integer(someFunction()); 

他们不使用:=Object Pascal 中的赋值吗?

于 2008-09-30T08:43:40.157 回答
0

@康斯坦丁

它必须是问题作者的错字。

@Blorgbeard

嗯...当您更改 TADOQuery 的 SQL 时,最好使用清除参数并重新创建然后使用 CreateParameter。我不会在运行时依赖 ParamCheck - 因为它使参数的属性大多未定义。在依赖 ParamCheck 自动填充参数时,我遇到了此类问题 - 很少见,但会发生。啊,如果您使用 CreateParameter 路线,请创建 @RETURN_VALUE 作为第一个参数,因为它会捕获 MSSQL SP 的返回值。

于 2008-09-30T14:32:34.887 回答
0

我唯一遇到过这样的问题是当数据库提供程序无法区分输出(始终将其设置为空)和输入输出(使用您提供的)参数时。

于 2008-09-30T14:42:45.770 回答
0

好的,取得了进展……有点。

@Robsoft 是正确的,设置参数方向来pdInput解决问题。

我追踪到 VCL 代码,它归结为TParameters.InternalRefresh.RefreshFromOleDB. 这个函数在我设置 SQL.Text 时被调用。这是(删节的)代码:

function TParameters.InternalRefresh: Boolean;
  procedure RefreshFromOleDB;
    // ..
        if OLEDBParameters.GetParameterInfo(ParamCount, PDBPARAMINFO(ParamInfo), @NamesBuffer) = S_OK then
          for I := 0 to ParamCount - 1 do
            with ParamInfo[I] do
            begin
              // ..
              Direction := dwFlags and $F;       // here's where the wrong value comes from
              // ..
            end;
     // ..
  end;
  // ..
end;

因此,OLEDBParameters.GetParameterInfo由于某种原因返回了错误的标志。

我已经验证了原始连接(dwFlags and $F)2( DBPARAMFLAGS_ISOUTPUT),而新连接是1( DBPARAMFLAGS_ISINPUT)。

我不确定我是否想深入挖掘,至少现在是这样。

在我有更多时间和意愿之前,我会确保pdInput在打开查询之前将所有参数设置为。
除非现在有人有更聪明的想法..?

无论如何,感谢大家迄今为止的建议。

于 2008-10-07T04:08:43.707 回答
0

我在使用 TADOQuery 检索一些 LDAP 信息时遇到了非常相似的问题,即使您的查询没有参数,TParameter.InternalRefresh 函数中也存在一个错误,该错误会导致访问冲突。

要解决这个问题,只需将 TADOQuery.ParamCheck 设置为 false。

于 2018-12-03T17:12:59.007 回答