What is pass by reference in oracle? - plsql

I read on internet and found that the IN parameter in procedure is pass by reference. Can you please explain this with an example? Thanks in advance.

To better understand, let's review how PL/SQL handles parameters in two ways:
By Reference
In this case, a pointer to the actual parameter is passed to the corresponding formal parameter. Both actual and formal parameters point to the same location in memory that holds the value of the parameter.
By Value
In this case, the value of the actual parameter is copied to the corresponding formal parameter. If the program then terminates without an exception, the formal parameter value is copied back to the actual parameter. If an error occurs, the changed values are not copied back to the actual parameter.
By default OUT and IN OUT parameters are passed by value and IN parameters are passed by reference. When an OUT or IN OUT parameter is modified inside the procedure the procedure actually only modifies a copy of the parameter value. Only when the procedure has finished without exception is the result value copied back to the formal parameter.
procedure add_numbers(
first_val in number,
second_val in out number
)
BEGIN
second_val := first_val + second_val;
--some other statements
END;
/
TEST:
BEGIN
par_in = 124;
par_inout = 76;
add_numbers(par_in, par_inout);
DBMS_OUTPUT.PUT_LINE(par_inout);
END;
/
The example above, will print 200 on the screen. There are two parameters passed to add_numbers procedure:
The first one is par_in which is of the mode IN. This parameter is passed by reference. Hence, in add_numbers procedure, no other copy of this parameter will be created. Rather, the same copy will be used. If you are allowed to modify the value first_val inside add_numbers procedure (but you are not), the value will reflect directly to par_in. Because simply both first_val and par_in are two names for the same memory location.
The second one is par_inout which is of the mode IN OUT. This parameter is passed by value by default. Hence, in add_numbers procedure, new (memory location) will be allocated to store the another copy of this parameter. Hence, par_inout is a name to different location in the memory than second_val. They two names to two different locations.
The implication of the second parameter is that, after the line second_val := first_val + second_val; is executed, the value of second_val is different to the value of par_inout until the end of the procedure. Only at the end of the procedure, the value of second_val will be passed to par_inout.
Now, if you pass a large collection as an OUT or an IN OUT parameter then it will be passed by value, in other words the entire collection will be copied to the formal parameter when entering the procedure and back again when exiting the procedure. If the collection is large this can lead to unnecessary CPU and memory consumption.
The NOCOPY Parameter Mode Hint alleviates this problem because you can use it to instruct the runtime engine to try to pass OUT or IN OUT parameters by reference instead of by value
The hint requests PL/SQL runtime engine to pass an IN OUT argument by reference rather than by value. This can speed up the performance of your programs, because by-reference arguments are not copied within the program unit. When you pass large, complex structures like collections, records, or objects, this copy step can be expensive.

Related

Automatic rollback of implicit transaction(s) for multiple statements?

