2016-09-15 8 views
0

update foo set bar = @bar, baz = @bazなどの更新ステートメントがあり、パラメータがないコマンドを作成すると、更新でこれらの列の現在の値が使用されているように見えます。Npgsqlのデフォルトのパラメータ動作

NpgsqlまたはPostgresqlのいずれのドキュメントでも、私が頼りにすることができないサポートされている機能ですか、それとも何か起こることがありますか?

簡単な例:

using System; 
using Npgsql; 

namespace MissingParametersUpdate 
{ 
    static class Program 
    { 
     // you will need to have CREATE TABLE foo (bar integer, baz integer) 
     static void Main(string[] args) 
     { 
      using (var connection = new NpgsqlConnection(args[0])) 
      { 
       connection.Open(); 

       using (var command = connection.CreateCommand()) 
       { 
        command.CommandText = @"delete from foo"; 
        command.ExecuteNonQuery(); 
       } 
       using (var command = connection.CreateCommand()) 
       { 
        command.CommandText = @"insert into foo (bar, baz) values (1, 2), (3, 4)"; 
        command.ExecuteNonQuery(); 
       } 

       DumpValues("Initial", connection); 

       // empty update 
       using (var command = connection.CreateCommand()) 
       { 
        command.CommandText = @"update foo set bar = @bar, baz = @baz"; 
        command.ExecuteNonQuery(); 
       } 

       DumpValues("Empty Update", connection); 

       // update bar 
       using (var command = connection.CreateCommand()) 
       { 
        command.CommandText = @"update foo set bar = @bar, baz = @baz"; 
        command.Parameters.AddWithValue(@"bar", 42); 
        command.ExecuteNonQuery(); 
       } 

       DumpValues("Update Bar", connection); 

       // update baz 
       using (var command = connection.CreateCommand()) 
       { 
        command.CommandText = @"update foo set bar = @bar, baz = @baz"; 
        command.Parameters.AddWithValue(@"baz", 12); 
        command.ExecuteNonQuery(); 
       } 

       DumpValues("Update Baz", connection); 
      } 
     } 

     private static void DumpValues(string caption, NpgsqlConnection connection) 
     { 
      Console.WriteLine(caption); 
      using (var command = connection.CreateCommand()) 
      { 
       command.CommandText = @"select bar, baz from foo"; 
       using (var reader = command.ExecuteReader()) 
        while (reader.Read()) 
         Console.WriteLine(" (bar: {0}, baz: {1})", reader.GetInt32(0), reader.GetInt32(1)); 
      } 
      Console.WriteLine(); 
     } 
    } 
} 

答えて

1

これは確かに少し奇妙である、ここで何が起こっているのです。

PostgreSQLは$ 1、$ 2などの形式の位置パラメータプレースホルダを受け入れます。しかし、.NETでは名前付きプレースホルダを持つことが多少標準です。 @ bar、@baz。これをサポートするために、NpgsqlはSQLプレースホルダを解析してパラメータプレースホルダを見つけます(例:@bar)。見つかると、NpgsqlCommandの対応する名前を持つNpgsqlParameterを探し、それをPostgreSQLと互換性のある定位置($ 1など)に置き換えます。

Npgsqlが対応するNpgsqlParameterを持たないのプレースホルダ{}を検出した場合、単にそれだけを残します。ある時点で例外がスローされましたが、Npgsqlの内部SQLパーサーでは不十分で、クエリの一部がパラメータのプレースホルダとして誤って識別されたケースもありました。対応するNpgsqlParameterを持たない識別されたプレースホルダを離れると、この問題が解決されます。

これは、PostgreSQLがNpgsqlの部分で何の操作もせずにSQL update foo set bar = @bar, baz = @bazという文字列を受け取るということです。さて、PostgreSQLは@を特殊文字とみなしています。それを演算子として定義することができます(https://www.postgresql.org/docs/current/static/sql-syntax-lexical.html参照)。しかし、デフォルトで@は全く何もしないように見えるので、あなたが実際に行ったのはupdate foo set bar = bar, baz = bazです。明らかに何もしません。 SELECT @fooを実行すると、@振る舞いを見ることができます。PostgreSQLは、column "foo" does not existというエラーで応答します。

これは、パラメータが設定されていないためそのままの状態でNpgsqlを実行し、PostgreSQLが@を無視しているためです。

関連する問題