Remove broken link
[phpmyadmin.git] / libraries / Tracker.php
blob9611632c7fe6f9d64e42312f6535abe554a97c96
1 <?php
2 /* vim: set expandtab sw=4 ts=4 sts=4: */
3 /**
4 * Tracking changes on databases, tables and views
6 * @package PhpMyAdmin
7 */
8 namespace PMA\libraries;
10 use PMA\libraries\plugins\export\ExportSql;
12 /**
13 * This class tracks changes on databases, tables and views.
15 * @package PhpMyAdmin
17 * @todo use stristr instead of strstr
19 class Tracker
21 /**
22 * Whether tracking is ready.
24 static protected $enabled = false;
26 /**
27 * Cache to avoid quering tracking status multiple times.
29 static protected $_tracking_cache = array();
31 /**
32 * Actually enables tracking. This needs to be done after all
33 * underlaying code is initialized.
35 * @static
37 * @return void
39 static public function enable()
41 self::$enabled = true;
44 /**
45 * Gets the on/off value of the Tracker module, starts initialization.
47 * @static
49 * @return boolean (true=on|false=off)
51 static public function isActive()
53 if (! self::$enabled) {
54 return false;
56 /* We need to avoid attempt to track any queries
57 * from PMA_getRelationsParam
59 self::$enabled = false;
60 $cfgRelation = PMA_getRelationsParam();
61 /* Restore original state */
62 self::$enabled = true;
63 if (! $cfgRelation['trackingwork']) {
64 return false;
67 $pma_table = self::_getTrackingTable();
68 if (isset($pma_table)) {
69 return true;
70 } else {
71 return false;
75 /**
76 * Parses the name of a table from a SQL statement substring.
78 * @param string $string part of SQL statement
80 * @static
82 * @return string the name of table
84 static protected function getTableName($string)
86 if (mb_strstr($string, '.')) {
87 $temp = explode('.', $string);
88 $tablename = $temp[1];
89 } else {
90 $tablename = $string;
93 $str = explode("\n", $tablename);
94 $tablename = $str[0];
96 $tablename = str_replace(';', '', $tablename);
97 $tablename = str_replace('`', '', $tablename);
98 $tablename = trim($tablename);
100 return $tablename;
105 * Gets the tracking status of a table, is it active or deactive ?
107 * @param string $dbname name of database
108 * @param string $tablename name of table
110 * @static
112 * @return boolean true or false
114 static public function isTracked($dbname, $tablename)
116 if (! self::$enabled) {
117 return false;
120 if (isset(self::$_tracking_cache[$dbname][$tablename])) {
121 return self::$_tracking_cache[$dbname][$tablename];
123 /* We need to avoid attempt to track any queries
124 * from PMA_getRelationsParam
126 self::$enabled = false;
127 $cfgRelation = PMA_getRelationsParam();
128 /* Restore original state */
129 self::$enabled = true;
130 if (! $cfgRelation['trackingwork']) {
131 return false;
134 $sql_query = " SELECT tracking_active FROM " . self::_getTrackingTable() .
135 " WHERE db_name = '" . $GLOBALS['dbi']->escapeString($dbname) . "' " .
136 " AND table_name = '" . $GLOBALS['dbi']->escapeString($tablename) . "' " .
137 " ORDER BY version DESC LIMIT 1";
139 $result = $GLOBALS['dbi']->fetchValue($sql_query, 0, 0, $GLOBALS['controllink']) == 1;
141 self::$_tracking_cache[$dbname][$tablename] = $result;
143 return $result;
147 * Returns the comment line for the log.
149 * @return string Comment, contains date and username
151 static public function getLogComment()
153 $date = date('Y-m-d H:i:s');
154 $user = preg_replace('/\s+/', ' ', $GLOBALS['cfg']['Server']['user']);
156 return "# log " . $date . " " . $user . "\n";
160 * Creates tracking version of a table / view
161 * (in other words: create a job to track future changes on the table).
163 * @param string $dbname name of database
164 * @param string $tablename name of table
165 * @param string $version version
166 * @param string $tracking_set set of tracking statements
167 * @param bool $is_view if table is a view
169 * @static
171 * @return int result of version insertion
173 static public function createVersion($dbname, $tablename, $version,
174 $tracking_set = '', $is_view = false
176 global $sql_backquotes, $export_type;
178 if ($tracking_set == '') {
179 $tracking_set
180 = $GLOBALS['cfg']['Server']['tracking_default_statements'];
183 // get Export SQL instance
184 include_once "libraries/plugin_interface.lib.php";
185 /* @var $export_sql_plugin \PMA\libraries\plugins\export\ExportSql */
186 $export_sql_plugin = PMA_getPlugin(
187 "export",
188 "sql",
189 'libraries/plugins/export/',
190 array(
191 'export_type' => $export_type,
192 'single_table' => false,
196 $sql_backquotes = true;
198 $date = date('Y-m-d H:i:s');
200 // Get data definition snapshot of table
202 $columns = $GLOBALS['dbi']->getColumns($dbname, $tablename, null, true);
203 // int indices to reduce size
204 $columns = array_values($columns);
205 // remove Privileges to reduce size
206 for ($i = 0, $nb = count($columns); $i < $nb; $i++) {
207 unset($columns[$i]['Privileges']);
210 $indexes = $GLOBALS['dbi']->getTableIndexes($dbname, $tablename);
212 $snapshot = array('COLUMNS' => $columns, 'INDEXES' => $indexes);
213 $snapshot = serialize($snapshot);
215 // Get DROP TABLE / DROP VIEW and CREATE TABLE SQL statements
216 $sql_backquotes = true;
218 $create_sql = "";
220 if ($GLOBALS['cfg']['Server']['tracking_add_drop_table'] == true
221 && $is_view == false
223 $create_sql .= self::getLogComment()
224 . 'DROP TABLE IF EXISTS ' . Util::backquote($tablename) . ";\n";
228 if ($GLOBALS['cfg']['Server']['tracking_add_drop_view'] == true
229 && $is_view == true
231 $create_sql .= self::getLogComment()
232 . 'DROP VIEW IF EXISTS ' . Util::backquote($tablename) . ";\n";
235 $create_sql .= self::getLogComment() .
236 $export_sql_plugin->getTableDef($dbname, $tablename, "\n", "");
238 // Save version
240 $sql_query = "/*NOTRACK*/\n" .
241 "INSERT INTO " . self::_getTrackingTable() . " (" .
242 "db_name, " .
243 "table_name, " .
244 "version, " .
245 "date_created, " .
246 "date_updated, " .
247 "schema_snapshot, " .
248 "schema_sql, " .
249 "data_sql, " .
250 "tracking " .
251 ") " .
252 "values (
253 '" . $GLOBALS['dbi']->escapeString($dbname) . "',
254 '" . $GLOBALS['dbi']->escapeString($tablename) . "',
255 '" . $GLOBALS['dbi']->escapeString($version) . "',
256 '" . $GLOBALS['dbi']->escapeString($date) . "',
257 '" . $GLOBALS['dbi']->escapeString($date) . "',
258 '" . $GLOBALS['dbi']->escapeString($snapshot) . "',
259 '" . $GLOBALS['dbi']->escapeString($create_sql) . "',
260 '" . $GLOBALS['dbi']->escapeString("\n") . "',
261 '" . $GLOBALS['dbi']->escapeString($tracking_set)
262 . "' )";
264 $result = PMA_queryAsControlUser($sql_query);
266 if ($result) {
267 // Deactivate previous version
268 self::deactivateTracking($dbname, $tablename, ($version - 1));
271 return $result;
276 * Removes all tracking data for a table or a version of a table
278 * @param string $dbname name of database
279 * @param string $tablename name of table
280 * @param string $version version
282 * @static
284 * @return int result of version insertion
286 static public function deleteTracking($dbname, $tablename, $version = '')
288 $sql_query = "/*NOTRACK*/\n"
289 . "DELETE FROM " . self::_getTrackingTable()
290 . " WHERE `db_name` = '"
291 . $GLOBALS['dbi']->escapeString($dbname) . "'"
292 . " AND `table_name` = '"
293 . $GLOBALS['dbi']->escapeString($tablename) . "'";
294 if ($version) {
295 $sql_query .= " AND `version` = '"
296 . $GLOBALS['dbi']->escapeString($version) . "'";
298 $result = PMA_queryAsControlUser($sql_query);
300 return $result;
304 * Creates tracking version of a database
305 * (in other words: create a job to track future changes on the database).
307 * @param string $dbname name of database
308 * @param string $version version
309 * @param string $query query
310 * @param string $tracking_set set of tracking statements
312 * @static
314 * @return int result of version insertion
316 static public function createDatabaseVersion($dbname, $version, $query,
317 $tracking_set = 'CREATE DATABASE,ALTER DATABASE,DROP DATABASE'
319 $date = date('Y-m-d H:i:s');
321 if ($tracking_set == '') {
322 $tracking_set
323 = $GLOBALS['cfg']['Server']['tracking_default_statements'];
326 $create_sql = "";
328 if ($GLOBALS['cfg']['Server']['tracking_add_drop_database'] == true) {
329 $create_sql .= self::getLogComment()
330 . 'DROP DATABASE IF EXISTS ' . Util::backquote($dbname) . ";\n";
333 $create_sql .= self::getLogComment() . $query;
335 // Save version
336 $sql_query = "/*NOTRACK*/\n" .
337 "INSERT INTO " . self::_getTrackingTable() . " (" .
338 "db_name, " .
339 "table_name, " .
340 "version, " .
341 "date_created, " .
342 "date_updated, " .
343 "schema_snapshot, " .
344 "schema_sql, " .
345 "data_sql, " .
346 "tracking " .
347 ") " .
348 "values (
349 '" . $GLOBALS['dbi']->escapeString($dbname) . "',
350 '" . $GLOBALS['dbi']->escapeString('') . "',
351 '" . $GLOBALS['dbi']->escapeString($version) . "',
352 '" . $GLOBALS['dbi']->escapeString($date) . "',
353 '" . $GLOBALS['dbi']->escapeString($date) . "',
354 '" . $GLOBALS['dbi']->escapeString('') . "',
355 '" . $GLOBALS['dbi']->escapeString($create_sql) . "',
356 '" . $GLOBALS['dbi']->escapeString("\n") . "',
357 '" . $GLOBALS['dbi']->escapeString($tracking_set)
358 . "' )";
360 $result = PMA_queryAsControlUser($sql_query);
362 return $result;
368 * Changes tracking of a table.
370 * @param string $dbname name of database
371 * @param string $tablename name of table
372 * @param string $version version
373 * @param integer $new_state the new state of tracking
375 * @static
377 * @return int result of SQL query
379 static private function _changeTracking($dbname, $tablename,
380 $version, $new_state
383 $sql_query = " UPDATE " . self::_getTrackingTable() .
384 " SET `tracking_active` = '" . $new_state . "' " .
385 " WHERE `db_name` = '" . $GLOBALS['dbi']->escapeString($dbname) . "' " .
386 " AND `table_name` = '" . $GLOBALS['dbi']->escapeString($tablename) . "' " .
387 " AND `version` = '" . $GLOBALS['dbi']->escapeString($version) . "' ";
389 $result = PMA_queryAsControlUser($sql_query);
391 return $result;
395 * Changes tracking data of a table.
397 * @param string $dbname name of database
398 * @param string $tablename name of table
399 * @param string $version version
400 * @param string $type type of data(DDL || DML)
401 * @param string|array $new_data the new tracking data
403 * @static
405 * @return bool result of change
407 static public function changeTrackingData($dbname, $tablename,
408 $version, $type, $new_data
410 if ($type == 'DDL') {
411 $save_to = 'schema_sql';
412 } elseif ($type == 'DML') {
413 $save_to = 'data_sql';
414 } else {
415 return false;
417 $date = date('Y-m-d H:i:s');
419 $new_data_processed = '';
420 if (is_array($new_data)) {
421 foreach ($new_data as $data) {
422 $new_data_processed .= '# log ' . $date . ' ' . $data['username']
423 . $GLOBALS['dbi']->escapeString($data['statement']) . "\n";
425 } else {
426 $new_data_processed = $new_data;
429 $sql_query = " UPDATE " . self::_getTrackingTable() .
430 " SET `" . $save_to . "` = '" . $new_data_processed . "' " .
431 " WHERE `db_name` = '" . $GLOBALS['dbi']->escapeString($dbname) . "' " .
432 " AND `table_name` = '" . $GLOBALS['dbi']->escapeString($tablename) . "' " .
433 " AND `version` = '" . $GLOBALS['dbi']->escapeString($version) . "' ";
435 $result = PMA_queryAsControlUser($sql_query);
437 return (boolean) $result;
441 * Activates tracking of a table.
443 * @param string $dbname name of database
444 * @param string $tablename name of table
445 * @param string $version version
447 * @static
449 * @return int result of SQL query
451 static public function activateTracking($dbname, $tablename, $version)
453 return self::_changeTracking($dbname, $tablename, $version, 1);
458 * Deactivates tracking of a table.
460 * @param string $dbname name of database
461 * @param string $tablename name of table
462 * @param string $version version
464 * @static
466 * @return int result of SQL query
468 static public function deactivateTracking($dbname, $tablename, $version)
470 return self::_changeTracking($dbname, $tablename, $version, 0);
475 * Gets the newest version of a tracking job
476 * (in other words: gets the HEAD version).
478 * @param string $dbname name of database
479 * @param string $tablename name of table
480 * @param string $statement tracked statement
482 * @static
484 * @return int (-1 if no version exists | > 0 if a version exists)
486 static public function getVersion($dbname, $tablename, $statement = null)
488 $sql_query = " SELECT MAX(version) FROM " . self::_getTrackingTable() .
489 " WHERE `db_name` = '" . $GLOBALS['dbi']->escapeString($dbname) . "' " .
490 " AND `table_name` = '" . $GLOBALS['dbi']->escapeString($tablename) . "' ";
492 if ($statement != "") {
493 $sql_query .= " AND FIND_IN_SET('"
494 . $statement . "',tracking) > 0" ;
496 $row = $GLOBALS['dbi']->fetchArray(PMA_queryAsControlUser($sql_query));
497 return isset($row[0])
498 ? $row[0]
499 : -1;
504 * Gets the record of a tracking job.
506 * @param string $dbname name of database
507 * @param string $tablename name of table
508 * @param string $version version number
510 * @static
512 * @return mixed record DDM log, DDL log, structure snapshot, tracked
513 * statements.
515 static public function getTrackedData($dbname, $tablename, $version)
517 $sql_query = " SELECT * FROM " . self::_getTrackingTable() .
518 " WHERE `db_name` = '" . $GLOBALS['dbi']->escapeString($dbname) . "' ";
519 if (! empty($tablename)) {
520 $sql_query .= " AND `table_name` = '"
521 . $GLOBALS['dbi']->escapeString($tablename) . "' ";
523 $sql_query .= " AND `version` = '" . $GLOBALS['dbi']->escapeString($version)
524 . "' " . " ORDER BY `version` DESC LIMIT 1";
526 $mixed = $GLOBALS['dbi']->fetchAssoc(PMA_queryAsControlUser($sql_query));
528 // Parse log
529 $log_schema_entries = explode('# log ', $mixed['schema_sql']);
530 $log_data_entries = explode('# log ', $mixed['data_sql']);
532 $ddl_date_from = $date = date('Y-m-d H:i:s');
534 $ddlog = array();
535 $first_iteration = true;
537 // Iterate tracked data definition statements
538 // For each log entry we want to get date, username and statement
539 foreach ($log_schema_entries as $log_entry) {
540 if (trim($log_entry) != '') {
541 $date = mb_substr($log_entry, 0, 19);
542 $username = mb_substr(
543 $log_entry, 20, mb_strpos($log_entry, "\n") - 20
545 if ($first_iteration) {
546 $ddl_date_from = $date;
547 $first_iteration = false;
549 $statement = rtrim(mb_strstr($log_entry, "\n"));
551 $ddlog[] = array( 'date' => $date,
552 'username'=> $username,
553 'statement' => $statement );
557 $date_from = $ddl_date_from;
558 $ddl_date_to = $date;
560 $dml_date_from = $date_from;
562 $dmlog = array();
563 $first_iteration = true;
565 // Iterate tracked data manipulation statements
566 // For each log entry we want to get date, username and statement
567 foreach ($log_data_entries as $log_entry) {
568 if (trim($log_entry) != '') {
569 $date = mb_substr($log_entry, 0, 19);
570 $username = mb_substr(
571 $log_entry, 20, mb_strpos($log_entry, "\n") - 20
573 if ($first_iteration) {
574 $dml_date_from = $date;
575 $first_iteration = false;
577 $statement = rtrim(mb_strstr($log_entry, "\n"));
579 $dmlog[] = array( 'date' => $date,
580 'username' => $username,
581 'statement' => $statement );
585 $dml_date_to = $date;
587 // Define begin and end of date range for both logs
588 $data = array();
589 if (strtotime($ddl_date_from) <= strtotime($dml_date_from)) {
590 $data['date_from'] = $ddl_date_from;
591 } else {
592 $data['date_from'] = $dml_date_from;
594 if (strtotime($ddl_date_to) >= strtotime($dml_date_to)) {
595 $data['date_to'] = $ddl_date_to;
596 } else {
597 $data['date_to'] = $dml_date_to;
599 $data['ddlog'] = $ddlog;
600 $data['dmlog'] = $dmlog;
601 $data['tracking'] = $mixed['tracking'];
602 $data['schema_snapshot'] = $mixed['schema_snapshot'];
604 return $data;
609 * Parses a query. Gets
610 * - statement identifier (UPDATE, ALTER TABLE, ...)
611 * - type of statement, is it part of DDL or DML ?
612 * - tablename
614 * @param string $query query
616 * @static
617 * @todo: using PMA SQL Parser when possible
618 * @todo: support multi-table/view drops
620 * @return mixed Array containing identifier, type and tablename.
623 static public function parseQuery($query)
625 // Usage of PMA_SQP does not work here
627 // require_once("libraries/sqlparser.lib.php");
628 // $parsed_sql = PMA_SQP_parse($query);
629 // $sql_info = PMA_SQP_analyze($parsed_sql);
631 $parser = new \PhpMyAdmin\SqlParser\Parser($query);
633 $tokens = $parser->list->tokens;
635 // Parse USE statement, need it for SQL dump imports
636 if ($tokens[0]->value == 'USE') {
637 $GLOBALS['db'] = $tokens[2]->value;
640 $result = array();
642 if (!empty($parser->statements)) {
643 $statement = $parser->statements[0];
644 $options = isset($statement->options) ? $statement->options->options : null;
647 * DDL statements
649 $result['type'] = 'DDL';
651 // Parse CREATE statement
652 if ($statement instanceof \PhpMyAdmin\SqlParser\Statements\CreateStatement) {
653 if (empty($options) || !isset($options[6])) {
654 return $result;
657 if ($options[6] == 'VIEW' || $options[6] == 'TABLE') {
658 $result['identifier'] = 'CREATE ' . $options[6];
659 $result['tablename'] = $statement->name->table ;
660 } elseif ($options[6] == 'DATABASE') {
661 $result['identifier'] = 'CREATE DATABASE' ;
662 $result['tablename'] = '' ;
664 // In case of CREATE DATABASE, table field of the CreateStatement is actually name of the database
665 $GLOBALS['db'] = $statement->name->table;
666 } elseif ($options[6] == 'INDEX'
667 || $options[6] == 'UNIQUE INDEX'
668 || $options[6] == 'FULLTEXT INDEX'
669 || $options[6] == 'SPATIAL INDEX'
671 $result['identifier'] = 'CREATE INDEX';
673 // In case of CREATE INDEX, we have to get the table name from body of the statement
674 $result['tablename'] = $statement->body[3]->value == '.' ? $statement->body[4]->value
675 : $statement->body[2]->value ;
679 // Parse ALTER statement
680 elseif ($statement instanceof \PhpMyAdmin\SqlParser\Statements\AlterStatement) {
681 if (empty($options) || !isset($options[3])) {
682 return $result;
685 if ($options[3] == 'VIEW' || $options[3] == 'TABLE') {
686 $result['identifier'] = 'ALTER ' . $options[3] ;
687 $result['tablename'] = $statement->table->table ;
688 } elseif ($options[3] == 'DATABASE') {
689 $result['identifier'] = 'ALTER DATABASE' ;
690 $result['tablename'] = '' ;
692 $GLOBALS['db'] = $statement->table->table ;
696 // Parse DROP statement
697 elseif ($statement instanceof \PhpMyAdmin\SqlParser\Statements\DropStatement) {
698 if (empty($options) || !isset($options[1])) {
699 return $result;
702 if ($options[1] == 'VIEW' || $options[1] == 'TABLE') {
703 $result['identifier'] = 'DROP ' . $options[1] ;
704 $result['tablename'] = $statement->fields[0]->table;
705 } elseif ($options[1] == 'DATABASE') {
706 $result['identifier'] = 'DROP DATABASE' ;
707 $result['tablename'] = '';
709 $GLOBALS['db'] = $statement->fields[0]->table;
710 } elseif ($options[1] == 'INDEX') {
711 $result['identifier'] = 'DROP INDEX' ;
712 $result['tablename'] = $statement->table->table;
716 // Prase RENAME statement
717 elseif ($statement instanceof \PhpMyAdmin\SqlParser\Statements\RenameStatement) {
718 $result['identifier'] = 'RENAME TABLE';
719 $result['tablename'] = $statement->renames[0]->old->table;
720 $result['tablename_after_rename'] = $statement->renames[0]->new->table;
723 if (isset($result['identifier'])) {
724 return $result ;
728 * DML statements
730 $result['type'] = 'DML';
732 // Parse UPDATE statement
733 if ($statement instanceof \PhpMyAdmin\SqlParser\Statements\UpdateStatement) {
734 $result['identifier'] = 'UPDATE';
735 $result['tablename'] = $statement->tables[0]->table;
738 // Parse INSERT INTO statement
739 if ($statement instanceof \PhpMyAdmin\SqlParser\Statements\InsertStatement) {
740 $result['identifier'] = 'INSERT';
741 $result['tablename'] = $statement->into->dest->table;
744 // Parse DELETE statement
745 if ($statement instanceof \PhpMyAdmin\SqlParser\Statements\DeleteStatement) {
746 $result['identifier'] = 'DELETE';
747 $result['tablename'] = $statement->from[0]->table;
750 // Parse TRUNCATE statement
751 if ($statement instanceof \PhpMyAdmin\SqlParser\Statements\TruncateStatement) {
752 $result['identifier'] = 'TRUNCATE' ;
753 $result['tablename'] = $statement->table->table;
757 return $result;
762 * Analyzes a given SQL statement and saves tracking data.
764 * @param string $query a SQL query
766 * @static
768 * @return void
770 static public function handleQuery($query)
772 // If query is marked as untouchable, leave
773 if (mb_strstr($query, "/*NOTRACK*/")) {
774 return;
777 if (! (substr($query, -1) == ';')) {
778 $query = $query . ";\n";
780 // Get some information about query
781 $result = self::parseQuery($query);
783 // Get database name
784 $dbname = trim(isset($GLOBALS['db']) ? $GLOBALS['db'] : '', '`');
785 // $dbname can be empty, for example when coming from Synchronize
786 // and this is a query for the remote server
787 if (empty($dbname)) {
788 return;
791 // If we found a valid statement
792 if (isset($result['identifier'])) {
793 if (! self::isTracked($dbname, $result['tablename'])) {
794 return;
797 $version = self::getVersion(
798 $dbname, $result['tablename'], $result['identifier']
801 // If version not exists and auto-creation is enabled
802 if ($GLOBALS['cfg']['Server']['tracking_version_auto_create'] == true
803 && $version == -1
805 // Create the version
807 switch ($result['identifier']) {
808 case 'CREATE TABLE':
809 self::createVersion($dbname, $result['tablename'], '1');
810 break;
811 case 'CREATE VIEW':
812 self::createVersion(
813 $dbname, $result['tablename'], '1', '', true
815 break;
816 case 'CREATE DATABASE':
817 self::createDatabaseVersion($dbname, '1', $query);
818 break;
819 } // end switch
822 // If version exists
823 if ($version != -1) {
824 if ($result['type'] == 'DDL') {
825 $save_to = 'schema_sql';
826 } elseif ($result['type'] == 'DML') {
827 $save_to = 'data_sql';
828 } else {
829 $save_to = '';
831 $date = date('Y-m-d H:i:s');
833 // Cut off `dbname`. from query
834 $query = preg_replace(
835 '/`' . preg_quote($dbname, '/') . '`\s?\./',
837 $query
840 // Add log information
841 $query = self::getLogComment() . $query ;
843 // Mark it as untouchable
844 $sql_query = " /*NOTRACK*/\n"
845 . " UPDATE " . self::_getTrackingTable()
846 . " SET " . Util::backquote($save_to)
847 . " = CONCAT( " . Util::backquote($save_to) . ",'\n"
848 . $GLOBALS['dbi']->escapeString($query) . "') ,"
849 . " `date_updated` = '" . $date . "' ";
851 // If table was renamed we have to change
852 // the tablename attribute in pma_tracking too
853 if ($result['identifier'] == 'RENAME TABLE') {
854 $sql_query .= ', `table_name` = \''
855 . $GLOBALS['dbi']->escapeString($result['tablename_after_rename'])
856 . '\' ';
859 // Save the tracking information only for
860 // 1. the database
861 // 2. the table / view
862 // 3. the statements
863 // we want to track
864 $sql_query .=
865 " WHERE FIND_IN_SET('" . $result['identifier'] . "',tracking) > 0" .
866 " AND `db_name` = '" . $GLOBALS['dbi']->escapeString($dbname) . "' " .
867 " AND `table_name` = '"
868 . $GLOBALS['dbi']->escapeString($result['tablename']) . "' " .
869 " AND `version` = '" . $GLOBALS['dbi']->escapeString($version) . "' ";
871 PMA_queryAsControlUser($sql_query);
877 * Returns the tracking table
879 * @return string tracking table
881 private static function _getTrackingTable()
883 $cfgRelation = PMA_getRelationsParam();
884 return Util::backquote($cfgRelation['db'])
885 . '.' . Util::backquote($cfgRelation['tracking']);