Detecting the number of ORACLE rows updated by a OCI OCIStmtExecute call - oracle

I have an ORACLE update statement that I call using the OCIStmtExecute function call.
Using an OCI function call I would like to know how many rows have been updated by the action, e.g. zero, one or more.
How do I do this ?

Use the OCIAttrGet function call on your OCIStmt statement handle with the attribute type set to OCI_ATTR_ROW_COUNT
So add the folllowing code to your program :
ub4 row_count;
rc = OCIAttrGet ( stmthp, OCI_HTYPE_STMT, &row_count, 0, OCI_ATTR_ROW_COUNT,
errhp );
where:
stmthp is the OCIStmt statement handle
errhp is the OCIError error handle
rc is the defined return code (sword)
The number of rows updated (or deleted and inserted if that is your operation) is written into the passed row_count variable

Invoke OCIAttrGet(OCI_ATTR_ROW_COUNT) on the statement handle.

Related

Oracle AQ dequeuing an array

Good day,
respective all!
Environment: Oracle 18XE 64-bit for Windows.
I have a question about dequeueing an array of messages from persistent queue.
It’s a simple point-to-point messaging. Queue is “single_consumer”, without propagation.
I registered my PL/SQL callback function.
I need to know an exact size of array of messages to dequeue
in every call of my callback function from Oracle AQ internal job.
And I found the only legal way how to have done it. And this way is to register callback
with qosflags parameter of sys.aq$reg_info equal to dbms_aq.NTFN_QOS_PAYLOAD.
Here is the registration PL/SQL block:
declare
v_qosflags number := dbms_aq.NTFN_QOS_PAYLOAD;
r_info SYS.AQ$_REG_INFO;
begin
r_info := SYS.AQ$_REG_INFO(
'STERN.FOUNDERS_QUEUE',
DBMS_AQ.NAMESPACE_AQ,
'plsql://stern.dosomecalc',
HEXTORAW('FF')
);
r_info.qosflags := v_qosflags;
r_info.ntfn_grouping_class := dbms_aq.NTFN_GROUPING_CLASS_TIME ;
r_info.ntfn_grouping_value := 60;
r_info.ntfn_grouping_type := dbms_aq.NTFN_GROUPING_TYPE_SUMMARY ;
DBMS_AQ.REGISTER (
SYS.AQ$_REG_INFO_LIST(
r_info
),
1
);
end;
Here is the declaration of callback procedure. It is a standard declaration:
create or replace procedure dosomecalc
(context RAW
,reginfo SYS.AQ$_REG_INFO
,descr SYS.AQ$_DESCRIPTOR
,payload raw
,payloadl NUMBER)
Now, thankfully to qosflags parameter initialized with dbms_aq.NTFN_QOS_PAYLOAD ,my callback function is registered in such a way that I always can see real size
of messages to dequeue in callback session.
This size is evaluated as counting size of descr.msgid_array part of descr parameter.
Without setting of qosflags during registration to some value - this part of descr parameter always comes empty to callback procedure call.
Once I know the real size of messages array , I can use it in
Dbms_aq.dequeue_array(…, array_size => descr.msgid_array.count,…)
dequeuing call inside my callback function.
Than, after investigating contents of descr parameter, I found in it an ntfnsRecdInGrp element,
and decided that ntfnsRecdInGrp is always equal to descr.msgid_array.count,
and just made for programmer’s convenience, just for duplicate descr.msgid_array.count.
AQ documentation says:
msgid_array - Group notification message ID list
ntfnsRecdInGrp - Notifications received in group
That was why I decided that they are equal by value.
It was a my mistake. When I use callback with array size equal to descr.msgid_array.count –
everything is OK. With ntfnsRecdInGrp – no. Sometimes descr.msgid_array.count
and ntfnsRecdInGrp equal to each other, sometimes not.
Now the question is:
What is the meaning of ntfnsRecdInGrp part of descr parameter?
Why it is not the same as msgid_array.count?
Thanks in advance.

PLSQL - Check if an object exists in a table of objects - type has no map

