.Net Oracle ORA-24338 'statement handle not executed' error and some error in one stored Procedure - asp.net

I have the following Stored Procedures
create or replace PROCEDURE WEB_AC
(
v_iDocid IN NUMBER DEFAULT NULL ,
v_valor IN VARCHAR2 DEFAULT NULL ,
v_campo IN VARCHAR2 DEFAULT NULL ,
v_error OUT NUMBER
)
AS
v_campoid NUMBER(5,0);
v_tipodato VARCHAR2(50);
v_DOCTYPE NUMBER;
v_tabla VARCHAR2(50);
v_procedure VARCHAR2(70);
BEGIN
v_error:= 0;
IF v_valor IS NULL
OR v_valor IS NULL
OR LENGTH(TRIM(v_valor)) = 0 THEN
BEGIN
v_error:= 3;
END;
else
Begin
bEGIN
SELECT campoid,
doctype,
tipodato
INTO v_campoid,
v_DOCTYPE,
v_tipodato
FROM TiposDocumento t
, DIGITALIZAMAIN d
, CatCamposDocumento c
where
c.tabla=t.tabla and
nombre=v_campo and
doctype = TipoDocumentoID and
docid = v_iDocid AND
Mostrar = 1;
EXCEPTION
WHEN OTHERS THEN
v_campoid := 0;
END;
--select #campoid
IF v_campoid != 0 THEN
Begin
EXECUTE IMMEDIATE 'BEGIN ABANCE3.WEB_UPDOC' || TRIM(TO_CHAR(v_DOCTYPE )) || 'C' || TRIM(TO_CHAR(v_campoid)) ||'(' ||
TO_CHAR (v_iDocid)||' , '||CHR(39)||v_valor||CHR(39)||',:2);END;'
USING out v_error;
END;
END IF;
end;
end if;
END;
And
create or replace PROCEDURE WEB_UPDOC1C6(v_idreg NUMBER,v_valor VARCHAR2,v_temp OUT NUMBER)
AS
v_sys_error NUMBER := 0;
BEGIN
BEGIN
SELECT count(*)
INTO v_sys_error
FROM DOC1
where DOCID = v_idreg;
EXCEPTION WHEN OTHERS THEN v_sys_error:=0;
END;
IF v_sys_error > 0 THEN
BEGIN
BEGIN
UPDATE DOC1
SET DESCRIPCION = v_valor
WHERE DOCID = v_idreg;
EXCEPTION WHEN OTHERS THEN v_sys_error:=0;
END;
IF v_sys_error = 0 THEN v_temp:=0 ;
ELSE v_temp:=1 ;
END IF;
END;
END IF;
END;
and I'm calling them from an Application with this code:
Friend Function ActualizaCampos(ByVal iDocID As Long, ByVal valor As String, ByVal Campo As String, ByVal ProyectoID As Integer) As String
Dim mstrCS as String = "Here goes the connection String to my server"
Dim db As Database
Dim dbCW As DbCommand
Dim iValor As String = "0"
Select Case Me.TipoBD
Case GlobalDef.eTipoBD.Oracle
db = New OracleDatabase(mstrCS)
dbCW = db.GetStoredProcCommand(WEB_AC, iDocid, valor, Campo, 0)
db.ExecuteNonQuery(dbCW)
Case GlobalDef.eTipoBD.SQLServer
db = New SqlDatabase(mstrCS)
dbCW = db.GetStoredProcCommand(WEB_AC, iDocid, valor, Campo)
iValor = db.ExecuteScalar(dbCW).ToString()
End Select
Return iValor
End Function
In this example the WEB_AC SP always execute the sp WEB_UPDOC1C6
I have two problems with this.
First problem: At some point in the application I have the valor parameter (of the visual Basic Function) as a string with spaces that is something like "some string with spaces". When this happens, the stored procedure don't update the table. If I execute the SP directly in the DB (with SQL Developer) all works fine. I know it has something to do with the string missing some quotes(') but I haven't make it work yet. Some ideas on this?
Second problem: Sometimes, when debuging the application, if I interrupt the execution, I start getting the ORA-24338 'statement handle not executed' error for hours every time I try to execute it again. I believe it has something to do with an open transaction. But honestly, as I'm new in working with Oracle, I really have no idea what the problem could be.
Can you help me?
UPDATE: I have found the ORA-24338 real reason. It was another SP that was causing the error. When i found the solution to my other problem I'll post it all here.

