2011-11-09 53 views
0

我通過ADO將以下PL/SQL發送到遠程Oracle 11gr2服務器。 它的目的是檢查用戶是否存在。如果是這樣,那就殺掉它的所有連接。最後它會丟棄用戶。Oracle PL/SQL語句引發錯誤

DECLARE 
    i INTEGER; 
BEGIN 
    select count(1) into i from dba_users where username='<schema>'; 
    if i=0 THEN 
    FOR c IN (SELECT s.sid,s.serial# FROM v$session s WHERE s.username = '<schema>') LOOP  
     EXECUTE IMMEDIATE 'alter system kill session ''' ||c.sid || ',' || c.serial# || ''''; 
    END LOOP; 
    drop user <schema> Cascade; 
    END IF; 
END; 

我許多次調整後,收到錯誤消息仍然是:

ERROR:[Microsoft][ODBC driver for Oracle][Oracle]ORA-06550: line 1, column 286: PLS-00103: Encountered the symbol "DROP" when expecting one of the following:

(begin case declare else elsif end exit for goto if loop mod
null pragma raise return select update while with << continue close current delete fetch lock insert open rollback savepoint set sql execute commit forall merge pipe purge

它不喜歡具有IF語句內下降的語法。有誰知道誰來讓這個運行正常嗎?

編輯: 要清楚,我通常不會以這種方式執行此聲明。但由於環境的原因,這是唯一可能的方式,並且不會產生任何安全風險。我知道我違反了幾乎所有的好習慣,但這次是必要的!

+1

我** **強烈建議您在存儲過程中做到這一點。這將完成以下幾件事:1)您將從該問題中移除jet解析器,並讓Oracle在內部處理此問題。 2)你可以構造SP,使其僅僅返回1或0作爲成功/失敗,從而拒絕任何注入嘗試。另外請注意* Ollie *的建議,並使用綁定參數來進一步保護任何sql事務。 – FlyingGuy

+0

@wave:另外,使用count(1)'count'(*)'沒有什麼優勢。此外,SQL解析引擎無論如何都會將「count(1)」更改爲「count(*)」。請參閱Tom Kyte關於此的許多文章:[Select Count(1):How it works](http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:1156151916789 ) – Wolf

回答

4

您不能在PL/SQL中直接發出DDL(即DROP)語句,您需要使用動態SQL來運行DROP語句。

實現這一目標的最簡單方法是使用EXECUTE IMMEDIATE聲明(以類似的方式如何,你已經使用過的ALTER SESSION命令): http://download.oracle.com/docs/cd/B12037_01/appdev.101/b10807/13_elems017.htm

DECLARE 
    i INTEGER; 
BEGIN 
    SELECT COUNT(1) 
    INTO i 
    FROM dba_users 
    WHERE username = '<schema>'; 

    IF i = 0 
    THEN 
     FOR c IN (SELECT s.sid, 
         s.serial# 
        FROM v$session s 
        WHERE s.username = '<schema>') 
     LOOP 
     EXECUTE IMMEDIATE 'alter system kill session ''' || 
          c.sid || ',' || c.serial# || ''''; 
     END LOOP; 

     EXECUTE IMMEDIATE 'DROP USER :username CASCADE' 
     USING '<schema>'; 
    END IF; 
END; 

順便說一句,你可能要考慮使用綁定變量而不是連接動態SQL中的值,因爲它可以提高性能,特別是在循環中。

例如

EXECUTE IMMEDIATE 'alter system kill session '':sid'','':serial''' 
USING c.sid, 
     c.serial#; 

希望它可以幫助...

+2

你不能在DDL中使用綁定變量,所以你不能用這種方法參數化'ALTER SYSTEM'或'DROP USER'命令。你必須連接用戶名。您可能希望使用'DBMS_ASSERT.SCHEMA_NAME'函數來驗證傳入的用戶名是否爲簡單模式名稱,以防止SQL注入攻擊,例如記錄呼叫和驗證用戶名是否合理等。不希望有人不小心丟棄Oracle交付的賬戶) –

+0

您不能在DDL中使用綁定變量(即'alter system'和'drop user')。 – Allan

+0

擺脫了綁定部分之後,這樣做了。非常感謝你。 – wave