[DATABASE] Update "modified" in Managed_DataObject instead of a DBMS trigger

Instead of relying on the MariaDB's ON UPDATE CURRENT_TIMESTAMP trigger update
"modified" attributes in Managed_DataObject. Every raw query that needs
adjusting is adjusted, as they won't update "modified" automatically anymore.

The main goal behind this change is to fix "modified" updates on PostgreSQL.
This commit is contained in:
Alexei Sorokin
2020-07-27 19:10:33 +03:00
parent 341f3d0ea5
commit ec86de2bc4
17 changed files with 224 additions and 140 deletions

View File

@@ -760,9 +760,12 @@ class File extends Managed_DataObject
if ($file instanceof File) {
throw new ServerException('URL already exists in DB');
}
$sql = 'UPDATE %1$s SET urlhash = %2$s, url = %3$s WHERE urlhash = %4$s;';
$result = $this->query(sprintf(
$sql,
<<<'END'
UPDATE %1$s
SET urlhash = %2$s, url = %3$s, modified = CURRENT_TIMESTAMP
WHERE urlhash = %4$s;
END,
$this->tableName(),
$this->_quote((string)self::hashurl($url)),
$this->_quote((string)$url),
@@ -939,7 +942,7 @@ class File extends Managed_DataObject
}
}
echo "...and now all the non-duplicates which are longer than 191 characters...\n";
$file->query('UPDATE file SET url=LEFT(url, 191) WHERE LENGTH(url)>191');
$file->query('UPDATE file SET url = LEFT(url, 191) WHERE LENGTH(url) > 191');
echo "\n...now running hacky pre-schemaupdate change for $table:";
// We have to create a urlhash that is _not_ the primary key,
@@ -973,7 +976,7 @@ class File extends Managed_DataObject
throw new ServerException('Unknown DB type selected.');
}
$tablefix->query(sprintf(
'UPDATE %1$s SET urlhash = %2$s;',
'UPDATE %1$s SET urlhash = %2$s, modified = CURRENT_TIMESTAMP;',
$tablefix->escapedTableName(),
$url_sha256
));

View File

@@ -468,7 +468,7 @@ class File_redirection extends Managed_DataObject
throw new ServerException('Unknown DB type selected.');
}
$tablefix->query(sprintf(
'UPDATE %1$s SET urlhash = %2$s;',
'UPDATE %1$s SET urlhash = %2$s, modified = CURRENT_TIMESTAMP;',
$tablefix->escapedTableName(),
$url_sha256
));

View File

