Получение выходного буфера из DBMS_OUTPUT.GET_LINES в C # - PullRequest
0 голосов
/ 21 ноября 2018

Я пытаюсь получить вывод из метода DBMS_OUTPUT.PUT_LINE() в моем анонимном PL / SQL-блоке через C #.Я рассмотрел пару других связанных с этим вопросов, но все еще испытываю проблемы.Код возврата выполнения анонимного блока возвращает -1, что должно быть правильным на основании документов .

Я устанавливаю 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 ]

0 голосов
/ 26 ноября 2018

Мне кажется, что вы делаете это в неправильном порядке ...

// 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).

0 голосов
/ 03 декабря 2018

Основная проблема с вашим кодом заключалась в том, что он не устанавливал размер привязки для каждого элемента вашего выходного буфера.Также не было должной индексации выходного буфера при получении результатов.И наконец, порядок выполнения также играет роль: вы должны сначала включить вывод, прежде чем выполнять анонимный блок кода.Каждое сделанное изменение комментируется в следующем 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.
0 голосов
/ 21 ноября 2018

Я не говорю на 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;
...