fix: proper type coercion for raw SQL import columns
Read column metadata (type, nullable, default) from SHOW COLUMNS and coerce values accordingly: empty string/false → 0 for NOT NULL numeric columns, null for nullable ones. Fixes is_internal import error. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -309,9 +309,12 @@ class EntityImporter
|
|||||||
return $newId;
|
return $newId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var array<string, string[]> Cache of existing columns per table */
|
/** @var array<string, string[]> Cache of existing column names per table */
|
||||||
private array $tableColumnsCache = [];
|
private array $tableColumnsCache = [];
|
||||||
|
|
||||||
|
/** @var array<string, array<string, array>> Cache of column metadata per table */
|
||||||
|
private array $tableColumnMetaCache = [];
|
||||||
|
|
||||||
/** @var array<string, string[]> Skipped columns log per entity type */
|
/** @var array<string, string[]> Skipped columns log per entity type */
|
||||||
private array $skippedColumnsLog = [];
|
private array $skippedColumnsLog = [];
|
||||||
|
|
||||||
@@ -348,10 +351,8 @@ class EntityImporter
|
|||||||
$value = json_encode($value, JSON_UNESCAPED_UNICODE);
|
$value = json_encode($value, JSON_UNESCAPED_UNICODE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fix empty strings for integer/bool columns (MySQL strict mode)
|
// Coerce value to match target column type
|
||||||
if ($value === '' || $value === false) {
|
$value = $this->coerceValue($tableName, $column, $value);
|
||||||
$value = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$columns[] = "`{$column}`";
|
$columns[] = "`{$column}`";
|
||||||
$values[] = $value;
|
$values[] = $value;
|
||||||
@@ -377,16 +378,59 @@ class EntityImporter
|
|||||||
$pdo = $this->entityManager->getPDO();
|
$pdo = $this->entityManager->getPDO();
|
||||||
$sth = $pdo->query("SHOW COLUMNS FROM `{$tableName}`");
|
$sth = $pdo->query("SHOW COLUMNS FROM `{$tableName}`");
|
||||||
$columns = [];
|
$columns = [];
|
||||||
|
$meta = [];
|
||||||
|
|
||||||
while ($row = $sth->fetch(\PDO::FETCH_ASSOC)) {
|
while ($row = $sth->fetch(\PDO::FETCH_ASSOC)) {
|
||||||
$columns[] = $row['Field'];
|
$columns[] = $row['Field'];
|
||||||
|
$meta[$row['Field']] = [
|
||||||
|
'type' => $row['Type'],
|
||||||
|
'nullable' => $row['Null'] === 'YES',
|
||||||
|
'default' => $row['Default'],
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->tableColumnsCache[$tableName] = $columns;
|
$this->tableColumnsCache[$tableName] = $columns;
|
||||||
|
$this->tableColumnMetaCache[$tableName] = $meta;
|
||||||
|
|
||||||
return $columns;
|
return $columns;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Coerce a value to be compatible with the target column type.
|
||||||
|
*/
|
||||||
|
private function coerceValue(string $tableName, string $column, mixed $value): mixed
|
||||||
|
{
|
||||||
|
$meta = $this->tableColumnMetaCache[$tableName][$column] ?? null;
|
||||||
|
|
||||||
|
if ($meta === null) {
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
$type = strtolower($meta['type']);
|
||||||
|
$isNumeric = str_contains($type, 'int') || str_contains($type, 'decimal')
|
||||||
|
|| str_contains($type, 'float') || str_contains($type, 'double')
|
||||||
|
|| str_contains($type, 'tinyint') || str_contains($type, 'smallint')
|
||||||
|
|| str_contains($type, 'bigint');
|
||||||
|
|
||||||
|
if ($isNumeric && ($value === '' || $value === false)) {
|
||||||
|
if ($meta['nullable']) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$meta['nullable'] && $value === null) {
|
||||||
|
if ($isNumeric) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $meta['default'] ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array<string, string[]> entityType => [skipped column names]
|
* @return array<string, string[]> entityType => [skipped column names]
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user