中央西門風痕影
有個運作 5 年的案子,在業主的母公司無預警地把 MySQL 5.7 升級到 8.0 之後,發生了語法錯誤

我們手邊都是 MariaDB 10.x,要重現有一點麻煩

不過,根據 syntax error 是從 ) 開始這點,我查到 MySQL 8.0 有個 2022 年被回報的 bug:
#107160 - Upgrade from 5.7 to 8.0 fails with syntax ...

這個回報目前只進入 Verified 狀態,還沒有被處理

問題似乎出在 subquery 外面的括號
機器狼🎸吉他生活第1課
(´⊙ω⊙`)(上班的時候偷偷睜著眼睛睡覺)
中央西門風痕影
這樣寫不行:
SELECT ... FROM ((SELECT ... FROM test.t1) t)

這樣寫可以:
SELECT ... FROM (SELECT ... FROM test.t1) t

原本的寫法在 MySQL 5.7 與 MariaDB 都沒有問題;而 MySQL 8.0 這邊不確定是改變了語法,還是有 bug

這篇 Stack Overflow 上的討論串:
Parentheses surrounding sub-query alias, syntax chan...

底下的回答認為,根據目前的文件,syntax 應該沒有變

說起來如果外面的括號也取一個 alias,不知道會不會正常
中央西門風痕影
不過對這個案子來說,要拿掉括號有一點麻煩:目前的 SQL 其實是用 Codeigniter 3 的 query builder 處理的

DB_query_builderfrom() 會用逗號( , )把傳入的參數分開,放入 $this->qb_from 陣列。這本來是為了 SELECT ... FROM test1, test2 這種情況而設計

但 subquery 如果是 (SELECT test.t1, test.t2) t 的話,就會因此被分割為 (SELECT t1t2) t
中央西門風痕影
CI_DB_mysqli_driverCI_DB_mysql_driver_from_tables() ,是用來組成 FROM ... 後面 table 名稱的部分。這裡當 $this->qb_join 不為空且 count($this->qb_from) > 1 的話,就會在輸出的字串外面多加一層小括號( (...) ),導致上面的情況

我最後用了有點奇怪的方法處理:由於 CI 的 DB driver 預設無法被 extends ,我 extends CI_Loader 然後把 database() 改成可以吃自訂的 driver 檔案

接著在想要蓋掉 from() 還是 _from_tables()
中央西門風痕影
我最後選擇把 from() 改成有 ( 的話,就不理會 ,,將它當成一整個 table 名稱(實際上也確實是一整個 table 名稱)

CI 3 最新版沒特別處理此問題,CI 4 我則不確定。不過 CI 4 有內建的 subquery builder,我猜可能不會有這個問題
中央西門風痕影
看起來 CI 4 是直接新增了一個 fromSubquery() 方法:
CodeIgniter4/system/Database/BaseBuilder.php at deve...

確實光靠 from() 本身區分是不是 subquery 應該超級不準確,我好像也該考慮在 CI 3 新增一個方法來處理
繡鏃
這是什麼超級惡夢 好可怕
快讓我醒來!!!
載入新的回覆