X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=include%2Fdba.php;h=478a1a10c2d40e673298121290f26676e3878321;hb=759dfe6bb1b03a80ebabe92d89eb55ab3081abad;hp=b24d9b409d00125ad7349848d822089a5e908aff;hpb=f63be91bd54fb29b3302bd259861fa92a0562067;p=friendica.git diff --git a/include/dba.php b/include/dba.php index b24d9b409d..478a1a10c2 100644 --- a/include/dba.php +++ b/include/dba.php @@ -1,5 +1,6 @@ save_timestamp($stamp1, "network"); @@ -100,6 +103,45 @@ class dba { return self::$connected; } + /** + * Disconnects the current database connection + */ + public static function disconnect() + { + if (is_null(self::$db)) { + return; + } + + switch (self::$driver) { + case 'pdo': + self::$db = null; + break; + case 'mysqli': + self::$db->close(); + self::$db = null; + break; + } + } + + /** + * Perform a reconnect of an existing database connection + */ + public static function reconnect() { + self::disconnect(); + + $ret = self::connect(self::$db_serveraddr, self::$db_user, self::$db_pass, self::$db_name); + return $ret; + } + + /** + * Return the database object. + * @return PDO|mysqli + */ + public static function get_db() + { + return self::$db; + } + /** * @brief Returns the MySQL server version string * @@ -385,7 +427,12 @@ class dba { } foreach ($args AS $param => $value) { - $stmt->bindParam($param, $args[$param]); + if (is_int($args[$param])) { + $data_type = PDO::PARAM_INT; + } else { + $data_type = PDO::PARAM_STR; + } + $stmt->bindParam($param, $args[$param], $data_type); } if (!$stmt->execute()) { @@ -430,23 +477,23 @@ class dba { break; } - $params = ''; + $param_types = ''; $values = []; foreach ($args AS $param => $value) { if (is_int($args[$param])) { - $params .= 'i'; + $param_types .= 'i'; } elseif (is_float($args[$param])) { - $params .= 'd'; + $param_types .= 'd'; } elseif (is_string($args[$param])) { - $params .= 's'; + $param_types .= 's'; } else { - $params .= 'b'; + $param_types .= 'b'; } $values[] = &$args[$param]; } if (count($values) > 0) { - array_unshift($values, $params); + array_unshift($values, $param_types); call_user_func_array([$stmt, 'bind_param'], $values); } @@ -469,7 +516,27 @@ class dba { $errorno = self::$errorno; logger('DB Error '.self::$errorno.': '.self::$error."\n". - System::callstack(8)."\n".self::replaceParameters($sql, $params)); + System::callstack(8)."\n".self::replaceParameters($sql, $args)); + + // On a lost connection we try to reconnect - but only once. + if ($errorno == 2006) { + if (self::$in_retrial || !self::reconnect()) { + // It doesn't make sense to continue when the database connection was lost + if (self::$in_retrial) { + logger('Giving up retrial because of database error '.$errorno.': '.$error); + } else { + logger("Couldn't reconnect after database error ".$errorno.': '.$error); + } + exit(1); + } else { + // We try it again + logger('Reconnected after database error '.$errorno.': '.$error); + self::$in_retrial = true; + $ret = self::p($sql, $args); + self::$in_retrial = false; + return $ret; + } + } self::$error = $error; self::$errorno = $errorno; @@ -536,6 +603,13 @@ class dba { logger('DB Error '.self::$errorno.': '.self::$error."\n". System::callstack(8)."\n".self::replaceParameters($sql, $params)); + // On a lost connection we simply quit. + // A reconnect like in self::p could be dangerous with modifications + if ($errorno == 2006) { + logger('Giving up because of database error '.$errorno.': '.$error); + exit(1); + } + self::$error = $error; self::$errorno = $errorno; } @@ -858,12 +932,15 @@ class dba { * * @param string $table Table name * @param array $conditions Field condition(s) + * @param array $options + * - cascade: If true we delete records in other tables that depend on the one we're deleting through + * relations (default: true) * @param boolean $in_process Internal use: Only do a commit after the last delete * @param array $callstack Internal use: prevent endless loops * * @return boolean|array was the delete successful? When $in_process is set: deletion data */ - public static function delete($table, array $conditions, $in_process = false, array &$callstack = []) + public static function delete($table, array $conditions, array $options = [], $in_process = false, array &$callstack = []) { if (empty($table) || empty($conditions)) { logger('Table and conditions have to be set'); @@ -886,13 +963,15 @@ class dba { $commands[$key] = ['table' => $table, 'conditions' => $conditions]; + $cascade = defaults($options, 'cascade', true); + // To speed up the whole process we cache the table relations - if (count(self::$relation) == 0) { + if ($cascade && count(self::$relation) == 0) { self::buildRelationData(); } // Is there a relation entry for the table? - if (isset(self::$relation[$table])) { + if ($cascade && isset(self::$relation[$table])) { // We only allow a simple "one field" relation. $field = array_keys(self::$relation[$table])[0]; $rel_def = array_values(self::$relation[$table])[0]; @@ -905,7 +984,7 @@ class dba { if ((count($conditions) == 1) && ($field == array_keys($conditions)[0])) { foreach ($rel_def AS $rel_table => $rel_fields) { foreach ($rel_fields AS $rel_field) { - $retval = self::delete($rel_table, [$rel_field => array_values($conditions)[0]], true, $callstack); + $retval = self::delete($rel_table, [$rel_field => array_values($conditions)[0]], $options, true, $callstack); $commands = array_merge($commands, $retval); } } @@ -919,7 +998,7 @@ class dba { while ($row = self::fetch($data)) { // Now we accumulate the delete commands - $retval = self::delete($table, [$field => $row[$field]], true, $callstack); + $retval = self::delete($table, [$field => $row[$field]], $options, true, $callstack); $commands = array_merge($commands, $retval); } @@ -966,7 +1045,7 @@ class dba { // Split the SQL queries in chunks of 100 values // We do the $i stuff here to make the code better readable $i = $counter[$key_table][$key_condition]; - if (count($compacted[$key_table][$key_condition][$i]) > 100) { + if (isset($compacted[$key_table][$key_condition][$i]) && count($compacted[$key_table][$key_condition][$i]) > 100) { ++$i; } @@ -1142,29 +1221,9 @@ class dba { $condition_string = self::buildCondition($condition); - $order_string = ''; - if (isset($params['order'])) { - $order_string = " ORDER BY "; - foreach ($params['order'] AS $fields => $order) { - if (!is_int($fields)) { - $order_string .= "`" . $fields . "` " . ($order ? "DESC" : "ASC") . ", "; - } else { - $order_string .= "`" . $order . "`, "; - } - } - $order_string = substr($order_string, 0, -2); - } + $param_string = self::buildParameter($params); - $limit_string = ''; - if (isset($params['limit']) && is_int($params['limit'])) { - $limit_string = " LIMIT " . $params['limit']; - } - - if (isset($params['limit']) && is_array($params['limit'])) { - $limit_string = " LIMIT " . intval($params['limit'][0]) . ", " . intval($params['limit'][1]); - } - - $sql = "SELECT " . $select_fields . " FROM `" . $table . "`" . $condition_string . $order_string . $limit_string; + $sql = "SELECT " . $select_fields . " FROM `" . $table . "`" . $condition_string . $param_string; $result = self::p($sql, $condition); @@ -1221,14 +1280,14 @@ class dba { * @param array $condition * @return string */ - private static function buildCondition(array &$condition = []) + public static function buildCondition(array &$condition = []) { $condition_string = ''; if (count($condition) > 0) { reset($condition); $first_key = key($condition); if (is_int($first_key)) { - $condition_string = " WHERE ".array_shift($condition); + $condition_string = " WHERE (" . array_shift($condition) . ")"; } else { $new_values = []; $condition_string = ""; @@ -1245,7 +1304,7 @@ class dba { $condition_string .= "`" . $field . "` = ?"; } } - $condition_string = " WHERE " . $condition_string; + $condition_string = " WHERE (" . $condition_string . ")"; $condition = $new_values; } } @@ -1253,6 +1312,39 @@ class dba { return $condition_string; } + /** + * @brief Returns the SQL parameter string built from the provided parameter array + * + * @param array $params + * @return string + */ + public static function buildParameter(array $params = []) + { + $order_string = ''; + if (isset($params['order'])) { + $order_string = " ORDER BY "; + foreach ($params['order'] AS $fields => $order) { + if (!is_int($fields)) { + $order_string .= "`" . $fields . "` " . ($order ? "DESC" : "ASC") . ", "; + } else { + $order_string .= "`" . $order . "`, "; + } + } + $order_string = substr($order_string, 0, -2); + } + + $limit_string = ''; + if (isset($params['limit']) && is_int($params['limit'])) { + $limit_string = " LIMIT " . $params['limit']; + } + + if (isset($params['limit']) && is_array($params['limit'])) { + $limit_string = " LIMIT " . intval($params['limit'][0]) . ", " . intval($params['limit'][1]); + } + + return $order_string.$limit_string; + } + /** * @brief Fills an array with data from a query *