Gumowy Kaczak
Gumowy Kaczak

Reputation: 1499

PL/SQL: bind variable does not exist

How to modify this procedure to let it use bind variables

PROCEDURE KILL(user IN VARCHAR2) AS
BEGIN
  FOR REC IN (SELECT sid,serial# serial FROM V$SESSION WHERE username = user)
  LOOP 
    execute immediate 'alter system kill session '' :1 , :2 '' immediate' 
    using rec.sid,  rec.serial; 
    END LOOP; 
END; 

It gives:

bind variable does not exist

Upvotes: 4

Views: 10724

Answers (2)

Alex Poole
Alex Poole

Reputation: 191245

The bind variables in your statement are being treated as literal strings rather than place holders. If you output the statement you're generating:

BEGIN
    FOR REC IN (SELECT sid,serial# serial FROM V$SESSION WHERE username = user)
    LOOP
        dbms_output.put_line('alter system kill session '':1,:2'' immediate');
    END LOOP;
END;
/

... you see lines like:

alter system kill session ':1,:2' immediate

The ':1,:2' is treated as a static value and not as two bind variables. You can't use bind variables in dynamic DDL, and I'm not sure if that applies to alter commands, so this may be impossible anyway.

The simplest way to achieve this may be to generate the whole statement in the cursor:

BEGIN
    FOR REC IN (
        SELECT 'alter system kill session ''' || sid ||','|| serial#
            ||''' immediate' stmt
        FROM V$SESSION WHERE username = user)
    LOOP
        dbms_output.put_line(rec.stmt);
        --execute immediate rec.stmt;
    END LOOP;
END;
/

With the execute commented out (I don't really want to kill my sessions just now) you can just see the commands it will run, like:

alter system kill session '58,47157' immediate

Your approach may still be flawed though as it will kill the session that is executing the block, and it may or may not kill it last. I think this is in the realms of undefined behaviour, and I don't really want to try it to find out what happens... I doubt that's what you actually want anyway.

Edit: 'flawed' comment was based on using user, which in my anonymous block would be the executing user; in your proc it would be the user from the parameter. Using a keyword as a parameter name is confusing though, so I'd recommend changing the name to something like p_user, in the args and the statement.

Upvotes: 5

Greg Reynolds
Greg Reynolds

Reputation: 10186

I believe this might work

PROCEDURE KILL(user IN VARCHAR2) AS
BEGIN
  FOR REC IN (SELECT sid,serial# serial FROM V$SESSION WHERE username = user)
  LOOP 
    execute immediate 'alter system kill session :1 '||','|| ':2 immediate' 
    using rec.sid,  rec.serial; 
    END LOOP; 
END; 

Upvotes: -1

Related Questions