天天看點

通過錯誤的sql來測試推理sql的解析過程

在學習Oracle的時候,必然會接觸到sql解析的過程。這個過程大體是這樣的步驟。

1.對sql的文法檢查,檢視是否有文法錯誤,比如from,select拼寫錯誤等。

2.在資料字典裡校驗sql涉及的對象是否存在。

3.将對象進行名稱轉換,比如同義詞轉義成對應的對象。比如select * from t t是一個同義詞指向hr.test

4.檢查語句的使用者是否具有通路對象的權限

5.生成執行計劃

6.将遊标産生執行計劃,sql文本裝載入library cache所在的heap中。

這個過程看起來比較容易了解,但是實際中我們也不能死記硬背,如果想推理一下其中的有些步驟,其實不用很精細的trace也可以辦到。我們就用最簡單的sql語句來測試。

當然思路需要轉換,要測試的是存在問題的sql語句,看oracle的編譯器會給我們什麼樣的解釋。

首先準備一個測試表

create table test (id number,name varchar2(30));

準備好之後,就開始測試一下。不過思路是用有問題的語句來測試,來推理。

下面的語句存在很多的問題,來看看oracle的反應。

select1 id1 from2 test1 where3 id1='aaa' group by4 id1 order  by5 id1

*

ERROR at line 1:

ORA-24333: zero iteration count

首先解析發現select的語句錯誤其實後面from,where,group by,order by都有錯誤。但是首先發現是select的部分。可見解析還是從左至右的方向來做文法解析。

接着修複select的文法錯誤,來繼續看看。

select id1 from test1 where3 id1='aaa' group by4 id1 order  by5 id1

                             *

ORA-00933: SQL command not properly ended

這個時候錯誤指向了id1而沒有指向where3,可見編譯器在處理的時候可能不知道該怎麼處理了。這一點上出乎我的意料。修複where的文法錯誤繼續測試。

select id1 from test1 where id1='aaa' group by4 id1 order  by5 id1

                                           *

ORA-00924: missing BY keyword

這個時候直接指向了group by的部分。通過這三個例子可以基本推理出文法解析是從左至右。對于是否存在表,是否字段存在問題都先不會解析。

然後我們修複了group by,order by的文法錯誤,繼續測試。

select id1 from test1 where id1='aaa' group by id1 order  by id1

                *

ORA-00942: table or view does not exist

發現錯誤指向了test1,發現沒有這個表。可見在文法解析之後開始校驗是否存在這個表。這個時候還沒有開始校驗字段的情況。

修複了表名的錯誤,繼續測試。

select id1 from test where id1='aaa' group by id1 order  by id1

                                                *

ORA-00904: "ID1": invalid identifier

發現這個時候是在解析group by 的字段名,對于select,where,order by中的先不解析。

然後修複group by中的錯誤,繼續測試。

select id1 from test where id1='aaa' group by id order  by id1

                           *

發現解析到了where 子句中的字段值。這個時候select,order by中還沒有開始解析。

修複where子句中的問題,繼續測試。

       *

這個時候錯誤就指向了select子句,這個時候就剩下了order by的部分。

修複select的部分。繼續測試。

SQL> select id from test where id='aaa' group by id order  by id1;

select id from test where id='aaa' group by id order  by id1

                                                         *

終于指向了order by,可見order by的部分是語句執行的最後的部分。

通過上面的錯誤測試,可以發現能夠基本得到語句解析中的處理順序。

我們更深一步。看看如果字段id為number,賦予varchar2的資料,是否會在解析的時候校驗出來。

SQL>  select id from test where id='aaa' group by id order  by id;        

 select id from test where id='aaa' group by id order  by id

                              *

ORA-01722: invalid number

這個時候發現錯誤已經在校驗資料的類型了。

怎麼看出在解析的時候是否校驗了資料類型呢,别急,來做一個操作即可。

SQL> delete from test ;

1 row deleted.

然後再次執行上面的語句。

SQL> select id from test where id='aaa' group by id order  by id;

no rows selected

就會發現這個時候oracle好像處理不了這種場景了。

好了,oracle編譯器已經很強大了。我們就最後以一個基本正常的語句結束。

SQL> select id from test where id='100' group by id order  by id;