sql server - una - Cómo iniciar sesión en T-SQL
para que sirve el usuario sa en sql server (10)
Estoy usando ADO.NET para acceder a SQL Server 2005 y me gustaría poder iniciar sesión desde los procedimientos almacenados de T-SQL que estoy llamando. ¿Es eso de alguna manera posible?
No puedo ver el resultado de la instrucción ''print'' cuando uso ADO.NET y dado que quiero usar el registro solo para depurar, la solución ideal sería emitir mensajes a DebugView desde SysInternals.
- El siguiente DDL sql le creará la tabla para almacenar los datos de registro USE [db] GO
/****** Object: Table [dbo].[tbData_Debug] Script Date: 02/12/2009 22:30:03 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[tbData_Debug](
[colTimeStamp] [timestamp] NULL,
[colNiceTime] [varchar](200) NULL,
[colDomain_User] [varchar](200) NULL,
[colMsg] [varchar](4000) NULL,
[colDebugLevel] [int] NULL,
[colDebugMsg] [varchar](4000) NULL,
[colPageName] [varchar](200) NULL,
[colClassName] [varchar](200) NULL,
[colMethodName] [varchar](200) NULL,
[colMethodNameGui] [varchar](4000) NULL,
[colRet] [int] NULL,
[colLineNumber] [int] NULL,
[colLineNumberGui] [int] NULL,
[colProcedureName] [varchar](200) NULL,
[colProcedureStep] [varchar](4000) NULL
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
-- This stored procedure does write to the log table
USE [db]
GO
/****** Object: StoredProcedure [dbo].[procUtils_AppDebug] Script Date: 02/12/2009 22:29:24 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[procUtils_AppDebug] (
@ret int = null OUT,
@msgIn varchar(4000) = null , -- the msg which the user has seen
@msgOut varchar(4000) = null OUT , -- the msg which the user has seen
@domain_user varchar(200) = null , -- the domain user echoing the message
@debugMsgIn varchar(4000) = null , -- the debug msg for internal use
@debugMsgOut varchar(4000) = null OUT, -- the debug msg for internal use
@pageName varchar(200) = null , -- the pageName originator of error
@className varchar(200) = null , -- the class Name orinator of error
@methodName varchar(200) = null , -- the methodName where the last error occured
@methodNameGui varchar(4000) = null , -- the methodNameOfTheGui where the last error occured
@lineNumber int = null , -- the line number of the line issueing the error
@lineNumberGui int = null, -- the line number of the line issueing the error
@procedureName varchar(200) = null , -- the procedureName currently envoked
@procedureStep varchar(4000) = null -- the steps of the procedure concatenated
)
AS
BEGIN -- proc start
SET NOCOUNT ON;
BEGIN TRY --begin try
declare @debugLevel int
select @debugLevel = Debug_Level from User_tb where Domain_Name = @domain_user
/*
select * from tbData_Debug order by 1 desc
delete from tbData_Debug
*/
insert into tbData_Debug ( colNiceTime , colDomain_User , colMsg , colDebugLevel ,
colDebugMsg , colPageName , colClassName , colMethodName , colMethodNameGui ,
colRet , colLineNumber , colLineNumberGui , colProcedureName , colProcedureStep) values (
dbo.funcGetNiceTime() , @domain_user , @msgIn , @debugLevel ,@debugMsgIn ,
@pageName , @className , @methodName ,@MethodNameGui , @ret ,
@lineNumber , @lineNumberGui , @procedureName , @procedureStep)
set @debugMsgOut = @debugMsgIn
set @msgOut = ''Action Registered''
set @ret = @@ERROR
return @ret
END TRY --end try
BEGIN CATCH
PRINT ''In CATCH block.
Error number: '' + CAST(ERROR_NUMBER() AS varchar(10)) + ''
Error message: '' + ERROR_MESSAGE() + ''
Error severity: '' + CAST(ERROR_SEVERITY() AS varchar(10)) + ''
Error state: '' + CAST(ERROR_STATE() AS varchar(10)) + ''
XACT_STATE: '' + CAST(XACT_STATE() AS varchar(10));
set @debugMsgOut = ''error at [procUtils_AppDebug]--- Error number: '' + CAST(ERROR_NUMBER() AS varchar(10)) + ''Error message: '' + ERROR_MESSAGE() + ''Error severity: '' +
CAST(ERROR_SEVERITY() AS varchar(10)) + ''Error state: '' + CAST(ERROR_STATE() AS varchar(10)) + ''XACT_STATE: '' + CAST(XACT_STATE() AS varchar(10))
set @msgIn= ''error while saving application error info into database''
insert into tbData_Debug ( colMsg ) values ( @msgIn )
set @debugMsgOut = @debugMsgIn + @debugMsgOut
set @msgOut = ''Action Registration failed''
set @ret = 1
END CATCH
return @ret
END --procedure end
/*
<procedureDocumentation>
<procedurename>procUtils_AppDebug<procedurename>
<procedureDescription> Records events from the Application Layer </procedureDescription>
<created>20090121</created>
<createdby>Yordan Georgiev</createdby>
<change>
<changewhen><changewhen>
<changeDescription></changeDescription>
<changedBy></changedBy>
</change>
<testUsage>
USE [db]
GO
DECLARE @return_value int,
@ret int,
@msgIn varchar(max),
@debugmsg varchar(4000)
SELECT @ret = 1
SELECT @msgIn = N''msg''
SELECT @debugmsg = N''before''
EXEC @return_value = [dbo].[procUtils_AppDebug]
@ret = @ret OUTPUT,
@msgIn = @msgIn OUTPUT,
@domain_user = N''domain_user'',
@debugmsg = @debugmsg OUTPUT,
@methodName = N''methodName''
SELECT @ret as N''@ret'',
@msgIn as N''@msgIn'',
@debugmsg as N''@debugmsg''
SELECT ''Return Value'' = @return_value
select * from tbData_Debug order by 1 desc
GO
</testUsage>
</procedureDocumentation>
*/
Creo que escribir en una tabla de registro sería mi preferencia.
Alternativamente, como está usando 2005, podría escribir un procedimiento simple SQLCLR para envolver el EventLog.
O podría usar xp_logevent si quisiera escribir en el registro de SQL
El registro desde dentro de un sproc SQL se haría mejor a la base de datos en sí. T-SQL puede escribir en archivos pero en realidad no está diseñado para eso.
Es posible que desee comprobar Log4TSQL . Proporciona registro de base de datos para procedimientos almacenados y desencadenantes en SQL Server 2005 - 2008. Tiene la posibilidad de establecer niveles de registro separados e independientes por procedimiento / desencadenador.
Está el comando PRINT , pero prefiero iniciar sesión en una tabla para poder consultarlo.
Lo resolví escribiendo un procedimiento SQLCLR como sugirió Eric Z Beard. El ensamblado debe estar firmado con un archivo de clave de nombre fuerte.
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
public partial class StoredProcedures
{
[Microsoft.SqlServer.Server.SqlProcedure]
public static int Debug(string s)
{
System.Diagnostics.Debug.WriteLine(s);
return 0;
}
}
}
Creado una clave y un inicio de sesión:
USE [master]
CREATE ASYMMETRIC KEY DebugProcKey FROM EXECUTABLE FILE =
''C:/../SqlServerProject1/bin/Debug/SqlServerProject1.dll''
CREATE LOGIN DebugProcLogin FROM ASYMMETRIC KEY DebugProcKey
GRANT UNSAFE ASSEMBLY TO DebugProcLogin
Importado en SQL Server:
USE [mydb]
CREATE ASSEMBLY SqlServerProject1 FROM
''C:/../SqlServerProject1/bin/Debug/SqlServerProject1.dll''
WITH PERMISSION_SET = unsafe
CREATE FUNCTION dbo.Debug( @message as nvarchar(200) )
RETURNS int
AS EXTERNAL NAME SqlServerProject1.[StoredProcedures].Debug
Luego pude iniciar sesión en los procedimientos de T-SQL usando
exec Debug @message = ''Hello World''
Puede escribir filas en una tabla de registro desde un procedimiento almacenado. Como han indicado otros, podría hacer todo lo posible por escribir en un archivo de texto u otro registro con CLR o xp_logevent, pero parece que necesita más volumen de lo que sería práctico para tales usos.
Los casos difíciles ocurren (y es esto de lo que realmente necesita su registro) cuando las transacciones fallan. Como cualquier registro que se produzca durante estas transacciones se retrotraerá junto con la transacción de la que forman parte, es mejor tener una API de registro que los clientes puedan usar para registrar los errores. Puede ser un DAL simple que se conecta a la misma base de datos o a una compartida.
Puede iniciar sesión en una tabla, simplemente insertando una nueva fila, o puede implementar un procedimiento CLR almacenado para escribir en un archivo.
Tenga cuidado al escribir en una tabla, porque si la acción ocurre en una transacción y la transacción se retrotrae, su entrada de registro desaparecerá.
Puede usar variables de salida para reenviar mensajes, pero eso depende de la ejecución del proceso sin errores.
create procedure usp_LoggableProc
@log varchar(max) OUTPUT
as
-- T-SQL statement here ...
select @log = @log + ''X is foo''
Y luego, en tu código ADO, algunos estaban:
string log = (string)SqlCommand.Parameters["@log"].Value;
Puede usar raiserror para crear sus propios errores personalizados con la información que necesita y que estará disponible para usted a través de la colección habitual de Errores SqlException en su código ADO:
RAISERROR(''X is Foo'', 10, 1)
Hmmm, pero sí, no puedo evitar sentir solo por la depuración y en su situación, simplemente inserte los mensajes varchar en una tabla de error como los otros han sugerido y seleccione * desde allí cuando esté depurando.
Por lo que vale, he descubierto que cuando no asigno un controlador de InfoMessage a mi SqlConnection:
sqlConnection.InfoMessage += new SqlInfoMessageEventHandler(MySqlConnectionInfoMessageHandler);
donde la firma de InfoMessageHandler se ve así:
MySqlConnectionInfoMessageHandler(object sender, SqlInfoMessageEventArgs e)
entonces mis declaraciones PRINT en mis procesos almacenados no aparecen en DbgView.