3
2

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 3 years have passed since last update.

MySQLの暗黙的な型変換の検証

Last updated at Posted at 2020-01-18

経緯

業務中、SELECT文で意図しないレコードがSELECTされた。

12.2 式評価での型変換

今更ではありますが私としてはMySQLでも暗黙的な型変換あったんだ~ってなりました。
型に沿った形で検索しないと暗黙的な型変換により意図しないレコードが検索される恐れがあるため、
プログラム側で適切なバリデーションを行い、MySQLへ引き渡して検索を行う必要がありますね。
…っていうのはわかってるんだけどもともとの作りでバリデーション厳密にしていないところとかってあるじゃないですか。
なのでそういうときにどういうレコードが検出される可能性があるのか考慮まとめておきました。

検証準備

検証用のテーブルを記載します。

定義

mysql> show create table users;
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                                                                                                                          |
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| users | CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci |
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

レコード

mysql> SELECT * FROM users;
+----+--------+
| id | name   |
+----+--------+
|  0 | ゼロ   |
|  1 | 太郎   |
|  2 | 次郎   |
|  3 | 三郎   |
+----+--------+
4 rows in set (0.00 sec)

※AUTO_INCREMENTなので通常id=1からですが検証のためid=0も挿入しております。

検証

WHERE id = 2

mysql> SELECT * FROM users WHERE id = 2;
+----+--------+
| id | name   |
+----+--------+
|  2 | 次郎   |
+----+--------+
1 row in set (0.00 sec)

特に問題なし。

WHERE id = '2'

mysql> SELECT * FROM users WHERE id = '2';
+----+--------+
| id | name   |
+----+--------+
|  2 | 次郎   |
+----+--------+
1 row in set (0.00 sec)

特に問題なし。

WHERE id = a

mysql> SELECT * FROM users WHERE id = a;
ERROR 1054 (42S22): Unknown column 'a' in 'where clause'
mysql> SHOW WARNINGS;
+-------+------+--------------------------------------+
| Level | Code | Message                              |
+-------+------+--------------------------------------+
| Error | 1054 | Unknown column 'a' in 'where clause' |
+-------+------+--------------------------------------+
1 row in set (0.00 sec)

エラーになってくれるので特に問題なし。

WHERE id = 'a'

mysql> SELECT * FROM users WHERE id = 'a';
+----+--------+
| id | name   |
+----+--------+
|  0 | ゼロ   |
+----+--------+
1 row in set, 1 warning (0.00 sec)
mysql> SHOW WARNINGS;
+---------+------+---------------------------------------+
| Level   | Code | Message                               |
+---------+------+---------------------------------------+
| Warning | 1292 | Truncated incorrect DOUBLE value: 'a' |
+---------+------+---------------------------------------+
1 row in set (0.00 sec)

ゼロさんが引っかかってしまいます。
誤ったDOUBLE値って扱いで切り捨てられ、0として検索したようですね。

WHERE id = a2

mysql> SELECT * FROM users WHERE id = a2;
ERROR 1054 (42S22): Unknown column 'a2' in 'where clause'
mysql> SHOW WARNINGS;
+-------+------+---------------------------------------+
| Level | Code | Message                               |
+-------+------+---------------------------------------+
| Error | 1054 | Unknown column 'a2' in 'where clause' |
+-------+------+---------------------------------------+
1 row in set (0.00 sec)

エラーになってくれるので特に問題なし。

WHERE id = 'a2'

mysql> SELECT * FROM users WHERE id = 'a2';
+----+--------+
| id | name   |
+----+--------+
|  0 | ゼロ   |
+----+--------+
1 row in set, 1 warning (0.00 sec)
mysql> SHOW WARNINGS;
+---------+------+----------------------------------------+
| Level   | Code | Message                                |
+---------+------+----------------------------------------+
| Warning | 1292 | Truncated incorrect DOUBLE value: 'a2' |
+---------+------+----------------------------------------+
1 row in set (0.00 sec)

ゼロさんが引っかかってしまいます。
誤ったDOUBLE値って扱いで切り捨てられ、0として検索したようですね。

WHERE id = 2a

mysql> SELECT * FROM users WHERE id = 2a;
ERROR 1054 (42S22): Unknown column '2a' in 'where clause'
mysql> SHOW WARNINGS;
+-------+------+---------------------------------------+
| Level | Code | Message                               |
+-------+------+---------------------------------------+
| Error | 1054 | Unknown column '2a' in 'where clause' |
+-------+------+---------------------------------------+
1 row in set (0.00 sec)

エラーになってくれるので特に問題なし。

WHERE id = '2a'

mysql> SELECT * FROM users WHERE id = '2a';
+----+--------+
| id | name   |
+----+--------+
|  2 | 次郎   |
+----+--------+
1 row in set, 1 warning (0.00 sec)
mysql> SHOW WARNINGS;
+---------+------+----------------------------------------+
| Level   | Code | Message                                |
+---------+------+----------------------------------------+
| Warning | 1292 | Truncated incorrect DOUBLE value: '2a' |
+---------+------+----------------------------------------+
1 row in set (0.00 sec)

次郎さんが引っかかってしまいます。
誤ったDOUBLE値って扱いで切り捨てられ、2として検索したようですね。

WHERE id = 2.1

mysql> SELECT * FROM users WHERE id = 2.1;
Empty set (0.00 sec)

特に問題なし。

WHERE id = '2.1'

mysql> SELECT * FROM users WHERE id = '2.1';
Empty set (0.00 sec)

特に問題なし。

WHERE id = '2a1'

mysql> SELECT * FROM users WHERE id = '2a1';
+----+--------+
| id | name   |
+----+--------+
|  2 | 次郎   |
+----+--------+
1 row in set, 1 warning (0.00 sec)
mysql> SHOW WARNINGS;
+---------+------+-----------------------------------------+
| Level   | Code | Message                                 |
+---------+------+-----------------------------------------+
| Warning | 1292 | Truncated incorrect DOUBLE value: '2a1' |
+---------+------+-----------------------------------------+
1 row in set (0.00 sec)

次郎さんが引っかかってしまいます。
誤ったDOUBLE値って扱いで切り捨てられ、2として検索したようですね。

3
2
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
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?