c# - 从 C# 中的 DBMS_OUTPUT.GET_LINES 获取输出缓冲区

标签 c# .net oracle odp.net oracle-manageddataaccess

我试图通过 C# 在我的匿名 PL/SQL block 中获取 DBMS_OUTPUT.PUT_LINE() 方法的输出。我在这里查看了其他几个相关问题,但仍然遇到问题。执行匿名 block 的返回码是返回-1,根据docs应该是正确的.

我将 DBMS_OUTPUT.ENABLE() 设置为 NULL 以便不设置特定的缓冲区大小,然后使用 DBMS_OUTPUT.GET_LINES() 方法以便从该缓冲区中获取行。

它在缓冲区中不返回任何内容(一个空的 OracleString[])并返回 0 行。我的匿名 PL/SQL block 很简单,但应该适用于任何地方。

DECLARE
    lvsName VARCHAR2(6) := 'Oracle';
BEGIN
    DBMS_OUTPUT.PUT_LINE('Do you see me?');
    DBMS_OUTPUT.PUT_LINE('My name is: ' || lvsName);    
END;

我错过了什么?

using (OracleDataAdapter oda = new OracleDataAdapter())
using (OracleCommand cmd = new OracleCommand(sql, _connection))
{
    // Execute anonymous PL/SQL block
    cmd.CommandType = CommandType.Text;
    var res = cmd.ExecuteNonQuery();

    // Set output Buffer
    cmd.CommandText = "BEGIN DBMS_OUTPUT.ENABLE(NULL); END;";
    cmd.CommandType = CommandType.Text;
    cmd.ExecuteNonQuery();

    // Get output
    cmd.CommandText = "BEGIN DBMS_OUTPUT.GET_LINES(:outString, :numLines); END;";
    cmd.CommandType = CommandType.Text;
    cmd.Parameters.Clear();
    cmd.Parameters.Add(new OracleParameter("outString", OracleDbType.Varchar2, int.MaxValue, ParameterDirection.Output));
    cmd.Parameters["outString"].CollectionType = OracleCollectionType.PLSQLAssociativeArray;
    cmd.Parameters["outString"].Size = sql.Length;
    cmd.Parameters["outString"].ArrayBindSize = new int[sql.Length];
    cmd.Parameters.Add(new OracleParameter("numLines", OracleDbType.Int32, ParameterDirection.InputOutput));
    cmd.Parameters["numLines"].Value = 10; // Get 10 lines
    cmd.ExecuteNonQuery();

     int numLines = Convert.ToInt32(cmd.Parameters["numLines"].Value.ToString());
     string outString = string.Empty;

     // Try to get more lines until there are zero left
     while (numLines > 0)
     {
         for (int i = 0; i < numLines; i++)
         {
             OracleString s = (OracleString)cmd.Parameters["outString"].Value;
             outString += s.ToString();
         }

         cmd.ExecuteNonQuery();
         numLines = Convert.ToInt32(cmd.Parameters["numLines"].Value.ToString());
     }

     return outString;
}

最佳答案

您的代码的主要问题是它没有为输出缓冲区的每个元素设置绑定(bind)大小。检索结果时也没有正确索引输出缓冲区。最后,执行顺序也很重要:在执行匿名代码块之前,您必须首先启用输出。所做的每一项更改都会在以下 MCVE 中进行评论.仅进行必要的更改以使其正常工作。

static void Main(string[] args)
{
    string str = "User Id=xxx; password=xxx; Data Source=localhost:1521/xxx;";
    string sql = @"DECLARE lvsName VARCHAR2(6) := 'Oracle'; BEGIN  DBMS_OUTPUT.PUT_LINE('Do you see me?'); DBMS_OUTPUT.PUT_LINE('My name is: ' || lvsName); END;";

    OracleConnection _connection = new OracleConnection(str);

    try
    {
        _connection.Open();

        //adapter not being used
        //using (OracleDataAdapter oda = new OracleDataAdapter())

        using (OracleCommand cmd = new OracleCommand(sql, _connection))
        {
            // First enable buffer output
            // Set output Buffer
            cmd.CommandText = "BEGIN DBMS_OUTPUT.ENABLE(NULL); END;";
            cmd.CommandType = CommandType.Text;
            cmd.ExecuteNonQuery();

            // Then execute anonymous block
            // Execute anonymous PL/SQL block
            cmd.CommandText = sql;
            cmd.CommandType = CommandType.Text;
            var res = cmd.ExecuteNonQuery();


            // Get output
            cmd.CommandText = "BEGIN DBMS_OUTPUT.GET_LINES(:outString, :numLines); END;";
            cmd.CommandType = CommandType.Text;

            cmd.Parameters.Clear();

            cmd.Parameters.Add(new OracleParameter("outString", OracleDbType.Varchar2, int.MaxValue, ParameterDirection.Output));
            cmd.Parameters["outString"].CollectionType = OracleCollectionType.PLSQLAssociativeArray;
            cmd.Parameters["outString"].Size = sql.Length;
            cmd.Parameters["outString"].ArrayBindSize = new int[sql.Length];

            // set bind size for each array element
            for (int i = 0; i < sql.Length; i++)
            {
                cmd.Parameters["outString"].ArrayBindSize[i] = 32000;
            }


            cmd.Parameters.Add(new OracleParameter("numLines", OracleDbType.Int32, ParameterDirection.InputOutput));
            cmd.Parameters["numLines"].Value = 10; // Get 10 lines
            cmd.ExecuteNonQuery();

            int numLines = Convert.ToInt32(cmd.Parameters["numLines"].Value.ToString());
            string outString = string.Empty;

            // Try to get more lines until there are zero left
            while (numLines > 0)
            {
                for (int i = 0; i < numLines; i++)
                {
                    // use proper indexing here
                    //OracleString s = (OracleString)cmd.Parameters["outString"].Value;
                    OracleString s = ((OracleString[])cmd.Parameters["outString"].Value)[i];
                    outString += s.ToString();

                    // add new line just for formatting
                    outString += "\r\n";
                }

                cmd.ExecuteNonQuery();
                numLines = Convert.ToInt32(cmd.Parameters["numLines"].Value.ToString());
            }

            Console.WriteLine(outString);
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.ToString());
    }

    _connection.Close();
    _connection.Dispose();

    Console.WriteLine("Press RETURN to exit.");
    Console.ReadLine();
}

输出结果为:

Do you see me?
My name is: Oracle

Press RETURN to exit.

关于c# - 从 C# 中的 DBMS_OUTPUT.GET_LINES 获取输出缓冲区,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53402356/

相关文章:

c# - 通过 .NET 提高 RDBMS (SQL) 事件溯源投影的性能

c# - 只要窗体处于事件状态,如何运行后台线程?

c# - 比较 .NET 中的字符串

oracle - C#中是否有空日期之类的东西

c# 使用 Skydrive REST API 的 PUT 请求出现问题

c# - ThreadLocal 并等待

c# - MySQL 本地/在线服务器不会响应 C#/.NET

时间:2019-04-10 标签:c#additional dependencies-opencvsharp

Oracle 在用户使用相同密码时锁定用户

oracle - 从 PL-SQL 函数返回 2 个值