Getting error ORA-06502 while creating Dynamic SQL query using procedure - oracle

I have created a procedure and it requires Dynamic SQL block.
Procedure is as below which complies correctly but when I try to run it , it gives the below error.
I have tried to use cast() for all the variable which are used here. But this does not help.
Also, I am trying to run this procedure on Oracle using SQL - Developer tool.
Once the dynamic SQL is stored in sqlquery variable I would try and run the dynamic query and display its results!
**Output**
*Connecting to the database XXX.
ORA-06502: PL/SQL: numeric or value error: character to number conversion error
ORA-06512: at "XXX.PROCEDURE2", line 28
ORA-06512: at line 6
Who are you ?
Process exited.
Disconnecting from the database XXX.*
Procedure
*create or replace PROCEDURE PROCEDURE2 (var_owner IN dba_tab_cols.owner%TYPE) AS
CURSOR col_ident IS
select col1_name,col2,col3,col4,nullable,'_NM' as s_type
from table_name
where col2 in var_owner
and col3 like 'exp%%'
and col4 like 'exp2%';
sample_record col_ident%ROWTYPE;
BEGIN
OPEN col_ident;
LOOP
FETCH col_ident INTO sample_record;
DECLARE
col_nm VARCHAR2(30);
tab_nm VARCHAR2(30);
schema_nm VARCHAR2(30);
--a1 VARCHAR2(30);
sqlquery VARCHAR2(400);
BEGIN
col_nm := sample_record.col2;
tab_nm := sample_record.col3;
schema_nm := sample_record.col1_name;
IF sample_record.col4 = 'VARCHAR2' THEN
DBMS_OUTPUT.PUT_LINE('Who are you ? ');
sqlquery:= ('select distinct ' +col_nm+ 'from' + schema_nm+'.'+tab_nm + 'where rownum < 1');
DBMS_OUTPUT.PUT_LINE('Do you know me ');
END IF;
EXIT WHEN col_ident%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(sample_record.col1_name||','||sample_record.col3
||','||sample_record.col2||','||sample_record.col4||','||
sample_record.col5||','||sample_record.nullable||','||
sample_record.s_type);
END;
END LOOP;
--Close CURSOR col_ident
CLOSE col_ident;
END PROCEDURE2;*

Related

Show the output of a procedure in Oracle

