2011-11-09 7 views
0

次のPL/SQLがADOを介してリモート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)ジェットパーサーを問題から削除し、Oracleで内部的に処理させます。 2)SPを構造化して、成功または失敗として1または0を返すだけで、注入の試行を拒否することができます。さらに、* Ollie *のアドバイスに注意して、バインドパラメータを使用してSQLトランザクションをさらに保護します。 – FlyingGuy

+0

@wave:また、 'count(1)'を 'count(*) 'に使う利点はありません。さらに、SQL解析エンジンは、とにかく 'count(1)'を 'count(*) 'に変更します。 Tom Kyteの多くの記事を参照してください。[Select Count(1):動作の仕方](http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:1156151916789 ) – Wolf

答えて

4

PL/SQLで直接DDL(DROP)文を発行することはできません。動的SQLを使用してDROP文を実行する必要があります。

これを達成するための最も簡単な方法は、(すでにALTER SESSIONコマンドのためにそれを使用している方法と同じように)EXECUTE IMMEDIATE文である。ちなみに 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

関連する問題