Отправляет email-рассылки с помощью сервиса Sendsay

Открыто о СУБД Oracle на русском

  Все выпуски  

Открыто о СУБД Oracle на русском : USING - ключевое слово PL/SQL 9i


Информационный Канал Subscribe.Ru

Выпуск 45

Уважаемые подписчики рассылки!

Этот выпуск посвящен двум особенностям работы PL/SQL-машины, которая в версиях 9.x объединена с SQL-машиной. Интересные особенности, которые могут всплыть при переносе программного обеспечения на новую версию сервера Oracle... По мотивам ответа Тома Кайта на вопросы, заданные 15 июня 2003 года.

USING - ключевое слово PL/SQL!

Том,

Я хотел бы задать два вопроса, которые меня сильно сбивают с толку.
Первый вопрос: Один из разработчиков написал следующий код в Oracle 8.1.7.3:

 
create table auxtab as select from dual; 
create or replace procedure p_insert_auxtab as 
begin 
  insert into auxtab using (select * from dual); 
  commit; 
end; 
/ 
 
Procedure created. 
 
SQL> show errors 
 
No errors. 

При попытке выполнения тех же действий в версии 9.2.0.3.0 получаем сообщение об ошибке:

 
create table auxtab as select from dual; 
create or replace procedure p_insert_auxtab as 
begin 
  insert into auxtab using (select * from dual); 
  commit; 
end; 
/ 
 
Warning: Procedure created with compilation errors. 
 
SQL> show errors 
 
Errors for PROCEDURE P_INSERT_AUXTAB: 
 
LINE/COL ERROR 
-------- ---------------------------------------------------- 
3/1      PL/SQL: SQL Statement ignored 
3/31     PL/SQL: ORA-00926: missing VALUES keyword 

Но если сделать так:

 
SQL> create or replace procedure p_insert_auxtab as 
  2  begin 
  3  insert into auxtab using select * from dual; 
  4  commit; 
  5* end; 
SQL> / 
 
Procedure created. 
 
SQL> show errors 
 
No errors. 

Я никогда не думал, что слово "using" может использоваться так. Я использовал слово using в операторах типа execute immediate или при открытии курсора. Мой вопрос: правильно ли использовать слово using в операторе "insert into..."? Почему разработчик смог скомпилировать и выполнить процедуру в версии 8i со скобками, а в версии 9i это уже не прошло?

Второй вопрос: Один из разработчиков сделал следующее в версии 8.1.7.3

 
SQL> create table test2 
  2  (colnum number) 
  3  ; 
 
Table created. 
 
SQL> create or replace procedure p_test2 as 
  2  x number:=0; 
  3  begin 
  4    select colnum into x from test2 where colnum mod 4 =0; 
  5    dbms_output.put_line(to_char(x)); 
  6* end; 
SQL> / 
 
Procedure created. 
 
SQL> show error 
 
No errors. 

В версии 9i я получаю:

 
SQL> create table test2 
  2  (colnum number) 
  3  ; 
 
Table created. 
 
SQL> create or replace procedure p_test2 as 
  2  x number:=0; 
  3  begin 
  4    select colnum into x from test2 where colnum mod 4 =0; 
  5    dbms_output.put_line(to_char(x)); 
  6* end; 
  7  / 
 
Warning: Procedure created with compilation errors. 
 
SQL> show errors 
 
Errors for PROCEDURE P_TEST2: 
 
LINE/COL ERROR 
-------- ----------------------------------------------------------------- 
4/1      PL/SQL: SQL Statement ignored 
4/59     PL/SQL: ORA-00920: invalid relational operator 

Почему версия 8i позволяла использовать функцию mod как оператор? Не должна ли былап выдаваться ошибка и в версии 8i? Я просмотрел документацию Oracle и не нашел ни одного примера, где mod используется как оператор. Можно ли использовать mod как оператор? Почему процедура перестала успешно компилироваться в версии 9i?

Ответ Тома Кайта

Первый вопрос:

 
insert into T  
(select * from dual); 

Такой оператор вас не удивляет, перавда? Так что:

 
insert into T T1 
(select * from dual); 

тоже не удивит. А дальше:

 
insert into T "using" 
(select * from dual); 

Это ведь аналогичная конструкция, как и:

 
insert into T using 
(select * from dual); 

USING - всего лишь "корреляционное имя", ПСЕВДОНИМ таблицы T, а не ключевое слово. Но в версии 9i появилось ключевое слово USING в языке PL/SQL, что усложнило ситуацию:

 
ops$tkyte@ORA920> create table t as select * from dual where 1=0; 
 
Table created. 
 
ops$tkyte@ORA920> begin 
  2          insert into t using (select * from dual); 
  3  end; 
  4  / 
 
end; 
   * 
ERROR at line 3: 
ORA-06550: line 2, column 16: 
PL/SQL: ORA-00926: missing VALUES keyword 
ORA-06550: line 2, column 2: 
PL/SQL: SQL Statement ignored 
 
ops$tkyte@ORA920> begin 
  2          insert into t using select * from dual; 
  3  end; 
  4  / 
 
PL/SQL procedure successfully completed. 
 
ops$tkyte@ORA920> begin 
  2          insert into t "using" (select * from dual); 
  3  end; 
  4  / 
 
PL/SQL procedure successfully completed. 
 
ops$tkyte@ORA920> begin 
  2          insert into t "using" select * from dual; 
  3  end; 
  4  / 
 
PL/SQL procedure successfully completed. 

Но если коротоко -- USING интерпретировалось как псевдоним, а не как ключевое слово. Его просто не нужно указывать.

Второй вопрос:

Уникальная ситуация - я с такой не сталкивался. Проблема связана с тем, что в версиях до 8i включительно PL/SQL-машина использовала отдельный анализатор SQL. В PL/SQL все операторы типа =, < и т.п. определялись как "функции", они переписывались. Если включить sql_trace и посмотреть на SQL, сгенерированный из PL/SQL, можно увидеть следующее:

 
SELECT COLNUM 
FROM 
 T  WHERE MOD (COLNUM,4) = 0 

Хотя в исходном коде и было написано:

 
ops$tkyte@ORA817DEV> create table t ( colnum number ); 
 
Table created. 
 
ops$tkyte@ORA817DEV> insert into t select rownum-1 from all_users where rownum <=4; 
 
4 rows created. 
 
ops$tkyte@ORA817DEV> create or replace procedure p_test2 as 
  2     x number:=0; 
  3  begin 
  4     select colnum into x from t where colnum mod 4 =0; 
  5     dbms_output.put_line(to_char(x)); 
  6  end; 
  7  / 
 
Procedure created. 
 
ops$tkyte@ORA817DEV> exec p_test2; 
 
0 
 
PL/SQL procedure successfully completed. 
 
ops$tkyte@ORA817DEV> select colnum from t where colnum mod 4 = 0; 
select colnum from t where colnum mod 4 = 0 
                                  * 
ERROR at line 1: 
ORA-00920: invalid relational operator 

Это нигде не описано в документации. Работало в 8i "случайно". Вот такие "странные, но интересные" особенности реализации...

Оригинал обсуждения этого вопроса можно найти здесь.


Copyright © 2003 Oracle Corporation


В следующем выпуске

О "накладных расходах" в индексе. По-прежнему следуем опубликованной программе развития рассылки.

С наилучшими пожеланиями,

  В.К.



http://subscribe.ru/
E-mail: ask@subscribe.ru
Отписаться
Убрать рекламу

В избранное