ASP con llamada a proc. Almacenado en SQLServer

Página ASP con objeto Command que llama a un procedimiento almacenado del SQLServer.
Dicho procedimiento puede ser algo tan sencillo como:
create procedure miproc @uno int, @dos char(30) output
As
Begin
insert into tabla
values (@uno)
if (@@error <>0)
begin
return -1
set @dos = 'Error al insertar'
end
set @dos = 'Todo bien'
end
Creo la página y llamo al procedimiento. Si todo va bien no hay problema, pero si el insert falla (por clave duplicada, por ejemplo), la página ASP deja de ejecutarse y muestra el error del gestor SQLServer (501 creo)
Si en la página Web pongo antes de la ejecución del proc. Almacenado
on error resume next
Sigue la ejecución, pero no devuelve nada y no puede capturar ni el valor de retorno ni la variable por referencia (output).
¿Cómo puedo solucionarlo?
Lo mejor es que en ORACLE funciona perfectamente, ya que me permite capturar los errores del gestor y mandar mis propios errores.

1 Respuesta

Respuesta
1
Es que en oracle es mucho más fácil, puede que el error se deba a que usas "set" en vez de "select", otro problema puede ser que el valor de retorno en la asp sea incorrecto, es decir, que el código proporcionado en el command sea incorrecto. ¿Cuál es el código de tu asp? AUnque primero prueba lo del select, y si no te da error ¿te saca el mensaje "todo bien"?
Ya probé con Select o con Set.
El problema es que al ejecutar el procedimiento salta el error interno del SQLServer (de su gestor:clave duplicada) y al realizar la llamada desde páginas ASP, le devuelve el control a la página ASP a través del Internet Information Server con el error 500:100 (clave duplicada) y no sigue ejecutando el procedimiento (eso es lo que yo creo).
Sin embargo, si lo haces desde el propio SQLServer (analizador de consultas) lanza la excepción del servidor (clave duplicada) pero continua la ejecución y puedo obtener los valores de retorno...
Veamos si te puedo ayudar, es que no tengo el sqlserver aquí y no puedo comprobarlo
Has probado a poner el
exception
when others then
OutputValue = -1;
Es que se que así puedes controlar los errores en oracle y luego haces un err. Raise y tan panchos, pero no se si existe eso en sqlserver
Ahí está. En ORACLE puedes coger la excepción y mandar devuelta lo que quieras.
Pero en SQLServer nada de nada, o por lo menos yo no lo encontré (y eso que me recorrí los libros en pantalla buscando por todo el índice).
De todas formas muchas gracias por atender mi pregunta y si te enteras de la posible respuesta te estaré muy agradecido.
Un saludo
Ahora que estoy en casa lo he mirado, fíjate en este código que te pongo y así lo hará bien.
CREATE PROCEDURE NuevaCuenta
(
@NombreUsuario VARCHAR2(20),
@Password VARCHAR2(20),
@Estado VARCHAR(40) OUTPUT
)
AS
Begin
DECLARE @Valor INT
IF LEN(@Password) < 6
BEGIN
SELECT @Estado = 'Cuenta no creada:Contraseña inválida'
END
ELSE
BEGIN
INSERT INTO Usuario(Apellido) VALUES (@NombreUsuario)
SELECT @Valor = @@ERROR
IF @Valor = 0
SELECT @Estado = 'Creada'
ELSE
SELECT @Estado = 'Ha ocurrido un error'
RETURN @Valor
END
END
Esa solución no me vale si introduces una clave duplicada por ejemplo...
Aquí te mando el error que aparece en ese caso. Si en la página ASP añado on error resume next, continúa su ejecución, pero no puedo recoger ni el código de vuelta ni el parámetro de retorno...
Error:
Información técnica (para personal de soporte técnico)
Tipo de error:
Microsoft OLE DB Provider for ODBC Drivers (0x80040E14)
[Microsoft][ODBC SQL Server Driver][SQL Server]Infracción de la restricción PRIMARY KEY 'PK_Alumnos'. No se puede insertar una clave duplicada en el objeto 'Alumnos'.
/centro/asp/Altaalumnos.asp, line 39
Procedimiento:
CREATE PROCEDURE Altaalumno @nif char(9),@nombre varchar(30),@mensaje varchar(30) OUTPUT
as
begin
set nocount on
set ansi_warnings off
insert into Alumnos
values (@nif, @nombre)
if @@error <> 0
begin
Select 0
set @mensaje = 'Error'
set nocount off
return 0
end
set @mensaje = 'Todo bien'
select 1
set nocount off
return 1
end
Página ASP
<%option explicit%>
<html>
<head></head>
<body>
<!--#include file="..\adovbs.inc"-->
<%
Dim Ob_conn,Ob_comand,Ob_rs, msDni,msNombre
Dim param1,param2,param3,param4,errores
set Ob_conn = server.createobject("adodb.connection")
Ob_conn.Open "Centro","centro","centro"
set Ob_comand = server.createobject("adodb.command")
Ob_comand.ActiveConnection = Ob_conn
Ob_comand.CommandType = adCmdStoredProc
Ob_comand.commandtext = "Altaalumno"
Set param1 = Ob_comand.CreateParameter("error",adInteger,adParamReturnValue)
Set param2 = Ob_comand.CreateParameter("dni",adVarChar,adParamInput,9)
Set param3 = Ob_comand.CreateParameter("nombre",adVarChar,adParamInput,40)
Set param4 = Ob_comand.CreateParameter("mensaje",adVarChar,adParamOutput,30)
Ob_comand.parameters.append param1
Ob_comand.parameters.append param2
Ob_comand.parameters.append param3
Ob_comand.parameters.append param4
Ob_comand("dni") = request.form("dni")
Ob_comand("nombre") = request.form("nombre")
' on error resume next
Set Ob_rs = Ob_comand.execute()
response.write ("Select de vuelta:" + CStr(Ob_rs(0)) + "<br>")
response.write ("Datos del recordset:" + ob_rs.recordcount)
response.write (" "+ob_rs.State)
Ob_rs.close
response.write("<Br>Codigo de error:" + CStr(Ob_comand("error"))+"<br>")
response.write ("Mensaje de error:" + Ob_comand("mensaje")+"<br>")
Ob_conn.close
Un saludo y seguiremos luchando...
if @@error <> 0
begin
Select 0
set @mensaje = 'Error'
set nocount off
return 0
end
¿ Pq no pones return @@error ?
No puedo hacerlo porque en esa línea @@error no tiene el código de error de la ejecución de la instrucción Insert.
Tendría que hacer antes:
set @error = @@error
y después return @error
Podría no ponerlo, simplemente es una forma de recuperar un error (la otra es con paramétros de retorno, que aquí viene a ser variables por referencia) o con select y recogerlo en la parte cliente a través del recordset.
Pero ello no modifica en nada el error que estamos tratando, que es el error que lanza el gestor con clave duplicada y como para la ejecución del procedimiento o bien no lo para, pero no se es capaz de leer los valores de retorno en el cliente...
Es que veamos, tienes que hacer un return del error y una vez realizado esto devolver el parámetro de tipo out
Es que si hago un return dentro del procedimiento automáticamente salgo de él, con lo cual es imposible que a continuación pueda hacer una asignación al parámetro de retorno.
De todas formas, eso no creo que influya en el error que da el gestor.
¿Probaste a provocar un error de clave duplicada en el ejemplo que me enviaste?
¿En ese caso eres capaz de recoger el código de retorno?
Es que ese es el ejemplo que tengo para insertar en un registro, de todos modos lo que puedes hacer es declarar un cursor y abrirlo con el código( id ) antes, si te devuelve null significa que no existe y por lo tanto puedes insertar, si de lo contrario te devuelve algo significa que existe y por lo tanto no insertas, es decir, en vez de quebrarte la cabeza sobre devolver el error haz eso y devuelve por ejemplo un código numérico, si es 0 es que se insertó y si es 1 es que no se insertó porque ya existía, ¿entiendes?
Si, una posible solución sería la de controlar cada vez que quieras hacer una operación de insert, update, delete ver si puedes hacerla y gestionar el error, pero es que de esa forma duplicas las operaciones, ya que cuando hago un insert, primero debo controlar si el valor a insertar existe en la tabla, y después añadirlo. No haría falta usar un cursor, podría usar algo como:
declare @puedo int
select @puedo = count(*)
from Tabla
Where id = id a insertar
if @puedo = 1
begin
Error
return
end
Sino Insertar...
Yo pensé que se podría hacer algo como en Oracle y su gestión de Excepciones...
Pero en fin, gracias por tu ayuda y seguiremos investigando...
Un saludo.
De nada, tenemos que ayudarnos entre nosotros.
Cierra la pregunta y puntúala para darla por terminada

Añade tu respuesta

Haz clic para o

Más respuestas relacionadas