When multiple statements are submitted together --separated by semicolons(;) but in the same string-- and are NOT wrapped in an explicit transaction, is only a single implicit transaction created or is an implicit transaction created for each statement separately? Further, if one of the later statements fail and an automatic rollback is performed, are all of the statements rolled back?
This other answer almost satisfies my question, but wording in the official documentation leaves me puzzled. In fact, this may seem like a duplicate, but I am specifically wondering about implicit transactions for multiple statements. The other answer does not explicitly address this particular case.
As an example (borrowing from the other question), the following are submitted as a single string:
INSERT INTO a (x, y) VALUES (0, 0);
INSERT INTO b (x, y) VALUES (1, 2); -- line 3 error here, b doesn't have column x
The documentation says
Automatically started transactions are committed when the last query finishes. (emphasis added)
and
An implicit transaction (a transaction that is started automatically, not a transaction started by BEGIN) is committed automatically when the last active statement finishes. A statement finishes when its prepared statement is reset or finalized. (emphasis added)
The keyword last implies to me the possibility of multiple statements. Of course if an implicit transaction is started for each individual statement, then taken individually each statement will be the "last" statement to be executed, but in context of individual statements then it should just say the statement to emphasize the context being one single statement at a time.
Or is there there a difference between prepared statements and unprepared SQL strings? (But as I understand, all statements are prepared even if the calling application doesn't preserve the prepared statement for reuse, so I'm not sure this even matters.)
In the case of all statements being successful, the result of a single commit or multiple commits are essentially the same, but the docs only mention that the single failing statement is automatically rolled back, but doesn't mention other statements submitted together.
The sqlite3_prepare interface compiles the first SQL statement in a query string. The pzTail parameter to these functions returns a pointer to the beginning of the unused portion of the query string.
For example, if you call sqlite3_prepare with the multi-statement SQL string in your example, the first statement is the only one that is active for the resulting prepared statement. The pzTail pointer, if provided, points to the beginning of the second statement. The second statement is not compiled as a prepared statement until you call sqlite3_prepare again with the pzTail pointer.
So, no, multiple statements are not rolled back. Each implicit transaction created by the SQLite engine encompasses a single prepared statement.

Using custom number of parameters while using Call db procedure step in Pentaho (PDI)

Description:
Recently I've been trying to automatize some tasks at work using Pentaho (PDI), and I've come upon a problem that I had no luck of solving/finding solution for (I did research for many hours, been trying to solve it on my own as well). My aim is to load a text file containing name of the PL/SQL procedure stored on the server, and custom ammount of parameters for the procedure. For example if the source text file would contain following text:
Test_schema.job_pkg.run_job;12345
It should run job_pkg.run_job procedure from the defined connection, and use 12345 as a single parameter.
The problem:
The Call DB procedure transformation step only accepts SET ammount of parameters, for exampe I set the step to accept 4 parameters, but the procedure I'm calling is only accepting 1 parameter. I want to be able to IGNORE other parameters set in the step. When I try to send for example just one parameter but the step is set to accept 4 parameters, it throws:
Call DB Procedure.0 - ORA-06550: row 1, column 7:
PLS-00306: wrong number or types of arguments in call to 'RUN_JOB'
ORA-06550: row 1, column 7: PL/SQL: Statement ignored
What I have so far:
I've made a job that starts the transformation that loads the contents of the source file to memory, splits it to correct fields using Modified Java Script value, sets Pentaho variables with extraced values, then second transformation is loaded, that reads these variables and passes them as fields to Call DB procedure step. The last step always fails unless I manually remove all unused arguments.
Solution:
Based on AlainD's answer I've tried to use the Switch / Case step which solved the problem. Now there is different problem regarding conversion of values. If I pass a number but set it as STRING in Call DB Procedure's parameters, it throws
ORA-01403 no data found
This can be solved by handling the data via Modified Java Script Value step or any other step in order to convert the data into the "correct" format.
What I do in cases like that is to build a SQL command in a String, something like Test_schema.job_pkg.run_job(12345) and execute it with an Execute SQL script.
An other workaround would be to cont the number of parameters in the Modified Javascript step, and use a Switch/Case to redirect the flow on a sequence of DB Procedure steps: one with 0 parameter, one with 1 parameter, one with 2 parameters,... This method assume that the max number of parameters is small.

bind parameter inside a lexical parameter oracle reports builder

