sqlplus註釋導致語句重複執行

yangtingkun發表於2012-09-03

意外發現一個sqlplus上一個註釋相關的bug

 

 

看一個簡單的例子:

solaris*orcl-/home/oracle$ sqlplus test/test

SQL*Plus: Release 11.2.0.3.0 Production on Mon Jun 11 17:09:57 2012

Copyright (c) 1982, 2011, Oracle. All rights reserved.


Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
With the Partitioning, Oracle Label Security and Real Application Testing options

SQL> set pages 100 lines 140
SQL> select 1 from dual;

這是一個最新的11.2.0.3sqlplus客戶端,那麼這個簡單的查詢結果是什麼?

SQL> select 1 from dual;

1
----------
         1

SQL> /* select */ select 2 from dual;

好,我承認是在故弄玄虛,結果就是簡單到不能再簡單的1,那麼問題來了,上面第二個查詢的結果是什麼?

SQL> /* select */ select 2 from dual;

2
----------
         2

SQL> /*select */ select 3 from dual;

不要扔磚,雖然結果還是意料之內的,但是見證奇蹟的時刻馬上就要到了,這第三個查詢的結果是什麼?

SQL> /*select */ select 3 from dual;

2
----------
         2

這個結果是不是很2?這個語句和上面第二個語句只是相差了一個空格,結果是完全不同的。對於第二個語句而言,註釋並沒有對語句產生任何的影響;而對於第三個語句,實際上Oracle並沒有把這個語句作為包含註釋的語句看待,實際上sqlplus執行的是/,也就是將快取中的語句再執行一次,而完全忽略了/之後的內容。

可能有些人認為這個bug對於系統的影響不大,而如果在資料庫中執行.sql檔案,或者透過shell呼叫sql指令碼,那麼這個問題出現的可能性就大大增加了。

考慮一下極端的情況,這個問題可能帶來哪些危害。最明顯的莫過於使得上一個執行的SQL重複執行。

SQL> delete t where rownum < 11;

10 rows deleted.

SQL> /*select*/ select count(*) from t;

10 rows deleted.

如果上一條是SELECT,則顯然對系統影響最小(事實上這個影響也不小,因為當前需要執行的SQL被跳過了,這可能影響這個SQL指令碼的邏輯),而如果是DELETE語句,如上所示,那麼表中資料就會被多刪除一次。

也許有人會說,刪除也無所謂,可以進行回滾,並沒有資料的損失。事實上,對於SHELL指令碼方式或者編寫好的SQL指令碼而言,是沒有辦法對其進行控制的。

即使不在指令碼中執行,有些情況下也是沒有機會回滾的,比如:

SQL> create procedure p_sqlplus as
2 begin
3 delete t where rownum < 5;
4 commit;
5 end;
6 /

Procedure created.

SQL> begin p_sqlplus; end;
2 /

PL/SQL procedure successfully completed.

SQL> /*another execute*/ select count(*) from t;

PL/SQL procedure successfully completed.

這種想要恢復就只能透過閃回了。而如果重複執行的是DDL,那麼連閃回的機會都沒有了。

重複DDL的一個例子:

SQL> alter table t_part exchange partition p1
2 with table t_temp_part
3 update indexes;

Table altered.

SQL> /*count the num*/ select count(*) from t_part partition (p1);

Table altered.

SQL> drop table t_temp_part purge;

Table dropped.

雖然並不會真正造成什麼資料的損失,但是資料的載入以及分割槽EXCHANGE的工作就完全白做了。

上面幾個例子都比較極端,但是這是為了說明對於SHELLSQL檔案中這種自動執行的指令碼,要小心這個bug帶來的不可預料的錯誤。

好在這個問題只是發生在sqlplus中,且SQL語句開頭是以/*方式的註釋開頭,註釋與後面的內容之間沒有空格的情況下,因此想要碰到這個錯誤也並不容易。

 

 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4227/viewspace-746121/,如需轉載,請註明出處,否則將追究法律責任。

相關文章