Path: blob/master/src/infrastructure/storage/future/QueryFuture.php
12241 views
<?php12/**3* This class provides several approaches for querying data from the database:4*5* # Async queries: Used under MySQLi with MySQLnd.6* # Parallel queries: Used under HPHP.7* # Multi queries: Used under MySQLi or HPHP.8* # Single queries: Used under MySQL.9*10* The class automatically decides which approach to use. Usage is like with11* other futures:12*13* $futures = array();14* $futures[] = new QueryFuture($conn1, 'SELECT 1');15* $futures[] = new QueryFuture($conn1, 'DELETE FROM table');16* $futures[] = new QueryFuture($conn2, 'SELECT 2');17*18* foreach (new FutureIterator($futures) as $future) {19* try {20* $result = $future->resolve();21* } catch (AphrontQueryException $ex) {22* }23* }24*25* `$result` contains a list of dicts for select queries or number of modified26* rows for modification queries.27*/28final class QueryFuture extends Future {2930private static $futures = array();3132private $conn;33private $query;34private $id;35private $async;36private $profilerCallID;3738public function __construct(39AphrontDatabaseConnection $conn,40$pattern/* , ... */) {4142$this->conn = $conn;4344$args = func_get_args();45$args = array_slice($args, 2);46$this->query = vqsprintf($conn, $pattern, $args);4748self::$futures[] = $this;49$this->id = last_key(self::$futures);50}5152public function isReady() {53if ($this->result !== null || $this->exception) {54return true;55}5657if (!$this->conn->supportsAsyncQueries()) {58if ($this->conn->supportsParallelQueries()) {59$queries = array();60$conns = array();61foreach (self::$futures as $id => $future) {62$queries[$id] = $future->query;63$conns[$id] = $future->conn;64}65$results = $this->conn->executeParallelQueries($queries, $conns);66$this->processResults($results);67return true;68}6970$conns = array();71$conn_queries = array();72foreach (self::$futures as $id => $future) {73$hash = spl_object_hash($future->conn);74$conns[$hash] = $future->conn;75$conn_queries[$hash][$id] = $future->query;76}77foreach ($conn_queries as $hash => $queries) {78$this->processResults($conns[$hash]->executeRawQueries($queries));79}80return true;81}8283if (!$this->async) {84$profiler = PhutilServiceProfiler::getInstance();85$this->profilerCallID = $profiler->beginServiceCall(86array(87'type' => 'query',88'query' => $this->query,89'async' => true,90));9192$this->async = $this->conn->asyncQuery($this->query);93return false;94}9596$conns = array();97$asyncs = array();98foreach (self::$futures as $id => $future) {99if ($future->async) {100$conns[$id] = $future->conn;101$asyncs[$id] = $future->async;102}103}104105$this->processResults($this->conn->resolveAsyncQueries($conns, $asyncs));106107if ($this->result !== null || $this->exception) {108return true;109}110return false;111}112113private function processResults(array $results) {114foreach ($results as $id => $result) {115$future = self::$futures[$id];116if ($result instanceof Exception) {117$future->exception = $result;118} else {119$future->result = $result;120}121unset(self::$futures[$id]);122if ($future->profilerCallID) {123$profiler = PhutilServiceProfiler::getInstance();124$profiler->endServiceCall($future->profilerCallID, array());125}126}127}128}129130131