2

わかりました、これは巻き毛です。私が書いていない Delphi コードに取り組んでいるのですが、非常に奇妙な問題に遭遇しています。ストアド プロシージャのパラメーターの 1 つが、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 を使用していることに注意してください。これが問題の原因になっている可能性はありますか?

もう 1 つの奇妙な点は、使用する TADOConnection に依存しているように見えることです。

プロジェクトは、別のアプリケーションから TADOConnection を渡される dll です。この接続を使用して、すべてのストアド プロシージャを呼び出します。

この接続を使用する代わりに、最初にこれを行います。

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'

残念ながら、これは私が従うには少し多すぎます。これに影響を与える可能性のある TADOConnection オプションの種類は何ですか?

誰にもアイデアはありますか?

編集: 以下の更新(この質問をもう作りたくありませんでした:P)

4

8 に答える 8

1

私のプログラムには、最初のスニペットと非常によく似たコードがたくさんありますが、この問題は発生していません。

それは実際にあなたのコードですか、それとも私たちが理解できるように問題を表現した方法ですか? SQL のテキストは DFM に保存されていますか、それとも動的に入力されていますか?

おそらくどういうわけか、クエリの Params プロパティが IDE で定義/キャッシュされたパラメーターのリストを既に取得しており、それが P1 が出力として表示されている理由を説明している可能性があるのではないかと思っていました (これはほぼ確実に NULL 問題を引き起こしています)。

ParamByName.Value を設定する直前に、試してください。

ParamByName("Foo").ParamType=ptInput;

そのクエリのパラメーターの内部的な意味をリセットしない限り、接続文字列を変更するとこれも修正される理由がわかりません。

TSQLQuery の下では、クエリの Params プロパティは、SQL.Text 値が変更されるたびにリセット/再作成されます (TADOQuery に当てはまるかどうかはわかりません)。ドロップされたという情報。

上記の「ParamByname.ParamType」の提案で問題が解決する場合は、クエリのどこか (作成時? フォーム上?) で何かが発生しており、Foo が出力パラメーターであると考えさせられています...

それはまったく役に立ちますか?:-)

于 2008-09-26T05:24:36.543 に答える
0

警告: 私はデルファイを知りませんが、この問題はかすかな鐘を鳴らしているので、私はそれに興味があります

TADOQuery の代わりに TADOStoredProc を使用すると、同じ結果が得られますか? Delphi 5 開発者ガイドを参照してください

また、最初のトレースは準備呼び出しを行わず、@P1 が実行の出力パラメーターであると考えているように見えますが、2 番目のトレースは @P1 を出力として準備呼び出しを行いますが、実行の出力として @P1 を示しません。ステップ - これは重要ですか? それは奇妙に思えるので、手がかりになるかもしれません

関数呼び出しを定数 1 に置き換えてみることもできます

頑張ってください、そしてあなたが見つけたことを私たちに知らせてください!

于 2008-09-26T03:55:13.310 に答える
0

このような問題が発生したのは、DB プロバイダーが Output (常に null に設定) パラメーターと InputOutput (提供されたものを使用) パラメーターを区別できなかったときだけでした。

于 2008-09-30T14:42:45.770 に答える
0
 ADOQuery1.Parameters.ParamByName("Foo").Value = Integer(someFunction()); 

:=Object Pascal で代入に使っていませんか?

于 2008-09-30T08:43:40.157 に答える
0

@コンスタンティン

質問の作成者からのタイプミスに違いありません。

@ブロッグビアード

うーん... TADOQuery の SQL を変更するときは、パラメータをクリアしてから CreateParameter を使用して再作成すると便利です。パラメータのプロパティがほとんど未定義のままになるため、実行時に ParamCheck に依存することはありません。パラメータを自動入力するために ParamCheck に依存しているときに、このようなタイプの問題が発生しました - まれですが発生します。ああ、CreateParameter ルートに行く場合は、最初のパラメーターとして @RETURN_VALUE を作成します。これは、MSSQL SP の戻り値をキャッチするためです。

于 2008-09-30T14:32:34.887 に答える
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

以前に ADOQuery を使用したために、いくつかのパラメーターの不一致が残っていると思われます。

SQL.Text を変更した後、パラメータをリセットしようとしましたか:

  ADOQuery1.Parameters.Refresh;

また、パラメーターをクリアして明示的に再作成することもできます。

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

接続を変更すると、実際にはパラメーターの InternalRefresh が強制されると思います。

于 2008-09-30T08:37:56.677 に答える