Saltar al contenido

Obtener el búfer de salida de DBMS_OUTPUT.GET_LINES en C #

Siéntete en la libertad de compartir nuestros tutoriales y códigos en tus redes, apóyanos para hacer crecer esta comunidad.

Solución:

El principal problema con su código era que no establecía el tamaño de enlace para cada elemento de su búfer de salida. Además, no indexaba correctamente el búfer de salida al recuperar los resultados. Y finalmente, el orden de ejecución también juega un papel: primero debe habilitar su salida antes de ejecutar su bloque de código anónimo. Cada uno de los cambios realizados se comenta en el siguiente MCVE. Solo se realizaron los cambios necesarios para que funcione.

static void Main(string[] args)
 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 += "rn";
                

                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();

Y el resultado de salida es:

Do you see me?
My name is: Oracle

Press RETURN to exit.

Gracias por la respuesta anterior de jsanalytics, que proporcionó una buena base para una solución. Sin embargo, existen algunos problemas con la solución anterior, principalmente relacionados con el uso de sql.Length en muchos lugares donde no tiene sentido. Aquí hay una solución reutilizable que corrige algunos de los problemas.

using Oracle.DataAccess.Client;
using Oracle.DataAccess.Types;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;

namespace MyNamespace

    public static class DbmsOutputHelper
    
        public const int DefaultReadBatchSize = 10;

        public static void EnableDbmsOutput(this OracleConnection conn)
        
            using (var cmd = conn.CreateCommand())
            
                cmd.CommandText = "DBMS_OUTPUT.ENABLE";
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.ExecuteNonQuery();
            
        

        public static void DisableDbmsOutput(this OracleConnection conn)
        
            using (var cmd = conn.CreateCommand())
            
                cmd.CommandText = "DBMS_OUTPUT.DISABLE";
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.ExecuteNonQuery();
            
        

        public static List ReadDbmsOutput(this OracleConnection conn, int readBatchSize = DefaultReadBatchSize)
        
            if (readBatchSize <= 0)
            
                throw new ArgumentOutOfRangeException(nameof(readBatchSize), "must be greater than zero");
            

            using (var cmd = conn.CreateCommand())
            
                cmd.CommandText = "DBMS_OUTPUT.GET_LINES";
                cmd.CommandType = CommandType.StoredProcedure;

                var linesParam = cmd.Parameters.Add(new OracleParameter("lines", OracleDbType.Varchar2, int.MaxValue, ParameterDirection.Output));
                linesParam.CollectionType = OracleCollectionType.PLSQLAssociativeArray;
                linesParam.Size = readBatchSize;
                linesParam.ArrayBindSize = Enumerable.Repeat(32767, readBatchSize).ToArray();   // set bind size for each array element

                var numLinesParam = cmd.Parameters.Add(new OracleParameter("numlines", OracleDbType.Int32, ParameterDirection.InputOutput));

                var result = new List();
                int numLinesRead;

                do
                
                    numLinesParam.Value = readBatchSize;
                    cmd.ExecuteNonQuery();
                    numLinesRead = ((OracleDecimal)numLinesParam.Value).ToInt32();

                    var values = (OracleString[])linesParam.Value;

                    for (int i = 0; i < numLinesRead; i++)
                    
                        result.Add(values[i].ToString());
                    

                 while (numLinesRead == readBatchSize);

                return result;
            
        
    

Me parece que lo estás haciendo en el orden incorrecto ...

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

Entre configurar (habilitar) el DBMS_OUTPUT y obteniendo la salida usando GET_LINES debería ser su comando de escritura, pero en cambio, es lo primero que está ejecutando.

Intente cambiar el orden. Avíseme si funciona porque no lo probé (no estoy acostumbrado a C # ... lo tengo en Java).

Aquí puedes ver las reseñas y valoraciones de los lectores

Si para ti ha resultado de ayuda este post, sería de mucha ayuda si lo compartieras con el resto entusiastas de la programación de este modo nos ayudas a extender esta información.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *