C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[3]: SQLParameterを利用した時のデータ切捨てについて


(過去ログ 13 を表示中)

[トピック内 4 記事 (1 - 4 表示)]  << 0 >>

■3959 / inTopicNo.1)  SQLParameterを利用した時のデータ切捨てについて
  
□投稿者/ Mr.T (52回)-(2007/05/30(Wed) 11:38:51)

分類:[.NET 全般] 

Mr.Tです、こんにちは。

Microsoft SQL Server Management Studio Express 9.00.3042.00
Microsoft .NET Framework 2.0.50727.42
Microsoft Visual Basic 2005   76541-000-0000011-00124

本来は、ASP.NETでのWebアプリケーション開発中にアレと思ったのですが、
Vb.NETでサンプル確認しても同じ現象だったので、.NET全般で質問させていただきます。

下記のサンプルを実行すると、SQLParameterを利用した場合と、SQLを直接渡した場合
とで挙動がことなってしまう件についてです。

Imports System.Data.SqlClient
Imports System.Data.SqlDbType

Public Class Form1

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Dim strSQL As String = "insert into TestTable values(@TestID,@TestName)"
        Dim TestIDPara As SqlParameter = New SqlParameter
        Dim TestNamePara As SqlParameter = New SqlParameter

        With TestIDPara
            .ParameterName = "@TestID"
            .SqlDbType = VarChar
            .Size = 5
            .Value = "12345678"
            .Direction = ParameterDirection.Input
        End With

        With TestNamePara
            .ParameterName = "@TestName"
            .SqlDbType = VarChar
            .Size = 10
            .Value = "1234567890"
            .Direction = ParameterDirection.Input
        End With

		'事前確認
        MessageBox.Show(TestIDPara.Value.ToString)

        Using con As SqlConnection = _
                New SqlConnection("Data Source=****;Initial Catalog=****;Persist Security Info=True;User ID=**;Password=***")
            Using sqlcom As SqlCommand = New SqlCommand(strSQL, con)
                con.Open()
                sqlcom.CommandType = CommandType.Text
                sqlcom.Parameters.Add(TestIDPara)
                sqlcom.Parameters.Add(TestNamePara)

                Dim retVal As Integer = sqlcom.ExecuteNonQuery()
                MessageBox.Show(retVal.ToString)
                con.Close()
            End Using

            Using sqlcom1 As SqlCommand = New SqlCommand("Insert into TestTable values('987654321','1234567890')", con)
                con.Open()
                sqlcom1.CommandType = CommandType.Text
                Dim retVal As Integer = sqlcom1.ExecuteNonQuery()
                MessageBox.Show(retVal.ToString)
                con.Close()
            End Using

        End Using

    End Sub
End Class

対象となるTestTableは次のようになります。

