在针对PostgreSQL使用Npgsql库时,我找不到任何方法将游标ref作为参数传递到FETCH
命令中。这可能吗?
using (DbConnection connection = new NpgsqlConnection(connectionString))
{
connection.Open();
using (DbTransaction transaction = connection.BeginTransaction())
{
var outCursor = new NpgsqlParameter("cursor", NpgsqlTypes.NpgsqlDbType.Refcursor);
outCursor.Direction = ParameterDirection.Output;
// get a refcursor from somewhere
using (DbCommand commandGet = connection.CreateCommand())
{
commandGet.CommandText = "get_cursor";
commandGet.CommandType = CommandType.StoredProcedure;
commandGet.Parameters.Add(outCursor);
commandGet.Connection = connection;
commandGet.ExecuteNonQuery();
}
// try to use it
using (DbCommand commandFetch = connection.CreateCommand())
{
var inCursor = new NpgsqlParameter("cursor", NpgsqlTypes.NpgsqlDbType.Refcursor);
inCursor.Direction = ParameterDirection.Input;
inCursor.Value = outCursor.Value;
// This commented out line using string interpolation works fine.
// Can it be done with a parameter, as I'm trying to do below?
//commandFetch.CommandText = $"FETCH 100 FROM \"{outCursor.Value}\"";
// The same inCursor pattern used here works fine when the cursor is being passed
// on to a function, but does not work for FETCH
commandFetch.CommandText = $"FETCH 100 FROM :cursor";
commandFetch.Parameters.Add(inCursor);
commandFetch.Connection = connection;
// This line fails for param-based version;
// works fine with string-interpolation version
using (var reader = commandFetch.ExecuteReader())
{
while (reader.Read())
{
int a = (int)reader[0];
}
}
}
// close it
using (DbCommand commandClose = connection.CreateCommand())
{
// I would like to be able to pass the cursor as a true parameter here, too
commandClose.CommandText = $"CLOSE \"{outCursor.Value}\"";
commandClose.Connection = connection;
var reader = commandClose.ExecuteNonQuery();
}
}
}
请注意注释掉的一行:我可以使代码正常工作,我只想找到一种使光标ref作为参数传递的方法。
我得到的例外是Npgsql.PostgresException : 42601: syntax error at or near "$1"
。
传递纯字符串值的参数(看起来可能可行...)也会失败,但有相同的例外。
如果将输入游标传递给函数,则上述从输出游标创建输入游标的模式也可以正常工作。
答案 0 :(得分:0)
This Stack Overflow answer及其后续注释基本上可以回答,由于底层数据库的局限性,无法执行我试图做的事情(至少在没有创建和执行动态SQL的情况下)。
您不能在FETCH语句中使用变量。使用动态SQL:EXECUTE格式('FETCH ALL FROM%I',foo);
所以这不是Npgsql的限制,另一个答案中建议的解决方法也可以在Npgsql中应用。或者,您也可以只将字符串插入SQL中,尽管这在某种程度上“难看”(至少在我看来),但实际上是绝对安全的。
(在这种情况下-但是将值直接内插到SQL中通常是一个不好的想法,至少没有第二和第三种思考原因,以及关于是否即使在任何给定的有限用例中,在所有情况下都可以安全地抵御注入攻击可能的情况。)