I'd suggest that you replace your WHEN OTHERS clause with one that specifically names the erros that you are expecting, or you raise the error after handling it anyway. WHEN OTHERS is a bit contraversial as it is notorious for hiding the real problem.

Related

open, fetch, into multiple variables

I am trying to get 2 variables out of a cursor without using a loop.
CREATE OR REPLACE PROCEDURE NAK.SET_ORDERS(P_ORDER_ID NAK.ORDER_ID%TYPE)
CURSOR C_GET_ORDER_NO IS
SELECT O.ORDER_ID, O.ORDER_MAL FROM NAK.ORDERS O WHERE O.ORDER_ID = P_ORDER_ID;
BEGIN
V_ORDER_SEQ := NULL;
V_ORDER_MAL := NULL;
OPEN C_GET_ORDER_NO;
FETCH C_GET_ORDER_NO VALUES(O.ORDER_ID, O.ORDER_MAL)
INTO (V_ORDER_ID, V_ORDER_MAL);
CLOSE C_GET_ORDER_NO;
END;
Do you really need an explicit cursor? You can simply do this:
CREATE OR REPLACE PROCEDURE NAK.SET_ORDERS(P_ORDER_ID IN NAK.ORDER_ID%TYPE)
V_ORDER_SEQ := NULL;
V_ORDER_MAL := NULL;
BEGIN
SELECT O.ORDER_ID,
O.ORDER_MAL
INTO V_ORDER_SEQ,
V_ORDER_MAL
FROM NAK.ORDERS O
WHERE O.ORDER_ID = P_ORDER_ID;
EXCEPTION
WHEN NO_DATA_FOUND THEN
dbms_output.put_line("No record found");
WHEN TOO_MANY_ROWS THEN
dbms_output.put_line("More than one record found");
WHEN OTHER THEN
dbms_output.put_line("Other problem happend");
END;
Important: this procedure will return a exception if the query doesn't return exactly one record. (ORA-01403: no data found or ORA-00913: too many values)
Alternatively you should be able to make something like:
CREATE OR REPLACE PROCEDURE NAK.SET_ORDERS(P_ORDER_ID NAK.ORDER_ID%TYPE)
CURSOR C_GET_ORDER_NO IS
SELECT O.ORDER_ID,
O.ORDER_MAL
FROM NAK.ORDERS O
WHERE O.ORDER_ID = P_ORDER_ID;
BEGIN
V_ORDER_SEQ := NULL;
V_ORDER_MAL := NULL;
OPEN C_GET_ORDER_NO;
FETCH C_GET_ORDER_NO INTO V_ORDER_ID, V_ORDER_MAL;
CLOSE C_GET_ORDER_NO;
END;

An unexpected token "EXCEPTION" was found In PL/SQL(DB2)

I am Wrting a Stored Function As below in db2.
CREATE OR replace FUNCTION moc_enddate( IN v_date VARCHAR(6),
IN v_message VARCHAR(20)) returns DATE
BEGIN
DECLARE v_temp DATE;
DECLARE v_end_date DATE;
DECLARE v_temp_string VARCHAR(8) DEFAULT '01';
SET v_temp_string = v_temp_string
|| v_date;
SET v_temp = to_date(v_temp_string,'DDMMYYYY');
SET v_end_date = (v_temp + 19 days);
RETURN v_end_date;
EXCEPTION
WHEN no_data_found THEN
SET v_message = 'SqlDataException';
WHEN OTHERS THEN
SET v_message = 'OTHER';
END;
But I am getting the following Exception.
ERROR [42601] [IBM][DB2/AIX64] SQL0104N An unexpected token "EXCEPTION" was found following "RN V_END_MOC_DATE; ". Expected tokens may include.
"<psm_case>".
Maybe, you are using DB2 SQL PL instead of PL/SQL. There is a difference between these languages. If it's the case, the following condition should work:
create or replace procedure CreatePlants
begin
declare sqlstate char(5) default '00000';
declare ErrorMsg varchar(96);
declare exit handler for sqlexception
begin
set ErrorMsg = 'SQLSTATE=' concat sqlstate;
signal sqlstate '99001'
set message_text = ErrorMsg;
end;
create table plants
( ID dec(3), Location varchar(16),
primary key (ID));
label on table plants is 'Plant master';
insert into plants values
( 1, 'Lost Angeles'),
( 2, 'New Yolk'),
( 3, 'Last Vegas');
end
For more references see:
Error Handling in SQL PL, Part 1
Determine The State Of The Error

