The following procedure:
create or replace
PROCEDURE ChangePassword
(
p_Name VARCHAR2,
p_Password VARCHAR2
)
AS
EXECUTE IMMEDIATE 'ALTER USER :a IDENTIFIED BY :b' USING p_Name, p_Password;
END;
compiles successfuly, but when executed:
exec ChangePassword('TestUser', 'newPassword');
results in error:
01935. 00000 - "missing user or role name"
*Cause: A user or role name was expected.
*Action: Specify a user or role name.
Why?
You can't use bind variables in place of identifiers, such as the user name in this statement. The value of the identifier needs to be known when the statement is parsed, whereas a bind value is incorporated after parsing, before execution.
I think that the following would work
create or replace PROCEDURE ChangePassword(p_Name IN VARCHAR2,
p_Old_password IN VARCHAR2,
p_New_password IN VARCHAR2)
AS
EXECUTE IMMEDIATE 'ALTER USER ' || p_name ||
' IDENTIFIED BY ' || p_New_password ||
' REPLACE ' || p_Old_password;
END;
Share and enjoy.
Related
create or replace
PROCEDURE TEST3(CREATED_BY_IN IN VARCHAR2,SRC_NAME IN VARCHAR2,TGT_NAME IN VARCHAR2,OUTPUT OUT VARCHAR2)
IS
CHECK_STATUS INTEGER;
SRCSQL VARCHAR(1000);
BEGIN
SRCSQL:= 'INSERT INTO TBLCNT SELECT '||''''||CREATED_BY_IN||''''||','|| ' COUNT(*),' ||''''||SRC_NAME||''''||' FROM '||SRC_NAME ;
EXECUTE IMMEDIATE SRCSQL USING CREATED_BY_IN,SRC_NAME;
OUTPUT:=SRCSQL;
END;
Iam getting the error stating 'Bind variable does not exist'.
Can anyone please help me with this
You are performing a query with concatenated text and variable, so you can't use execute immediate with binded variables since they are not used in this case.
the right syntaxe is :
SRCSQL:= 'INSERT INTO TBLCNT SELECT :p1, COUNT(*), :p2 FROM :p2';
EXECUTE IMMEDIATE SRCSQL USING CREATED_BY_IN, SRC_NAME, SRC_NAME;
See documentation https://docs.oracle.com/cd/B13789_01/appdev.101/b10807/13_elems017.htm
You can use this without the help of bind variables. Hope below snippet helps .
CREATE OR REPLACE PROCEDURE TEST3(
CREATED_BY_IN IN VARCHAR2,
SRC_NAME IN VARCHAR2,
TGT_NAME IN VARCHAR2,
OUTPUT OUT VARCHAR2)
IS
CHECK_STATUS INTEGER;
SRCSQL VARCHAR(1000);
BEGIN
SRCSQL:= 'INSERT INTO TBLCNT SELECT '||''''||CREATED_BY_IN||''''||','|| ' COUNT(*),' ||''''||SRC_NAME||''''||' FROM '||SRC_NAME ;
EXECUTE IMMEDIATE SRCSQL;
OUTPUT:=SRCSQL;
END;
Here is the definition of the stored procedure:
CREATE OR REPLACE PROCEDURE usp_dropTable(schema VARCHAR, tblToDrop VARCHAR) IS
BEGIN
DECLARE v_cnt NUMBER;
BEGIN
SELECT COUNT(*)
INTO v_cnt
FROM all_tables
WHERE owner = schema
AND table_name = tblToDrop;
IF v_cnt > 0 THEN
EXECUTE IMMEDIATE('DROP TABLE someschema.some_table PURGE');
END IF;
END;
END;
Here is the call:
CALL usp_dropTable('SOMESCHEMA', 'SOME_TABLE');
For some reason, I keep getting insufficient privileges error for the EXECUTE IMMEDIATE command. I looked online and found out that the insufficient privileges error usually means the oracle user account does not have privileges for the command used in the query that is passes, which in this case is DROP. However, I have drop privileges. I am really confused and I can't seem to find a solution that works for me.
Thanks to you in advance.
SOLUTION:
As Steve mentioned below, Oracle security model is weird in that it needs to know explicitly somewhere in the procedure what kind of privileges to use. The way to let Oracle know that is to use AUTHID keyword in the CREATE OR REPLACE statement. If you want the same level of privileges as the creator of the procedure, you use AUTHID DEFINER. If you want Oracle to use the privileges of the user currently running the stored procedure, you want to use AUTHID CURRENT_USER. The procedure declaration looks as follows:
CREATE OR REPLACE PROCEDURE usp_dropTable(schema VARCHAR, tblToDrop VARCHAR)
AUTHID CURRENT_USER IS
BEGIN
DECLARE v_cnt NUMBER;
BEGIN
SELECT COUNT(*)
INTO v_cnt
FROM all_tables
WHERE owner = schema
AND table_name = tblToDrop;
IF v_cnt > 0 THEN
EXECUTE IMMEDIATE('DROP TABLE someschema.some_table PURGE');
END IF;
END;
END;
Thank you everyone for responding. This was definitely very annoying problem to get to the solution.
Oracle's security model is such that when executing dynamic SQL using Execute Immediate (inside the context of a PL/SQL block or procedure), the user does not have privileges to objects or commands that are granted via role membership. Your user likely has "DBA" role or something similar. You must explicitly grant "drop table" permissions to this user. The same would apply if you were trying to select from tables in another schema (such as sys or system) - you would need to grant explicit SELECT privileges on that table to this user.
You should use this example with AUTHID CURRENT_USER :
CREATE OR REPLACE PROCEDURE Create_sequence_for_tab (VAR_TAB_NAME IN VARCHAR2)
AUTHID CURRENT_USER
IS
SEQ_NAME VARCHAR2 (100);
FINAL_QUERY VARCHAR2 (100);
COUNT_NUMBER NUMBER := 0;
cur_id NUMBER;
BEGIN
SEQ_NAME := 'SEQ_' || VAR_TAB_NAME;
SELECT COUNT (*)
INTO COUNT_NUMBER
FROM USER_SEQUENCES
WHERE SEQUENCE_NAME = SEQ_NAME;
DBMS_OUTPUT.PUT_LINE (SEQ_NAME || '>' || COUNT_NUMBER);
IF COUNT_NUMBER = 0
THEN
--DBMS_OUTPUT.PUT_LINE('DROP SEQUENCE ' || SEQ_NAME);
-- EXECUTE IMMEDIATE 'DROP SEQUENCE ' || SEQ_NAME;
-- ELSE
SELECT 'CREATE SEQUENCE COMPTABILITE.' || SEQ_NAME || ' START WITH ' || ROUND (DBMS_RANDOM.VALUE (100000000000, 999999999999), 0) || ' INCREMENT BY 1'
INTO FINAL_QUERY
FROM DUAL;
DBMS_OUTPUT.PUT_LINE (FINAL_QUERY);
cur_id := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.parse (cur_id, FINAL_QUERY, DBMS_SQL.v7);
DBMS_SQL.CLOSE_CURSOR (cur_id);
-- EXECUTE IMMEDIATE FINAL_QUERY;
END IF;
COMMIT;
END;
/
you could use "AUTHID CURRENT_USER" in body of your procedure definition for your requirements.
Alternatively you can grant the user DROP_ANY_TABLE privilege if need be and the procedure will run as is without the need for any alteration. Dangerous maybe but depends what you're doing :)
I have the below query:
DECLARE vquery Varchar2(5000) := 'CREATE TABLE MYSCHEMA.MyTable ( ID INTEGER NOT NULL, Badge INTEGER NOT NULL,Password NVARCHAR2(50),PRIMARY KEY (ID))' ;
Begin
--EXECUTE IMMEDIATE vquery;--This is what I want to execute
dbms_output.put_line('VQUERY is: '' || vquery || ');--Just wanted to test
End;
Now the Problems are:
It is saying PL/SQL successfully completed,but I want to see the vquery in put_line as output,it is not coming.
All I want is to create that table by finally running:
EXECUTE IMMEDIATE vquery;
I am using PL/SQL Developer.
Thanks in advance.
There was a minor syntax error, vquery was a string as you included the variable as part of the string
DBMS_OUTPUT.put_line ('VQUERY is: ' || vquery);
instead of
DBMS_OUTPUT.put_line('VQUERY is: '' || vquery || ');
so try as
DECLARE
vquery VARCHAR2 (5000);
BEGIN
vquery :=
'CREATE TABLE MyTable ( ID INTEGER NOT NULL, Badge INTEGER NOT NULL,Password NVARCHAR2(50),PRIMARY KEY (ID))';
--EXECUTE IMMEDIATE vquery;--This is what I want to execute
DBMS_OUTPUT.put_line ('VQUERY is: ' || vquery); --Just wanted to test
END;
You can try using DEFINE instead of DECLARE:
DEFINE vquery = 'CREATE TABLE MYSCHEMA.MyTable ( ID INTEGER NOT NULL, -
Badge INTEGER NOT NULL, Password NVARCHAR2(50),PRIMARY KEY (ID))'
&vquery;
I'm not 100% positive on this one, but I am adapting it from this: Define a VIEW in Oracle without using CREATE. There are a couple of good solutions that both worked for me there.
I have a delete procedure which is taking table name and some values to delete record from that table, hence I have created a procedure with execute immediate which is forming the delete query by taking the parameter and delete.
But when ever I am passing the char value in the parameter it is getting error :
invalid identifier
as query formed with out single quote for the character value. Please let me know how can I pass char value in the procedure to form a string correctly.
Below is the procedure:
CREATE OR replace PROCEDURE Prd_delete(p_tbl_name IN VARCHAR2,
p_sys VARCHAR2,
p_b_id VARCHAR2,
p_c_date NUMBER)
IS
dlt_query VARCHAR2(200);
BEGIN
dlt_query := 'delete from '
||p_tbl_name
||' where system='
||p_sys
|| ' And batch_id='
||p_b_id
|| ' And cobdate='
||p_c_date;
--dbms_output.put_line(dlt_query);
EXECUTE IMMEDIATE dlt_query;
END;
/
Below is the running command :
exec prd_delete ('TBL_HIST_DATA','M','N1',20141205);
Below is the error :
ORA-00904:"N1" invalid identifier.
How to pass this value correctly ? please suggest.
At first place, why do you need PL/SQL for the DELETE. You could do it in plain SQL.
Why is P_C_DATE a NUMBER, What data type is cobdate COLUMN. A date should always be a DATE. If the column data type is DATE, then you will run into more errors. Always pay attention to declaring correct data types.
With dynamic SQL, before directly executing, it is always a good practice to see whether the query is formed correctly using DBMS_OUTPUT. I would also suggest to use quoting string literal technique to make it even easier.
DBMS_OUTPUT.PUT_LINE(dlt_query);
The issue with the query is that you are missing the single-quotation marks around the VARCHAR2 type.
Modify the query to -
dlt_query := 'delete from '||P_TBL_NAME||' where system='||P_SYS||
' And batch_id='||''''||P_B_ID|| '''' ||
' And cobdate='||P_C_DATE;
you are losing the quotes around N1 during concatination
you can fix by adding quotes before and after , eg.
dlt_query := 'delete from '||P_TBL_NAME||' where system='||P_SYS||
' And batch_id='||''''||P_B_ID|| '''' ||
' And cobdate='||P_C_DATE;
If you have to use the EXECUTE IMMEDIATE statement, you should use bind variables:
CREATE OR REPLACE PROCEDURE prd_delete (P_TBL_NAME IN VARCHAR2,
P_SYS VARCHAR2,
P_B_ID VARCHAR2,
P_C_DATE NUMBER) IS
dlt_query VARCHAR2 (200);
BEGIN
dlt_query := 'delete from ' || P_TBL_NAME || ' where system=:1 and batch_id=:2 and cobdate=:3';
BEGIN
EXECUTE IMMEDIATE dlt_query USING P_SYS, P_B_ID, P_C_DATE;
EXCEPTION
WHEN OTHERS THEN
-- catch exception !!
END;
END;
/
There is UserA and UserB in my oracle.
This is the package from UserA:
CREATE OR REPLACE PACKAGE BODY pkgA AS
PROCEDURE procA
AS
l_sql = 'BEGIN ' || UserB.procB || (:l_v1,:l_v2) END;';
EXECUTE IMMEDIATE l_sql USING IN l_v1,IN l_v2;
END;
Thie procB is come from UserB;
When I run this, I get the error:
PLS-00201:IDENTIFIER 'UserB.procB' must be declared;
User A need the EXECUTE right on the userb.procB.
grant the right as User B:
grant execute on UserB.procB to userA;
Unless it's supplied as a parameter, the procedure name needs to be inside the string as a fixed value; you have it outside so it's trying to be interpreted as a variable name, which doesn't exist:
l_sql = 'BEGIN UserB.procB(:l_v1,:l_v2) END;';
But then you wouldn't need to execut it dynamically anyway, you could just do:
PROCEDURE ProcA AS
BEGIN
UserB.procB(l_v1, l_v2);
END;
If you were passing the procedure as a variable, which would be a little odd, you'd have something like:
PROCEDURE procA (proc_name in varchar2) AS
BEGIN
l_sql = 'BEGIN ' || proc_name || '(:l_v1,:l_v2) END;';
EXECUTE IMMEDIATE l_sql USING IN l_v1,IN l_v2;
END;
... and you'd call that as procA('UserB.procB'). I don't think that's what you're trying to do, but it isn't entirely clear.
In both cases you don't seem to have l_v1 or l_v2 defined, so I guess you've just missed that part of the code out.