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
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) {
21 * $result = $future->resolve();
22 * } catch (AphrontQueryException $ex) {
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();
37 private $profilerCallID;
39 public function __construct(
40 AphrontDatabaseConnection
$conn,
41 $pattern/* , ... */) {
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
) {
58 if (!$this->conn
->supportsAsyncQueries()) {
59 if ($this->conn
->supportsParallelQueries()) {
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);
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));
85 $profiler = PhutilServiceProfiler
::getInstance();
86 $this->profilerCallID
= $profiler->beginServiceCall(
89 'query' => $this->query
,
93 $this->async
= $this->conn
->asyncQuery($this->query
);
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
) {
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;
120 $future->result
= $result;
122 unset(self
::$futures[$id]);
123 if ($future->profilerCallID
) {
124 $profiler = PhutilServiceProfiler
::getInstance();
125 $profiler->endServiceCall($future->profilerCallID
, array());