是否可以将 refcursor 作为参数直接传递给 Npgsql 上的 FETCH?

Is it possible to pass a refcursor as a parameter directly to FETCH on Npgsql?

在对 PostgreSQL 使用 Npgsql 库时,我找不到任何方法将游标引用作为参数传递给 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();
        }
    }
}

注意注释掉的行:我可以让代码工作,我只是想找到一种方法让它工作,将游标引用作为参数传回。

我得到的异常是 Npgsql.PostgresException : 42601: syntax error at or near ""

传递纯字符串值参数(看起来可能有效...)也失败,但有相同的异常。

如果将输入游标传递给函数,上述用于从输出游标创建输入游标的模式工作正常。

由于底层数据库的限制。

you cannot use a variable in a FETCH statement. Use dynamic SQL: EXECUTE format('FETCH ALL FROM %I', foo);

所以这不是 Npgsql 的限制,其他答案中建议的解决方法也可以应用于 Npgsql。或者,您可以将字符串插入 SQL,尽管在某种程度上 'ugly'(至少在我看来)实际上是完全安全的。

(在这种情况下 - 但将值直接插入 SQL 通常是一个坏主意,至少没有第二和第三次思考为什么,甚至在任何给定的限制 use-case 中在所有可能的情况下都可以安全地抵御注入攻击。)