Oracle AFTER INSERT Trigger

The following trigger will not fire. The trigger worked before adding the 'SELECT c.deposit_id … piece of code. Any help will be greatly appreciated. The trigger is meant to fire after an insert is made on CASH_OR_CREDIT table if the foreign key in this table is found to be linked to another table (TRANSACTION_TABLE).
`
CREATE OR REPLACE TRIGGER SEND_MONEY
AFTER INSERT
ON cash_or_credit
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
DECLARE
system_header_info NUMBER := 0;
l_dep_key NUMBER := 0;
CURSOR cur (cover_id NUMBER)
IS
SELECT header_id
FROM headers
WHERE party_site_id = cover_id;
system_header_info VARCHAR2 (10)
:= schema.necessay_functions.get_system_id ('DEPOSITS');
BEGIN
fnd_profile.put ('company_debugger', 'Y');
schema.necessay_functions.debugger ('old.deposit_id =' || :OLD.deposit_id);
schema.necessay_functions.debugger ('new.deposit_id =' || :NEW.deposit_id);
OPEN cur (system_header_info);
system_header_info := 0;
FETCH cur1 INTO system_header_info;
CLOSE cur1;
schema.necessay_functions.debugger (
'super_user.user_id =' || super_user.user_id);
schema.necessay_functions.debugger (
schema.necessay_functions.obtain_user_id (
schema.necessay_functions.get_system_id ('DEPOSITS')));
SELECT c.deposit_id
INTO l_dep_key
FROM schema.transaction_table o,
schema.linker_table r,
schema.cash_or_credit c
WHERE o.primary_key = r.primary_key
AND o.table_name = 'INDIVIDUAL_REC'
AND o.system_id = '265226'
AND o.status = 'A'
AND r.status = 'A'
AND c.foreign_key = r.primary_key
AND c.deposit_id = :NEW.deposit_id
AND r.relationship_code IN ('EMPLOYER_OF');
IF super_user.user_id =
schema.necessay_functions.obtain_user_id (
schema.necessay_functions.get_system_id ('DEPOSITS'))
AND l_dep_key = :NEW.deposit_id
THEN
schema.necessay_functions.debugger ('Inside If Condition');
FOR sys_comp
IN (SELECT *
FROM schema.transaction_table
WHERE status = 'A'
AND table_name = 'DEPOSITS'
AND primary_key = :NEW.deposit_id
AND system_id =
schema.necessay_functions.get_system_id (
'DEPOSITS'))
LOOP
schema.necessay_functions.debugger ('Inside Loop');
schema.necessay_functions.send_xml_message ('SEND_SYSTEM_MSG',
'SEND.UPDATE',
system_header_info,
sys_comp.system_id,
sys_comp.system_key);
END LOOP;
ELSE
schema.necessay_functions.send_xml_message ('SEND_SYSTEM_MSG',
'SEND.CREATE',
system_header_info,
system_header_id,
:NEW.deposit_id);
END IF;
EXCEPTION
WHEN OTHERS
THEN
schema.necessay_functions.debugger ('Sqlerrm:' || SQLERRM);
END SEND_MONEY;
/`
If it works without the SELECT c.deposit_id … piece then, presumably, that is what is causing an exception which is then being swallowed by the WHEN OTHERS exception handler being used and causing the trigger to look like it is not firing. You should be able to confirm that by checking whatever table/log schema.necessay_functions.debugger( is logging to.
What are the business rules around the l_dep_key value? Specifically, is it expected that the SELECT statement used to populate l_dep_key will always return a result (and only 1 result at that)? If so, at the very least wrap that statement with an anonymous block and explicitly handle any exceptions that conflict with those business rules.
BEGIN
SELECT c.deposit_id
INTO l_dep_key
FROM schema.transaction_table o,
schema.linker_table r,
schema.cash_or_credit c
WHERE o.primary_key = r.primary_key
AND o.table_name = 'INDIVIDUAL_REC'
AND o.system_id = '265226'
AND o.status = 'A'
AND r.status = 'A'
AND c.foreign_key = r.primary_key
AND c.deposit_id = :NEW.deposit_id
AND r.relationship_code IN ('EMPLOYER_OF');
EXCEPTION
WHEN NO_DATA_FOUND THEN
...TAKE APPROPRIATE ACTION HERE...
...POSSIBLY LOG AND RAISE...
WHEN TOO_MANY_ROWS THEN
...TAKE APPROPRIATE ACTION HERE...
...POSSIBLY LOG AND RAISE...
END;
As OldProgrammer stated in a comment, the exception handling in your provided code has much room for improvement. Should you really be swallowing any and all exceptions that may be thrown by the code in this trigger?
Also, as a general tip, when logging exceptions instead of just logging SQLERRM use DBMS_UTILITY.FORMAT_ERROR_BACKTRACE() instead, as it gives you more context around the exception. Future you and/or future debuggers of this will thank you for it.
Thank you for all of your advice and input. I solved the problem. The exception text revealed that the table mutates when you attempt to query it leading to the trigger failure. The trick to checking the validity of the child table to the parent table after an INSERT and allowing the trigger to fire is to remove the reference to the child (trigger) table and to perform the join using :NEW.foreign_key to join to the parent table. I learned a lot while trying to debug this :)
BEGIN
SELECT COUNT(1)
INTO l_dep_key
FROM schema.transaction_table o,
schema.linker_table r
WHERE o.primary_key = r.primary_key
AND o.table_name = 'INDIVIDUAL_REC'
AND o.system_id = '265226'
AND o.status = 'A'
AND r.status = 'A'
AND o.foreign_key = r.primary_key
AND r.primary_key = :NEW.foreign_key
AND r.relationship_code IN ('EMPLOYER_OF');

