エラーの発生状況ワークフローを自動化するためにカスタムのMySQL関数を作成し、実行ボタンを押して成功メッセージを待っていたところ、データベースから次のような苛立たしいエラーメッセージが返されることがあります。
ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled...
このエラーは、レプリケーションやポイントインタイムリカバリのためにバイナリログ(binlog)が有効になっている本番サーバーでよく発生します。AWS RDSやGoogle Cloud SQLなどのマネージドサービスを使用している場合、バックアップや高可用性を維持するためにデフォルトでバイナリログが有効になっているため、このエラーに遭遇することが頻繁にあります。
なぜMySQLがブロックするのかバイナリログをフライトレコーダーのようなものだと考えてください。レプリカサーバーをマスターと完全に同期させるには、MySQLはすべての関数呼び出しが両方のマシンで同じ結果を生成することを保証する必要があります。関数が「予測不能」な場合、2つのサーバーの結果はやがて乖離し、データの破損につながります。
例えば、UUID()やRAND()を使用する関数は「非決定論的(non-deterministic)」です。実行するたびに異なる値を生成します。MySQLが特定の宣言なしにこれらの関数を許可すると、マスターでは「ID-A」が保存され、レプリカでは「ID-B」が保存されるといった事態が起こり得ます。このような悪夢を防ぐため、MySQLはデフォルトで log_bin_trust_function_creators を 0 (OFF) に設定し、関数が安全であることを証明することを義務付けています。
修正方法解決策は2つあります。関数の意図を宣言してより適切なSQLを記述するか、MySQLに盲目的に信頼するように指示するかです。本番環境では、前者の方法がプロフェッショナルな標準とされています。
方法1:関数の特性を宣言する(推奨)特定のキーワードを追加することで、関数がデータとどのように対話するかをMySQLに正確に伝えます。RETURNS句の直後に、以下のいずれかのキーワードを配置します。
- DETERMINISTIC: 同じ入力に対して常に同じ出力を返す(例:税計算など)。- NO SQL: データベースに一切触れない(例:文字列操作など)。- READS SQL DATA:
SELECTを使用するが、データは変更しない。- MODIFIES SQL DATA:INSERT、UPDATE、またはDELETE操作を実行する。修正済みの関数の例:
DELIMITER //
CREATE FUNCTION get_discount_price(price DECIMAL(10,2))
RETURNS DECIMAL(10,2)
DETERMINISTIC
BEGIN
RETURN price * 0.90;
END //
DELIMITER ;
方法2:グローバル変数「Trust」による修正数百ものレガシー関数を移行する場合や、ローカルの開発環境で作業している場合、すべてのスクリプトを手動で更新するのは面倒です。その場合、グローバル変数を切り替えることで厳密なチェックを無効にできます。これには SUPER 権限が必要であり、マネージドクラウドデータベースでは「パラメータグループ」を先に変更しないと機能しない場合があります。
ターミナルで以下を実行します:
SET GLOBAL log_bin_trust_function_creators = 1;
注意:この変更は一時的なものです。MySQLサービスを再起動すると、設定は0に戻ります。
方法3:永続的な設定再起動後も信頼設定を維持するには、サーバーの設定ファイル(Linuxの場合は my.cnf、Windowsの場合は my.ini)に追加します。
- 設定ファイル(通常は
/etc/mysql/内)を開きます。-[mysqld]セクションを探します。- 次の行を追加します:log_bin_trust_function_creators = 1- サービスを再起動します:sudo systemctl restart mysql## 解決策の確認システム変数をクエリして、変更が反映されたか確認します:
SHOW GLOBAL VARIABLES LIKE 'log_bin_trust_function_creators';
値が ON であれば準備完了です。特性を指定せずにダミー関数を作成してテストしてみましょう:
CREATE FUNCTION quick_test() RETURNS INT RETURN 1;
結論として、方法2の方が手っ取り早いですが、エンジニアリングとしては方法1の方が優れています。コードの動作を文書化し、レプリケーションログの予測可能性とクリーンさを保つことができるからです。