@@ -74,15 +74,20 @@ class Local_group extends Managed_DataObject
public function setNickname($nickname)
{
$this->decache();
$modified = common_sql_now();
$result = $this->query(sprintf(
'UPDATE local_group SET nickname = %1$s WHERE group_id = %2$d;',
<<<'END'
UPDATE local_group SET nickname = %1$s, modified = %2$s
WHERE group_id = %3$d;
END,
$this->_quote($nickname),
$this->_quote($modified),
$this->group_id
));
if ($result) {
$this->nickname = $nickname;
$this->fixupTimestamps();
$this->modified = $modified;
$this->encache();
} else {
common_log_db_error($local, 'UPDATE', __FILE__);

View File

@@ -522,6 +522,25 @@ abstract class Managed_DataObject extends Memcached_DataObject
return $aliases;
}
/**
* Set the attribute defined as "timestamp" to CURRENT_TIMESTAMP.
* This is hooked in update() and updateWithKeys() to update "modified".
*
* @access private
* @return void
*/
private function updateAutoTimestamps(): void
{
$table = static::schemaDef();
foreach ($table['fields'] as $name => $col) {
if ($col['type'] === 'timestamp'
&& !array_key_exists('default', $col)
&& !isset($this->$name)) {
$this->$name = common_sql_now();
}
}
}
/**
* update() won't write key columns, so we have to do it ourselves.
* This also automatically calls "update" _before_ it sets the keys.
@@ -548,6 +567,10 @@ abstract class Managed_DataObject extends Memcached_DataObject
// do it in a transaction
$this->query('START TRANSACTION');
// ON UPDATE CURRENT_TIMESTAMP behaviour
// @fixme Should the value be reverted back if transaction failed?
$this->updateAutoTimestamps();
$parts = [];
foreach ($this->keys() as $k) {
$v = $this->table()[$k];
@@ -664,12 +687,25 @@ abstract class Managed_DataObject extends Memcached_DataObject
public function insert()
{
$this->onInsert();
return parent::insert();
$result = parent::insert();
// Make this object aware of the changed "modified" attribute.
// Sets it approximately to the same value as DEFAULT CURRENT_TIMESTAMP
// just did (@fixme).
if ($result) {
$this->updateAutoTimestamps();
}
return $result;
}
public function update($dataObject=false)
public function update($dataObject = false)
{
$this->onUpdate($dataObject);
// ON UPDATE CURRENT_TIMESTAMP behaviour
// @fixme Should the value be reverted back if transaction failed?
$this->updateAutoTimestamps();
return parent::update($dataObject);
}
}

View File

@@ -443,7 +443,6 @@ class Memcached_DataObject extends Safe_DataObject
{
$result = parent::insert();
if ($result) {
$this->fixupTimestamps();
$this->encache(); // in case of cached negative lookups
}
return $result;
@@ -456,7 +455,6 @@ class Memcached_DataObject extends Safe_DataObject
}
$result = parent::update($dataObject);
if ($result !== false) {
$this->fixupTimestamps();
$this->encache();
}
return $result;
@@ -931,22 +929,6 @@ class Memcached_DataObject extends Safe_DataObject
return $c->delete($cacheKey);
}
public function fixupTimestamps()
{
// Fake up timestamp columns
$columns = $this->table();
foreach ($columns as $name => $type) {
if ($type & DB_DATAOBJECT_MYSQLTIMESTAMP) {
$this->$name = common_sql_now();
}
}
}
public function debugDump()
{
common_debug("debugDump: " . common_log_objstring($this));
}
public function raiseError($message, $type = null, $behavior = null)
{
$id = get_class($this);

View File

@@ -3243,7 +3243,11 @@ class Notice extends Managed_DataObject
unset($notice);
$notice = new Notice();
$notice->query(sprintf(
'UPDATE %1$s SET %2$s = NULL WHERE id IN (%3$s)',
<<<'END'
UPDATE %1$s
SET %2$s = NULL, modified = CURRENT_TIMESTAMP
WHERE id IN (%3$s)
END,
$notice->escapedTableName(),
$field,
implode(',', $ids)

View File

@@ -86,6 +86,7 @@ class Oauth_application_user extends Managed_DataObject
return true;
}
$toupdate = implode(', ', $parts);
$toupdate .= ', modified = CURRENT_TIMESTAMP';
$table = $this->tableName();
$tableName = $this->escapedTableName();

View File

@@ -292,14 +292,16 @@ class Profile_tag extends Managed_DataObject
public static function moveTag($orig, $new)
{
$tags = new Profile_tag();
$qry = "UPDATE profile_tag SET tag = '%s', tagger = '%s' " .
"WHERE tag = '%s' AND tagger = '%s'";
$result = $tags->query(sprintf(
$qry,
$tags->escape($new->tag),
$tags->escape($new->tagger),
$tags->escape($orig->tag),
$tags->escape($orig->tagger)
<<<'END'
UPDATE profile_tag
SET tag = %1$s, tagger = %2$s, modified = CURRENT_TIMESTAMP
WHERE tag = %3$s AND tagger = %4$s
END,
$tags->_quote($new->tag),
$tags->_quote($new->tagger),
$tags->_quote($orig->tag),
$tags->_quote($orig->tagger)
));
if ($result === false) {

View File

@@ -104,11 +104,22 @@ class Queue_item extends Managed_DataObject
*/
public function releaseClaim()
{
// DB_DataObject doesn't let us save nulls right now
$sql = sprintf("UPDATE queue_item SET claimed=NULL WHERE id=%d", $this->getID());
$this->query($sql);
$modified = common_sql_now();
// @fixme Consider $this->sqlValue('NULL')
$ret = $this->query(sprintf(
<<<'END'
UPDATE queue_item
SET claimed = NULL, modified = %1$s
WHERE id = %2$d
END,
$this->_quote($modified),
$this->getID()
));
$this->claimed = null;
$this->encache();
if ($ret) {
$this->claimed = null;
$this->modified = $modified;
$this->encache();
}
}
}