diff --git a/include/dba.php b/include/dba.php index f695902afe..b0d05f4458 100644 --- a/include/dba.php +++ b/include/dba.php @@ -23,6 +23,7 @@ class dba { public $error = false; private $_server_info = ''; private static $dbo; + private static $relation = array(); function __construct($server, $user, $pass, $db, $install = false) { $a = get_app(); @@ -753,6 +754,101 @@ class dba { return self::e($sql, $param); } + /** + * @brief Build the array with the table relations + * + * The array is build from the database definitions in dbstructure.php + * + * This process must only be started once, since the value is cached. + */ + static private function build_relation_data() { + $definition = db_definition(); + + foreach ($definition AS $table => $structure) { + foreach ($structure['fields'] AS $field => $field_struct) { + if (isset($field_struct['relation'])) { + foreach ($field_struct['relation'] AS $rel_table => $rel_field) { + self::$relation[$rel_table][$rel_field][$table] = $field; + } + } + } + } + } + + /** + * @brief Insert a row into a table + * + * @param string $table Table name + * @param array $param parameter array + * @param boolean $in_commit Internal use: Only do a commit after the last delete + * @param array $callstack Internal use: prevent endless loops + * + * @return boolean was the delete successfull? + */ + static public function delete($table, $param, $in_commit = false, $callstack = array()) { + + // Create a key for the loop prevention + $key = $table.':'.implode(':', array_keys($param)).':'.implode(':', $param); + + // We quit when this key already exists in the callstack. + if (isset($callstack[$key])) { + return true; + } + + $callstack[$key] = $key; + + $table = self::$dbo->escape($table); + + // To speed up the whole process we cache the table relations + if (count(self::$relation) == 0) { + self::build_relation_data(); + } + + if (!$in_commit) { + self::p("COMMIT"); + self::p("START TRANSACTION"); + } + + // Is there a relation entry for the table? + if (isset(self::$relation[$table])) { + foreach (self::$relation[$table] AS $field => $rel_def) { + // Fetch all rows that are to be deleted + $sql = "SELECT ".self::$dbo->escape($field)." FROM `".$table."` WHERE `". + implode("` = ? AND `", array_keys($param))."` = ?"; + + $retval = false; + $data = self::p($sql, $param); + while ($row = self::fetch($data)) { + foreach ($rel_def AS $rel_table => $rel_field) { + // We do a separate delete process per row + $retval = self::delete($rel_table, array($rel_field => $row[$field]), true, $callstack); + if (!$retval) { + return false; + } + } + } + if (!$retval) { + return true; + } + } + } + + $sql = "DELETE FROM `".$table."` WHERE `". + implode("` = ? AND `", array_keys($param))."` = ?"; + + $retval = self::e($sql, $param); + + if (!$in_commit) { + if ($retval) { + self::p("COMMIT"); + } else { + self::p("ROLLBACK"); + } + } + + return $retval; + } + /** * @brief Updates rows * diff --git a/include/dbstructure.php b/include/dbstructure.php index 744dc22dcc..cedef40d98 100644 --- a/include/dbstructure.php +++ b/include/dbstructure.php @@ -1078,7 +1078,7 @@ function db_definition() { "type" => array("type" => "varchar(255)", "not null" => "1", "default" => ""), "wall" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"), "gravity" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"), - "parent" => array("type" => "int(10) unsigned", "not null" => "1", "default" => "0"), + "parent" => array("type" => "int(10) unsigned", "not null" => "1", "default" => "0", "relation" => array("item" => "id")), "parent-uri" => array("type" => "varchar(255)", "not null" => "1", "default" => ""), "extid" => array("type" => "varchar(255)", "not null" => "1", "default" => ""), "thr-parent" => array("type" => "varchar(255)", "not null" => "1", "default" => ""), @@ -1284,7 +1284,7 @@ function db_definition() { "notify-id" => array("type" => "int(11)", "not null" => "1", "default" => "0", "relation" => array("notify" => "id")), "master-parent-item" => array("type" => "int(10) unsigned", "not null" => "1", "default" => "0", "relation" => array("item" => "id")), "parent-item" => array("type" => "int(10) unsigned", "not null" => "1", "default" => "0"), - "receiver-uid" => array("type" => "int(11)", "not null" => "1", "default" => "0", "relation" => array("user" => "id")), + "receiver-uid" => array("type" => "int(11)", "not null" => "1", "default" => "0", "relation" => array("user" => "uid")), ), "indexes" => array( "PRIMARY" => array("id"),