USING - ключевое слово PL/SQL в версии 9iИсточник: ln
Эта статья посвящена двум особенностям работы PL/SQL-машины, которая в версиях 9.x объединена с SQL-машиной. Интересные особенности, которые могут всплыть при переносе программного обеспечения на новую версию сервера Oracle... По мотивам ответа Тома Кайта на вопросы, заданные 15 июня 2003 года. USING - ключевое слово PL/SQL!Том,
Я хотел бы задать два вопроса, которые меня сильно сбивают с толку. 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 "случайно". Вот такие "странные, но интересные" особенности реализации... |