Error 500 di Halaman Admin dan Count Query yang Kehilangan Join
Satu filter di WHERE bareng bikin halaman admin 500 padahal query list aman. Ternyata count query lupa bawa join yang sama.
Ringkasan
Buka halaman moderasi di KotaPortal malah jadi error 500 padahal login sebagai superadmin. Ternyata query COUNT buat pagination nggak join tabel categories jadi filter c module bikin MySQL protes kolom nggak dikenal. Akhirnya beres setelah nambahin LEFT JOIN categories biar dua query punya join yang sama.
Saya buka halaman daftar moderasi di dashboard KotaPortal, dan yang muncul cuma layar putih dengan kode status HTTP 500. Anehnya, ini terjadi bahkan saat saya login sebagai superadmin. Padahal, data di halaman sebelumnya terlihat normal-normal saja.
Dugaan Awal yang Meleset
Dugaan pertama saya tentu saja masalah izin akses. Mungkin ada middleware yang salah tangkap role superadmin, atau query-nya tiba-tiba nge-filter berdasarkan ID user yang nggak seharusnya. Saya langsung ngecek log error di server dengan asumsi bakal menemukan pesan penolakan autentikasi atau batas role.
Ternyata, pesannya sangat spesifik: Error 1054 (42S22): Unknown column 'c.module' in 'where clause'. Menurut referensi error MySQL, kode 1054 berarti kolom tidak dikenal [3]. Saya langsung bingung. Alias c itu merujuk ke tabel categories. Padahal, di query utama untuk mengambil data halaman, tabel categories sudah di-join dengan benar. Kenapa tiba-tiba error di bagian count?
Akar Masalah di Dua Query Terpisah
Setelah saya telusuri kode builder query-nya, fakta yang muncul cukup menampar. Halaman daftar yang dipaginasi itu sebenarnya menjalankan dua query terpisah yang berbagi satu klausa WHERE yang sama. Query pertama adalah SELECT biasa untuk mengambil data halaman saat ini. Query kedua adalah SELECT COUNT(*), dan menurut dokumentasi MySQL, COUNT(*) itu cuma menghitung jumlah baris [2]. Total inilah yang dipakai sistem buat menghitung jumlah halaman pagination.
Masalahnya, query COUNT(*) ini cuma melakukan join ke tabel reviews dan entities. Tabel categories nggak ikut di-join di sini. Sementara itu, ada filter berbasis modul (c.module = 'moderation') yang disuntikkan ke klausa WHERE bersama. Akibatnya, saat database mencoba mengeksekusi query count, dia mencari kolom c.module padahal alias c sama sekali belum didefinisikan dalam scope query tersebut.
Dokumentasi JOIN MySQL [1] menyebutkan bahwa klausa ON hanya bisa merujuk ke operand-nya sendiri, dan mencampurkan operator koma dengan JOIN tanpa kondisi yang tepat bisa memicu error kolom tidak dikenal. Dalam kasus ini, alias-nya memang benar-benar tidak ada di query count.
Di sisi aplikasi Go, fungsi GetContext dari paket sqlx [4] menjalankan QueryRow lalu memindai hasilnya ke variabel tujuan. Kalo query-nya gagal di level database karena kolom tidak dikenal, GetContext langsung mengembalikan error itu ke layer handler. Nggak ada fallback otomatis. Inilah yang bikin halaman admin langsung ambruk jadi 500.
Menyelaraskan Permukaan Join
Solusinya sebenarnya sepele tapi dampaknya besar. Saya harus memastikan kedua query punya permukaan join yang identik. Saya nambahin satu baris LEFT JOIN ke query count biar selaras dengan query utama.
-- Sebelum: join categories hilang, alias c nggak dikenal di WHERE
SELECT COUNT(*) FROM reviews r
INNER JOIN entities e ON e.id = r.entity_id
-- WHERE c.module = (moderasi) muncul di sini dan langsung error
-- Sesudah: satu LEFT JOIN nambahin alias yang sama dengan query list
SELECT COUNT(*) FROM reviews r
INNER JOIN entities e ON e.id = r.entity_id
LEFT JOIN categories c ON c.id = e.category_id
WHERE c.module = 'moderation'Dengan nambahin LEFT JOIN categories c ke query count, alias c sekarang sah dipakai di klausa WHERE. Database nggak lagi protes, dan total halaman pagination kembali terhitung dengan benar. Insiden ini ninggalin satu aturan praktis yang sekarang selalu saya pegang.
Kapan pun ada filter baru yang masuk ke builder WHERE bareng, grep semua query yang make builder itu. Jangan berasumsi query COUNT(*) otomatis mewarisi semua konteks join dari query SELECT utama. Mereka dua entitas terpisah di mata database. Menyamakan join surface antara keduanya bukan cuma soal kerapian kode, tapi soal njaga sistem biar nggak tiba-tiba gagal cuma gara-gara satu alias yang kelewat.