Можно ли передать refcursor в качестве параметра непосредственно в FETCH на Npgsql? - PullRequest
0 голосов
/ 13 мая 2019

Я не могу найти способ передать курсор в команду FETCH в качестве параметра при использовании библиотеки Npgsql против PostgreSQL. Возможно ли это?

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".

Передача параметра со строковым значением (который выглядит так, как будто он может работать ...) также завершается неудачей, с тем же исключением.

Приведенный выше шаблон для создания курсора ввода из выходного курсора работает нормально, если курсор ввода передается в функцию.

1 Ответ

0 голосов
/ 13 мая 2019

Этот ответ переполнения стека плюс его последующие комментарии в основном отвечают, что невозможно выполнить то, что я пытаюсь сделать (по крайней мере, не без создания и выполнения динамического SQL) из-за ограниченияв базовой базе данных.

вы не можете использовать переменную в операторе FETCH.Использовать динамический формат SQL: EXECUTE ('FETCH ALL FROM%% I', foo);

Так что это не ограничение Npgsql, и обходные пути, предложенные в другом ответе, могут также применяться в Npgsql.Или вы могли бы просто жить с интерполяцией строки в SQL, что, хотя в некотором смысле «некрасиво» (по крайней мере, на мой взгляд), на самом деле совершенно безопасно.

(В ЭТОМ СЛУЧАЕ - но интерполяция значений напрямуюв SQL, как правило, является ПЛОХОЙ идеей, по крайней мере без второго и третьего размышлений о том, почему, и о том, действительно ли даже в любом конкретном случае ограниченного использования она ДЕЙСТВИТЕЛЬНО безопасна от атак инъекций при всех возможных обстоятельствах.)

...