@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
at recaptime-dev/main 132 lines 3.4 kB view raw
1<?php 2 3final class AphrontIsolatedDatabaseConnection 4 extends AphrontDatabaseConnection { 5 6 private $configuration; 7 private static $nextInsertID; 8 private $insertID; 9 10 private $transcript = array(); 11 12 private $allResults; 13 private $affectedRows; 14 15 public function __construct(array $configuration) { 16 $this->configuration = $configuration; 17 18 if (self::$nextInsertID === null) { 19 // Generate test IDs into a distant ID space to reduce the risk of 20 // collisions and make them distinctive. 21 self::$nextInsertID = 55555000000 + mt_rand(0, 1000); 22 } 23 } 24 25 public function openConnection() { 26 return; 27 } 28 29 public function close() { 30 return; 31 } 32 33 public function escapeUTF8String($string) { 34 return '<S>'; 35 } 36 37 public function escapeBinaryString($string) { 38 return '<B>'; 39 } 40 41 public function escapeColumnName($name) { 42 return '<C>'; 43 } 44 45 public function escapeMultilineComment($comment) { 46 return '<K>'; 47 } 48 49 public function escapeStringForLikeClause($value) { 50 return '<L>'; 51 } 52 53 private function getConfiguration($key, $default = null) { 54 return idx($this->configuration, $key, $default); 55 } 56 57 public function getInsertID() { 58 return $this->insertID; 59 } 60 61 public function getAffectedRows() { 62 return $this->affectedRows; 63 } 64 65 public function selectAllResults() { 66 return $this->allResults; 67 } 68 69 public function executeQuery(PhutilQueryString $query) { 70 71 // NOTE: "[\s<>K]*" allows any number of (properly escaped) comments to 72 // appear prior to the allowed keyword, since this connection escapes 73 // them as "<K>" (above). 74 75 $display_query = $query->getMaskedString(); 76 $raw_query = $query->getUnmaskedString(); 77 78 $keywords = array( 79 'INSERT', 80 'UPDATE', 81 'DELETE', 82 'START', 83 'SAVEPOINT', 84 'COMMIT', 85 'ROLLBACK', 86 ); 87 $preg_keywords = array(); 88 foreach ($keywords as $key => $word) { 89 $preg_keywords[] = preg_quote($word, '/'); 90 } 91 $preg_keywords = implode('|', $preg_keywords); 92 93 if (!preg_match('/^[\s<>K]*('.$preg_keywords.')\s*/i', $raw_query)) { 94 throw new AphrontNotSupportedQueryException( 95 pht( 96 "Database isolation currently only supports some queries. You are ". 97 "trying to issue a query which does not begin with an allowed ". 98 "keyword (%s): '%s'.", 99 implode(', ', $keywords), 100 $display_query)); 101 } 102 103 $this->transcript[] = $display_query; 104 105 // NOTE: This method is intentionally simplified for now, since we're only 106 // using it to stub out inserts/updates. In the future it will probably need 107 // to grow more powerful. 108 109 $this->allResults = array(); 110 111 // NOTE: We jitter the insert IDs to keep tests honest; a test should cover 112 // the relationship between objects, not their exact insertion order. This 113 // guarantees that IDs are unique but makes it impossible to hard-code tests 114 // against this specific implementation detail. 115 self::$nextInsertID += mt_rand(1, 10); 116 $this->insertID = self::$nextInsertID; 117 $this->affectedRows = 1; 118 } 119 120 public function executeRawQueries(array $raw_queries) { 121 $results = array(); 122 foreach ($raw_queries as $id => $raw_query) { 123 $results[$id] = array(); 124 } 125 return $results; 126 } 127 128 public function getQueryTranscript() { 129 return $this->transcript; 130 } 131 132}