The procedure uses the previous function to display the list of the products: num, designation and mention on the application.
SET SERVEROUTPUT ON;
CREATE OR REPLACE FUNCTION STORE(num_produit IN INTEGER) RETURN VARCHAR AS
N INTEGER := 0;
incre INTEGER := 0;
BEGIN
SELECT SUM(qte) INTO N FROM Ligne_Fact WHERE num_produit = produit;
IF N > 15 THEN
RETURN 'fort';
ELSIF N > 11 THEN
RETURN 'moyen';
END IF;
RETURN 'faible';
END;
/
CREATE OR REPLACE PROCEDURE SHOW_PRODUITS IS
SOME_VAR VARCHAR2(256);
BEGIN
SELECT num, designation, STORE(num) INTO SOME_VAR FROM Produit;
dbms_output.enable();
dbms_output.put_line('result : '|| SOME_VAR);
END;
/
BEGIN
SHOW_PRODUITS;
END;
/
I am sure that all the tables are filled with some dummy data, but I am getting the following error:
Function STOCKER compiled
Procedure AFFICHER_PRODUITS compiled
LINE/COL ERROR
--------- -------------------------------------------------------------
4/4 PL/SQL: SQL Statement ignored
4/56 PL/SQL: ORA-00947: not enough values
Errors: check compiler log
Error starting at line : 28 in command -
BEGIN
AFFICHER_PRODUITS;
END;
Error report -
ORA-06550: line 2, column 5:
PLS-00905: object SYSTEM.SHOW_PRODUITS is invalid
ORA-06550: line 2, column 5:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
The first major mistake you've made is to create your objects in SYSTEM schema. It, just like SYS, are special and should be used only for system maintenance. Create your own user and do whatever you're doing there.
As of your question: select returns 3 values, but you're trying to put them into a single some_var variable. That won't work. Either add another local variables (for num and designation), or remove these columns from the select:
CREATE OR REPLACE PROCEDURE SHOW_PRODUITS IS
SOME_VAR VARCHAR2(256);
BEGIN
SELECT STORE(num) INTO SOME_VAR FROM Produit; --> here
dbms_output.enable();
dbms_output.put_line('result : '|| SOME_VAR);
END;
/
Code, as you put it, presumes that produit contains a single record (it can't be empty nor it can have 2 or more rows because you'll get various errors).
Maybe you wanted to access all rows; in that case, consider using a loop, e.g.
CREATE OR REPLACE PROCEDURE SHOW_PRODUITS IS
SOME_VAR VARCHAR2(256);
BEGIN
FOR cur_r IN (SELECT num, designation, STORE(num) some_var FROM Produit) LOOP
dbms_output.put_line(cur_r.num ||', '|| cur_r.designation ||', result : '|| cur_r.some_var);
END LOOP;
END;
/
Then
set serveroutput on
BEGIN
SHOW_PRODUITS;
END;
/
You are trying to compile some stored routine which calls another stored routine named AFFICHER_PRODUITS and that routine calls SHOW_PRODUITS but SHOW_PRODUITS does not compile, hence the error. (By the way, it is recommended not to create your own stored routines in the SYSTEM schema.)
SHOW_PRODUITS does not compile because of this line:
SELECT num, designation, STORE(num) INTO SOME_VAR FROM Produit;
It appears that you want to get the query results as a string. In order to do that, you need to concatenate the column values, i.e.
SELECT num || designation || STORE(num) INTO SOME_VAR FROM Produit;
Of-course if all you want to do is display the query results, using DBMS_OUTPUT, you can declare a separate variable for each column.
CREATE OR REPLACE PROCEDURE SHOW_PRODUITS IS
SOME_NUM Produit.num%type;
SOME_DES Produit.designation%type;
SOME_VAR VARCHAR2(6);
BEGIN
SELECT num
,designation
,STORE(num)
INTO SOME_NUM
,SOME_DES
,SOME_VAR
FROM Produit;
dbms_output.enable();
dbms_output.put_line('result : ' || SOME_NUM || SOME_DES || SOME_VAR);
END;
Note that if the query returns more than one row, you will [probably] need to use a cursor.
CREATE OR REPLACE PROCEDURE SHOW_PRODUITS IS
SOME_NUM Produit.num%type;
SOME_DES Produit.designation%type;
SOME_VAR VARCHAR2(6);
--
CURSOR c1 IS
SELECT num, designation, STORE(num) FROM Produit;
BEGIN
OPEN c1;
LOOP
FETCH c1 INTO SOME_NUM, SOME_DES, SOME_VAR;
EXIT WHEN c1%NOTFOUND;
dbms_output.put_line('result : ' || SOME_NUM || SOME_DES || SOME_VAR);
END LOOP;
CLOSE c1;
END;

Create Oracle sequence via execute immediate without pipe || operator

create sequence s1 ;
declare
v_value number;
v_sql_stmt varchar2(4000);
v_seq_name varchar2(30);
BEGIN
v_seq_name:='S1'; -- **this is dynamic and the sequence will be passed in the proc as input parameter at runtime**
v_sql_stmt:= 'select :v_seq_name'||'.nextval from dual' ;
EXECUTE IMMEDIATE v_sql_stmt INTO v_value USING v_seq_name ;
--**below is working but I dont want to do in this way because of sql injection issue, let me know how to fix the above**
--EXECUTE IMMEDIATE 'select ' || v_seq_name || '.nextval from dual' INTO v_value;
dbms_output.put_line(v_value);
end;
/
the above code is throwing error, please help to fix.
If you run the commented code then it will run but I dont want to use || in execute immediate. I want to use colon : only.
the sequence name will be passed at run time. The above code will be converted to a proc later.
I understand your concern about SQL injection. To my knowledge, table/column/sequence names cannot be specified with bind variables. However, you could do a simple check before executing the unsafe code:
CREATE SEQUENCE s1;
CREATE SEQUENCE s2;
CREATE OR REPLACE FUNCTION p(seq_name VARCHAR2) RETURN NUMBER AS
v_value number;
v_sql_stmt varchar2(4000);
v_seq_name varchar2(128 BYTE);
BEGIN
v_seq_name:= DBMS_ASSERT.SIMPLE_SQL_NAME(seq_name);
v_sql_stmt:= 'select '||v_seq_name||'.nextval from dual';
EXECUTE IMMEDIATE v_sql_stmt INTO v_value;
RETURN v_value;
END p;
/
If a valid name is used, everything works as expected:
select p('s1') from dual;
1
select p('s2') from dual;
2
However, if seq_name is not a valid Oracle name, DBMS_ASSERT throws an exception:
select p('1; DROP TABLE x') from dual;
ORA-44003: invalid SQL name
ORA-06512: at "SYS.DBMS_ASSERT", line 215
ORA-06512: at "WFL.P", line 6
44003. 0000 - "invalid SQL name"

