Satu deployment PostgreSQL pengeluaran telah tergendala selepas seorang pembangun menambah argumen pilihan kepada fungsi sedia ada menggunakan CREATE OR REPLACE FUNCTION. Perubahan tersebut meninggalkan dua fungsi dengan nama yang sama, menyebabkan pangkalan data mengembalikan ralat “function is not unique” dan API mengeluarkan ralat 400. Insiden ini menunjukkan bagaimana satu kesilapan migrasi tunggal boleh merosakkan skema langsung secara senyap dan mengapa semakan pada peringkat kod sahaja tidak mencukupi.

Apa yang telah berlaku

Pasukan tersebut perlu memperluas prosedur tersimpan (stored procedure) dengan parameter tambahan yang bersifat pilihan. Mereka menjalankan CREATE OR REPLACE FUNCTION …, dengan mengandaikan ia akan menggantikan definisi lama. PostgreSQL hanya menggantikan fungsi apabila senarai argumen lengkap sepadan dengan tepat. Mengubah tandatangan (signature) akan mencipta entri fungsi yang baharu sepenuhnya sambil meninggalkan fungsi asal tanpa sebarang perubahan.

Oleh kerana argumen baharu tersebut mempunyai nilai lalai (default value), pemanggil yang membekalkan jumlah argumen lama boleh sepadan dengan mana-mana definisi tersebut. PostgreSQL tidak dapat memutuskan mana satu yang perlu dipanggil dan mengeluarkan ralat “function is not unique”, yang kemudiannya muncul sebagai respons 400 daripada API.

Repositori kod menunjukkan satu definisi tunggal, dan skrip tersuai yang mengimbas pokok sumber (source tree) melaporkan tiada duplikasi. Duplikasi tersebut hanya wujud dalam pangkalan data, yang diperkenalkan apabila fail migrasi lama dijalankan semula pada pelayan.

Mengapa migrasi tersebut terlepas

Migrasi yang menambah parameter pilihan tersebut hanya menjalankan CREATE OR REPLACE FUNCTION. Apabila migrasi dijalankan buat kali kedua—mungkin selepas 'rollback' atau semasa deployment berulang—pangkalan data menganggap arahan tersebut sebagai "tambah 'overload' baharu" dan bukannya "gantikan yang sedia ada". Migrasi tersebut tidak mengesahkan keadaan yang terhasil, menyebabkan duplikasi itu kekal tanpa disedari.

Skrip yang menyemak repositori memeriksa fail sumber, bukannya skema langsung. Ia seolah-olah memerhati pintu hadapan sementara pepijat masuk melalui pintu belakang.

Risikonya

Satu fungsi yang kabur (ambiguous) boleh menjatuhkan mana-mana perkhidmatan yang bergantung kepadanya. Penyelesaiannya melibatkan pengembalian (rollback) transaksi jika jumlah fungsi adalah salah dan memaklumkan cache skema untuk memuat semula.

Cara melindungi migrasi

Pasukan tersebut membina semula migrasi dengan semakan eksplisit, menjadikannya satu operasi yang mengesahkan diri sendiri:

  • Mulakan transaksi supaya sebarang kegagalan akan melakukan 'rollback' terhadap keseluruhan perubahan.
  • Padam (drop) fungsi lama secara eksplisit sebelum mencipta versi baharu, bagi menjamin hanya satu definisi wujud.
  • Cipta fungsi baharu dengan tandatangan yang diingini.
  • Kira jumlah fungsi dengan nama yang diberikan dalam pg_catalog dan sahkan jumlahnya adalah tepat satu.
  • Lakukan 'rollback' transaksi jika jumlahnya menyimpang, bagi menghalang duplikasi daripada kekal.
  • Maklumkan cache skema untuk memuat semula, bagi memastikan pertanyaan (query) seterusnya melihat definisi yang telah dikemas kini.

Dengan bertanya kepada pangkalan data "apakah fungsi yang ada?" dan bukannya mengandaikan kod adalah betul, migrasi menjadi lebih boleh dipercayai terhadap larian berulang, deployment separa, atau suntingan manual.

Hujah balas: kemudahan vs. keselamatan

CREATE OR REPLACE FUNCTION adalah menarik kerana ia membolehkan pembangun melakukan iterasi dengan cepat tanpa perlu menulis pernyataan drop yang berasingan. Dalam persekitaran di mana migrasi hanya dijalankan sekali dan tidak pernah diulang, jalan pintas ini berfungsi dengan baik. Risiko muncul apabila migrasi dimainkan semula—sama ada disebabkan oleh saluran paip CI yang menetapkan semula pangkalan data ujian, 'rollback' automatik, atau aplikasi semula secara manual dalam pengeluaran.

Kesimpulan

Mengubah tandatangan fungsi dengan CREATE OR REPLACE tidak menjamin penggantian—PostgreSQL akan mencipta 'overload' secara senyap jika senarai argumen berbeza. Persekitaran pengeluaran yang bergantung kepada migrasi mesti mengesahkan skema yang terhasil, bukan sekadar kod sumber. Menyertakan arahan drop yang eksplisit, semakan transaksi, dan pengesahan pasca-migrasi menukarkan jalan pintas yang memudahkan kepada proses yang boleh dipercayai dan boleh diulang.