I have a procedure that has got this variables of type table of objects:
lsa_final_filter_ports t_modifylink_multicolumnlist;
lsa_initial_filter_ports t_modifylink_multicolumnlist;
Definition of t_modifylink_multicolumnlist is:
CREATE OR REPLACE TYPE "T_MODIFYLINK_MULTICOLUMNLIST" IS TABLE OF o_modifylink_multicolumnlist;
TYPE o_modifylink_multicolumnlist AS OBJECT(some properties);
lsa_final_filter_ports variable is populated like this
SELECT b.name INTO ls_bandwidth_name FROM bandwidth b
WHERE b.bandwidthid = lna_compatible_port_bw(i);
SELECT CAST(MULTISET(SELECT *
FROM TABLE(piosa_all_ports)
WHERE ITEMNAME4 = ls_bandwidth_name)
AS t_modifylink_multicolumnlist)
INTO lsa_final_filter_ports
FROM dual;
Where piosa_all_ports is I/O parameter having same type t_modifylink_multicolumnlist
Second parameter is initialized at the beginig of procedure with a second I/O parameter that the procedure has
lsa_initial_filter_ports := piosa_filtered_ports;
What I want to achieve is to check if an object from lsa_final_filter_ports exists in lsa_initial_filter_ports and if so then skip adding that object in lsa_initial_filter_ports which will be an output parameter used by the outside calling procedure.
What I've tried is iterating through lsa_final_filter_ports objects and checking if that object already exists like this:
FOR i in 1..lsa_final_filter_ports.COUNT LOOP
IF lsa_final_filter_ports(i) MEMBER OF lsa_initial_filter_ports THEN
CONTINUE;
END IF;
lsa_initial_filter_ports.EXTEND();
lsa_initial_filter_ports(lsa_initial_filter_ports.COUNT) := lsa_final_filter_ports(i);
END LOOP;
But with this code I'm getting the following error:
Error: PLS-00801: internal error [*** ASSERT at file pdw4.c, line
2181; Type 0x0x7f991127aef8 has no MAP method.;
NR_WIZARDVALIDATIONS__CUSTOMISATIONS__B__166833[33]
I'm not sure if this kind of comparation can be made, maybe someone can clarify this.
Thank you
Unfortunately, if you have objects in PlSql, which only exist in RAM (that means those, that are NOT stored persistently in a table), assigning them to another variables always causes a (deep) copy of the origin object.
(which is really a problem, if you often assign objects with nested objects to working-variables and back to the collection ...)
Therefore, you´ll never will be able to compare two (copies) of the same object on object-pointer level.
Only thing you can do, is comparing some unique attributes of the objects.
Let´s say, you´ll have an ID in your piosa_all_ports, then you might modify your loop above with the comparison in something similar to this:
v_exists integer;
FOR i in 1..lsa_final_filter_ports.COUNT LOOP
select nvl(max(1),0)
from table(lsa_initial_filter_ports) x
where x.id = lsa_final_filter_ports(i).id;
if (v_exists = 0) then
lsa_initial_filter_ports.EXTEND();
lsa_initial_filter_ports(lsa_initial_filter_ports.COUNT) := lsa_final_filter_ports(i);
end if;
END LOOP;
(rem.: i know, that switching PlSql- and SQL-Context in sample above is time-consuming, but otherwise, you have to write a function that tests the existance of an ID by iterating the whole list)

Return type error in eXist-db

I have just realized my logger is very active in the case of a function responsible for generating epubs. The problem is it works as expected. Hence I wonder what is going on here.
The error:
java:org.exist.xquery.XPathException, exerr:ERROR The actual return type does not match the sequence type declared in the function's signature: epub-util:render-epub(node()+, xs:string) xs:base64Binary. Expected cardinality: exactly one, got 0.
… epub is properly served to the client.
As for exerr:ERROR, I checked the general log in $EXIST_HOME/webapp/WEB-INF/logs/exist.log. There are no associated errors caught.
The suspected function:
declare function epub-util:render-epub($entries as node()+, $name as xs:string) as xs:base64Binary {
let $zip-file := compression:zip($entries, true())
let $archiveName := $name
return
response:stream-binary($zip-file, 'application/epub+zip', lower-case(replace($archiveName, ' ', '-')) || '.epub')
};
I run eXist on Ubuntu Server 14.04, eXist-db is 3.0.RC1.
response:stream-binary() is a very special function, that in essence directly writes bytes to a servlet output stream , hence it can only be used in the REST interface.
It can only write a byte stream to a HTTP agent, that is e.g. your web browser. It is not possible to store this data in a variable.
I agree that even item() is not a good thing, it should be something like void but that does not exist.
The common use-case it to have this expression as the last function call in a xquery script. A similar construct we use in the JFreechart library.
According to the eXist-db function documentation for response:stream-binary(), this function returns item(), not xs:base64binary. Replacing the return type with item() should fix the error.

LINQ to SQL - Nesting Stored Procedures

I have two stored procedures. One (test_proc_outside) makes a call to a second one (test_proc_inside).
When I create a new LINQ to SQL .dbml file visually by dragging over my test_proc_outside stored proc, the generated class (test_proc_outsideResult) actually contains the modelling for the inner proc's (test_proc_inside) result set.
Here is the code for the outside stored proc (test_proc_outside):
CREATE PROCEDURE [dbo].[test_proc_outside]
#test1 int = 1,
#test2 int = 2,
#test3 int = 3
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- The result of this proc call gets modelled into DBML:
EXEC dbo.test_proc_inside #test1, #test2
-- This SELECT statement does NOT get modelled into DBML:
SELECT #test1 AS Test1,
#test2 AS Test2,
#test3 AS Test3
END
GO
Here is the code for the inside stored proc (test_proc_inside):
CREATE PROCEDURE [dbo].[test_proc_inside]
-- Add the parameters for the stored procedure here
#test1 int = 1,
#test2 int = 2
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- This is the result set that gets modelled by the DBML file:
SELECT #test1 AS Test1_Inside,
#test2 AS Test2_Inside
END
GO
It appears that the DBML generation looks for the very first result set in the stored procedure (or nested stored procedures) and spits out the model for that.
If I change the nested proc call to a function instead, I get my desired model (test_proc_outside).
Is there a configuration setting to tell the DBML file to generate the class for the result set on the outside proc (test_proc_outside) and not to bother with the inner results from test_proc_inside?
Thanks in advance,
Craig
I think it's possible to get the result you want with L2S but you also have to get all the other results as well. You can't do it with the designer, you'll have to map the sproc by extending the DataContext in a partial class with a method that returns an instance of the IMultipleResults interface. See this blog post:
http://blogs.msdn.com/b/dinesh.kulkarni/archive/2008/05/16/linq-to-sql-tips-7.aspx
Also, if the stored proc is returning result sets that don't map to entity in your L2S model, you'll need create special types to represent those results manually by defining them in code the same way L2S normally generates types for stored procedure results in its designer.cs.

How can I call an Oracle function from Delphi?

I created a function in Oracle that inserts records in specific tables and return an output according to what occurs within the function. e.g (ins_rec return number)
How do I call this function and see its output in Delphi?
I got a reply (with all my thanks) for sql plus but I need to know how can I do this in Delphi
Just pass the user defined function as column name in the query and it will work.
Example:
Var
RetValue: Integer;
begin
Query1.Clear;
Query1.Sql.Text := 'Select MyFunction(Param1) FunRetValue from dual';
Query1.Open;
if not Query1.Eof then
begin
RetValue := Query1.FieldByName('FunRetValue').AsInteger;
end;
end;
How to accomplish it may depend on what DB access library you use (BDE? dbExpress? ADO? others), some may offer a "stored procedure" component that may work with functions as well.
A general approach it to use an anonymous PL/SQL block to call the function (and a parameter to read the return value), PL/SQL resembles Pascal a lot...:
Qry.SQL.Clear;
Qry.SQL.Add('BEGIN');
Qry.SQL.Add(' :Rez := ins_rec;');
Qry.SQL.Add('END;');
// Set the parameter type here...
...
Qry.ExecSQL;
...
ReturnValue := Qry.ParamByName('Rez').Value;
I would not have used a function, though, but a stored procedure with an OUT value. Moreover, Oracle offers packages that are a very nice way to organize procedure and functions, and they also offer useful features like session variables and initialization/finalization sections... very much alike a Delphi unit.
we run an Oracle stored procedure using this code that utilizes the BDE (I know please don't bash because we used the BDE!)
Try
DMod.Database1.Connected:= False;
DMod.Database1.Connected:= True;
with DMod.StoredProc1 do
begin
Active:= False;
ParamByName('V_CASE_IN').AsString:= Trim(strCaseNum);
ParamByName('V_WARRANT_IN').AsString:= strWarrantNum;
ParamByName('V_METRO_COMMENTS').AsString:= strComment;
Prepare;
ExecProc;
Result:= ParamByName('Result').AsString;
end;
Except

Resources