94 lines
3.4 KiB
PHP
94 lines
3.4 KiB
PHP
<?php
|
||
/**
|
||
* 排查 dice_player 删除报错:
|
||
* - 表结构
|
||
* - 外键引用情况
|
||
* - 实际 destroy 流程(不真的删,仅 dry-run 抓异常)
|
||
*
|
||
* 用法:php server/db/inspect_player_destroy.php [<id1>,<id2>,...]
|
||
*/
|
||
require_once __DIR__ . '/../vendor/autoload.php';
|
||
require_once __DIR__ . '/../support/bootstrap.php';
|
||
|
||
use support\think\Db;
|
||
|
||
$config = config('database');
|
||
$default = $config['default'];
|
||
$conn = $config['connections'][$default];
|
||
$dbName = $conn['database'] ?? '';
|
||
echo "[DB] {$default} -> {$dbName}\n\n";
|
||
|
||
echo "--- dice_player columns ---\n";
|
||
$cols = Db::query("SHOW FULL COLUMNS FROM `dice_player`");
|
||
foreach ($cols as $c) {
|
||
echo str_pad((string)$c['Field'], 26) . ' | ' . str_pad((string)$c['Type'], 24) . ' | NULL=' . $c['Null'] . ' | Key=' . $c['Key'] . "\n";
|
||
}
|
||
echo "\n";
|
||
|
||
echo "--- referenced by foreign keys (other tables -> dice_player) ---\n";
|
||
$fks = Db::query("SELECT TABLE_NAME, COLUMN_NAME, CONSTRAINT_NAME, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME
|
||
FROM information_schema.KEY_COLUMN_USAGE
|
||
WHERE TABLE_SCHEMA = ? AND REFERENCED_TABLE_NAME = 'dice_player'", [$dbName]);
|
||
if (empty($fks)) {
|
||
echo " (none)\n";
|
||
} else {
|
||
foreach ($fks as $f) {
|
||
echo " {$f['TABLE_NAME']}.{$f['COLUMN_NAME']} -> {$f['REFERENCED_TABLE_NAME']}.{$f['REFERENCED_COLUMN_NAME']} [{$f['CONSTRAINT_NAME']}]\n";
|
||
}
|
||
}
|
||
echo "\n";
|
||
|
||
echo "--- top 3 dice_player rows ---\n";
|
||
$rows = Db::table('dice_player')->limit(3)->select()->toArray();
|
||
foreach ($rows as $r) {
|
||
echo "id={$r['id']} dept_id={$r['dept_id']} username={$r['username']} delete_time=" . ($r['delete_time'] ?? 'null') . "\n";
|
||
}
|
||
echo "\n";
|
||
|
||
$idsArg = $argv[1] ?? '';
|
||
if ($idsArg === '') {
|
||
echo "(no ids passed, skip dry-run delete)\n";
|
||
return;
|
||
}
|
||
$ids = array_filter(array_map('intval', explode(',', $idsArg)));
|
||
if (empty($ids)) {
|
||
echo "(invalid ids)\n";
|
||
return;
|
||
}
|
||
|
||
echo "--- dry-run destroy ids: " . implode(',', $ids) . " ---\n";
|
||
$beforeAll = Db::query('SELECT id, delete_time FROM dice_player WHERE id IN (' . implode(',', array_fill(0, count($ids), '?')) . ')', $ids);
|
||
echo "before (raw): " . count($beforeAll) . " rows\n";
|
||
|
||
$placeholders = implode(',', array_fill(0, count($ids), '?'));
|
||
|
||
// Case A: static destroy
|
||
try {
|
||
Db::startTrans();
|
||
$result = \app\dice\model\player\DicePlayer::destroy($ids, true);
|
||
$afterAny = Db::query("SELECT COUNT(*) AS c FROM dice_player WHERE id IN ({$placeholders})", $ids);
|
||
echo "[static destroy] returned: " . var_export($result, true) . ", remaining raw rows: " . ($afterAny[0]['c'] ?? 'n/a') . "\n";
|
||
Db::rollback();
|
||
} catch (\Throwable $e) {
|
||
Db::rollback();
|
||
echo "EXCEPTION (static destroy): " . get_class($e) . ": " . $e->getMessage() . "\n";
|
||
}
|
||
|
||
// Case B: instance ->delete()
|
||
try {
|
||
Db::startTrans();
|
||
$instance = \app\dice\model\player\DicePlayer::find($ids[0]);
|
||
if ($instance) {
|
||
$r = $instance->delete();
|
||
$afterAny = Db::query("SELECT COUNT(*) AS c FROM dice_player WHERE id = ?", [$ids[0]]);
|
||
echo "[instance delete] returned: " . var_export($r, true) . ", remaining raw rows for id={$ids[0]}: " . ($afterAny[0]['c'] ?? 'n/a') . "\n";
|
||
} else {
|
||
echo "[instance delete] no instance found for id={$ids[0]}\n";
|
||
}
|
||
Db::rollback();
|
||
} catch (\Throwable $e) {
|
||
Db::rollback();
|
||
echo "EXCEPTION (instance delete): " . get_class($e) . ": " . $e->getMessage() . "\n";
|
||
}
|
||
echo "(both rolled back, no actual delete)\n";
|