Oracle PL / SQL оператор выбрасывает ошибки - PullRequest
0 голосов
/ 09 ноября 2011

У меня есть следующий PL / SQL, отправляемый на удаленный сервер oracle 11gr2 через ADO. Его цель - проверить, существует ли пользователь. Тогда, если это произойдет, убить все его соединения. Наконец это сбрасывает пользователя.

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;

Сообщение об ошибке, которое я получил после долгих настроек, по-прежнему:

ОШИБКА: [Microsoft] [Драйвер ODBC для Oracle] [Oracle] ORA-06550: строка 1, столбец 286: PLS-00103: Обнаружен символ «DROP» при ожидании одно из следующего:

(начало регистра объявляет иначе elsif end выход для goto if loop mod
null Pragma Повышение Возврат Выберите Обновление в то время как с << продолжить закрыть текущий удалить извлечение блокировки вставить открытый откат набор точек сохранения sql выполнить коммит для очистки канала слияния </p>

Ему не нравится синтаксис, который должен быть внутри оператора IF. Кто-нибудь знает, кто должен сделать это правильно?

EDIT: Чтобы было ясно, я обычно никогда не выполнял бы это утверждение таким способом. Но из-за окружающей среды это единственный возможный путь, который не создает никаких угроз безопасности. Я знаю, что нарушаю почти все хорошие практики, но на этот раз это необходимо!

1 Ответ

4 голосов
/ 09 ноября 2011

Вы не можете выдавать операторы DDL (т.е. DROP) непосредственно в PL / SQL, вам нужно будет запустить оператор DROP с использованием динамического SQL.

Самый простой способ добиться этого - с помощью оператора 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#;

Надеюсь, это поможет ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...