0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Laravel existsのバリデーションルールで存在しないidをPOSTするとバリデーションエラーではなくSQLのエラーが返る

Posted at

概要

Laravel + PostgreSQLの環境でとあるテーブルのidをつかってexistsのバリデーションをかけた。バリデーションルールにちゃんと引っかかることを確認したくて999999という値をidのキーでPOSTした。なぜかバリデーションチェックエラーではなくSQL系のエラーが返された。何が起きたのか簡単にまとめておく。

原因

当該テーブルのidカラムのデータ型の値範囲を超えてexistsルールでチェックしていた。

返されたSQLエラー

バリデーションエラーで400が帰ってほしいのに下記が返された。

SQLSTATE[25P02]: In failed sql transaction: 7 ERROR:  current transaction is aborted, commands ignored until end of transaction block

このとき自分はexistsのバリデーションルールがSQLを投げてチェックしていることを完全に失念しており、「なんでありえないIDを投げているのにバリデーションルール通過して、DB書き込み処理まで到達してしまったんだ!!!」というようにプチパニック担っていた。

簡単な説明

先に原因で書いたように当該のidカラムのデータ型を超えた値を渡してしまったのでエラーになった。
ようはexistsでルールはもちろん裏でSQLを実行しており、その時に「引数で渡された値がカラムの値格納範囲越えてるからエラーね。」と訴えかけてきていた。

よく見たら当該のidはマイグレーションでtinyIncrementsが指定されていた。
このとき自分は「tinyIncrementsならインクリメントだしUNSIGNEDだから最大値255か〜、ってことはidの値を255渡したときはバリデーションエラーで、256渡したときはこのSQLのエラーが返るんだろうな。それで裏付け取れるわ。」って思ってた。甘かった。知らなかったんです。PostgreSQLがTINYINTとUNSIGNEDが無いことを。当然、256をPOSTしてもSQLのエラーではなくバリデーションエラーが返る。またもパニック。

ちょっと調べたらPostgreSQLはTINYINTとUNSIGNEDが無いこと発覚、laravelは頭が良いのでマイグレーションでtinyIncrementsって指定されててもDBのクライアントを判断してSMALLINTでカラムを作ってくれるらしい。
SMALLINTの最大値である32767をIDとしてPOSTしたらバリデーションエラーになり、32768をIDとしてPOSTしたらSQLのエラーが返ってきたので裏付けが取れた。

Q.E.D

これで今夜はスッキリして眠れそう。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?