I'm using Node 10.x,and Oracledb 3.0
I'm trying to execute a stored procedure in node.js
I've Exception block in the procedure,like below:
EXCEPTION
WHEN NO_DATA_FOUND THEN
OUT_STATUS:='FAILURE';
OUT_STATUS_DESC:='USER NOT MAPPED TO A GROUP';
WHEN OTHERS THEN
OUT_STATUS:='FAILURE';
OUT_STATUS_DESC:=dbms_utility.format_error_backtrace;
whenever control goes to Exception block throwing below error in node.js.
Error: ORA-24338: statement handle not executed
But,explicitly if i execute procedure in db with same IN parameters it's giving proper OUT parameters with error and CURSOR is closed.
These are the OUT parameter types in procedure.
OUT_STATUS OUT VARCHAR2,
OUT_STATUS_DESC OUT VARCHAR2,
OUT_MENU_NAME OUT SYS_REFCURSOR
What could be the issue?
All OUT variables must be set to something even if you don't intend to use them in the node-oracledb code, see https://github.com/oracle/node-oracledb/issues/886
It turns out this is true in all Oracle DB drivers (e.g. node-oracledb) based on Oracle's C 'OCI' API, but symptomatic problems are more commonly seen in node-oracledb.
A work-around is, if it has not been opened before then open the OUT_MENU_NAME cursor with zero rows in the exception blocks:
EXCEPTION
WHEN NO_DATA_FOUND THEN
OUT_STATUS:='FAILURE';
OUT_STATUS_DESC:='USER NOT MAPPED TO A GROUP';
-- Replicate your normal cursor output and filter on something that will never be true:
OPEN OUT_MENU_NAME FOR
SELECT 'Nothing' AS col1,
DATE '1970-01-01' AS col2,
0 AS col3
FROM DUAL
WHERE 1 = 0;
WHEN OTHERS THEN
OUT_STATUS:='FAILURE';
OUT_STATUS_DESC:=dbms_utility.format_error_backtrace;
-- Replicate your normal cursor output and filter on something that will never be true:
OPEN OUT_MENU_NAME FOR
SELECT 'Nothing' AS col1,
DATE '1970-01-01' AS col2,
0 AS col3
FROM DUAL
WHERE 1 = 0;
Related
I have a multi-line PL/SQL procedure, which I have to create.
The SQL procedure is similar to the one below,
CREATE OR REPLACE PROCEDURE HELLO AS
TYPE cur_cur is REF CURSOR;
v_cur_cur cur_cur;
age NUMBER;
day VARCHAR2(10);
date DATE;
BEGIN
<Some Execute Immediate stmts>
<Some insert stmts>
commit;
END;
Currently what I am doing is,
host= "localhost"
port= 1521
sid= "abcbcadacsw.com"
user= "groups"
password= "hello!bye1209"
dsn_tns = oracledb.makedsn(host, port, service_name=sid)
print(dsn_tns)
db_conn = oracledb.connect(user=user, password=password, dsn=dsn_tns)
curs= db_conn.cursor()
curs.execute("""
CREATE OR REPLACE PROCEDURE HELLO AS
TYPE cur_cur is REF CURSOR;
v_cur_cur cur_cur;
age NUMBER;
day VARCHAR2(10);
date DATE;
BEGIN
<Some Execute Immediate stmts>
<Some insert stmts>
commit;
END;
""")
The thing is the code runs without any issues, there are not runtime errors or anything ... but when i log into the DB to check for the created procedure, its not present. When i try to execute the procedure, it says 'identifier must be declared ... '.
I have tried converting it into a single line
curs.execute("""CREATE OR REPLACE PROCEDURE HELLO AS TYPE cur_cur is REF CURSOR; v_cur_cur cur_cur; age NUMBER; day VARCHAR2(10); date DATE; BEGIN <Some Execute Immediate stmts> <Some insert stmts> commit; END;""")
This also does not work.
Please assist, ignore the correctness of the above shown procedure, i cannot put the original here, and i dont know much of SQL, i just need to know how to successfully create it in Python.
The driver doesn't (yet) return Oracle DB's 'success with info' errors so if there is a problem with the PL/SQL code you won't find out about it unless you explicitly query the error view.
In SQL*Plus:
create or replace procedure fred as
begin
f();
end;
/
would give:
Warning: Procedure created with compilation errors.
and a subsequent show errors will give
Errors for PROCEDURE FRED:
LINE/COL ERROR
-------- -----------------------------------------------------------------
3/3 PL/SQL: Statement ignored
3/3 PLS-00201: identifier 'F' must be declared
With cx_Oracle (and its new version python-oracledb) you don't get the initial indication there was a problem so you always should do the equivalent of the show errors command to check the error view. Try something like:
with connection.cursor() as cursor:
sql = """create or replace procedure fred as
begin
f();
end;"""
cursor.execute(sql)
sql = """select name, type, line, position, text
from user_errors
order by name, type, line, position"""
for r in cursor.execute(sql):
print(r)
which will show output like:
('FRED', 'PROCEDURE', 3, 20, 'PL/SQL: Statement ignored')
('FRED', 'PROCEDURE', 3, 20, "PLS-00201: identifier 'F' must be declared")
This is shown in the documentation Creating Stored Procedures and Packages.
In my Lotus Notes script, i do have this piece of logic as shown below. This is basically for two SELECT statements, followed by Fetch for each of the SELECT statement separately and the SELECT is for the same DB2 table with a variation in WHERE clause. The error i'm getting is for the second FETCH. The error i'm getting is ---> Field count mismatch error:
count = 0
If (srccon.Execute(selectstatement, fldLst1) = 0) Then
Goto GetNextDoc
End If
count = srccon.Fetch(fldLst1)
If ( count = 0 ) Then
Goto GetNextDoc
End If
The above cursor select and fetch does not give me any error.
The cursor down which is for the same DB2 table with a slight variation
in WHERE clause is causing the error:
count1 = 0
If (srccon.Execute(selectstatement1, fldLst) = 0) Then
Goto GetNextDoc
End If
count1 = srccon.Fetch(fldLst) ---> The error is pointing to this line
and the error is
I would appreciate any help in this regard. I would also thank the gentleman who
did excellent solution for my previous problem for current date minus 30 days.
With much thanks
I suspect it's because when you call Execute, you're reusing the same LCFieldList object from a previous call. Execute and Select statements append their list of result fields to the object you pass them, so you must pass them an empty fieldlist -- one you just created. Otherwise you get a combined fieldlist of all the fields in the result sets of multiple calls to Select or Execute.
You may find the LotusScript chapter of this Redbook useful.
In my trigger procedures I use RAISE EXCEPTION for messages. I have no problem with simple messages, but if I want to give the user some more complex feedback, I face a problem: the concatenation operator doesn't work within RAISE EXCEPTION statement.
First, I tried this:
CREATE OR REPLACE FUNCTION hlidej_datum_kon() RETURNS trigger AS $$
DECLARE
od date;
BEGIN
SELECT a.datum_od FROM akce AS a WHERE a.kod_akce = (
SELECT b.kod_akce FROM sj AS b WHERE b.kod_sj = NEW.kod_sj
) INTO od;
IF NEW.datum < od THEN
RAISE EXCEPTION 'Kontext nemohl být odkryt před začátkem akce ('||TO_CHAR(od)||')!'
ROLLBACK;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
Didn't work. So I tried to put the whole text to a text variable, but I didn't find how to put the variable's contents to the exception statement so that it would be printed as a message.
My question is: how to print a message containing variables in a PostgreSQL trigger function?
Just for sake of completeness, here is my trigger:
CREATE TRIGGER hlidej_datum_kon
AFTER INSERT OR UPDATE ON kontext
FOR EACH ROW
EXECUTE PROCEDURE hlidej_datum_kon();
END;
You not need to use concat. You can use wildcards instead:
RAISE EXCEPTION 'Kontext nemohl být odkryt před začátkem akce (%)!', od;
There are two bugs
first parameter of RAISE statement is format string - this string should be constant. It can contains a substitution symbols '%' and values for these symbols are places as others parameters of RAISE statement.
There should not be used ROLLBACK statement. RAISE EXCEPTION throws exceptions and ROLLBACK statement is newer executed. You cannot control transaction explicitly in PL/pgSQL - so you cannot use ROLLBACK or COMMIT statement in plpgsql ever.You can use a exception trapping
BEGIN
RAISE EXCEPTION 'blabla';
EXCEPTION WHEN some_exception_identif_see_list_of_exception_in_doc THEN
.. do some or do nothing
END;
I have a column with type double precision and I'd like copy values from this column to another column with type numeric(19,2).
When I do select CONVERT( numeric(19,2), PriceNettoTmp) from Table it works but when I do update Table set PriceNetto = CONVERT( numeric(19,2), PriceNettoTmp) it doesn't.
Error message for update when executing in Squirrel SQL:
Data Truncation error occured on a write of column -1Data was -1
bytes long and -1 bytes were transferred.
Error message for update when executing in Sybase Central:
Could not execute statement. Arithmetic overflow during explicit
conversion of FLOAT NULL value '10,449999999999999.0' to a NUMERIC
field . Sybase error code=247 Severity Level=16, State=1, Transaction
State=0 Line 1
Anybody knows what can be wrong?
EDIT
I found a solution which works: update Table set PriceNetto = CONVERT( numeric(19,2), str_replace(str(PriceNettoTmp,19,2),',','.'))
Although I still don't understand why select was working and update not. And is there any simpler solution than my?
Solution (as stated by OP)
update Table set PriceNetto = CONVERT( numeric(19,2), str_replace(str(PriceNettoTmp,19,2),',','.'))
I use Delphi/NexusDB and I build SQL (about 800 char long) at run time then I pass it to the nexusdb query.sql.text property to execute it but I found error of invalid token on execution.
I pass SQL like this
Query.SQL.Text := VarStrSQL; // <<---- string variable holding the SQL
when I traced I found SQL string in the Query.SQL.Text is trimmed to 326 character !!
While the string variable that hold the SQL is complete and fine but when I assign that variable to query.sql.text only 326 character passed and of course this result in an error for invalid SQL syntax
Please advise why the SQL string trimmed like that ?
Update:
*I tried memo1.lines.text := VarStrSQL and the memo component also display the string trimmed !! is it possible a character in my string cause that !! a bug in Delphi 2010 that cause TStrings to trim my string ?*
Thanks
Sounds like a bug in DB provider itself. There is no such limitation in TQuery.
My advice shall be to use small SQL, but bound parameters to set the data.
Instead of
Query.SQL.Text := 'INSERT INTO Store_Information (store_name, Sales, Date)
VALUES ('Los Angeles ... ... ...', 900, '10-Jan-1999')';
code
Query.FieldByName('store').AsString := 'Los Angeles ... ... ...'; // here you should have no limitation
Query.FieldByName('sales').AsInteger := 900;
Query.FIeldByName('Date').AsDAteTime := Now;
Query.SQL.Text := 'INSERT INTO Store_Information (store_name, Sales, Date)
VALUES (:store,:sales,:date)';
And your request will be faster, since the statement could be preparated by the engine, then reused.
I found the problem:
It is nxtChar Fields when they are null they have the value #0 and that cause string trimming
however although I check for null like this varisnull() the char fields was able to skip this trap function !!! which makes me go around myself for hours finally I now check them like this
If <nxtChar field> = #0 then <nxtChar field> = '' (or <nxtChar field> = null)