How to call a PL SQL stored procedure from Oracle Data Integrator (ODI)

I am trying to call the following PL SQL procedure from ODI. The code is runnig perfectly in SQL Developer.
create or replace PROCEDURE OMS_UPD_CODE_STATO (myUID_ELAB IN NUMBER, myTABLE_NAME IN VARCHAR2, P_RESULT OUT VARCHAR2) AS
C_TREC NUMBER;
C_TOT NUMBER;
str1 varchar2(1000);
str2 varchar2(1000);
BEGIN
str1:='select to_number(rtrim(substr(utente, 18,23),''0'')) from '|| myTABLE_NAME || ' where TREC =''99'' AND UID_ELAB = '||myUID_ELAB;
EXECUTE IMMEDIATE STR1 INTO C_TREC;
str2:='select count(*) from '|| myTABLE_NAME || ' where TREC is not null';
EXECUTE IMMEDIATE STR2 INTO C_TOT;
IF C_TOT = C_TREC THEN
execute immediate 'update'|| myTABLE_NAME || 'set CODE_STATO = ''N'' WHERE UID_ELAB = '|| myUID_ELAB;
P_RESULT:='OK';
commit;
ELSE
P_RESULT:='KO';
END IF;
END OMS_UPD_CODE_STATO;
In ODI I wrote the procedure as follow:
declare
P_RESULT VARCHAR2(100);
begin
OMS_UPD_CODE_STATO( #OMS.UID_ELAB, #OMS.ATTR_NOME_TABELLA, P_RESULT);
end;
where the first two parameters are INPUT parm while the third one, P_RESULT, is the OUT param present inside the PL SQL Stored Procedure. By calling the procedure from ODI I get the following error:
ODI-1228: Task Procedure-omsUpdateStato-callStored fails on the target connection OMS_DEV.
Caused By: java.sql.SQLException: ORA-06550: line 5, column 27:
PLS-00357: Table,View Or Sequence reference 'OMS_S_PERSONE_FISICHE' not allowed in this context
ORA-06550: line 5, column 1:
PL/SQL: Statement ignored
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:466)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:407)
at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:1113)
at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:546)
at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:269)
at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:603)
at oracle.jdbc.driver.T4CStatement.doOall8(T4CStatement.java:218)
at oracle.jdbc.driver.T4CStatement.doOall8(T4CStatement.java:31)
at oracle.jdbc.driver.T4CStatement.executeForRows(T4CStatement.java:1000)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1316)
at oracle.jdbc.driver.OracleStatement.executeInternal(OracleStatement.java:2168)
at oracle.jdbc.driver.OracleStatement.execute(OracleStatement.java:2100)
at oracle.jdbc.driver.OracleStatementWrapper.execute(OracleStatementWrapper.java:363)
at oracle.odi.runtime.agent.execution.sql.SQLCommand.execute(SQLCommand.java:205)
at oracle.odi.runtime.agent.execution.sql.SQLExecutor.execute(SQLExecutor.java:141)
at oracle.odi.runtime.agent.execution.sql.SQLExecutor.execute(SQLExecutor.java:28)
at oracle.odi.runtime.agent.execution.TaskExecutionHandler.handleTask(TaskExecutionHandler.java:52)
at oracle.odi.runtime.agent.execution.SessionTask.processTask(SessionTask.java:206)
at oracle.odi.runtime.agent.execution.SessionTask.doExecuteTask(SessionTask.java:117)
at oracle.odi.runtime.agent.execution.AbstractSessionTask.execute(AbstractSessionTask.java:886)
at oracle.odi.runtime.agent.execution.SessionExecutor$SerialTrain.runTasks(SessionExecutor.java:2227)
at oracle.odi.runtime.agent.execution.SessionExecutor.executeSession(SessionExecutor.java:611)
at oracle.odi.runtime.agent.processor.TaskExecutorAgentRequestProcessor$1.doAction(TaskExecutorAgentRequestProcessor.java:719)
at oracle.odi.runtime.agent.processor.TaskExecutorAgentRequestProcessor$1.doAction(TaskExecutorAgentRequestProcessor.java:611)
at oracle.odi.core.persistence.dwgobject.DwgObjectTemplate.execute(DwgObjectTemplate.java:203)
at oracle.odi.runtime.agent.processor.TaskExecutorAgentRequestProcessor.doProcessStartAgentTask(TaskExecutorAgentRequestProcessor.java:801)
at oracle.odi.runtime.agent.processor.impl.StartSessRequestProcessor.access$1400(StartSessRequestProcessor.java:74)
at oracle.odi.runtime.agent.processor.impl.StartSessRequestProcessor$StartSessTask.doExecute(StartSessRequestProcessor.java:702)
at oracle.odi.runtime.agent.processor.task.AgentTask.execute(AgentTask.java:180)
at oracle.odi.runtime.agent.support.DefaultAgentTaskExecutor$2.run(DefaultAgentTaskExecutor.java:108)
at java.lang.Thread.run(Thread.java:745)
Do you have any idea how to solve it? Am I doing any wrong call?
Thank you

