【发布时间】:2016-06-09 04:59:55
【问题描述】:
我有一个数据库升级脚本,它采用当前数据库版本,通过一个巨大的 switch 语句传递它,没有任何中断,所以所有后续查询都会运行,然后将数据库编号更新为最新版本。
免责声明:我知道可能有更好的方法来做到这一点(比如只是一堆if($version>1507) 检查,所以我不必有“空”版本的案例)但我没有时间重构和测试。我最终会的,但我真的不认为这个问题是相关的。
这是升级脚本的示例,包括给我带来问题的行:
case 1508:
addNotification("Updating 1508: Adding feature specific tables for wake-up calls, virtual dispatcher and screen pop, to allow better usage and billing tracking", "success");
dbQuery("CREATE TABLE IF NOT EXISTS `feature_wakeup_calls` ( `feature_wakeup_call_id` int(12) NOT NULL AUTO_INCREMENT, `employee_id` int(12) NOT NULL, `date` date NOT NULL, `confirmed` datetime DEFAULT NULL, `employee_sms_id` int(12) DEFAULT NULL, `employee_call_id` int(12) DEFAULT NULL, `authority_call_id` int(12) DEFAULT NULL COMMENT 'call record to the authority', `balance_id` int(12) NOT NULL COMMENT 'references balance table', PRIMARY KEY (`feature_wakeup_call_id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;");
dbQuery("CREATE TABLE IF NOT EXISTS `feature_virtual_dispatcher` ( `feature_virtual_dispatcher_id` int(12) NOT NULL AUTO_INCREMENT, `inbound_call_id` int(12) NOT NULL, `outbound_call_id` int(12) DEFAULT NULL, `balance_id` int(12) NOT NULL, PRIMARY KEY (`feature_virtual_dispatcher_id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;");
dbQuery("CREATE TABLE IF NOT EXISTS `feature_screen_pop_endpoints` ( `feature_screen_pop_endpoint_id` int(12) NOT NULL AUTO_INCREMENT, `mac_address` varchar(50) NOT NULL, `created_by` int(12) DEFAULT NULL, `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`feature_screen_pop_endpoint_id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;");
dbQuery("CREATE TABLE IF NOT EXISTS `feature_screen_pop` ( `feature_screen_pop_id` int(12) NOT NULL AUTO_INCREMENT, `mac` varchar(200) DEFAULT NULL, `phone_number` int(12) NOT NULL, `format` varchar(200) DEFAULT NULL COMMENT 'ex: xml, html, etc', `when` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`feature_screen_pop_id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;");
case 1509:
case 1510:
case 1511:
addNotification("Updating 1511: New columns to the phone companion endpoints table", "success");
dbQuery("ALTER TABLE `feature_screen_pop_endpoints` ADD `name` VARCHAR(200) NULL AFTER `feature_screen_pop_endpoint_id`;");
dbQuery("ALTER TABLE `feature_screen_pop_endpoints` ADD `extension` VARCHAR(50) NULL DEFAULT NULL AFTER `mac_address`, ADD `manufacturer` ENUM('Polycom','Astra','Mitel/YeaLink','Grandstream') NULL DEFAULT NULL AFTER `extension`, ADD `model` VARCHAR(50) NULL DEFAULT NULL AFTER `manufacturer`;");
我遇到的问题是在 1511 之后立即调用 dbQuery 失败。如果我将其注释掉,则下一个将失败。这是 dbQuery 函数:
function dbQuery($query, $returnId = false, $connection = null) {
$close = true; // by default, close the connection once done
if($connection == null) $connection = connect();
else $close = false; // don't close the connection if it was passed to us
if($returnId == false) {
$result = mysqli_query($connection, $query);
if($result == false && !stringContains($query, "notification_log")) { // prevent infinite loops
addNotification("Query Failed: ".$query." with error: ".mysqli_error($connection));
}
if($close) mysqli_close($connection);
return $result;
}
else {
$result = mysqli_query($connection, $query);
if($result == false) {
if($close) mysqli_close($connection);
return $result;
}
else {
$result = mysqli_insert_id($connection);
if($close) mysqli_close($connection);
return $result;
}
}
}
注意Query Failed 部分。我的日志说:
Query Failed: ALTER TABLE `feature_screen_pop_endpoints` ADD `name` VARCHAR(200) NULL AFTER `feature_screen_pop_endpoint_id` with error: Duplicate column name 'name'
如果我只注释掉那一行并完全重新开始(新数据库和所有内容),我会在下一行收到类似的错误:
Query Failed: ALTER TABLE `feature_screen_pop_endpoints` ADD `extension` VARCHAR(50) NULL DEFAULT NULL AFTER `mac_address`, ADD `manufacturer` ENUM('Polycom','Astra','Mitel/YeaLink','Grandstream') NULL DEFAULT NULL AFTER `extension`, ADD `model` VARCHAR(50) NULL DEFAULT NULL AFTER `manufacturer` with error: Duplicate column name 'extension'
当然,我检查了其他地方是否创建了这些表(它们没有,如果我注释掉 1508 中的行,它们永远不存在)并且有类似的 dbQuery 调用完美地执行 ALTER TABLE table_name ADD 操作。例如,上面几行是这样的:
case 1502:
addNotification("Updating 1502: More data for the balance table", "success");
dbQuery("ALTER TABLE `balance` ADD `extra` VARCHAR(500) NULL AFTER `method`, ADD `unique` VARCHAR(200) NULL AFTER `extra`;");
我已经反复测试,所以我知道这是关于 这些行(1511 集)的问题,但我之前遇到过这个问题,我不得不重新设置整个数据库的基线,绕过交换机中的前约 1300 个案例。虽然这在这里会起作用,但它只是在治疗一种症状并且不会扩大规模。
有人知道可能出了什么问题吗?
【问题讨论】:
-
您确定此处显示的代码只运行一次吗?调试步骤:考虑在你的case语句后添加
die()或echo,看看它是否真的运行了整个case两次。 -
有一个
notification_log表,这就是那些addNotification函数所调用的。我逐步完成查询并确认每个dbQuery调用只有一个条目。一旦发生错误,它就是致命的,脚本会完全停止。 -
1511 是否与上述任何一种情况重复?你有这个查询
ALTER TABLE feature_screen_pop_endpoints ADD name...在你的 switch 语句中还有其他地方吗? -
我绝对不会。因此,为什么如果我只注释掉那一行
name字段根本就不会创建。要么保留它会导致duplicate错误,要么将其注释掉会导致它永远不会被创建。