Page MenuHomePhabricator

D14846.diff
No OneTemporary

D14846.diff

diff --git a/resources/sql/autopatches/20151221.search.2.ownersngrams.sql b/resources/sql/autopatches/20151221.search.2.ownersngrams.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20151221.search.2.ownersngrams.sql
@@ -0,0 +1,7 @@
+CREATE TABLE {$NAMESPACE}_owners.owners_name_ngrams (
+ id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ objectID INT UNSIGNED NOT NULL,
+ ngram CHAR(3) NOT NULL COLLATE {$COLLATE_TEXT},
+ KEY `key_object` (objectID),
+ KEY `key_ngram` (ngram, objectID)
+) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
diff --git a/resources/sql/autopatches/20151221.search.3.reindex.php b/resources/sql/autopatches/20151221.search.3.reindex.php
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20151221.search.3.reindex.php
@@ -0,0 +1,11 @@
+<?php
+
+$table = new PhabricatorOwnersPackage();
+
+foreach (new LiskMigrationIterator($table) as $package) {
+ PhabricatorSearchWorker::queueDocumentForIndexing(
+ $package->getPHID(),
+ array(
+ 'force' => true,
+ ));
+}
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -2548,6 +2548,8 @@
'PhabricatorNamedQueryQuery' => 'applications/search/query/PhabricatorNamedQueryQuery.php',
'PhabricatorNavigationRemarkupRule' => 'infrastructure/markup/rule/PhabricatorNavigationRemarkupRule.php',
'PhabricatorNeverTriggerClock' => 'infrastructure/daemon/workers/clock/PhabricatorNeverTriggerClock.php',
+ 'PhabricatorNgramsIndexEngineExtension' => 'applications/search/engineextension/PhabricatorNgramsIndexEngineExtension.php',
+ 'PhabricatorNgramsInterface' => 'applications/search/interface/PhabricatorNgramsInterface.php',
'PhabricatorNotificationBuilder' => 'applications/notification/builder/PhabricatorNotificationBuilder.php',
'PhabricatorNotificationClearController' => 'applications/notification/controller/PhabricatorNotificationClearController.php',
'PhabricatorNotificationClient' => 'applications/notification/client/PhabricatorNotificationClient.php',
@@ -2636,7 +2638,9 @@
'PhabricatorOwnersPackage' => 'applications/owners/storage/PhabricatorOwnersPackage.php',
'PhabricatorOwnersPackageDatasource' => 'applications/owners/typeahead/PhabricatorOwnersPackageDatasource.php',
'PhabricatorOwnersPackageEditEngine' => 'applications/owners/editor/PhabricatorOwnersPackageEditEngine.php',
+ 'PhabricatorOwnersPackageFulltextEngine' => 'applications/owners/query/PhabricatorOwnersPackageFulltextEngine.php',
'PhabricatorOwnersPackageFunctionDatasource' => 'applications/owners/typeahead/PhabricatorOwnersPackageFunctionDatasource.php',
+ 'PhabricatorOwnersPackageNameNgrams' => 'applications/owners/storage/PhabricatorOwnersPackageNameNgrams.php',
'PhabricatorOwnersPackageOwnerDatasource' => 'applications/owners/typeahead/PhabricatorOwnersPackageOwnerDatasource.php',
'PhabricatorOwnersPackagePHIDType' => 'applications/owners/phid/PhabricatorOwnersPackagePHIDType.php',
'PhabricatorOwnersPackageQuery' => 'applications/owners/query/PhabricatorOwnersPackageQuery.php',
@@ -3047,6 +3051,8 @@
'PhabricatorSearchManagementIndexWorkflow' => 'applications/search/management/PhabricatorSearchManagementIndexWorkflow.php',
'PhabricatorSearchManagementInitWorkflow' => 'applications/search/management/PhabricatorSearchManagementInitWorkflow.php',
'PhabricatorSearchManagementWorkflow' => 'applications/search/management/PhabricatorSearchManagementWorkflow.php',
+ 'PhabricatorSearchNgrams' => 'applications/search/ngrams/PhabricatorSearchNgrams.php',
+ 'PhabricatorSearchNgramsDestructionEngineExtension' => 'applications/search/engineextension/PhabricatorSearchNgramsDestructionEngineExtension.php',
'PhabricatorSearchOrderController' => 'applications/search/controller/PhabricatorSearchOrderController.php',
'PhabricatorSearchOrderField' => 'applications/search/field/PhabricatorSearchOrderField.php',
'PhabricatorSearchPreferencesSettingsPanel' => 'applications/settings/panel/PhabricatorSearchPreferencesSettingsPanel.php',
@@ -6802,6 +6808,7 @@
'PhabricatorNamedQueryQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorNavigationRemarkupRule' => 'PhutilRemarkupRule',
'PhabricatorNeverTriggerClock' => 'PhabricatorTriggerClock',
+ 'PhabricatorNgramsIndexEngineExtension' => 'PhabricatorIndexEngineExtension',
'PhabricatorNotificationBuilder' => 'Phobject',
'PhabricatorNotificationClearController' => 'PhabricatorNotificationController',
'PhabricatorNotificationClient' => 'Phobject',
@@ -6907,10 +6914,14 @@
'PhabricatorCustomFieldInterface',
'PhabricatorDestructibleInterface',
'PhabricatorConduitResultInterface',
+ 'PhabricatorFulltextInterface',
+ 'PhabricatorNgramsInterface',
),
'PhabricatorOwnersPackageDatasource' => 'PhabricatorTypeaheadDatasource',
'PhabricatorOwnersPackageEditEngine' => 'PhabricatorEditEngine',
+ 'PhabricatorOwnersPackageFulltextEngine' => 'PhabricatorFulltextEngine',
'PhabricatorOwnersPackageFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
+ 'PhabricatorOwnersPackageNameNgrams' => 'PhabricatorSearchNgrams',
'PhabricatorOwnersPackageOwnerDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
'PhabricatorOwnersPackagePHIDType' => 'PhabricatorPHIDType',
'PhabricatorOwnersPackageQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
@@ -7414,6 +7425,8 @@
'PhabricatorSearchManagementIndexWorkflow' => 'PhabricatorSearchManagementWorkflow',
'PhabricatorSearchManagementInitWorkflow' => 'PhabricatorSearchManagementWorkflow',
'PhabricatorSearchManagementWorkflow' => 'PhabricatorManagementWorkflow',
+ 'PhabricatorSearchNgrams' => 'PhabricatorSearchDAO',
+ 'PhabricatorSearchNgramsDestructionEngineExtension' => 'PhabricatorDestructionEngineExtension',
'PhabricatorSearchOrderController' => 'PhabricatorSearchBaseController',
'PhabricatorSearchOrderField' => 'PhabricatorSearchField',
'PhabricatorSearchPreferencesSettingsPanel' => 'PhabricatorSettingsPanel',
diff --git a/src/applications/config/schema/PhabricatorConfigSchemaSpec.php b/src/applications/config/schema/PhabricatorConfigSchemaSpec.php
--- a/src/applications/config/schema/PhabricatorConfigSchemaSpec.php
+++ b/src/applications/config/schema/PhabricatorConfigSchemaSpec.php
@@ -201,7 +201,8 @@
$is_binary = ($this->getUTF8Charset() == 'binary');
$matches = null;
- if (preg_match('/^(fulltext|sort|text)(\d+)?\z/', $data_type, $matches)) {
+ $pattern = '/^(fulltext|sort|text|char)(\d+)?\z/';
+ if (preg_match($pattern, $data_type, $matches)) {
// Limit the permitted column lengths under the theory that it would
// be nice to eventually reduce this to a small set of standard lengths.
@@ -220,6 +221,7 @@
'text8' => true,
'text4' => true,
'text' => true,
+ 'char3' => true,
'sort255' => true,
'sort128' => true,
'sort64' => true,
@@ -266,10 +268,14 @@
// the majority of cases.
$column_type = 'longtext';
break;
+ case 'char':
+ $column_type = 'char('.$size.')';
+ break;
}
switch ($type) {
case 'text':
+ case 'char':
if ($is_binary) {
// We leave collation and character set unspecified in order to
// generate valid SQL.
diff --git a/src/applications/owners/editor/PhabricatorOwnersPackageTransactionEditor.php b/src/applications/owners/editor/PhabricatorOwnersPackageTransactionEditor.php
--- a/src/applications/owners/editor/PhabricatorOwnersPackageTransactionEditor.php
+++ b/src/applications/owners/editor/PhabricatorOwnersPackageTransactionEditor.php
@@ -334,4 +334,8 @@
return $body;
}
+ protected function supportsSearch() {
+ return true;
+ }
+
}
diff --git a/src/applications/owners/query/PhabricatorOwnersPackageFulltextEngine.php b/src/applications/owners/query/PhabricatorOwnersPackageFulltextEngine.php
new file mode 100644
--- /dev/null
+++ b/src/applications/owners/query/PhabricatorOwnersPackageFulltextEngine.php
@@ -0,0 +1,26 @@
+<?php
+
+final class PhabricatorOwnersPackageFulltextEngine
+ extends PhabricatorFulltextEngine {
+
+ protected function buildAbstractDocument(
+ PhabricatorSearchAbstractDocument $document,
+ $object) {
+
+ $package = $object;
+ $document->setDocumentTitle($package->getName());
+
+ // TODO: These are bogus, but not currently stored on packages.
+ $document->setDocumentCreated(PhabricatorTime::getNow());
+ $document->setDocumentModified(PhabricatorTime::getNow());
+
+ $document->addRelationship(
+ $package->isArchived()
+ ? PhabricatorSearchRelationship::RELATIONSHIP_CLOSED
+ : PhabricatorSearchRelationship::RELATIONSHIP_OPEN,
+ $package->getPHID(),
+ PhabricatorOwnersPackagePHIDType::TYPECONST,
+ PhabricatorTime::getNow());
+ }
+
+}
diff --git a/src/applications/owners/query/PhabricatorOwnersPackageQuery.php b/src/applications/owners/query/PhabricatorOwnersPackageQuery.php
--- a/src/applications/owners/query/PhabricatorOwnersPackageQuery.php
+++ b/src/applications/owners/query/PhabricatorOwnersPackageQuery.php
@@ -9,7 +9,6 @@
private $authorityPHIDs;
private $repositoryPHIDs;
private $paths;
- private $namePrefix;
private $statuses;
private $controlMap = array();
@@ -78,9 +77,10 @@
return $this;
}
- public function withNamePrefix($prefix) {
- $this->namePrefix = $prefix;
- return $this;
+ public function withNameNgrams($ngrams) {
+ return $this->withNgramsConstraint(
+ new PhabricatorOwnersPackageNameNgrams(),
+ $ngrams);
}
public function needPaths($need_paths) {
@@ -208,15 +208,6 @@
$this->statuses);
}
- if (strlen($this->namePrefix)) {
- // NOTE: This is a hacky mess, but this column is currently case
- // sensitive and unique.
- $where[] = qsprintf(
- $conn,
- 'LOWER(p.name) LIKE %>',
- phutil_utf8_strtolower($this->namePrefix));
- }
-
if ($this->controlMap) {
$clauses = array();
foreach ($this->controlMap as $repository_phid => $paths) {
diff --git a/src/applications/owners/query/PhabricatorOwnersPackageSearchEngine.php b/src/applications/owners/query/PhabricatorOwnersPackageSearchEngine.php
--- a/src/applications/owners/query/PhabricatorOwnersPackageSearchEngine.php
+++ b/src/applications/owners/query/PhabricatorOwnersPackageSearchEngine.php
@@ -25,6 +25,10 @@
->setDescription(
pht('Search for packages with specific owners.'))
->setDatasource(new PhabricatorProjectOrUserDatasource()),
+ id(new PhabricatorSearchTextField())
+ ->setLabel(pht('Name Contains'))
+ ->setKey('name')
+ ->setDescription(pht('Search for packages by name substrings.')),
id(new PhabricatorSearchDatasourceField())
->setLabel(pht('Repositories'))
->setKey('repositoryPHIDs')
@@ -69,6 +73,10 @@
$query->withStatuses($map['statuses']);
}
+ if (strlen($map['name'])) {
+ $query->withNameNgrams($map['name']);
+ }
+
return $query;
}
diff --git a/src/applications/owners/storage/PhabricatorOwnersPackage.php b/src/applications/owners/storage/PhabricatorOwnersPackage.php
--- a/src/applications/owners/storage/PhabricatorOwnersPackage.php
+++ b/src/applications/owners/storage/PhabricatorOwnersPackage.php
@@ -7,7 +7,9 @@
PhabricatorApplicationTransactionInterface,
PhabricatorCustomFieldInterface,
PhabricatorDestructibleInterface,
- PhabricatorConduitResultInterface {
+ PhabricatorConduitResultInterface,
+ PhabricatorFulltextInterface,
+ PhabricatorNgramsInterface {
protected $name;
protected $originalName;
@@ -46,7 +48,7 @@
self::CONFIG_TIMESTAMPS => false,
self::CONFIG_AUX_PHID => true,
self::CONFIG_COLUMN_SCHEMA => array(
- 'name' => 'text128',
+ 'name' => 'sort128',
'originalName' => 'text255',
'description' => 'text',
'primaryOwnerPHID' => 'phid?',
@@ -54,17 +56,6 @@
'mailKey' => 'bytes20',
'status' => 'text32',
),
- self::CONFIG_KEY_SCHEMA => array(
- 'key_phid' => null,
- 'phid' => array(
- 'columns' => array('phid'),
- 'unique' => true,
- ),
- 'name' => array(
- 'columns' => array('name'),
- 'unique' => true,
- ),
- ),
) + parent::getConfiguration();
}
@@ -433,4 +424,23 @@
);
}
+
+/* -( PhabricatorFulltextInterface )--------------------------------------- */
+
+
+ public function newFulltextEngine() {
+ return new PhabricatorOwnersPackageFulltextEngine();
+ }
+
+
+/* -( PhabricatorNgramInterface )------------------------------------------ */
+
+
+ public function newNgrams() {
+ return array(
+ id(new PhabricatorOwnersPackageNameNgrams())
+ ->setValue($this->getName()),
+ );
+ }
+
}
diff --git a/src/applications/owners/storage/PhabricatorOwnersPackageNameNgrams.php b/src/applications/owners/storage/PhabricatorOwnersPackageNameNgrams.php
new file mode 100644
--- /dev/null
+++ b/src/applications/owners/storage/PhabricatorOwnersPackageNameNgrams.php
@@ -0,0 +1,18 @@
+<?php
+
+final class PhabricatorOwnersPackageNameNgrams
+ extends PhabricatorSearchNgrams {
+
+ public function getNgramKey() {
+ return 'name';
+ }
+
+ public function getColumnName() {
+ return 'name';
+ }
+
+ public function getApplicationName() {
+ return 'owners';
+ }
+
+}
diff --git a/src/applications/owners/storage/PhabricatorOwnersPackageTransaction.php b/src/applications/owners/storage/PhabricatorOwnersPackageTransaction.php
--- a/src/applications/owners/storage/PhabricatorOwnersPackageTransaction.php
+++ b/src/applications/owners/storage/PhabricatorOwnersPackageTransaction.php
@@ -27,6 +27,14 @@
switch ($this->getTransactionType()) {
case self::TYPE_OWNERS:
+ if (!is_array($old)) {
+ $old = array();
+ }
+
+ if (!is_array($new)) {
+ $new = array();
+ }
+
$add = array_diff($new, $old);
foreach ($add as $phid) {
$phids[] = $phid;
diff --git a/src/applications/owners/typeahead/PhabricatorOwnersPackageDatasource.php b/src/applications/owners/typeahead/PhabricatorOwnersPackageDatasource.php
--- a/src/applications/owners/typeahead/PhabricatorOwnersPackageDatasource.php
+++ b/src/applications/owners/typeahead/PhabricatorOwnersPackageDatasource.php
@@ -22,7 +22,7 @@
$results = array();
$query = id(new PhabricatorOwnersPackageQuery())
- ->withNamePrefix($raw_query)
+ ->withNameNgrams($raw_query)
->setOrder('name');
$packages = $this->executeQuery($query);
diff --git a/src/applications/search/engineextension/PhabricatorFulltextIndexEngineExtension.php b/src/applications/search/engineextension/PhabricatorFulltextIndexEngineExtension.php
--- a/src/applications/search/engineextension/PhabricatorFulltextIndexEngineExtension.php
+++ b/src/applications/search/engineextension/PhabricatorFulltextIndexEngineExtension.php
@@ -65,6 +65,9 @@
try {
$comment = $xaction->getApplicationTransactionCommentObject();
+ if (!$comment) {
+ return 'none';
+ }
} catch (Exception $ex) {
return 'none';
}
diff --git a/src/applications/search/engineextension/PhabricatorNgramsIndexEngineExtension.php b/src/applications/search/engineextension/PhabricatorNgramsIndexEngineExtension.php
new file mode 100644
--- /dev/null
+++ b/src/applications/search/engineextension/PhabricatorNgramsIndexEngineExtension.php
@@ -0,0 +1,34 @@
+<?php
+
+final class PhabricatorNgramsIndexEngineExtension
+ extends PhabricatorIndexEngineExtension {
+
+ const EXTENSIONKEY = 'ngrams';
+
+ public function getExtensionName() {
+ return pht('Ngrams Engine');
+ }
+
+ public function getIndexVersion($object) {
+ $ngrams = $object->newNgrams();
+ $map = mpull($ngrams, 'getValue', 'getNgramKey');
+ ksort($map);
+ $serialized = serialize($map);
+
+ return PhabricatorHash::digestForIndex($serialized);
+ }
+
+ public function shouldIndexObject($object) {
+ return ($object instanceof PhabricatorNgramsInterface);
+ }
+
+ public function indexObject(
+ PhabricatorIndexEngine $engine,
+ $object) {
+
+ foreach ($object->newNgrams() as $ngram) {
+ $ngram->writeNgram($object->getID());
+ }
+ }
+
+}
diff --git a/src/applications/search/engineextension/PhabricatorSearchNgramsDestructionEngineExtension.php b/src/applications/search/engineextension/PhabricatorSearchNgramsDestructionEngineExtension.php
new file mode 100644
--- /dev/null
+++ b/src/applications/search/engineextension/PhabricatorSearchNgramsDestructionEngineExtension.php
@@ -0,0 +1,31 @@
+<?php
+
+final class PhabricatorSearchNgramsDestructionEngineExtension
+ extends PhabricatorDestructionEngineExtension {
+
+ const EXTENSIONKEY = 'search.ngrams';
+
+ public function getExtensionName() {
+ return pht('Search Ngram');
+ }
+
+ public function canDestroyObject(
+ PhabricatorDestructionEngine $engine,
+ $object) {
+ return ($object instanceof PhabricatorNgramsInterface);
+ }
+
+ public function destroyObject(
+ PhabricatorDestructionEngine $engine,
+ $object) {
+
+ foreach ($object->newNgrams() as $ngram) {
+ queryfx(
+ $ngram->establishConnection('w'),
+ 'DELETE FROM %T WHERE objectID = %d',
+ $ngram->getTableName(),
+ $object->getID());
+ }
+ }
+
+}
diff --git a/src/applications/search/interface/PhabricatorNgramsInterface.php b/src/applications/search/interface/PhabricatorNgramsInterface.php
new file mode 100644
--- /dev/null
+++ b/src/applications/search/interface/PhabricatorNgramsInterface.php
@@ -0,0 +1,7 @@
+<?php
+
+interface PhabricatorNgramsInterface {
+
+ public function newNgrams();
+
+}
diff --git a/src/applications/search/ngrams/PhabricatorSearchNgrams.php b/src/applications/search/ngrams/PhabricatorSearchNgrams.php
new file mode 100644
--- /dev/null
+++ b/src/applications/search/ngrams/PhabricatorSearchNgrams.php
@@ -0,0 +1,113 @@
+<?php
+
+abstract class PhabricatorSearchNgrams
+ extends PhabricatorSearchDAO {
+
+ protected $objectID;
+ protected $ngram;
+
+ private $value;
+
+ abstract public function getNgramKey();
+ abstract public function getColumnName();
+
+ final public function setValue($value) {
+ $this->value = $value;
+ return $this;
+ }
+
+ final public function getValue() {
+ return $this->value;
+ }
+
+ protected function getConfiguration() {
+ return array(
+ self::CONFIG_TIMESTAMPS => false,
+ self::CONFIG_COLUMN_SCHEMA => array(
+ 'objectID' => 'uint32',
+ 'ngram' => 'char3',
+ ),
+ self::CONFIG_KEY_SCHEMA => array(
+ 'key_ngram' => array(
+ 'columns' => array('ngram', 'objectID'),
+ ),
+ 'key_object' => array(
+ 'columns' => array('objectID'),
+ ),
+ ),
+ ) + parent::getConfiguration();
+ }
+
+ public function getTableName() {
+ $application = $this->getApplicationName();
+ $key = $this->getNgramKey();
+ return "{$application}_{$key}_ngrams";
+ }
+
+ final public function tokenizeString($value) {
+ $value = trim($value, ' ');
+ $value = preg_split('/ +/', $value);
+ return $value;
+ }
+
+ final public function getNgramsFromString($value, $mode) {
+ $tokens = $this->tokenizeString($value);
+
+ $ngrams = array();
+ foreach ($tokens as $token) {
+ $token = phutil_utf8_strtolower($token);
+
+ switch ($mode) {
+ case 'query':
+ break;
+ case 'index':
+ $token = ' '.$token.' ';
+ break;
+ case 'prefix':
+ $token = ' '.$token;
+ break;
+ }
+
+ $len = (strlen($token) - 2);
+ for ($ii = 0; $ii < $len; $ii++) {
+ $ngram = substr($token, $ii, 3);
+ $ngrams[$ngram] = $ngram;
+ }
+ }
+
+ ksort($ngrams);
+
+ return array_keys($ngrams);
+ }
+
+ final public function writeNgram($object_id) {
+ $ngrams = $this->getNgramsFromString($this->getValue(), 'index');
+ $conn_w = $this->establishConnection('w');
+
+ $sql = array();
+ foreach ($ngrams as $ngram) {
+ $sql[] = qsprintf(
+ $conn_w,
+ '(%d, %s)',
+ $object_id,
+ $ngram);
+ }
+
+ queryfx(
+ $conn_w,
+ 'DELETE FROM %T WHERE objectID = %d',
+ $this->getTableName(),
+ $object_id);
+
+ if ($sql) {
+ queryfx(
+ $conn_w,
+ 'INSERT INTO %T (objectID, ngram) VALUES %Q',
+ $this->getTableName(),
+ implode(', ', $sql));
+ }
+
+ return $this;
+ }
+
+}
diff --git a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php
--- a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php
+++ b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php
@@ -26,6 +26,7 @@
private $edgeLogicConstraintsAreValid = false;
private $spacePHIDs;
private $spaceIsArchived;
+ private $ngrams = array();
protected function getPageCursors(array $page) {
return array(
@@ -253,6 +254,7 @@
$joins = array();
$joins[] = $this->buildEdgeLogicJoinClause($conn);
$joins[] = $this->buildApplicationSearchJoinClause($conn);
+ $joins[] = $this->buildNgramsJoinClause($conn);
return $joins;
}
@@ -274,6 +276,7 @@
$where[] = $this->buildPagingClause($conn);
$where[] = $this->buildEdgeLogicWhereClause($conn);
$where[] = $this->buildSpacesWhereClause($conn);
+ $where[] = $this->buildNgramsWhereClause($conn);
return $where;
}
@@ -324,6 +327,10 @@
return true;
}
+ if ($this->shouldGroupNgramResultRows()) {
+ return true;
+ }
+
return false;
}
@@ -1345,6 +1352,138 @@
}
+/* -( Ngrams )------------------------------------------------------------- */
+
+
+ protected function withNgramsConstraint(
+ PhabricatorSearchNgrams $index,
+ $value) {
+
+ if (strlen($value)) {
+ $this->ngrams[] = array(
+ 'index' => $index,
+ 'value' => $value,
+ 'length' => count(phutil_utf8v($value)),
+ );
+ }
+
+ return $this;
+ }
+
+
+ protected function buildNgramsJoinClause(AphrontDatabaseConnection $conn) {
+ $flat = array();
+ foreach ($this->ngrams as $spec) {
+ $index = $spec['index'];
+ $value = $spec['value'];
+ $length = $spec['length'];
+
+ if ($length >= 3) {
+ $ngrams = $index->getNgramsFromString($value, 'query');
+ $prefix = false;
+ } else if ($length == 2) {
+ $ngrams = $index->getNgramsFromString($value, 'prefix');
+ $prefix = false;
+ } else {
+ $ngrams = array(' '.$value);
+ $prefix = true;
+ }
+
+ foreach ($ngrams as $ngram) {
+ $flat[] = array(
+ 'table' => $index->getTableName(),
+ 'ngram' => $ngram,
+ 'prefix' => $prefix,
+ );
+ }
+ }
+
+ // MySQL only allows us to join a maximum of 61 tables per query. Each
+ // ngram is going to cost us a join toward that limit, so if the user
+ // specified a very long query string, just pick 16 of the ngrams
+ // at random.
+ if (count($flat) > 16) {
+ shuffle($flat);
+ $flat = array_slice($flat, 0, 16);
+ }
+
+ $alias = $this->getPrimaryTableAlias();
+ if ($alias) {
+ $id_column = qsprintf($conn, '%T.%T', $alias, 'id');
+ } else {
+ $id_column = qsprintf($conn, '%T', 'id');
+ }
+
+ $idx = 1;
+ $joins = array();
+ foreach ($flat as $spec) {
+ $table = $spec['table'];
+ $ngram = $spec['ngram'];
+ $prefix = $spec['prefix'];
+
+ $alias = 'ngm'.$idx++;
+
+ if ($prefix) {
+ $joins[] = qsprintf(
+ $conn,
+ 'JOIN %T %T ON %T.objectID = %Q AND %T.ngram LIKE %>',
+ $table,
+ $alias,
+ $alias,
+ $id_column,
+ $alias,
+ $ngram);
+ } else {
+ $joins[] = qsprintf(
+ $conn,
+ 'JOIN %T %T ON %T.objectID = %Q AND %T.ngram = %s',
+ $table,
+ $alias,
+ $alias,
+ $id_column,
+ $alias,
+ $ngram);
+ }
+ }
+
+ return $joins;
+ }
+
+
+ protected function buildNgramsWhereClause(AphrontDatabaseConnection $conn) {
+ $where = array();
+
+ foreach ($this->ngrams as $ngram) {
+ $index = $ngram['index'];
+ $value = $ngram['value'];
+
+ $column = $index->getColumnName();
+ $alias = $this->getPrimaryTableAlias();
+ if ($alias) {
+ $column = qsprintf($conn, '%T.%T', $alias, $column);
+ } else {
+ $column = qsprintf($conn, '%T', $column);
+ }
+
+ $tokens = $index->tokenizeString($value);
+ foreach ($tokens as $token) {
+ $where[] = qsprintf(
+ $conn,
+ '%Q LIKE %~',
+ $column,
+ $token);
+ }
+ }
+
+ return $where;
+ }
+
+
+ protected function shouldGroupNgramResultRows() {
+ return (bool)$this->ngrams;
+ }
+
+
/* -( Edge Logic )--------------------------------------------------------- */

File Metadata

Mime Type
text/plain
Expires
Tue, Mar 25, 3:25 PM (1 w, 5 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7704877
Default Alt Text
D14846.diff (24 KB)

Event Timeline