無駄と文化

実用的ブログ

BigQueryのCASTとSAFE_CASTは名前が逆じゃないか?

ふたつのキャスト

BigQuery には値をキャストする関数として CAST()SAFE_CAST() の二つがある。
このように動作する。

SELECT CAST('0xDEADBEEF' AS INT64) AS number;
/*------------*
 | number     |
 +------------+
 | 3735928559 |
 *------------*/

SELECT SAFE_CAST('0xDEADBEEF' AS INT64) AS number;
/*------------*
 | number     |
 +------------+
 | 3735928559 |
 *------------*/

この時点では挙動が同じなので違いは見えない。キャストに失敗する値を渡してやると違いが見える。

SELECT CAST('0xDEADCHICKEN' AS INT64) AS number;
/* Error: Bad int64 value: 0xDEADCHICKEN */

SELECT SAFE_CAST('0xDEADCHICKEN' AS INT64) AS number;
/*--------*
 | number |
 +--------+
 | NULL   |
 *--------*/

16進数としてパースできない '0xDEADCHICKEN' を渡した場合、CAST はエラーになる。一方で SAFE_CAST はエラーにはならず NULL が返る。

キャスト可能な引数 キャスト不可な引数
CAST CAST('42' AS INT) = 42 CAST('a' AS INT) → エラー
SAFE_CAST SAFE_CAST('42' AS INT) = 42 SAFE_CAST('a' AS INT) IS NULL

 

ドキュメントにも書いてある。

cloud.google.com

If you want to protect your queries from these types of errors, you can use SAFE_CAST.

意訳: 実行時エラーからクエリを守りたいなら SAFE_CAST を使ってくれ

なるほど。SAFE_CAST を使えば安全。

 

逆じゃない?

設計原則に "Let It Crash" というのがある。
私の理解では

  • 正常じゃないのに動き続けている処理はたちが悪い
  • 処理の事前条件が満たされていないならさっさとクラッシュするのが被害最小

というような意味だ。

 

その思想で言えば、キャストが必要な処理にキャスト不可な値が入ってきた場合には即座に処理を中止して全体をロールバックさせるのが安全 (Safe) だ。
キャスト不可な値が NULL に差し替えられて正常終了してしまうほうが危険に思える。

 

というのは言いがかりで

まぁそういうネーミングなので仕方ない。

BigQuery の関数には CAST()SAFE_CAST() のように通常版・安全版がそれぞれ用意された関数がいくつかある。

通常版 安全版
/ (除算) SAFE_DIVIDE(x, y) y=0 のとき NULL を返す
+ (加算) SAFE_ADD(x, y) オーバーフロー時に NULL を返す
PARSE_DATETIME() SAFE.PARSE_DATETIME() パース失敗時に NULL を返す
PARSE_JSON() SAFE.PARSE_JSON() パース失敗時に NULL を返す
arr[0] arr[SAFE_OFFSET(0)] インデックスが存在しない時に NULL を返す

arr[SAFE_OFFSET(0)] めっちゃ癖あるなぁー。

 

まとめ

私は名前が逆だと思いました。みなさんはどう思いますか?

 

 

私からは以上です。