启用严格模式时,MySQL 进行哪些验证?

22
当我发现MySQL允许我向一个被创建成NOT NULL的字段中插入NULL时,我感到非常惊讶。我进行了一些研究,并发现了如何启用严格模式。然而,我不确定在启用STRICT_ALL_TABLES时MySQL执行何种验证。
手册说:
“严格模式控制MySQL处理无效或缺失的输入值。值可能因为多种原因而无效。例如,它可能对于列来说有错误的数据类型,或者超出范围。”
我理解它认为什么是缺失的和它如何处理。我不清楚它认为什么是无效的。我进行了一些测试并发现以下内容:
- 字符串过长是无效的 - 超出范围的数字是无效的 - 对于非NULL列的NULL是无效的 - TRUEFALSE似乎总是有效的(它们分别变成1和0) - 无效日期是无效的 - 零日期是有效的(可以启用其他模式来更改此行为) - 整数字段中的浮点数是有效的(它们会四舍五入) - 数字字段中的字母是无效的
MySQL除了上述提到的检查之外,还进行其他验证吗?
手册说“列的数据类型错误”,但我看到这实际上只在数字字段中出现字母的情况下才会发生。还有其他数据类型错误的例子吗?
是否有一个清单列出了MySQL执行的确切检查内容?
编辑:就记录而言,我的应用程序已经进行了广泛的验证。我将严格模式用作最后一道防线,以防万一检查遗漏。如果我忘记检查某些内容,我希望它可以“尽早失败”,而不是“静默地破坏我的数据”。

我感觉你希望数据库为你执行数据验证。如果是这样,那么这条路不可取。 - siride
3
@siride说:DBMS存在的目的就是进行验证(外键、主键、检查约束、类型验证)。在我看来,MySQL允许存储“2月31日”是一个bug。或者换句话说,如果DBMS不进行任何验证,那么这将是一条非常糟糕的路。 - user330315
4
我已经在应用程序中进行了验证。我使用严格模式不是作为良好编程的替代品,而是作为确保良好编程的一种方式。 - toxalot
2
刚看到你最新的评论。听起来不错。但我会在这里留下我的评论,供将来寻找仅基于数据库验证解决方案的人参考。 - Mike Brant
4
天啊,这是一个高质量的、经过研究的问题。 - Jim
显示剩余3条评论
2个回答

9
一个好的资源是检查MySQL源代码,并阅读mysql-test/t/strict.test,查看在设置STRICT模式或TRADITIONAL模式(STRICT的超集)后他们测试的所有案例。
您已经进行了优秀的研究和测试,但还有一些其他情况,例如:
  • 试图插入未定义的ENUM值。
  • 尝试为没有定义默认值的NOT NULL列插入默认值。
  • 尝试使用CAST()将字符串转换为整数等。
  • 如果给出大于65536的长度,则将VARCHAR转换为MEDIUMTEXT或LONGTEXT。
  • 对表和列的COMMENT字符串进行截断。
  • 将字符串转换为YEAR类型。
  • 使用重复条目定义SET或ENUM列。
此外,还有mysql-test/include/strict_autoinc.inc,因为它测试了当自动增量值增长过大时的溢出情况。
还有一些其他测试文件会针对特定测试使用STRICT模式,但我没有检查它们。

另一个情况是尝试将负数插入到UNSIGNED列中。 - toxalot
请访问http://dev.mysql.com/downloads/mysql/#downloads,选择“源代码”作为平台。 - Bill Karwin
是的,在无符号列中的负数是测试覆盖的另一种情况,但我认为这是超出列范围的数字的情况。 - Bill Karwin
“无符号列中的负数超出范围” - 您当然是对的,但很多人都没有理解到这一点。 - toxalot

4

我在MySQL 5.5.28(社区服务器版本)的源代码中使用grep查找了STRICT_ALL_TABLES的使用情况。

从我看到的情况来看,似乎您的列表已经非常完整,但以下是我对STRICT_ALL_TABLES使用的更多了解。第一个是另一个验证,而其余所有内容都涉及错误和警告。

  • 几何列不能有默认值。(sql/field.cc:9394)
  • 如果表注释超过2048个字符,则MySQL会产生错误,而不是通过警告截断注释。(sql/unireg.cc:231)
  • 如果字段注释超过1024个字符,则MySQL会产生错误,而不是通过警告截断注释。(sql/unireg.cc:739)
  • 在插入或更新时,如果SET或ENUM中存在重复值,则MySQL会产生错误而不是警告。(sql/sql_table.cc:2503)
  • 有许多操作将在严格模式下立即停止执行,并生成错误消息,而不是仅显示警告。这些太多了,我无法一一列出,并且设置abort_on_warning标志距离创建警告的代码太远,以至于我很难文档化(甚至理解)它们。但是,如果有人想要深入了解源代码,一些起点是sql/sql_update.cc:630sql/sql_insert.cc:841

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接