mcrblog

vcpp-ml

2003年01月

31

[vcpp 00060295] RE: [C++からストアドプロシージャ実行]

島野です。補足です。

「引数が多すぎます」の件ですが、こちらでも現象が再現しました。
どうやら「戻り値」を指定する順番に関係あるようです。

  cd.Parameters.Append result     ' 戻り値
  cd.Parameters.Append paramIn    ' 引数1(入力)
  cd.Parameters.Append paramInOut ' 引数2(入出力)
  cd.Parameters.Append paramOut   ' 引数3(出力)

のように、戻り値、引数1、引数2、引数3・・・と、
Command オブジェクトにパラメータを追加する場合は、問題ありませんが、

  cd.Parameters.Append paramIn    ' 引数1(入力)
  cd.Parameters.Append paramInOut ' 引数2(入出力)
  cd.Parameters.Append paramOut   ' 引数3(出力)
  cd.Parameters.Append result     ' 戻り値

のように、順番を替えると「引数が多すぎます」のエラーになりました。
( result が「出力」パラメータとして扱われるようです。)
「「戻り値」パラメータは先頭で Append する必要がある」という明示的な
記述がヘルプに見当たらないのですが、恐らくこれが原因かと思います。

また、CreateParameter の第1引数の名称ですが、必ずしも
SP の引数の名前(パラメータ名)にする必要はありません。
逆に、明示的に NamedParameters(名前付きパラメータ)を True にセット
した場合は、SP のパラメータ名を指定する必要があります。

