Remove product literal strings in "pht()", part 18
[phabricator.git] / src / infrastructure / storage / future / QueryFuture.php
blob98785812147481477e02930de4bef79d6d00c7de
1 <?php
3 /**
4 * This class provides several approaches for querying data from the database:
6 * # Async queries: Used under MySQLi with MySQLnd.
7 * # Parallel queries: Used under HPHP.
8 * # Multi queries: Used under MySQLi or HPHP.
9 * # Single queries: Used under MySQL.
11 * The class automatically decides which approach to use. Usage is like with
12 * other futures:
14 * $futures = array();
15 * $futures[] = new QueryFuture($conn1, 'SELECT 1');
16 * $futures[] = new QueryFuture($conn1, 'DELETE FROM table');
17 * $futures[] = new QueryFuture($conn2, 'SELECT 2');
19 * foreach (new FutureIterator($futures) as $future) {
20 * try {
21 * $result = $future->resolve();
22 * } catch (AphrontQueryException $ex) {
23 * }
24 * }
26 * `$result` contains a list of dicts for select queries or number of modified
27 * rows for modification queries.
29 final class QueryFuture extends Future {
31 private static $futures = array();
33 private $conn;
34 private $query;
35 private $id;
36 private $async;
37 private $profilerCallID;
39 public function __construct(
40 AphrontDatabaseConnection $conn,
41 $pattern/* , ... */) {
43 $this->conn = $conn;
45 $args = func_get_args();
46 $args = array_slice($args, 2);
47 $this->query = vqsprintf($conn, $pattern, $args);
49 self::$futures[] = $this;
50 $this->id = last_key(self::$futures);
53 public function isReady() {
54 if ($this->result !== null || $this->exception) {
55 return true;
58 if (!$this->conn->supportsAsyncQueries()) {
59 if ($this->conn->supportsParallelQueries()) {
60 $queries = array();
61 $conns = array();
62 foreach (self::$futures as $id => $future) {
63 $queries[$id] = $future->query;
64 $conns[$id] = $future->conn;
66 $results = $this->conn->executeParallelQueries($queries, $conns);
67 $this->processResults($results);
68 return true;
71 $conns = array();
72 $conn_queries = array();
73 foreach (self::$futures as $id => $future) {
74 $hash = spl_object_hash($future->conn);
75 $conns[$hash] = $future->conn;
76 $conn_queries[$hash][$id] = $future->query;
78 foreach ($conn_queries as $hash => $queries) {
79 $this->processResults($conns[$hash]->executeRawQueries($queries));
81 return true;
84 if (!$this->async) {
85 $profiler = PhutilServiceProfiler::getInstance();
86 $this->profilerCallID = $profiler->beginServiceCall(
87 array(
88 'type' => 'query',
89 'query' => $this->query,
90 'async' => true,
91 ));
93 $this->async = $this->conn->asyncQuery($this->query);
94 return false;
97 $conns = array();
98 $asyncs = array();
99 foreach (self::$futures as $id => $future) {
100 if ($future->async) {
101 $conns[$id] = $future->conn;
102 $asyncs[$id] = $future->async;
106 $this->processResults($this->conn->resolveAsyncQueries($conns, $asyncs));
108 if ($this->result !== null || $this->exception) {
109 return true;
111 return false;
114 private function processResults(array $results) {
115 foreach ($results as $id => $result) {
116 $future = self::$futures[$id];
117 if ($result instanceof Exception) {
118 $future->exception = $result;
119 } else {
120 $future->result = $result;
122 unset(self::$futures[$id]);
123 if ($future->profilerCallID) {
124 $profiler = PhutilServiceProfiler::getInstance();
125 $profiler->endServiceCall($future->profilerCallID, array());