開発業者が納品したWebアプリケーションがエラーを吐いていた。
致命的な問題で無かったことから発覚が遅れ、瑕疵担保責任を追及できる期間はとうに過ぎていたので、自分で直したという話。
調査ついでにエラーログの見方を簡単に説明しよう。
出力されたエラーメッセージ
_mysql_exceptions.DataError:(1264,"Out of range value for column 'カラム名' at row 1")
MySQLdbというPythonのモジュールが投げた例外のようだ。
最初の 1264は4桁なので、MySQL独自のエラーコードだろう。
2つのエラー番号
MySQLのエラー番号には、
- MySQL独自のエラーコード(4桁)
- ODBCやANSI SQLで定められたSQLSTATE(5桁)
がある。
SQLSTATEは汎化されているので、MySQLに特化した独自コードの方が詳細に特定できる。
公式サイトですべてのエラーメッセージを確認できるが、特に良く見かけるものを以下に抜粋する。
Row 行番号 doesn't contain data for all columns
- エラーコード:1261
- SQLSTATE:01000
- 意味:すべてのカラムへのデータを含んでいない
Row 行番号 was truncated; it contained more data than there were input columns
- エラーコード:1262
- SQLSTATE:01000
- 意味:カラムよりも多いデータを含んでいたので、切り捨てたデータがある
Column set to default value; NULL supplied to NOT NULL column 'カラム名' at row 行番号
- エラーコード:1263
- SQLSTATE:22004
- 意味:NOT NULL のカラムにデフォルト値の NULL を登録した
Out of range value for column 'カラム名' at row 行番号
- エラーコード:1264
- SQLSTATE:22003
- 意味:範囲外の値だったので、取り敢えず限界の値で登録した
▶ 今回出力されたエラーメッセージである。
Data truncated for column 'カラム名' at row 行番号
- エラーコード:1265
- SQLSTATE:01000
- 意味:先頭からみて入れられるところまで登録し、残りは切り捨てた
つまり…
エラーコード 1264は、データ型の範囲を超えた値をINSERTしたときに発生するWarningである。直前に実行したSQLのWarningは SHOW WARNINGS
で確認できる。
データ型の範囲を超えると、そのデータ型の最大値または最小値に調整されて登録されるはずだが、PythonがDataError例外を投げたのでrollbackされたと推測。実際にも登録されていなかった。
スタックトレース例
insertintozzzzz_tablevalues(5,1611728121,0,162,58.2,63.9,1,27.5)Traceback(mostrecentcalllast):File"/foo/bar/example.py",line547,in<module>fooList()File"/foo/bar/example.py",line164,inbarListcursor.execute(qstr)File"/usr/lib/python2.7/dist-packages/MySQLdb/cursors.py",line226,inexecuteself.errorhandler(self,exc,value)File"/usr/lib/python2.7/dist-packages/MySQLdb/connections.py",line36,indefaulterrorhandlerraiseerrorvalue_mysql_exceptions.DataError:(1264,"Out of range value for column 'xxxxx' at row 1")
データ型
対象カラムのデータ型をDESC
で確認するとTINYINT
であった。TINYINT
の取りうる範囲は次の通り。
- バイト数: 1バイト
- デフォルト桁数: tinyint(4)
- 符号付き(SIGNED)の範囲:-128 ~ 127
データ型の後にUNSIGNED
を付けると符号なしとなり、0~255の範囲になる。
ちなみに tinyint(1) はBoolean型と同じだ。
直前のSQLで127を超える値をINSERTしていたが、運用上ありえない値なのでソースコードを修正した。