Inconsistent results of stored procedure execution - ASP.net code vs Direct SP call

Thanks in advance for anyone's help. This is mystery which is driving me crazyyyy :(.
IF I run this following stored procedure directly on SQL server 2008R2, it returns the desired rows. But if I call this via ASP.net(3.5) it returns empty data from the last Select statement in SP.
Is there any scoping involved in this regarding the temp table #_CalendarDate?
Stored Procedure:
USE[DB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [WC].[spsGetDayCyclePeriod]
(
#Param_StartDate datetime,
#NumberOfDayRange int,
#Campus_Type varchar(2)
)
AS
DECLARE #DateRangeStart datetime
DECLARE #DateRangeEnd datetime
DECLARE #_CalendarDate TABLE (CollegeDate datetime)
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
SET DATEFIRST 1
SELECT #DateRangeStart=max(CalendarDate) FROM [X].dbo.CalendarEvents
WHERE CalendarDate <= #Param_StartDate and left(CalendarType,1)= #Campus_Type
and (CalendarType <> #Campus_Type+'_H' and CalendarType<>'H'
and convert(INT, right(CalendarType, len(CalendarType)-3))>0)
SELECT #DateRangeEnd=min(CalendarDate) FROM [X].dbo.CalendarEvents
WHERE CalendarDate >= dateadd(day, #NumberOfDayRange-1, #Param_StartDate)
and left(CalendarType,1)= #Campus_Type and (CalendarType <> #Campus_Type+'_H'
and CalendarType<>'H' and convert(INT, right(CalendarType, len(CalendarType)-3))=0)
--Get all Dates within range
;WITH CollegeDate AS
(
SELECT #DateRangeStart AS DateValue
union all
SELECT dateadd(day, 1, DateValue)
FROM CollegeDate
WHERE dateadd(day, 1, DateValue) <= #DateRangeEnd
)
INSERT INTO #_CalendarDate (CollegeDate)
SELECT DateValue FROM CollegeDate OPTION (MAXRECURSION 0)
SELECT * from #_CalendarDate
END
ASP.Net code:
DataTable dayCycle = new DataTable();
var dateTimestr = startDate.ToString("yyyy-MM-dd HH:mm:ss");
using (SqlCommand sqlCommand = new SqlCommand("WC.spsGetDayCyclePeriod", new SqlConnection(Connection)))
{
sqlCommand.CommandType = CommandType.StoredProcedure;
var range = endDate.Subtract(startDate).Days;
sqlCommand.Parameters.Add(new SqlParameter("#Param_StartDate", dateTimestr));
sqlCommand.Parameters.Add(new SqlParameter("#NumberOfDayRange", range));
sqlCommand.Parameters.Add(new SqlParameter("#Campus_Type", campus));
//dayCycle = SqlHelper.GetDataTableUsingSqlCommand(sqlCommand);
try
{
SqlDataAdapter _dap = new SqlDataAdapter(sqlCommand);
_dap.Fill(dayCycle);
}
catch (Exception ex)
{ throw new Exception(ex.ToString()); }
return dayCycle;
Pass #Param_StartDate as a date time object rather than a string.
Thanks everyone for help.
Solved the problem myself ! Hopefully it will help someone else as well in future. Here is the answer:
In above ASP.net code:
sqlCommand.Parameters.Add(new SqlParameter("#Campus_Type", campus));
campus is a enum type and when I was calling the above method with enum type I was actually passing the int value instead of string. So this is what I change to. This was confusing because when I was debugging my code I was using cursor on top of the #campus which basically calls toString so I was seeing the right value (which was wrong) the actual value was passed was number of enum.
sqlCommand.Parameters.Add(new SqlParameter("#Campus_Type", campus.ToString()));
And the above change solved the problem.
What I learned from this is Always...Always confirm that the arguments you intend to pass to SP is what SP is receiving so retrieve back your passed arguments by running the following before you do anything with Stored procedures...
Select #Your_Param1, #Your_Param2
And then check on code side that you are receiving what you are expecting.

Check a record IS NOT NULL in plsql

I have a function which would return a record with type my_table%ROWTYPE, and in the caller, I could check if the returned record is null, but PL/SQL complains the if-statement that
PLS-00306: wrong number or types of arguments in call to 'IS NOT NULL'
Here is my code:
v_record my_table%ROWTYPE;
v_row_id my_table.row_id%TYPE := 123456;
begin
v_record := myfunction(v_row_id)
if (v_record is not null) then
-- do something
end if;
end;
function myfunction(p_row_id in my_table.row_id%TYPE) return my_table%ROWTYPE is
v_record_out my_table%ROWTYPE := null;
begin
select * into v_record_out from my_table
where row_id = p_row_id;
return v_record_out;
end myfunction;
Thanks.
As far as I know, it's not possible. Checking the PRIMARY KEY or a NOT NULL column should be sufficient though.
You can check for v_record.row_id IS NULL.
Your function would throw a NO_DATA_FOUND exception though, when no record is found.
You can't test for the non-existence of this variable so there are two ways to go about it. Check for the existence of a single element. I don't like this as it means if anything changes your code no longer works. Instead why not just raise an exception when there's no data there:
I realise that the others in the exception is highly naughty but it'll only really catch my table disappearing when it shouldn't and nothing else.
v_record my_table%ROWTYPE;
v_row_id my_table.row_id%TYPE := 123456;
begin
v_record := myfunction(v_row_id)
exception when others then
-- do something
end;
function myfunction(p_row_id in my_table.row_id%TYPE) return my_table%ROWTYPE is
v_record_out my_table%ROWTYPE := null;
cursor c_record_out(c_row_id char) is
select *
from my_table
where row_id = p_row_id;
begin
open c_record_out(p_row_id);
fetch c_record_out into v_record_out;
if c_record_out%NOTFOUND then
raise_application_error(-20001,'no data);
end if;
close c_record_out;
return v_record_out;
end myfunction;

Resources