/*---------------------------------------------------------/
/* パラメータに入力、入出力、出力を持つSP(sp_test4.sql) */
/*---------------------------------------------------------/
create procedure sp_test4( @in integer, @inout integer output, @out integer output )
as
set @inout = @inout * 10
set @out = @in * 10
return @in

' ----------------------------------------------
' 戻り値を取得するサンプル(adotest4.vbs)
' ----------------------------------------------
Main

const adCmdStoredProc = 4
const adInteger = 3
const adParamInput = 1
const adParamOutput = 2
const adParamInputOutput = 3
const adParamReturnValue = 4

Sub Main()
  Dim cn
  Dim cd
  Set cn = CreateObject("ADODB.Connection")
  Set cd = CreateObject("ADODB.Command")
  cn.Open "SERVER=(local);DATABASE=db_test;PROVIDER=SQLOLEDB;", "sa", "passwordpassword"
  cd.CommandText = "sp_test4"
  cd.CommandType = adCmdStoredProc
  Dim paramIn    ' ADODB.Parameter
  Dim paramInOut ' ADODB.Parameter
  Dim paramOut   ' ADODB.Parameter
  Dim result
  Dim value1
  Dim value2
  value1 = 10 ' 初期値
  value2 = 20 ' 初期値
  ' CreateParameter により、Parameter オブジェクトを作成する。
  Set result     = cd.CreateParameter( "戻り値", adInteger, adParamReturnValue )
  Set paramIn    = cd.CreateParameter( "引数1", adInteger, adParamInput, , value1 )
  Set paramInOut = cd.CreateParameter( "引数2", adInteger, adParamInputOutput, , value2 )
  Set paramOut   = cd.CreateParameter( "引数3", adInteger, adParamOutput )

' 名前付きパラメータを利用した場合
'  cd.NamedParameters = True
'  Set result     = cd.CreateParameter( "戻り値", adInteger, adParamReturnValue )
'  Set paramIn    = cd.CreateParameter( "@in", adInteger, adParamInput, , value1 )
'  Set paramInOut = cd.CreateParameter( "@inout", adInteger, adParamInputOutput, , value2 )
'  Set paramOut   = cd.CreateParameter( "@out", adInteger, adParamOutput )

  ' 「戻り値」は常に先頭で Append しなければならないらしい(調査中)
  ' NamedParameters(名前付きパラメータ)を True にセットした場合は、
  ' 2番目以降の Append の順番を変更することができる。
  ' 
  cd.Parameters.Append result     ' 戻り値
  cd.Parameters.Append paramIn    ' 引数1(入力)
  cd.Parameters.Append paramInOut ' 引数2(入出力)
  cd.Parameters.Append paramOut   ' 引数3(出力)
  Set cd.ActiveConnection = cn

  WScript.Echo "<SP 実行前>"
  WScript.Echo result.Name     + ":" + CStr(result.Value)     ' 戻り値
  WScript.Echo paramIn.Name    + ":" + CStr(paramIn.Value)    ' 引数1
  WScript.Echo paramInOut.Name + ":" + CStr(paramInOut.Value) ' 引数2
  WScript.Echo paramOut.Name   + ":" + CStr(paramOut.Value)   ' 引数3

  ' SP を実行
  cd.Execute

  WScript.Echo "<SP 実行後>"
  WScript.Echo result.Name     + ":" + CStr(result.Value)     ' 戻り値
  WScript.Echo paramIn.Name    + ":" + CStr(paramIn.Value)    ' 引数1
  WScript.Echo paramInOut.Name + ":" + CStr(paramInOut.Value) ' 引数2
  WScript.Echo paramOut.Name   + ":" + CStr(paramOut.Value)   ' 引数3

  Set cd.ActiveConnection = Nothing
End Sub

--
31

[vcpp 00060294] RE: [C++からストアドプロシージャ実行]

島野です。

> ここでいう"result"!!
> こいつが、SP側の引数でもってないと動作しないので。

そんなことはありません。

> 私が述べたいことは、SPで@resultを引数でもっていないとき。
> 例えば、直書きでreturn 10 とした場合取得できます???
> ってことです。

以下のコードで取得できました。

/*---------------------------------------------------/
/* パラメータ無し。戻り値のみ返すSP(sp_test3.sql) */
/*---------------------------------------------------/
create procedure sp_test3
as
return 10

' ----------------------------------------------
' 戻り値を取得するサンプル(adotest3.vbs)
' コマンドラインにて CScript adotest3.vbs を実行
' ----------------------------------------------
Main
const adCmdStoredProc = 4
const adInteger = 3
const adParamReturnValue = 4
Sub Main()
  Dim cn
  Dim cd
  Set cn = CreateObject("ADODB.Connection")
  Set cd = CreateObject("ADODB.Command")
  cn.Open "SERVER=(local);DATABASE=db_test;PROVIDER=SQLOLEDB;", "sa", ""
  cd.CommandText = "sp_test3"
  cd.CommandType = adCmdStoredProc
  cd.Parameters.Append cd.CreateParameter( "result", adInteger, adParamReturnValue )
  Set cd.ActiveConnection = cn
  cd.Execute
  WScript.Echo "return=" + CStr(cd("result"))
  Set cd.ActiveConnection = Nothing
End Sub

<結果>
return=10

> PrintProviderErrorで、引数が多すぎます。
> とエラーが返ってきてしますのです。

adParamReturnValue はパラメータとして扱われないはずですので、
別のパラメータが悪さをしているのでは?と思います。
試しに、SQL Server 付属のツール「SQL プロファイラ」を使って、
実際に発行されているクエリを確認してみてはいかがでしょうか?
「SQL プロファイラ」は、
[プログラム] - [Microsoft SQL Server] - [プロファイラ]

(SQL Server のバージョンにより、多少メニュー構成が違うかもしれませんが)
より、起動できると思います。

上記の、VBScript の例では、adParamReturnValue しか渡してない為、
------------------------------
exec sp_test3
------------------------------
というトレース結果が出力されるはずです。
もし、入力パラメータ(もしくは入出力パラメータ)を渡していれば、
違うトレース結果が出力されると思います。

確認してみてください。

--
31

[vcpp 00060294] RE: [C++からストアドプロシージャ実行]

島野です。

> ここでいう"result"!!
> こいつが、SP側の引数でもってないと動作しないので。

そんなことはありません。

> 私が述べたいことは、SPで@resultを引数でもっていないとき。
> 例えば、直書きでreturn 10 とした場合取得できます???
> ってことです。

以下のコードで取得できました。

/*---------------------------------------------------/
/* パラメータ無し。戻り値のみ返すSP(sp_test3.sql) */
/*---------------------------------------------------/
create procedure sp_test3
as
return 10

' ----------------------------------------------
' 戻り値を取得するサンプル(adotest3.vbs)
' コマンドラインにて CScript adotest3.vbs を実行
' ----------------------------------------------
Main
const adCmdStoredProc = 4
const adInteger = 3
const adParamReturnValue = 4
Sub Main()
  Dim cn
  Dim cd
  Set cn = CreateObject("ADODB.Connection")
  Set cd = CreateObject("ADODB.Command")
  cn.Open "SERVER=(local);DATABASE=db_test;PROVIDER=SQLOLEDB;", "sa", ""
  cd.CommandText = "sp_test3"
  cd.CommandType = adCmdStoredProc
  cd.Parameters.Append cd.CreateParameter( "result", adInteger, adParamReturnValue )
  Set cd.ActiveConnection = cn
  cd.Execute
  WScript.Echo "return=" + CStr(cd("result"))
  Set cd.ActiveConnection = Nothing
End Sub

<結果>
return=10

> PrintProviderErrorで、引数が多すぎます。
> とエラーが返ってきてしますのです。

adParamReturnValue はパラメータとして扱われないはずですので、
別のパラメータが悪さをしているのでは?と思います。
試しに、SQL Server 付属のツール「SQL プロファイラ」を使って、
実際に発行されているクエリを確認してみてはいかがでしょうか?
「SQL プロファイラ」は、
[プログラム] - [Microsoft SQL Server] - [プロファイラ]

(SQL Server のバージョンにより、多少メニュー構成が違うかもしれませんが)
より、起動できると思います。

上記の、VBScript の例では、adParamReturnValue しか渡してない為、
------------------------------
exec sp_test3
------------------------------
というトレース結果が出力されるはずです。
もし、入力パラメータ(もしくは入出力パラメータ)を渡していれば、
違うトレース結果が出力されると思います。

確認してみてください。

--
31

[vcpp 00060293] RE: [C++からストアドプロシージャ実行]


お世話になっております。  藤沢です。


島野さん

お返事遅くなりました。
(並びに操作ミスによる署名のみの投稿申し訳ありませんでした。)

> | adParamInput       … パラメータが入力パラメータであることを表します。
> | adParamInputOutput … パラメータが入出力パラメータであることを表します。
> | adParamOutput      … パラメータが出力パラメータであることを表します。
> | adParamReturnValue … パラメータが戻り値であることを表します。
> と書いてあります。

ここら辺は理解しているつもりです。
もちろんSPの戻り値は取得できるのですが・・・

> つまり、昨日のコードの
> > cd.Parameters.Append cd.CreateParameter( "result", adInteger,
adParamReturnValue )
> > cd.Parameters.Append cd.CreateParameter( "param1", adInteger, , ,
param1 )
> は、
> 戻り値(adParamReturnValue) :result
> 引数1(adParamInput:既定値):param1
> という意味になり、引数は "param1" 1つだけ指定していることになります。

ここでいう"result"!!
こいつが、SP側の引数でもってないと動作しないので。
SP側で@resultをoutputでもっているときのみSPがreturn @result
した値は上記方法で取得できます。

もっとも、SPの引数で@result Integer output と指定してあれば、
CreateParameterの第三引数でadParamReturnValueを指定し
なくとも、adParamInputOutputを指定すれば取得できますけど。

私が述べたいことは、SPで@resultを引数でもっていないとき。
例えば、直書きでreturn 10 とした場合取得できます???
ってことです。
この場合10って値は変数に格納されていないので、C++側で
は受け取る変数を架空(?)に宣言して取得しなければならない
と思います。
よって、上記コードのように適当い受け取る変数を宣言します
と(cd.Parameters.Append cd.CreateParameter( "result",
adInteger, adParamReturnValue ))
PrintProviderErrorで、引数が多すぎます。
とエラーが返ってきてしますのです。
adParamReturnValueを指定しているにも関わらず。。。

順序が悪いのかと思い、パラメータ設定の前や後、途中と試し
ましたがうまくいかずでした。

ん~ 根本的なところかポカミスしてるかもしれませんが。

しかしながら、本当に御丁寧にソース付きで解説してくださいま
してありがとうございます。
感謝です。

本の紹介までありがとうございました。
31

[vcpp 00060293] RE: [C++からストアドプロシージャ実行]


お世話になっております。  藤沢です。


島野さん

お返事遅くなりました。
(並びに操作ミスによる署名のみの投稿申し訳ありませんでした。)

> | adParamInput       … パラメータが入力パラメータであることを表します。
> | adParamInputOutput … パラメータが入出力パラメータであることを表します。
> | adParamOutput      … パラメータが出力パラメータであることを表します。
> | adParamReturnValue … パラメータが戻り値であることを表します。
> と書いてあります。

ここら辺は理解しているつもりです。
もちろんSPの戻り値は取得できるのですが・・・

> つまり、昨日のコードの
> > cd.Parameters.Append cd.CreateParameter( "result", adInteger,
adParamReturnValue )
> > cd.Parameters.Append cd.CreateParameter( "param1", adInteger, , ,
param1 )
> は、
> 戻り値(adParamReturnValue) :result
> 引数1(adParamInput:既定値):param1
> という意味になり、引数は "param1" 1つだけ指定していることになります。

ここでいう"result"!!
こいつが、SP側の引数でもってないと動作しないので。
SP側で@resultをoutputでもっているときのみSPがreturn @result
した値は上記方法で取得できます。

もっとも、SPの引数で@result Integer output と指定してあれば、
CreateParameterの第三引数でadParamReturnValueを指定し
なくとも、adParamInputOutputを指定すれば取得できますけど。

私が述べたいことは、SPで@resultを引数でもっていないとき。
例えば、直書きでreturn 10 とした場合取得できます???
ってことです。
この場合10って値は変数に格納されていないので、C++側で
は受け取る変数を架空(?)に宣言して取得しなければならない
と思います。
よって、上記コードのように適当い受け取る変数を宣言します
と(cd.Parameters.Append cd.CreateParameter( "result",
adInteger, adParamReturnValue ))
PrintProviderErrorで、引数が多すぎます。
とエラーが返ってきてしますのです。
adParamReturnValueを指定しているにも関わらず。。。

順序が悪いのかと思い、パラメータ設定の前や後、途中と試し
ましたがうまくいかずでした。

ん~ 根本的なところかポカミスしてるかもしれませんが。

しかしながら、本当に御丁寧にソース付きで解説してくださいま
してありがとうございます。
感謝です。

本の紹介までありがとうございました。
記事検索
Amazon.co.jp
  • ライブドアブログ