代码之家  ›  专栏  ›  技术社区  ›  Jimenemex

从c中的dbms_output.get_行获取输出缓冲区#

  •  9
  • Jimenemex  · 技术社区  · 6 年前

    我正在尝试从 DBMS_OUTPUT.PUT_LINE() 方法在匿名pl/sql块中通过c_。我看过其他几个相关的问题,但仍然有问题。执行匿名块的返回代码正在返回 -1 ,根据 docs .

    我正在设置 DBMS_OUTPUT.ENABLE() NULL 为了不设置特定的缓冲区大小,请使用 DBMS_OUTPUT.GET_LINES() 方法以从该缓冲区获取行。

    它在缓冲区中不返回任何内容(空 OracleString[] )和回报 0 线。我的匿名pl/sql块很简单,但是可以用于任何一个。

    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;
    }
    
    3 回复  |  直到 6 年前
        1
  •  3
  •   jsanalytics    6 年前

    您的代码的主要问题是它没有为输出缓冲区的每个元素设置绑定大小。另外,在检索结果时,它没有正确地索引输出缓冲区。最后,执行顺序也扮演了一个角色:在执行匿名代码块之前,必须首先启用输出。每一次更改都会在下面的注释中 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.
    
        2
  •  1
  •   Arkadiusz Łukasiewicz    6 年前

    我不会说C,但在代码中我看不到您在为numlines变量赋值。

      DBMS_OUTPUT.GET_LINES (
       lines       OUT     CHARARR,
       numlines    IN OUT  INTEGER);
    

    PLSQL中的示例:

    DECLARE
       v_array       DBMS_OUTPUT.CHARARR;
       v_lines   NUMBER;
    BEGIN
       DBMS_OUTPUT.PUT_LINE ('aaaaa');
       DBMS_OUTPUT.put_line ('bbbb');
       DBMS_OUTPUT.put_line ('ccccc');
       v_lines := 1000; -- Number of lines you want to retrieve from the buffer.  
       DBMS_OUTPUT.GET_LINES (v_array, v_lines);
    
       DBMS_OUTPUT.put_line(v_lines); -- Lines retrieved from buffer.
       FOR idx IN nvl(v_array.FIRST,1) .. nvl(v_array.LAST,-1)
       LOOP
          DBMS_OUTPUT.put_line (v_array (idx));
       END LOOP;
    END;
    
        3
  •  1
  •   Felypp Oliveira    6 年前

    在我看来你做的顺序不对…

    // 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;";
    

    在设置(启用)之间 DBMS_OUTPUT 并使用 GET_LINES 应该是您的写命令,但它是您执行的第一件事。

    试着改变顺序。让我知道它是否有效,因为我没有尝试过(我不习惯C……我在Java中有它。