Is there a way to use a bind parameter inside a lexical parameter query something like this?:
select col from tbl where col = :bind_param
note: the code above is an input in a lexical parameter
When saying a "lexical query", do you mean a "lexical parameter"?
If I understood you correctly, then yes - you can do that, by setting it in the After Parameter Form trigger. (BTW, that's where I set my lexical parameters' values, always).
Open Reports Online Help System and search for "lexical". It is very well described. I believe that this is what you are asking:
A lexical reference cannot be used to create additional bind variables
after the After Form trigger fires. For example, suppose you have a
query like the following (note that the WHERE clause is replaced by a
lexical reference):
SELECT ENAME, SAL FROM EMP
&where_clause
If the value of the where_clause parameter contains a reference to a
bind variable, you must specify the value in the After Form trigger or
earlier (*LF). You would get an error if you supplied the following value
for the parameter in the Before Report trigger:
WHERE SAL = :new_bind
If you supplied this same value in the After Form trigger, the report
would run.
(*LF) Now, that's somewhat contradictory - "or earlier" actually is the Before Report trigger, so ... take it with caution. As I've said (and I'll repeat it): I set lexical parameters' values in the After Parameter Form. Worked always (for me).

What is Better for Mimicking PL/SQL Returning SQL in Interactive Reports: Collection or Pipelined-Function

The worst aspect of the Interactive Report (IR) is that you cannot create it using a PL/SQL returning SQL statement. I have gotten around this using two methods:
1) APEX_COLLECTION.CREATE_COLLECTION in the Before Header Process, which takes a SQL statement (that is constructed in PL/SQL in the process), and have the IR's source be select c001 alias1, c002 alias2 ... from apex_collections a where collection_name = '...'
2) Make a badass pipeline function with a parameter list as long as you need and then have the IR's source be select * from table(package_name.pipelined_function_name(:P1_parameter1, :P1_Parameter2))
Is there a performance difference? I originally used the first method but then ran into an occurrence where it was giving me a bug so I tried the pipelined function and found I just liked it better and have tended to use them ever since unless it was inappropriate to do so (namely when there is a large number of items to be passed to the parameter).
First method gives you opportunity to cache data by re-creating the collection only when you need it. Using n00X and d00X columns will give you some additional performance and right column types for the report definition. You can also create a view based on that collection with type casting and column aliases to add more convenience:
create or replace view apx_my_report
as
select n001 id, c001 data, d001 some_date
from apex_collections
where collection_name = 'MY_REPORT'
/
In that case you report source will be like that:
select id, data, some_date from apx_my_report
/
On the other hand, when you need to execute an ad-hoc query every time when page is rendered, it leads to the unavoidable re-creation of a such collection, therefore the performance goes down because of unwanted transaction maintaining: undo, redo etc.
So, it depends.

Oracle SQL Update passed as parameter (into stored procedure) string from .NET

I would like to know how to accomplish this task. I've looked at CASE, DECODE or IF condition and I'm not able to make it work. My goal is to pass a block of predefined column/value pair constructed from ASP.NET data to my Oracle stored procedure. I am trying to only update certain columns out of many to preserve other columns not needing updates. So here's my set up:
Stored procedure:
UpdateSelectedColumns(myValuePairString, updatedBy)
-- Passed variable from ASP.NET, myValuePairString = 'col1 = 10,col2 = 'Dog''
-- update statement final
UPDATE MyTable
SET
col1 = 10,
col2 = 'Dog'
col3 = 'john';
COMMIT;
Thank you in advance...
Ricky
For once I'm gonna advise to not use a stored proc. There is no point here in using a stored procedure.
As it is your stored procedure would blindly accept its arguments and execute the update without adding any value. Furthermore, by using this procedure, you preclude the use of binds and exposes yourself to bugs (whenever you encouner a value with a quote '), performance hit and SQL injection vulnerability.
The advantage of PL/SQL (simple transparent binding, transparent use and reuse of cursors, strict static SQL parsing and metadata dependancy) are all pointless if you take an aribtrary string as argument and put it in a dynamic cursor.
You'll be better off to use your language native cursors and use bind variables.
If you really want to use PL/SQL, replace your single argument with a couple of tables. One for the column names, one for the variable values. You could then use DBMS_SQL to parse the statement and use appropriate bind variables. You'll need some convention to be able to parse date, number and character values. You'll need to read metadata from the database to check the datatypes. This would be a lot of code for not a bit of value.

Resources