2011-11-09 3 views
0

ADO를 통해 원격 Oracle 11gr2 서버로 다음 PL/SQL을 보내고 있습니다. 사용자의 존재 여부를 확인하는 것이 목적입니다. 그런 다음 모든 연결을 종료하십시오. 마지막으로 사용자를 삭제합니다. 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 (*)보다'count (1)'을 사용하는 것은 장점이 없습니다. 또한, 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

동적 SQL을 사용하여 DROP 문을 실행해야하는 경우 PL/SQL에서 직접 DDL (즉, 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 주입 공격을 방지 할 수 있습니다. 누군가 실수로 오라클 제공 계정을 삭제하는 것을 원하지 않음) –

+0

DDL에서 바인드 변수를 사용할 수 없습니다 (예 :'alter system' 및'drop user'). – Allan

+0

바인딩 부분을 없애고 트릭을 만들었습니다. 고맙습니다. – wave

관련 문제