Get result of anonymous pl/sql block in scala - oracle

I am calling a function in scala to truncate table. I am able to call a function and able to truncate a table as well. But, I would also print the value of result. If the truncate is successfully then the function is returning 1 as Int and I would to like to print this value to make sure the operation is successful but I am not sure how to do it ?
Query to call function :
truncQuery = "declare
result number;
begin
result := TRUNCATE_TABLE('PROV');
end;"
The value is being stored in the result but how can I print the result in the scala code below?
Code :
def truncateTbl (truncQuery : String ): Unit ={
val con = oracleUtil.auxdbOracleUtil()
val callableStatement = con.prepareCall(truncQuery)
callableStatement.execute()
callableStatement.close()
con.close()

Your TRUNCATE_TABLE function must be like:
CREATE OR REPLACE FUNCTION (PARAM_TABLE IN VARCHAR2)
RETURN NUMBER
AS
BEGIN
EXECUTE IMMEDIATE 'TRUNCATE TABLE ' || PARAM_TABLE;
RETURN 0
EXCEPTION
WHEN OTHERS THEN
RETURN 1
END;
/

Related

writing function but been getting this error

the question:
Write a blocK PL/SQL that display the total commission amount of a job id. Use function “compute_commission” that accepts a job id equal to 9 and return his total commission of all corresponding employees.
the error:
`Error at line 11: PLS-00103: Encountered the symbol "DECLARE"
CREATE OR REPLACE FUNCTION compute_commission (C_employee_id in number)
RETURN number
is `
the code:
CREATE OR REPLACE FUNCTION compute_commission (C_employee_id in number)
RETURN number
is
sum_commission number;
begin
select sum(job_id)
into sum_commission from employees
where employee_ref_id = C_employee_id;
return sum_commission;
end compute_commission;
declare
cal_sum_commission number;
begin
cal_sum_commission = compute_commission(cal_sum_commission);
dbms_output.put_line ('employee commission is: ' || compute_commission(cal_sum_commission);
end;
Should be something like this:
CREATE OR REPLACE FUNCTION compute_commission (C_employee_id IN NUMBER)
RETURN NUMBER
IS
sum_commission NUMBER;
BEGIN
SELECT SUM (job_id)
INTO sum_commission
FROM employees
WHERE employee_ref_id = C_employee_id;
RETURN sum_commission;
END compute_commission;
/
DECLARE
cal_sum_commission NUMBER := 12345;
BEGIN
cal_sum_commission := compute_commission (cal_sum_commission);
DBMS_OUTPUT.put_line (
'employee commission is: ' || cal_sum_commission);
END;
/
Note that I modified anonymous PL/SQL block and
added local variable's value (otherwise you'd pass NULL to the function) (you'll, of course, use some valid value; this - 12345 - is just an example)
used local variable in DBMS_OUTPUT.PUT_LINE
terminated statement with a semi-colon (you've had a colon)
fixed assignment operator (:= instead of just =)
Also, is sum_commision really sum of JOB_ID values? Looks strange to me ...

I can't call the function using jdbc, but if it is pipelined, then everything works

I using spring jdbc and oracle 12.
I can't get a response from the package function. But if I use exactly the same function but with the pipeline everything works.
Created a package and declared 2 functions in it. Both of them take a number as input, and output a table of pl/sql records. The difference in the function is that one is pipelined and the other is not
The declaration is:
type o_client is record(subs_id NUMBER);
type t_client is table of o_client;
function piplined_func (p_subs_id in NUMBER) return t_client pipelined;
function no_piplined_func (p_subs_id in NUMBER) return t_client;
The body is:
function piplined_func(p_subs_id in NUMBER) return t_client PIPELINED AS
v_pipe o_client;
BEGIN
FOR ids IN 1..10 LOOP
v_pipe.subs_id := ids;
PIPE ROW(v_pipe);
END LOOP;
return ;
END;
function no_piplined_func (p_subs_id in number) return t_client AS
l_tab t_client;
v_pipe o_client;
BEGIN
l_tab := t_client();
FOR ids IN 1..10 LOOP
v_pipe.subs_id := ids;
l_tab.extend;
l_tab(l_tab.last) := v_pipe;
END LOOP;
return l_tab;
END;
The first function is work correct:
System.out.println("Pipelined");
Processor processor = new Processor(oracleDataSource);
final String query = "select * MY_CATALOG.piplined_func(:p_subs_id)";
SqlParameterSource inputParams = new MapSqlParameterSource().addValue("p_subs_id", 1);
List<Wrapper> result = namedParameterJdbcTemplate.query(query, inputParams, BeanPropertyRowMapper.newInstance(Wrapper.class));
for (Wrapper wrapper : result) {
System.out.println(wrapper.toString());
}
Out:
Wrapper{subs_id=1}
Wrapper{subs_id=2}
Wrapper{subs_id=3}
The second function is not work correct:
System.out.println("Not Pipelined");
Processor processor = new Processor(oracleDataSource);
final String query = "select * from MY_CATALOG.no_piplined_func(:p_subs_id)";
SqlParameterSource inputParams = new MapSqlParameterSource().addValue("p_subs_id", 1);
List<Wrapper> result = namedParameterJdbcTemplate.query(query, inputParams, BeanPropertyRowMapper.newInstance(Wrapper.class));
for (Wrapper wrapper : result) {
System.out.println(wrapper.toString());
}
org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [select * from sa_db_test.no_piplined_func(?)]; nested exception is java.sql.SQLSyntaxErrorException: ORA-00902: invalid datatype
I tried to use SimpleJdbcCall in the same way, but also unsuccessfully.
SimpleJdbcCall simpleJdbcCall = new SimpleJdbcCall(oracleDataSource)
.withSchemaName("MY_SCHEMA")
.withCatalogName("MY_CATALOG")
.withProcedureName("no_piplined_func")
.withoutProcedureColumnMetaDataAccess()
.declareParameters( new SqlParameter("p_subs_id", Types.NUMERIC),);
SqlParameterSource in = new MapSqlParameterSource().addValue("p_subs_id", 1);
Map<String, Object> out = simpleJdbcCall.execute(in);
Exception in thread "main" org.springframework.jdbc.BadSqlGrammarException: CallableStatementCallback; bad SQL grammar [{call MY_SCHEMA.MY_CATALOG.NO_PIPLINED_FUNC(?)}]; nested exception is java.sql.SQLException: ORA-06550: line 1, column 7:
PLS-00221: 'NO_PIPLINED_FUNC' is not a procedure or is undefined
A RECORD is a PL/SQL ONLY data-type that cannot be used in SQL statements.
A PIPELINED function is designed to be used in SQL statements and despite you declaring that it returns a table of RECORD data types, it does not actually do that and, instead, creates equivalent SQL data-types (i.e. OBJECT data-types) that can be used in SQL statements.
If you want both to work then declare o_client and t_client in the SQL scope using:
CREATE TYPE o_client IS OBJECT (subs_id NUMBER);
CREATE TYPE t_o_client IS TABLE OF o_client;
Then you can use SQL data-types and not PL/SQL data-types:
CREATE PACKAGE pkg IS
type r_client is record(subs_id NUMBER);
type t_client is table of r_client;
function pipelined_func return t_client pipelined;
function no_pipelined_func return t_client;
function no_pipelined_func_obj return t_o_client;
END;
/
and the body:
CREATE PACKAGE BODY pkg IS
FUNCTION pipelined_func
RETURN t_client PIPELINED
AS
v_pipe r_client;
BEGIN
FOR ids IN 1..10 LOOP
v_pipe.subs_id := ids;
PIPE ROW(v_pipe);
END LOOP;
END;
FUNCTION no_pipelined_func
RETURN t_client
AS
l_tab t_client;
v_pipe r_client;
BEGIN
l_tab := t_client();
FOR ids IN 1..10 LOOP
v_pipe.subs_id := ids;
l_tab.extend;
l_tab(l_tab.last) := v_pipe;
END LOOP;
RETURN l_tab;
END;
FUNCTION no_pipelined_func_obj
RETURN t_o_client
AS
l_tab t_o_client := t_o_client();
BEGIN
FOR ids IN 1..10 LOOP
l_tab.extend;
l_tab(l_tab.last) := o_client(ids);
END LOOP;
RETURN l_tab;
END;
END;
/
Then:
SELECT * FROM pkg.no_pipelined_func();
Fails with:
ORA-00902: invalid datatype
But:
SELECT * FROM pkg.pipelined_func();
and
SELECT * FROM pkg.no_pipelined_func_obj();
Both output:
SUBS_ID
1
2
3
4
5
6
7
8
9
10
db<>fiddle here

Oracle using the like comparison taken from function in value

I am trying to create a simple function that takes in 3 parameters, 2 numbers and a string. I have written the function but am not getting the expected results from a simple select statement when using the LIKE comparison for the string.
The select from the function below returns no rows when executed with the string input value set to ebts, but if I run this as a standalone select state it returns 2 rows which what I would expect. Have used dbms output to determine if whitespace were being passed but all looks OK.
CREATE OR REPLACE FUNCTION OPC_OP.sitezone_exists
(in_site_id IN NUMBER, in_zone_id IN NUMBER, in_mod VARCHAR2)
RETURN NUMBER
IS
v_count_rec NUMBER;
v_return NUMBER;
v_mod VARCHAR2(4) := in_mod;
BEGIN
SELECT COUNT(*)
INTO v_count_rec
FROM AW_ACTIVE_ALARMS
WHERE AW_ACTIVE_ALARMS.site_id = in_site_id
AND AW_ACTIVE_ALARMS.zone_id = in_zone_id
AND AW_ACTIVE_ALARMS.module LIKE 'v_mod%';
IF v_count_rec > 0
THEN
DBMS_OUTPUT.PUT_LINE('count'||v_count_rec||'=========='||v_mod||'=============');
v_return:= 1;
RETURN (v_return);
ELSE
DBMS_OUTPUT.PUT_LINE('count'||v_count_rec||'=========='||v_mod||'=============');
v_return:= 0;
RETURN (v_return);
END IF;
END sitezone_exists;
When passing in values 12, 12, ebts the output displayed is:
count 0 ==========ebts=============
RetVal = 0
If I run the same select subtituting only passing in the above values the query returns 2 rows - I have removed the like clause of the function and it then returns 2 rows, any idea why the like part of clause is failing to match with rows.
You are trying to match a string literal with this:
AND AW_ACTIVE_ALARMS.module LIKE 'v_mod%';
Change it to:
AND AW_ACTIVE_ALARMS.module LIKE v_mod||'%';
MarioAna has the right answer, IMO, but as an aside (which is too long for a comment), your function can be better written.
You're duplicating the dbms_output code, plus it's considered best practice to have a single RETURN in a function (although I would argue that more might be ok - one in the body and one per exception in the exception block...), so you could rewrite it as:
CREATE OR REPLACE FUNCTION OPC_OP.sitezone_exists
(in_site_id IN NUMBER, in_zone_id IN NUMBER, in_mod VARCHAR2)
RETURN NUMBER
IS
v_count_rec NUMBER;
v_return NUMBER;
v_mod VARCHAR2(4) := in_mod;
BEGIN
SELECT COUNT(*)
INTO v_count_rec
FROM AW_ACTIVE_ALARMS aaa
WHERE aaa.site_id = in_site_id
AND aaa.zone_id = in_zone_id
AND aaa.module LIKE v_mod||'%';
DBMS_OUTPUT.PUT_LINE('count '||v_count_rec||'=========='||v_mod||'=============');
IF v_count_rec > 0 THEN
v_return := 1;
ELSE
v_return:= 0;
END IF;
RETURN (v_return);
END sitezone_exists;
/

returning query in oracle function

i am new to oracle database. Trying to make a simple function but it is returning complete select query which is in single quotes. I do not know why. kindly help. and yes! it in the end of function compiling also says "hint: nm parameter never used" I am confused.
-- function to return a single letter grade
create or replace function update_grade(nm number) return varchar2
as
grd varchar2(3);
begin
grd := 'select gradeid from grade where nm between marks_s and markks_e';
return grd;
end;
You are not executing any query. You are just assigning the query string to the returned result variable.
I've not tried to compile it, but something like this:
create or replace function update_grade(nm number) return varchar2
as
grd varchar2(3);
begin
SELECT gradeid INTO grd from grade where nm between marks_s and markks_e;
return grd;
end;
You might consider adding handling for the case when no data is found:
EXCEPTION
WHEN NO_DATA_FOUND THEN
grd:= NULL;

Oracle, calling PL/SQL issues from within SQL-Plus file x.sql says my_function "may not be a function"

so simple, if I create my function as CREATE OR REPLACE FUNCTION MD5_ENCODE it will run smoothly, but if it stays anonymously within the SQL-Plus block as PL/SQL --> "may not be a function" error.
What is this Oracle "feature" again?
DECLARE
FUNCTION MD5_ENCODE(CLEARTEXT IN VARCHAR2) RETURN VARCHAR2 IS
CHK VARCHAR2(16);
HEX VARCHAR2(32);
I INTEGER;
C INTEGER;
H INTEGER;
BEGIN
IF CLEARTEXT IS NULL THEN
RETURN '';
ELSE
CHK := DBMS_OBFUSCATION_TOOLKIT.MD5(INPUT_STRING
=> CLEARTEXT);
FOR I IN 1 .. 16 LOOP
C := ASCII(SUBSTR(CHK, I, 1));
H := TRUNC(C / 16);
IF H >= 10 THEN
HEX := HEX || CHR(H + 55);
ELSE
HEX := HEX || CHR(H + 48);
END IF;
H := MOD(C, 16);
IF H >= 10 THEN
HEX := HEX || CHR(H + 55);
ELSE
HEX := HEX || CHR(H + 48);
END IF;
END LOOP;
RETURN HEX;
END IF;
END;
BEGIN
UPDATE ADDRESSES_T SET STREET = MD5ENCODE(STREET) ;
-- etc...
END
http://forums.oracle.com/forums/thread.jspa?threadID=245112
There are a number of things it could be.
My #1 candidate is, we can only use functions in SQL statements that are public i.e. declared in a package spec. This is the case even for SQL statements executed within the same Package Body. The reson is that SQL statements are executed by a different engine which can only see publicly declared functions.
Long story short, function must be defined in a package, like CREATE OR REPLACE FUNCTION MD5ENCODE(IN_TEXT IN VARCHAR2) RETURN VARCHAR2 IS ...
In order to call a function within a SQL statement, it needs to exist as a function object within the database. The SQL statement is parsed and executed separately from your PL/SQL code, so it doesn't have access to the locally defined function.
If you really don't want to create the function object, you could use a cursor to loop over the rows in the table, execute the function in a PL/SQL statement, and update each row as you go.
Your first problem is you have a typo.
FUNCTION MD5_ENCODE(CLEARTEXT IN
VARCHAR2) RETURN VARCHAR2 IS
versus
UPDATE ADDRESSES_T SET STREET =
MD5ENCODE(STREET) ;
You are missing the underscore in the function call in the update statement.
The next error you will encounter is :
PLS-00231: function 'MD5_ENCODE' may not be used in SQL
So you can simply assign the function results to a variable and use it in the Update statement.
As it mentioned above comments, this could be useful.
DECLARE
V NUMBER := 0;
FUNCTION GET_SQ(A NUMBER) RETURN NUMBER AS
BEGIN
RETURN A * A;
END;
BEGIN
V := GET_SQ(5);
--DBMS_OUTPUT.PUT_LINE(V);
UPDATE MYTABLE A SET A.XCOL = V;
END;

Resources