fix(core): una fecha ausente solo se rellena si la columna es NOT NULL sin DEFAULT
This commit is contained in:
@@ -87,9 +87,13 @@ class AcaiAPI
|
|||||||
$lastId = 0;
|
$lastId = 0;
|
||||||
$count = 0;
|
$count = 0;
|
||||||
|
|
||||||
|
// Columnas que MySQL exige en un INSERT (NOT NULL sin DEFAULT): solo a
|
||||||
|
// esas se les pone valor si no vienen. null = no se pudo saber.
|
||||||
|
$requiredCols = $ignoreSchema ? [] : self::requiredColumns($db, $prefix . $table);
|
||||||
|
|
||||||
foreach ($records as $record) {
|
foreach ($records as $record) {
|
||||||
list($setParts, $params, $uploadFields) = self::buildSetClause(
|
list($setParts, $params, $uploadFields) = self::buildSetClause(
|
||||||
$record, $schema, $functions, $ignoreSchema, true, $forceNum
|
$record, $schema, $functions, $ignoreSchema, true, $forceNum, $requiredCols
|
||||||
);
|
);
|
||||||
|
|
||||||
if (empty($setParts)) continue;
|
if (empty($setParts)) continue;
|
||||||
@@ -1366,7 +1370,8 @@ class AcaiAPI
|
|||||||
array $functions,
|
array $functions,
|
||||||
$ignoreSchema,
|
$ignoreSchema,
|
||||||
$isInsert,
|
$isInsert,
|
||||||
$forceNum
|
$forceNum,
|
||||||
|
$requiredCols = null
|
||||||
) {
|
) {
|
||||||
$now = date('Y-m-d H:i:s');
|
$now = date('Y-m-d H:i:s');
|
||||||
$user = 1;
|
$user = 1;
|
||||||
@@ -1439,15 +1444,21 @@ class AcaiAPI
|
|||||||
$params[] = time();
|
$params[] = time();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Campos `date` que NO vienen en el alta -> fecha actual, como el
|
// Campos `date` que NO vienen en el alta -> fecha actual, SOLO si la
|
||||||
// Admin clasico (save.php: "default date fields to current date").
|
// columna es NOT NULL sin DEFAULT (MySQL rechazaria el INSERT sin
|
||||||
// El bloque de campos de usuario, abajo, solo cubre la fecha que
|
// ella: cms_vacantes.fecha_publicacion). En una columna que admite
|
||||||
// llega VACIA; si la clave falta, una columna `datetime NOT NULL`
|
// NULL, vacio SIGNIFICA algo (notas_internas.deleted_at = no
|
||||||
// sin DEFAULT (cms_vacantes.fecha_publicacion) tumbaba el INSERT.
|
// borrada, cms_users.fecha_caducidad = no caduca): rellenarla con
|
||||||
if (!$ignoreSchema && is_array($schema)) {
|
// "ahora" marcaba cada nota nueva como borrada (regresion de
|
||||||
|
// 14ddf16). Si no se sabe que columnas exige ($requiredCols null)
|
||||||
|
// no se rellena nada: mejor un error claro que un dato falso. Un
|
||||||
|
// `date` del schema sin columna real tampoco entra (no esta en la
|
||||||
|
// lista).
|
||||||
|
if (!$ignoreSchema && is_array($schema) && is_array($requiredCols)) {
|
||||||
foreach ($schema as $field => $def) {
|
foreach ($schema as $field => $def) {
|
||||||
if (array_key_exists($field, $record)) continue;
|
if (array_key_exists($field, $record)) continue;
|
||||||
if (!is_array($def) || ($def['type'] ?? '') !== 'date') continue;
|
if (!is_array($def) || ($def['type'] ?? '') !== 'date') continue;
|
||||||
|
if (!isset($requiredCols[$field])) continue;
|
||||||
$setParts[] = "`$field` = ?";
|
$setParts[] = "`$field` = ?";
|
||||||
$params[] = $now;
|
$params[] = $now;
|
||||||
}
|
}
|
||||||
@@ -1661,6 +1672,39 @@ class AcaiAPI
|
|||||||
* reintentaba a ciegas. isset(): una web con Db.php personalizado (sin
|
* reintentaba a ciegas. isset(): una web con Db.php personalizado (sin
|
||||||
* lastError) sigue funcionando, solo que sin el detalle.
|
* lastError) sigue funcionando, solo que sin el detalle.
|
||||||
*/
|
*/
|
||||||
|
/** Cache por peticion: tabla completa => [columna => true]. */
|
||||||
|
private static $requiredColsCache = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Columnas de `$fullTable` que un INSERT tiene que traer: NOT NULL, sin
|
||||||
|
* DEFAULT y no auto_increment. Devuelve [columna => true], o null si no se
|
||||||
|
* pudo consultar (el llamador no rellena nada en ese caso). Solo usa
|
||||||
|
* Db::executeS, que existe en todas las versiones de Db.php.
|
||||||
|
*/
|
||||||
|
private static function requiredColumns($db, $fullTable)
|
||||||
|
{
|
||||||
|
if (array_key_exists($fullTable, self::$requiredColsCache)) {
|
||||||
|
return self::$requiredColsCache[$fullTable];
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$rows = $db->executeS(
|
||||||
|
"SELECT COLUMN_NAME FROM information_schema.COLUMNS"
|
||||||
|
. " WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ?"
|
||||||
|
. " AND IS_NULLABLE = 'NO' AND COLUMN_DEFAULT IS NULL"
|
||||||
|
. " AND EXTRA NOT LIKE '%auto_increment%'",
|
||||||
|
[$fullTable]
|
||||||
|
);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return self::$requiredColsCache[$fullTable] = null;
|
||||||
|
}
|
||||||
|
$cols = [];
|
||||||
|
foreach ((array) $rows as $row) {
|
||||||
|
$name = is_array($row) ? ($row['COLUMN_NAME'] ?? reset($row)) : null;
|
||||||
|
if ($name) $cols[$name] = true;
|
||||||
|
}
|
||||||
|
return self::$requiredColsCache[$fullTable] = $cols;
|
||||||
|
}
|
||||||
|
|
||||||
private static function dbErrorSuffix($db)
|
private static function dbErrorSuffix($db)
|
||||||
{
|
{
|
||||||
return (is_object($db) && isset($db->lastError) && $db->lastError !== '')
|
return (is_object($db) && isset($db->lastError) && $db->lastError !== '')
|
||||||
|
|||||||
Reference in New Issue
Block a user