CREATE TABLE [dbo].[TestTable](
	[TestID] [varchar](5) NOT NULL,
	[TestName] [varchar](10) NOT NULL,
 CONSTRAINT [PK_TestTable] PRIMARY KEY CLUSTERED 
(
	[TestID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

SQLParameterを利用した場合、例外やエラーが発生しません。
しかし、次のSQL発行処理は、予想通り(フィールドサイズよりも大きいサイズのパラメータですので)
例外が発生して処理されません。

なんで?と発行前にTestIDPara.Valueを確認しましたが、この時点では与えたパラメータが
そのまま表示されます。

SQLCommand.Prepare()(http://msdn2.microsoft.com/ja-jp/library/system.data.sqlclient.sqlcommand.prepare(vs.80).aspx)
を行うと、パラメータで指定した場合には切り詰められることがあるようですが、
今回は実際利用してません。

SQLParameterを利用した場合でフィールドサイズより大きいかどうか、というのは
事前にチェックするロジックはもちろん組み込みますが、実行したらいきなりデータが
切り捨てられるのもちょっと乱暴な感じがします。

その他情報をあさってみましたが、上記に当てはまるものはちょっと見受けられませんでした。
SQLParameterを利用した場合ではなぜ、こういう挙動なのか、どなたかわかりますでしょうか?
#それとも、私が知らないだけで当然な現象なのでしょうか。

引用返信 編集キー/
■3964 / inTopicNo.2)  Re[1]: SQLParameterを利用した時のデータ切捨てについて
□投稿者/ 片桐 (11回)-(2007/05/30(Wed) 13:08:22)
こちら全く別件でプロファイラを使ってて、気がついた事。

SQLCommandオブジェクトに渡されるCommandTextって、実際にSQLサーバー上で実行される前に文法チェックを受けていて、それがOKになって初めて実行されてたんです。つまり、直接SQL文を書いて動かす場合、例外となるタイミングはかなり早くてSQLサーバーで実行される前、なんじゃないでしょうか?

一方のParameter使う場合、CommandTextに書かれたSQL文は当然エラーにならないでSQLサーバーまで渡されて、SQLサーバー上ではじめてSQLParamerを割りあてて、「あれ?長いじゃん、切っちゃえ」で動いちゃうんじゃないかと。

だから挙動が変わるんだと思うんですけれど。
あくまでも現場でのプロファイラ覗いたレベルの憶測です(大汗)
引用返信 編集キー/
■3966 / inTopicNo.3)  Re[2]: SQLParameterを利用した時のデータ切捨てについて
□投稿者/ Mr.T (53回)-(2007/05/30(Wed) 13:39:01)
Mr.Tです、こんにちは。

> 一方のParameter使う場合、CommandTextに書かれたSQL文は当然エラーにならないでSQLサーバーまで渡されて、SQLサーバー上ではじめてSQLParamerを割りあてて、「あれ?長いじゃん、切っちゃえ」で動いちゃうんじゃないかと。
>
> だから挙動が変わるんだと思うんですけれど。
> あくまでも現場でのプロファイラ覗いたレベルの憶測です(大汗)

ありがとうございます。
片桐さんの返信を見て、うわぁ.NETの問題じゃなくてSQLServerの問題?と思い、
ちょいとTestTableを更新するだけのストアド作成して実行してみました。

CREATE PROCEDURE [dbo].[InsertTestTable]
@TestID varchar(5),
@TestName varchar(10)
AS
BEGIN

insert into TestTable values(@TestID,@TestName)

return @@error
end

で、実行の際、パラメータは当然エラーになるように...
exec dbo.InsertTestTable '1234567890' 'Test'
としてみたところ、エラーにならずに戻ってきます。
で、当然、TestIDには切り捨てで格納されている。

そういうものなのかなぁ、と思いながら今、SQLServerで情報あさってます...
#だって、切り捨てるっておかしいやんか...思いました。
#フィールドが可変長じゃなくて、固定長ならエラーになるんかなぁ?
引用返信 編集キー/
■3998 / inTopicNo.4)  Re[3]: SQLParameterを利用した時のデータ切捨てについて
□投稿者/ Mr.T (54回)-(2007/05/31(Thu) 11:24:34)
Mr.Tです。

MSDNから以下のものを見つけました。
http://msdn2.microsoft.com/ja-jp/library/ms161953.aspx

>変数に代入されるすべての動的な Transact-SQL は、その変数に割り当てられているバッファよりも大きい場合は切り捨てられます。予期しない長さの文字列をストアド プロシージャに渡すことで、強制的にステートメントの切り捨てを行うことができれば、攻撃者が結果を操作することも可能になります。たとえば、次のスクリプトによって作成されるストアド プロシージャは、切り捨てによって有効になるインジェクションの影響を受けやすくなります。

どうして切り捨てにするのかはわかりませんが、基本動作なんですね(汗
#エラーにしてくれりゃあいいのに。

とりあえず解決済みにします。
ありがとうございました。

解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -