pdo数据库驱动存在一个无法获取数据表主键的Bug,导致此Bug的原因并非逻辑缺陷,而是TP开发人员的粗心大意
ThinkPHP pdo数据库驱动存在一个无法获取数据表主键的Bug,此Bug会导致所有与数据表主键有关的操作发生错乱、失败甚至无法预料的结果(数据表主键为id或者Model里自定义pk则不受影响).如果你的数据表主键不是"id",对数据库进行一系列依赖主键的操作会发生错误.
Bug影响版本:3.1.3及以下
Bug位置:
Extend/Driver/Db/DbPdo.class.php
或:
Lib/Driver/Db/DbPdo.class.php
代码位置:定位到函数getFields
public function getFields($tableName) {
$this->initConnect(true);
if(C('DB_DESCRIBE_TABLE_SQL')) {
// 定义特殊的字段查询SQL
$sql = str_replace('%table%',$tableName,C('DB_DESCRIBE_TABLE_SQL'));
}else{
switch($this->dbType) {
case 'MSSQL':
case 'SQLSRV':
$sql = "SELECT column_name as 'Name', data_type as 'Type', column_default as 'Default', is_nullable as 'Null'
FROM information_schema.tables AS t
JOIN information_schema.columns AS c
ON t.table_catalog = c.table_catalog
AND t.table_schema = c.table_schema
AND t.table_name = c.table_name
WHERE t.table_name = '$tableName'";
break;
case 'SQLITE':
$sql = 'PRAGMA table_info ('.$tableName.') ';
break;
case 'ORACLE':
case 'OCI':
$sql = "SELECT a.column_name \"Name\",data_type \"Type\",decode(nullable,'Y',0,1) notnull,data_default \"Default\",decode(a.column_name,b.column_name,1,0) \"pk\" "
."FROM user_tab_columns a,(SELECT column_name FROM user_constraints c,user_cons_columns col "
."WHERE c.constraint_name=col.constraint_name AND c.constraint_type='P' and c.table_name='".strtoupper($tableName)
."') b where table_name='".strtoupper($tableName)."' and a.column_name=b.column_name(+)";
break;
case 'PGSQL':
$sql = 'select fields_name as "Name",fields_type as "Type",fields_not_null as "Null",fields_key_name as "Key",fields_default as "Default",fields_default as "Extra" from table_msg('.$tableName.');';
break;
case 'IBASE':
break;
case 'MYSQL':
default:
$sql = 'DESCRIBE '.$tableName;//备注: 驱动类不只针对mysql,不能加``
}
}
$result = $this->query($sql);
$info = array();
if($result) {
foreach ($result as $key => $val) {
$val = array_change_key_case($val);
$val['name'] = isset($val['name'])?$val['name']:"";
$val['type'] = isset($val['type'])?$val['type']:"";
$name = isset($val['field'])?$val['field']:$val['name'];
$info[$name] = array(
'name' => $name ,
'type' => $val['type'],
'notnull' => (bool)(((isset($val['null'])) && ($val['null'] === '')) || ((isset($val['notnull'])) && ($val['notnull'] === ''))), // not null is empty, null is yes
'default' => isset($val['default'])? $val['default'] :(isset($val['dflt_value'])?$val['dflt_value']:""),
'primary' => isset($val['dey'])?strtolower($val['dey']) == 'pri':(isset($val['pk'])?$val['pk']:false),
'autoinc' => isset($val['extra'])?strtolower($val['extra']) == 'auto_increment':(isset($val['key'])?$val['key']:false),
);
}
}
return $info;
}
定位到此行:
'primary' => isset($val['dey'])?strtolower($val['dey']) == 'pri':(isset($val['pk'])?$val['pk']:false),
你会看到原本为"key"的数组键名被错输为"dey",没错,导致此Bug的问题就出现在此行代码.
解决办法:将dey修改为key,修改后代码为:
'primary' => isset($val['key'])?strtolower($val['key']) == 'pri':(isset($val['pk'])?$val['pk']:false),