Oracle Variable as select

I have to call oracle SQL statement inside my project.
All connection related stuff is done, but my tool does not capture the output parameter executed by oracle.
Hence I need alter this query to return p_num value in a select statement.
i.e. the table which has 1 column ('p_num') with column name called 'Result' and which has only one row which is p_num value.
Following is the sql statement which currently gives output value with help of dbms_output.put_line
DECLARE
p_num varchar2(4000);
message varchar2(4000) ;
BEGIN
p_num := MyFunction();
dbms_output.put_line('Message : ' || p_num) ;
END;
What I want is p_num value in a SELECT statement so that I can capture specific column inside my bpm tool.
You can directly call the function in the SELECT statement.
1) First way is to do it VIA plain SQL
SELECT MyFunction FROM DUAL;
2) Second way is PLSQL but i will not recommend it unless its unavoidable
set serveroutput on;
declare
lv_var VARCHAR2(100);
lv_out_param VARCHAR2(100);
BEGIN
lv_var:=MyFunction(lv_out_param);
dbms_output.put_line(lv_var||' '||lv_out_param);
END;
/

Dynamic Query Error in PLSQL

I am trying to execute this procedure:
CREATE OR REPLACE PROCEDURE SP_DYNAMIC
AS
tbl_list VARCHAR2(2000);
DBLINK VARCHAR2(100);
V_SQL VARCHAR2(1000);
BEGIN
DBLINK := 'SOME_LINK';
V_SQL := 'SELECT table_name,table_owner FROM dba_tab_modifications#:DB_LINK';
EXECUTE IMMEDIATE V_SQL USING DBLINK;
COMMIT;
Dbms_Output.PUT_LINE (TBL_LIST);
END;
But When I execute the stored procedure I get the error:
ORA-01729: database link name expected
ORA-06512: at "SYSTEM.SP_DYNAMIC"
ORA-06512: at line 2
Can somebody help me with what I am doing wrong here?
The reason it doesn't work is because you can't use a bind variable as the dblink. You get the same error when running the following:
select * from dual#:dblink;
If you absolutely must use dynamic sql, you'd have to concatenate the dblink name into the statement - but you'll have to be aware that you're now open to SQL Injection:
V_SQL := 'SELECT table_name,table_owner FROM dba_tab_modifications#'||DB_LINK;

Resources