PageRenderTime 48ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/administrator/components/com_finder/helpers/indexer/driver/mysql.php

https://bitbucket.org/eternaware/joomus
PHP | 668 lines | 370 code | 82 blank | 216 comment | 22 complexity | 8c1bb96f48461931d5a58059a6582531 MD5 | raw file
Possible License(s): LGPL-2.1
  1. <?php
  2. /**
  3. * @package Joomla.Administrator
  4. * @subpackage com_finder
  5. *
  6. * @copyright Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.
  7. * @license GNU General Public License version 2 or later; see LICENSE
  8. */
  9. defined('_JEXEC') or die;
  10. jimport('joomla.filesystem.file');
  11. /**
  12. * Indexer class supporting MySQL(i) for the Finder indexer package.
  13. *
  14. * The indexer class provides the core functionality of the Finder
  15. * search engine. It is responsible for adding and updating the
  16. * content links table; extracting and scoring tokens; and maintaining
  17. * all referential information for the content.
  18. *
  19. * Note: All exceptions thrown from within this class should be caught
  20. * by the controller.
  21. *
  22. * @package Joomla.Administrator
  23. * @subpackage com_finder
  24. * @since 3.0
  25. */
  26. class FinderIndexerDriverMysql extends FinderIndexer
  27. {
  28. /**
  29. * Method to index a content item.
  30. *
  31. * @param FinderIndexerResult $item The content item to index.
  32. * @param string $format The format of the content. [optional]
  33. *
  34. * @return integer The ID of the record in the links table.
  35. *
  36. * @since 3.0
  37. * @throws Exception on database error.
  38. */
  39. public function index($item, $format = 'html')
  40. {
  41. // Mark beforeIndexing in the profiler.
  42. static::$profiler ? static::$profiler->mark('beforeIndexing') : null;
  43. $db = JFactory::getDBO();
  44. $nd = $db->getNullDate();
  45. // Check if the item is in the database.
  46. $query = $db->getQuery(true);
  47. $query->select($db->quoteName('link_id') . ', ' . $db->quoteName('md5sum'));
  48. $query->from($db->quoteName('#__finder_links'));
  49. $query->where($db->quoteName('url') . ' = ' . $db->quote($item->url));
  50. // Load the item from the database.
  51. $db->setQuery($query);
  52. $link = $db->loadObject();
  53. // Get the indexer state.
  54. $state = static::getState();
  55. // Get the signatures of the item.
  56. $curSig = static::getSignature($item);
  57. $oldSig = isset($link->md5sum) ? $link->md5sum : null;
  58. // Get the other item information.
  59. $linkId = empty($link->link_id) ? null : $link->link_id;
  60. $isNew = empty($link->link_id) ? true : false;
  61. // Check the signatures. If they match, the item is up to date.
  62. if (!$isNew && $curSig == $oldSig)
  63. {
  64. return $linkId;
  65. }
  66. /*
  67. * If the link already exists, flush all the term maps for the item.
  68. * Maps are stored in 16 tables so we need to iterate through and flush
  69. * each table one at a time.
  70. */
  71. if (!$isNew)
  72. {
  73. for ($i = 0; $i <= 15; $i++)
  74. {
  75. // Flush the maps for the link.
  76. $query->clear();
  77. $query->delete();
  78. $query->from($db->quoteName('#__finder_links_terms' . dechex($i)));
  79. $query->where($db->quoteName('link_id') . ' = ' . (int) $linkId);
  80. $db->setQuery($query);
  81. $db->execute();
  82. }
  83. // Remove the taxonomy maps.
  84. FinderIndexerTaxonomy::removeMaps($linkId);
  85. }
  86. // Mark afterUnmapping in the profiler.
  87. static::$profiler ? static::$profiler->mark('afterUnmapping') : null;
  88. // Perform cleanup on the item data.
  89. $item->publish_start_date = (int) $item->publish_start_date != 0 ? $item->publish_start_date : $nd;
  90. $item->publish_end_date = (int) $item->publish_end_date != 0 ? $item->publish_end_date : $nd;
  91. $item->start_date = (int) $item->start_date != 0 ? $item->start_date : $nd;
  92. $item->end_date = (int) $item->end_date != 0 ? $item->end_date : $nd;
  93. // Prepare the item description.
  94. $item->description = FinderIndexerHelper::parse($item->summary);
  95. /*
  96. * Now, we need to enter the item into the links table. If the item
  97. * already exists in the database, we need to use an UPDATE query.
  98. * Otherwise, we need to use an INSERT to get the link id back.
  99. */
  100. if ($isNew)
  101. {
  102. $columnsArray = array(
  103. $db->quoteName('url'), $db->quoteName('route'), $db->quoteName('title'), $db->quoteName('description'),
  104. $db->quoteName('indexdate'), $db->quoteName('published'), $db->quoteName('state'), $db->quoteName('access'),
  105. $db->quoteName('language'), $db->quoteName('type_id'), $db->quoteName('object'), $db->quoteName('publish_start_date'),
  106. $db->quoteName('publish_end_date'), $db->quoteName('start_date'), $db->quoteName('end_date'), $db->quoteName('list_price'),
  107. $db->quoteName('sale_price')
  108. );
  109. // Insert the link.
  110. $query->clear();
  111. $query->insert($db->quoteName('#__finder_links'));
  112. $query->columns($columnsArray);
  113. $query->values(
  114. $db->quote($item->url) . ', '
  115. . $db->quote($item->route) . ', '
  116. . $db->quote($item->title) . ', '
  117. . $db->quote($item->description) . ', '
  118. . $query->currentTimestamp() . ', '
  119. . '1, '
  120. . (int) $item->state . ', '
  121. . (int) $item->access . ', '
  122. . $db->quote($item->language) . ', '
  123. . (int) $item->type_id . ', '
  124. . $db->quote(serialize($item)) . ', '
  125. . $db->quote($item->publish_start_date) . ', '
  126. . $db->quote($item->publish_end_date) . ', '
  127. . $db->quote($item->start_date) . ', '
  128. . $db->quote($item->end_date) . ', '
  129. . $db->quote($item->list_price) . ', '
  130. . $db->quote($item->sale_price)
  131. );
  132. $db->setQuery($query);
  133. $db->execute();
  134. // Get the link id.
  135. $linkId = (int) $db->insertid();
  136. }
  137. else
  138. {
  139. // Update the link.
  140. $query->clear();
  141. $query->update($db->qn('#__finder_links'));
  142. $query->set($db->qn('route') . ' = ' . $db->quote($item->route));
  143. $query->set($db->qn('title') . ' = ' . $db->quote($item->title));
  144. $query->set($db->qn('description') . ' = ' . $db->quote($item->description));
  145. $query->set($db->qn('indexdate') . ' = ' . $query->currentTimestamp());
  146. $query->set($db->qn('state') . ' = ' . (int) $item->state);
  147. $query->set($db->qn('access') . ' = ' . (int) $item->access);
  148. $query->set($db->qn('language') . ' = ' . $db->quote($item->language));
  149. $query->set($db->qn('type_id') . ' = ' . (int) $item->type_id);
  150. $query->set($db->qn('object') . ' = ' . $db->quote(serialize($item)));
  151. $query->set($db->qn('publish_start_date') . ' = ' . $db->quote($item->publish_start_date));
  152. $query->set($db->qn('publish_end_date') . ' = ' . $db->quote($item->publish_end_date));
  153. $query->set($db->qn('start_date') . ' = ' . $db->quote($item->start_date));
  154. $query->set($db->qn('end_date') . ' = ' . $db->quote($item->end_date));
  155. $query->set($db->qn('list_price') . ' = ' . $db->quote($item->list_price));
  156. $query->set($db->qn('sale_price') . ' = ' . $db->quote($item->sale_price));
  157. $query->where('link_id = ' . (int) $linkId);
  158. $db->setQuery($query);
  159. $db->execute();
  160. }
  161. // Set up the variables we will need during processing.
  162. $tokens = array();
  163. $count = 0;
  164. // Mark afterLinking in the profiler.
  165. static::$profiler ? static::$profiler->mark('afterLinking') : null;
  166. // Truncate the tokens tables.
  167. $db->truncateTable('#__finder_tokens');
  168. // Truncate the tokens aggregate table.
  169. $db->truncateTable('#__finder_tokens_aggregate');
  170. /*
  171. * Process the item's content. The items can customize their
  172. * processing instructions to define extra properties to process
  173. * or rearrange how properties are weighted.
  174. */
  175. foreach ($item->getInstructions() as $group => $properties)
  176. {
  177. // Iterate through the properties of the group.
  178. foreach ($properties as $property)
  179. {
  180. // Check if the property exists in the item.
  181. if (empty($item->$property))
  182. {
  183. continue;
  184. }
  185. // Tokenize the property.
  186. if (is_array($item->$property))
  187. {
  188. // Tokenize an array of content and add it to the database.
  189. foreach ($item->$property as $ip)
  190. {
  191. // If the group is path, we need to a few extra processing
  192. // steps to strip the extension and convert slashes and dashes
  193. // to spaces.
  194. if ($group === static::PATH_CONTEXT)
  195. {
  196. $ip = JFile::stripExt($ip);
  197. $ip = str_replace('/', ' ', $ip);
  198. $ip = str_replace('-', ' ', $ip);
  199. }
  200. // Tokenize a string of content and add it to the database.
  201. $count += $this->tokenizeToDB($ip, $group, $item->language, $format);
  202. // Check if we're approaching the memory limit of the token table.
  203. if ($count > static::$state->options->get('memory_table_limit', 30000))
  204. {
  205. $this->toggleTables(false);
  206. }
  207. }
  208. }
  209. else
  210. {
  211. // If the group is path, we need to a few extra processing
  212. // steps to strip the extension and convert slashes and dashes
  213. // to spaces.
  214. if ($group === static::PATH_CONTEXT)
  215. {
  216. $item->$property = JFile::stripExt($item->$property);
  217. $item->$property = str_replace('/', ' ', $item->$property);
  218. $item->$property = str_replace('-', ' ', $item->$property);
  219. }
  220. // Tokenize a string of content and add it to the database.
  221. $count += $this->tokenizeToDB($item->$property, $group, $item->language, $format);
  222. // Check if we're approaching the memory limit of the token table.
  223. if ($count > static::$state->options->get('memory_table_limit', 30000))
  224. {
  225. $this->toggleTables(false);
  226. }
  227. }
  228. }
  229. }
  230. /*
  231. * Process the item's taxonomy. The items can customize their
  232. * taxonomy mappings to define extra properties to map.
  233. */
  234. foreach ($item->getTaxonomy() as $branch => $nodes)
  235. {
  236. // Iterate through the nodes and map them to the branch.
  237. foreach ($nodes as $node)
  238. {
  239. // Add the node to the tree.
  240. $nodeId = FinderIndexerTaxonomy::addNode($branch, $node->title, $node->state, $node->access);
  241. // Add the link => node map.
  242. FinderIndexerTaxonomy::addMap($linkId, $nodeId);
  243. // Tokenize the node title and add them to the database.
  244. $count += $this->tokenizeToDB($node->title, static::META_CONTEXT, $item->language, $format);
  245. }
  246. }
  247. // Mark afterProcessing in the profiler.
  248. static::$profiler ? static::$profiler->mark('afterProcessing') : null;
  249. /*
  250. * At this point, all of the item's content has been parsed, tokenized
  251. * and inserted into the #__finder_tokens table. Now, we need to
  252. * aggregate all the data into that table into a more usable form. The
  253. * aggregated data will be inserted into #__finder_tokens_aggregate
  254. * table.
  255. */
  256. $query = 'INSERT INTO ' . $db->quoteName('#__finder_tokens_aggregate') .
  257. ' (' . $db->quoteName('term_id') .
  258. ', ' . $db->quoteName('term') .
  259. ', ' . $db->quoteName('stem') .
  260. ', ' . $db->quoteName('common') .
  261. ', ' . $db->quoteName('phrase') .
  262. ', ' . $db->quoteName('term_weight') .
  263. ', ' . $db->quoteName('context') .
  264. ', ' . $db->quoteName('context_weight') .
  265. ', ' . $db->quoteName('language') . ')' .
  266. ' SELECT' .
  267. ' t.term_id, t1.term, t1.stem, t1.common, t1.phrase, t1.weight, t1.context, ' .
  268. ' ROUND( t1.weight * COUNT( t2.term ) * %F, 8 ) AS context_weight, t1.language' .
  269. ' FROM (' .
  270. ' SELECT DISTINCT t1.term, t1.stem, t1.common, t1.phrase, t1.weight, t1.context, t1.language' .
  271. ' FROM ' . $db->quoteName('#__finder_tokens') . ' AS t1' .
  272. ' WHERE t1.context = %d' .
  273. ' ) AS t1' .
  274. ' JOIN ' . $db->quoteName('#__finder_tokens') . ' AS t2 ON t2.term = t1.term' .
  275. ' LEFT JOIN ' . $db->quoteName('#__finder_terms') . ' AS t ON t.term = t1.term' .
  276. ' WHERE t2.context = %d' .
  277. ' GROUP BY t1.term' .
  278. ' ORDER BY t1.term DESC';
  279. // Iterate through the contexts and aggregate the tokens per context.
  280. foreach ($state->weights as $context => $multiplier)
  281. {
  282. // Run the query to aggregate the tokens for this context..
  283. $db->setQuery(sprintf($query, $multiplier, $context, $context));
  284. $db->execute();
  285. }
  286. // Mark afterAggregating in the profiler.
  287. static::$profiler ? static::$profiler->mark('afterAggregating') : null;
  288. /*
  289. * When we pulled down all of the aggregate data, we did a LEFT JOIN
  290. * over the terms table to try to find all the term ids that
  291. * already exist for our tokens. If any of the rows in the aggregate
  292. * table have a term of 0, then no term record exists for that
  293. * term so we need to add it to the terms table.
  294. */
  295. $db->setQuery(
  296. 'INSERT IGNORE INTO ' . $db->quoteName('#__finder_terms') .
  297. ' (' . $db->quoteName('term') .
  298. ', ' . $db->quoteName('stem') .
  299. ', ' . $db->quoteName('common') .
  300. ', ' . $db->quoteName('phrase') .
  301. ', ' . $db->quoteName('weight') .
  302. ', ' . $db->quoteName('soundex') .
  303. ', ' . $db->quoteName('language') . ')' .
  304. ' SELECT ta.term, ta.stem, ta.common, ta.phrase, ta.term_weight, SOUNDEX(ta.term), ta.language' .
  305. ' FROM ' . $db->quoteName('#__finder_tokens_aggregate') . ' AS ta' .
  306. ' WHERE ta.term_id = 0' .
  307. ' GROUP BY ta.term'
  308. );
  309. $db->execute();
  310. /*
  311. * Now, we just inserted a bunch of new records into the terms table
  312. * so we need to go back and update the aggregate table with all the
  313. * new term ids.
  314. */
  315. $query = $db->getQuery(true);
  316. $query->update($db->quoteName('#__finder_tokens_aggregate') . ' AS ta');
  317. $query->join('INNER', $db->quoteName('#__finder_terms') . ' AS t ON t.term = ta.term');
  318. $query->set('ta.term_id = t.term_id');
  319. $query->where('ta.term_id = 0');
  320. $db->setQuery($query);
  321. $db->execute();
  322. // Mark afterTerms in the profiler.
  323. static::$profiler ? static::$profiler->mark('afterTerms') : null;
  324. /*
  325. * After we've made sure that all of the terms are in the terms table
  326. * and the aggregate table has the correct term ids, we need to update
  327. * the links counter for each term by one.
  328. */
  329. $query->clear();
  330. $query->update($db->quoteName('#__finder_terms') . ' AS t');
  331. $query->join('INNER', $db->quoteName('#__finder_tokens_aggregate') . ' AS ta ON ta.term_id = t.term_id');
  332. $query->set('t.' . $db->quoteName('links') . ' = t.links + 1');
  333. $db->setQuery($query);
  334. $db->execute();
  335. // Mark afterTerms in the profiler.
  336. static::$profiler ? static::$profiler->mark('afterTerms') : null;
  337. /*
  338. * Before we can insert all of the mapping rows, we have to figure out
  339. * which mapping table the rows need to be inserted into. The mapping
  340. * table for each term is based on the first character of the md5 of
  341. * the first character of the term. In php, it would be expressed as
  342. * substr(md5(substr($token, 0, 1)), 0, 1)
  343. */
  344. $query->clear();
  345. $query->update($db->quoteName('#__finder_tokens_aggregate'));
  346. $query->set($db->quoteName('map_suffix') . ' = SUBSTR(MD5(SUBSTR(' . $db->quoteName('term') . ', 1, 1)), 1, 1)');
  347. $db->setQuery($query);
  348. $db->execute();
  349. /*
  350. * At this point, the aggregate table contains a record for each
  351. * term in each context. So, we're going to pull down all of that
  352. * data while grouping the records by term and add all of the
  353. * sub-totals together to arrive at the final total for each token for
  354. * this link. Then, we insert all of that data into the appropriate
  355. * mapping table.
  356. */
  357. for ($i = 0; $i <= 15; $i++)
  358. {
  359. // Get the mapping table suffix.
  360. $suffix = dechex($i);
  361. /*
  362. * We have to run this query 16 times, one for each link => term
  363. * mapping table.
  364. */
  365. $db->setQuery(
  366. 'INSERT INTO ' . $db->quoteName('#__finder_links_terms' . $suffix) .
  367. ' (' . $db->quoteName('link_id') .
  368. ', ' . $db->quoteName('term_id') .
  369. ', ' . $db->quoteName('weight') . ')' .
  370. ' SELECT ' . (int) $linkId . ', ' . $db->quoteName('term_id') . ',' .
  371. ' ROUND(SUM(' . $db->quoteName('context_weight') . '), 8)' .
  372. ' FROM ' . $db->quoteName('#__finder_tokens_aggregate') .
  373. ' WHERE ' . $db->quoteName('map_suffix') . ' = ' . $db->quote($suffix) .
  374. ' GROUP BY ' . $db->quoteName('term') .
  375. ' ORDER BY ' . $db->quoteName('term') . ' DESC'
  376. );
  377. $db->execute();
  378. }
  379. // Mark afterMapping in the profiler.
  380. static::$profiler ? static::$profiler->mark('afterMapping') : null;
  381. // Update the signature.
  382. $query->clear();
  383. $query->update($db->quoteName('#__finder_links'));
  384. $query->set($db->quoteName('md5sum') . ' = ' . $db->quote($curSig));
  385. $query->where($db->quoteName('link_id') . ' = ' . $db->quote($linkId));
  386. $db->setQuery($query);
  387. $db->execute();
  388. // Mark afterSigning in the profiler.
  389. static::$profiler ? static::$profiler->mark('afterSigning') : null;
  390. // Truncate the tokens tables.
  391. $db->truncateTable('#__finder_tokens');
  392. // Truncate the tokens aggregate table.
  393. $db->truncateTable('#__finder_tokens_aggregate');
  394. // Toggle the token tables back to memory tables.
  395. $this->toggleTables(true);
  396. // Mark afterTruncating in the profiler.
  397. static::$profiler ? static::$profiler->mark('afterTruncating') : null;
  398. return $linkId;
  399. }
  400. /**
  401. * Method to remove a link from the index.
  402. *
  403. * @param integer $linkId The id of the link.
  404. *
  405. * @return boolean True on success.
  406. *
  407. * @since 2.5
  408. * @throws Exception on database error.
  409. */
  410. public function remove($linkId)
  411. {
  412. $db = JFactory::getDBO();
  413. $query = $db->getQuery(true);
  414. // Get the indexer state.
  415. $state = static::getState();
  416. // Update the link counts and remove the mapping records.
  417. for ($i = 0; $i <= 15; $i++)
  418. {
  419. // Update the link counts for the terms.
  420. $query->update($db->quoteName('#__finder_terms') . ' AS t');
  421. $query->join('INNER', $db->quoteName('#__finder_links_terms' . dechex($i)) . ' AS m ON m.term_id = t.term_id');
  422. $query->set($db->quoteName('t'). '.' . $db->quoteName('links') . ' ='. $db->quoteName('t') .'.' . $db->quoteName('links') . ' - 1');
  423. $query->where($db->quoteName('m') . '.' . $db->quoteName('link_id') . ' = ' . $db->quote((int) $linkId));
  424. $db->setQuery($query);
  425. $db->execute();
  426. // Remove all records from the mapping tables.
  427. $query->clear();
  428. $query->delete();
  429. $query->from($db->quoteName('#__finder_links_terms' . dechex($i)));
  430. $query->where($db->quoteName('link_id') . ' = ' . (int) $linkId);
  431. $db->setQuery($query);
  432. $db->execute();
  433. }
  434. // Delete all orphaned terms.
  435. $query->clear();
  436. $query->delete();
  437. $query->from($db->quoteName('#__finder_terms'));
  438. $query->where($db->quoteName('links') . ' <= 0');
  439. $db->setQuery($query);
  440. $db->execute();
  441. // Delete the link from the index.
  442. $query->clear();
  443. $query->delete();
  444. $query->from($db->quoteName('#__finder_links'));
  445. $query->where($db->quoteName('link_id') . ' = ' . $db->quote((int) $linkId));
  446. $db->setQuery($query);
  447. $db->execute();
  448. // Remove the taxonomy maps.
  449. FinderIndexerTaxonomy::removeMaps($linkId);
  450. // Remove the orphaned taxonomy nodes.
  451. FinderIndexerTaxonomy::removeOrphanNodes();
  452. return true;
  453. }
  454. /**
  455. * Method to optimize the index. We use this method to remove unused terms
  456. * and any other optimizations that might be necessary.
  457. *
  458. * @return boolean True on success.
  459. *
  460. * @since 2.5
  461. * @throws Exception on database error.
  462. */
  463. public function optimize()
  464. {
  465. // Get the database object.
  466. $db = JFactory::getDBO();
  467. $query = $db->getQuery(true);
  468. // Delete all orphaned terms.
  469. $query->delete();
  470. $query->from($db->quoteName('#__finder_terms'));
  471. $query->where($db->quoteName('links') . ' <= 0');
  472. $db->setQuery($query);
  473. $db->execute();
  474. // Optimize the links table.
  475. $db->setQuery('OPTIMIZE TABLE ' . $db->quoteName('#__finder_links'));
  476. $db->execute();
  477. for ($i = 0; $i <= 15; $i++)
  478. {
  479. // Optimize the terms mapping table.
  480. $db->setQuery('OPTIMIZE TABLE ' . $db->quoteName('#__finder_links_terms' . dechex($i)));
  481. $db->execute();
  482. }
  483. // Optimize the terms mapping table.
  484. $db->setQuery('OPTIMIZE TABLE ' . $db->quoteName('#__finder_links_terms'));
  485. $db->execute();
  486. // Remove the orphaned taxonomy nodes.
  487. FinderIndexerTaxonomy::removeOrphanNodes();
  488. // Optimize the taxonomy mapping table.
  489. $db->setQuery('OPTIMIZE TABLE ' . $db->quoteName('#__finder_taxonomy_map'));
  490. $db->execute();
  491. return true;
  492. }
  493. /**
  494. * Method to add a set of tokens to the database.
  495. *
  496. * @param mixed $tokens An array or single FinderIndexerToken object.
  497. * @param mixed $context The context of the tokens. See context constants. [optional]
  498. *
  499. * @return integer The number of tokens inserted into the database.
  500. *
  501. * @since 2.5
  502. * @throws Exception on database error.
  503. */
  504. protected function addTokensToDB($tokens, $context = '')
  505. {
  506. // Get the database object.
  507. $db = JFactory::getDBO();
  508. $query = $db->getQuery(true);
  509. // Force tokens to an array.
  510. $tokens = is_array($tokens) ? $tokens : array($tokens);
  511. // Count the number of token values.
  512. $values = 0;
  513. // Iterate through the tokens to create SQL value sets.
  514. foreach ($tokens as $token)
  515. {
  516. $query->values(
  517. $db->quote($token->term) . ', '
  518. . $db->quote($token->stem) . ', '
  519. . (int) $token->common . ', '
  520. . (int) $token->phrase . ', '
  521. . (float) $token->weight . ', '
  522. . (int) $context . ', '
  523. . $db->quote($token->language)
  524. );
  525. $values++;
  526. }
  527. // Insert the tokens into the database.
  528. $query->insert($db->quoteName('#__finder_tokens'));
  529. $query->columns(
  530. array(
  531. $db->quoteName('term'),
  532. $db->quoteName('stem'),
  533. $db->quoteName('common'),
  534. $db->quoteName('phrase'),
  535. $db->quoteName('weight'),
  536. $db->quoteName('context'),
  537. $db->quoteName('language')
  538. )
  539. );
  540. $db->setQuery($query);
  541. $db->execute();
  542. return $values;
  543. }
  544. /**
  545. * Method to switch the token tables from Memory tables to MyISAM tables
  546. * when they are close to running out of memory.
  547. *
  548. * @param boolean $memory Flag to control how they should be toggled.
  549. *
  550. * @return boolean True on success.
  551. *
  552. * @since 2.5
  553. * @throws Exception on database error.
  554. */
  555. protected function toggleTables($memory)
  556. {
  557. static $state;
  558. // Get the database adapter.
  559. $db = JFactory::getDBO();
  560. // Check if we are setting the tables to the Memory engine.
  561. if ($memory === true && $state !== true)
  562. {
  563. // Set the tokens table to Memory.
  564. $db->setQuery('ALTER TABLE ' . $db->quoteName('#__finder_tokens') . ' ENGINE = MEMORY');
  565. $db->execute();
  566. // Set the tokens aggregate table to Memory.
  567. $db->setQuery('ALTER TABLE ' . $db->quoteName('#__finder_tokens_aggregate') . ' ENGINE = MEMORY');
  568. $db->execute();
  569. // Set the internal state.
  570. $state = $memory;
  571. }
  572. // We must be setting the tables to the MyISAM engine.
  573. elseif ($memory === false && $state !== false)
  574. {
  575. // Set the tokens table to MyISAM.
  576. $db->setQuery('ALTER TABLE ' . $db->quoteName('#__finder_tokens') . ' ENGINE = MYISAM');
  577. $db->execute();
  578. // Set the tokens aggregate table to MyISAM.
  579. $db->setQuery('ALTER TABLE ' . $db->quoteName('#__finder_tokens_aggregate') . ' ENGINE = MYISAM');
  580. $db->execute();
  581. // Set the internal state.
  582. $state = $memory;
  583. }
  584. return true;
  585. }
  586. }