Bug: Live query chart always zero
[phpmyadmin/tyronm.git] / libraries / Tracker.class.php
blobe71b7d601e06fd2cb4a29761835cb38938674d7d
1 <?php
2 /* vim: set expandtab sw=4 ts=4 sts=4: */
3 /**
5 * @package phpMyAdmin
6 */
8 /**
9 * This class tracks changes on databases, tables and views.
10 * For more information please see phpMyAdmin/Documentation.html
12 * @package phpMyAdmin
14 * @todo use stristr instead of strstr
16 class PMA_Tracker
18 /**
19 * Whether tracking is ready.
21 static protected $enabled = false;
23 /**
24 * Defines the internal PMA table which contains tracking data.
26 * @access protected
27 * @var string
29 static protected $pma_table;
31 /**
32 * Defines the usage of DROP TABLE statment in SQL dumps.
34 * @access protected
35 * @var boolean
37 static protected $add_drop_table;
39 /**
40 * Defines the usage of DROP VIEW statment in SQL dumps.
42 * @access protected
43 * @var boolean
45 static protected $add_drop_view;
47 /**
48 * Defines the usage of DROP DATABASE statment in SQL dumps.
50 * @access protected
51 * @var boolean
53 static protected $add_drop_database;
55 /**
56 * Defines auto-creation of tracking versions.
58 * @var boolean
60 static protected $version_auto_create;
62 /**
63 * Defines the default set of tracked statements.
65 * @var string
67 static protected $default_tracking_set;
69 /**
70 * Initializes settings. See phpMyAdmin/Documentation.html.
72 * @static
74 * @return nothing
76 static public function init()
78 self::$pma_table = PMA_backquote($GLOBALS['cfg']['Server']['pmadb']) .".".
79 PMA_backquote($GLOBALS['cfg']['Server']['tracking']);
81 self::$add_drop_table = $GLOBALS['cfg']['Server']['tracking_add_drop_table'];
83 self::$add_drop_view = $GLOBALS['cfg']['Server']['tracking_add_drop_view'];
85 self::$add_drop_database = $GLOBALS['cfg']['Server']['tracking_add_drop_database'];
87 self::$default_tracking_set = $GLOBALS['cfg']['Server']['tracking_default_statements'];
89 self::$version_auto_create = $GLOBALS['cfg']['Server']['tracking_version_auto_create'];
92 /**
93 * Actually enables tracking. This needs to be done after all
94 * underlaying code is initialized.
96 * @static
98 * @return nothing
100 static public function enable()
102 self::$enabled = true;
106 * Gets the on/off value of the Tracker module, starts initialization.
108 * @static
110 * @return boolean (true=on|false=off)
112 static public function isActive()
114 if (! self::$enabled) {
115 return false;
117 /* We need to avoid attempt to track any queries from PMA_getRelationsParam */
118 self::$enabled = false;
119 $cfgRelation = PMA_getRelationsParam();
120 /* Restore original state */
121 self::$enabled = true;
122 if (! $cfgRelation['trackingwork']) {
123 return false;
125 self::init();
127 if (isset(self::$pma_table)) {
128 return true;
129 } else {
130 return false;
135 * Parses the name of a table from a SQL statement substring.
137 * @param string $string part of SQL statement
139 * @static
141 * @return string the name of table
143 static protected function getTableName($string)
145 if (strstr($string, '.')) {
146 $temp = explode('.', $string);
147 $tablename = $temp[1];
148 } else {
149 $tablename = $string;
152 $str = explode("\n", $tablename);
153 $tablename = $str[0];
155 $tablename = str_replace(';', '', $tablename);
156 $tablename = str_replace('`', '', $tablename);
157 $tablename = trim($tablename);
159 return $tablename;
164 * Gets the tracking status of a table, is it active or deactive ?
166 * @param string $dbname name of database
167 * @param string $tablename name of table
169 * @static
171 * @return boolean true or false
173 static public function isTracked($dbname, $tablename)
175 if (! self::$enabled) {
176 return false;
178 /* We need to avoid attempt to track any queries from PMA_getRelationsParam */
179 self::$enabled = false;
180 $cfgRelation = PMA_getRelationsParam();
181 /* Restore original state */
182 self::$enabled = true;
183 if (! $cfgRelation['trackingwork']) {
184 return false;
187 $sql_query = " SELECT tracking_active FROM " . self::$pma_table .
188 " WHERE db_name = '" . PMA_sqlAddSlashes($dbname) . "' " .
189 " AND table_name = '" . PMA_sqlAddSlashes($tablename) . "' " .
190 " ORDER BY version DESC";
192 $row = PMA_DBI_fetch_array(PMA_query_as_controluser($sql_query));
194 if (isset($row['tracking_active']) && $row['tracking_active'] == 1) {
195 return true;
196 } else {
197 return false;
202 * Returns the comment line for the log.
204 * @return string Comment, contains date and username
206 static public function getLogComment()
208 $date = date('Y-m-d H:i:s');
210 return "# log " . $date . " " . $GLOBALS['cfg']['Server']['user'] . "\n";
214 * Creates tracking version of a table / view
215 * (in other words: create a job to track future changes on the table).
217 * @param string $dbname name of database
218 * @param string $tablename name of table
219 * @param string $version version
220 * @param string $tracking_set set of tracking statements
221 * @param bool $is_view if table is a view
223 * @static
225 * @return int result of version insertion
227 static public function createVersion($dbname, $tablename, $version, $tracking_set = '', $is_view = false)
229 global $sql_backquotes;
231 if ($tracking_set == '') {
232 $tracking_set = self::$default_tracking_set;
235 include_once './libraries/export/sql.php';
237 $sql_backquotes = true;
239 $date = date('Y-m-d H:i:s');
241 // Get data definition snapshot of table
243 $columns = PMA_DBI_get_columns($dbname, $tablename, true);
244 // int indices to reduce size
245 $columns = array_values($columns);
246 // remove Privileges to reduce size
247 for ($i = 0; $i < count($columns); $i++) {
248 unset($columns[$i]['Privileges']);
251 $sql_query = '
252 SHOW INDEX FROM ' . PMA_backquote($dbname) . '.' . PMA_backquote($tablename);
254 $sql_result = PMA_DBI_query($sql_query);
256 $indexes = array();
258 while ($row = PMA_DBI_fetch_assoc($sql_result)) {
259 $indexes[] = $row;
262 $snapshot = array('COLUMNS' => $columns, 'INDEXES' => $indexes);
263 $snapshot = serialize($snapshot);
265 // Get DROP TABLE / DROP VIEW and CREATE TABLE SQL statements
266 $sql_backquotes = true;
268 $create_sql = "";
270 if (self::$add_drop_table == true && $is_view == false) {
271 $create_sql .= self::getLogComment() .
272 'DROP TABLE IF EXISTS ' . PMA_backquote($tablename) . ";\n";
276 if (self::$add_drop_view == true && $is_view == true) {
277 $create_sql .= self::getLogComment() .
278 'DROP VIEW IF EXISTS ' . PMA_backquote($tablename) . ";\n";
281 $create_sql .= self::getLogComment() .
282 PMA_getTableDef($dbname, $tablename, "\n", "");
284 // Save version
286 $sql_query = "/*NOTRACK*/\n" .
287 "INSERT INTO" . self::$pma_table . " (" .
288 "db_name, " .
289 "table_name, " .
290 "version, " .
291 "date_created, " .
292 "date_updated, " .
293 "schema_snapshot, " .
294 "schema_sql, " .
295 "data_sql, " .
296 "tracking " .
297 ") " .
298 "values (
299 '" . PMA_sqlAddSlashes($dbname) . "',
300 '" . PMA_sqlAddSlashes($tablename) . "',
301 '" . PMA_sqlAddSlashes($version) . "',
302 '" . PMA_sqlAddSlashes($date) . "',
303 '" . PMA_sqlAddSlashes($date) . "',
304 '" . PMA_sqlAddSlashes($snapshot) . "',
305 '" . PMA_sqlAddSlashes($create_sql) . "',
306 '" . PMA_sqlAddSlashes("\n") . "',
307 '" . PMA_sqlAddSlashes($tracking_set) . "' )";
309 $result = PMA_query_as_controluser($sql_query);
311 if ($result) {
312 // Deactivate previous version
313 self::deactivateTracking($dbname, $tablename, ($version - 1));
316 return $result;
321 * Removes all tracking data for a table
323 * @param string $dbname name of database
324 * @param string $tablename name of table
326 * @static
328 * @return int result of version insertion
330 static public function deleteTracking($dbname, $tablename)
332 $sql_query = "/*NOTRACK*/\n" .
333 "DELETE FROM " . self::$pma_table . " WHERE `db_name` = '" . PMA_sqlAddSlashes($dbname) . "' AND `table_name` = '" . PMA_sqlAddSlashes($tablename) . "'";
334 $result = PMA_query_as_controluser($sql_query);
336 return $result;
340 * Creates tracking version of a database
341 * (in other words: create a job to track future changes on the database).
343 * @param string $dbname name of database
344 * @param string $version version
345 * @param string $query query
346 * @param string $tracking_set set of tracking statements
348 * @static
350 * @return int result of version insertion
352 static public function createDatabaseVersion($dbname, $version, $query, $tracking_set = 'CREATE DATABASE,ALTER DATABASE,DROP DATABASE')
354 $date = date('Y-m-d H:i:s');
356 if ($tracking_set == '') {
357 $tracking_set = self::$default_tracking_set;
360 include_once './libraries/export/sql.php';
362 $create_sql = "";
364 if (self::$add_drop_database == true) {
365 $create_sql .= self::getLogComment() .
366 'DROP DATABASE IF EXISTS ' . PMA_backquote($dbname) . ";\n";
369 $create_sql .= self::getLogComment() . $query;
371 // Save version
372 $sql_query = "/*NOTRACK*/\n" .
373 "INSERT INTO" . self::$pma_table . " (" .
374 "db_name, " .
375 "table_name, " .
376 "version, " .
377 "date_created, " .
378 "date_updated, " .
379 "schema_snapshot, " .
380 "schema_sql, " .
381 "data_sql, " .
382 "tracking " .
383 ") " .
384 "values (
385 '" . PMA_sqlAddSlashes($dbname) . "',
386 '" . PMA_sqlAddSlashes('') . "',
387 '" . PMA_sqlAddSlashes($version) . "',
388 '" . PMA_sqlAddSlashes($date) . "',
389 '" . PMA_sqlAddSlashes($date) . "',
390 '" . PMA_sqlAddSlashes('') . "',
391 '" . PMA_sqlAddSlashes($create_sql) . "',
392 '" . PMA_sqlAddSlashes("\n") . "',
393 '" . PMA_sqlAddSlashes($tracking_set) . "' )";
395 $result = PMA_query_as_controluser($sql_query);
397 return $result;
403 * Changes tracking of a table.
405 * @param string $dbname name of database
406 * @param string $tablename name of table
407 * @param string $version version
408 * @param integer $new_state the new state of tracking
410 * @static
412 * @return int result of SQL query
414 static private function _changeTracking($dbname, $tablename, $version, $new_state)
416 $sql_query = " UPDATE " . self::$pma_table .
417 " SET `tracking_active` = '" . $new_state . "' " .
418 " WHERE `db_name` = '" . PMA_sqlAddSlashes($dbname) . "' " .
419 " AND `table_name` = '" . PMA_sqlAddSlashes($tablename) . "' " .
420 " AND `version` = '" . PMA_sqlAddSlashes($version) . "' ";
422 $result = PMA_query_as_controluser($sql_query);
424 return $result;
428 * Changes tracking data of a table.
430 * @param string $dbname name of database
431 * @param string $tablename name of table
432 * @param string $version version
433 * @param string $type type of data(DDL || DML)
434 * @param string|array $new_data the new tracking data
436 * @static
438 * @return bool result of change
440 static public function changeTrackingData($dbname, $tablename, $version, $type, $new_data)
442 if ($type == 'DDL') {
443 $save_to = 'schema_sql';
444 } elseif ($type == 'DML') {
445 $save_to = 'data_sql';
446 } else {
447 return false;
449 $date = date('Y-m-d H:i:s');
451 $new_data_processed = '';
452 if (is_array($new_data)) {
453 foreach ($new_data as $data) {
454 $new_data_processed .= '# log ' . $date . ' ' . $data['username']
455 . PMA_sqlAddSlashes($data['statement']) . "\n";
457 } else {
458 $new_data_processed = $new_data;
461 $sql_query = " UPDATE " . self::$pma_table .
462 " SET `" . $save_to . "` = '" . $new_data_processed . "' " .
463 " WHERE `db_name` = '" . PMA_sqlAddSlashes($dbname) . "' " .
464 " AND `table_name` = '" . PMA_sqlAddSlashes($tablename) . "' " .
465 " AND `version` = '" . PMA_sqlAddSlashes($version) . "' ";
467 $result = PMA_query_as_controluser($sql_query);
469 return $result;
473 * Activates tracking of a table.
475 * @param string $dbname name of database
476 * @param string $tablename name of table
477 * @param string $version version
479 * @static
481 * @return int result of SQL query
483 static public function activateTracking($dbname, $tablename, $version)
485 return self::_changeTracking($dbname, $tablename, $version, 1);
490 * Deactivates tracking of a table.
492 * @param string $dbname name of database
493 * @param string $tablename name of table
494 * @param string $version version
496 * @static
498 * @return int result of SQL query
500 static public function deactivateTracking($dbname, $tablename, $version)
502 return self::_changeTracking($dbname, $tablename, $version, 0);
507 * Gets the newest version of a tracking job
508 * (in other words: gets the HEAD version).
510 * @param string $dbname name of database
511 * @param string $tablename name of table
512 * @param string $statement tracked statement
514 * @static
516 * @return int (-1 if no version exists | > 0 if a version exists)
518 static public function getVersion($dbname, $tablename, $statement = null)
520 $sql_query = " SELECT MAX(version) FROM " . self::$pma_table .
521 " WHERE `db_name` = '" . PMA_sqlAddSlashes($dbname) . "' " .
522 " AND `table_name` = '" . PMA_sqlAddSlashes($tablename) . "' ";
524 if ($statement != "") {
525 $sql_query .= " AND FIND_IN_SET('" . $statement . "',tracking) > 0" ;
527 $row = PMA_DBI_fetch_array(PMA_query_as_controluser($sql_query));
528 return isset($row[0])
529 ? $row[0]
530 : -1;
535 * Gets the record of a tracking job.
537 * @param string $dbname name of database
538 * @param string $tablename name of table
539 * @param string $version version number
541 * @static
543 * @return mixed record DDM log, DDL log, structure snapshot, tracked statements.
545 static public function getTrackedData($dbname, $tablename, $version)
547 if (! isset(self::$pma_table)) {
548 self::init();
550 $sql_query = " SELECT * FROM " . self::$pma_table .
551 " WHERE `db_name` = '" . PMA_sqlAddSlashes($dbname) . "' ";
552 if (! empty($tablename)) {
553 $sql_query .= " AND `table_name` = '" . PMA_sqlAddSlashes($tablename) ."' ";
555 $sql_query .= " AND `version` = '" . PMA_sqlAddSlashes($version) ."' ".
556 " ORDER BY `version` DESC LIMIT 1";
558 $mixed = PMA_DBI_fetch_assoc(PMA_query_as_controluser($sql_query));
560 // Parse log
561 $log_schema_entries = explode('# log ', $mixed['schema_sql']);
562 $log_data_entries = explode('# log ', $mixed['data_sql']);
564 $ddl_date_from = $date = date('Y-m-d H:i:s');
566 $ddlog = array();
567 $i = 0;
569 // Iterate tracked data definition statements
570 // For each log entry we want to get date, username and statement
571 foreach ($log_schema_entries as $log_entry) {
572 if (trim($log_entry) != '') {
573 $date = substr($log_entry, 0, 19);
574 $username = substr($log_entry, 20, strpos($log_entry, "\n") - 20);
575 if ($i == 0) {
576 $ddl_date_from = $date;
578 $statement = rtrim(strstr($log_entry, "\n"));
580 $ddlog[] = array( 'date' => $date,
581 'username'=> $username,
582 'statement' => $statement );
583 $i++;
587 $date_from = $ddl_date_from;
588 $date_to = $ddl_date_to = $date;
590 $dml_date_from = $date_from;
592 $dmlog = array();
593 $i = 0;
595 // Iterate tracked data manipulation statements
596 // For each log entry we want to get date, username and statement
597 foreach ($log_data_entries as $log_entry) {
598 if (trim($log_entry) != '') {
599 $date = substr($log_entry, 0, 19);
600 $username = substr($log_entry, 20, strpos($log_entry, "\n") - 20);
601 if ($i == 0) {
602 $dml_date_from = $date;
604 $statement = rtrim(strstr($log_entry, "\n"));
606 $dmlog[] = array( 'date' => $date,
607 'username' => $username,
608 'statement' => $statement );
609 $i++;
613 $dml_date_to = $date;
615 // Define begin and end of date range for both logs
616 if (strtotime($ddl_date_from) <= strtotime($dml_date_from)) {
617 $data['date_from'] = $ddl_date_from;
618 } else {
619 $data['date_from'] = $dml_date_from;
621 if (strtotime($ddl_date_to) >= strtotime($dml_date_to)) {
622 $data['date_to'] = $ddl_date_to;
623 } else {
624 $data['date_to'] = $dml_date_to;
626 $data['ddlog'] = $ddlog;
627 $data['dmlog'] = $dmlog;
628 $data['tracking'] = $mixed['tracking'];
629 $data['schema_snapshot'] = $mixed['schema_snapshot'];
631 return $data;
636 * Parses a query. Gets
637 * - statement identifier (UPDATE, ALTER TABLE, ...)
638 * - type of statement, is it part of DDL or DML ?
639 * - tablename
641 * @param string $query query
643 * @static
644 * @todo: using PMA SQL Parser when possible
645 * @todo: support multi-table/view drops
647 * @return mixed Array containing identifier, type and tablename.
650 static public function parseQuery($query)
653 // Usage of PMA_SQP does not work here
655 // require_once("libraries/sqlparser.lib.php");
656 // $parsed_sql = PMA_SQP_parse($query);
657 // $sql_info = PMA_SQP_analyze($parsed_sql);
659 $query = str_replace("\n", " ", $query);
660 $query = str_replace("\r", " ", $query);
662 $query = trim($query);
663 $query = trim($query, ' -');
665 $tokens = explode(" ", $query);
666 $tokens = array_map('strtoupper', $tokens);
668 // Parse USE statement, need it for SQL dump imports
669 if (substr($query, 0, 4) == 'USE ') {
670 $prefix = explode('USE ', $query);
671 $GLOBALS['db'] = self::getTableName($prefix[1]);
675 * DDL statements
678 $result['type'] = 'DDL';
680 // Parse CREATE VIEW statement
681 if (in_array('CREATE', $tokens) == true
682 && in_array('VIEW', $tokens) == true
683 && in_array('AS', $tokens) == true
685 $result['identifier'] = 'CREATE VIEW';
687 $index = array_search('VIEW', $tokens);
689 $result['tablename'] = strtolower(self::getTableName($tokens[$index + 1]));
692 // Parse ALTER VIEW statement
693 if (in_array('ALTER', $tokens) == true
694 && in_array('VIEW', $tokens) == true
695 && in_array('AS', $tokens) == true
696 && ! isset($result['identifier'])
698 $result['identifier'] = 'ALTER VIEW';
700 $index = array_search('VIEW', $tokens);
702 $result['tablename'] = strtolower(self::getTableName($tokens[$index + 1]));
705 // Parse DROP VIEW statement
706 if (! isset($result['identifier']) && substr($query, 0, 10) == 'DROP VIEW ') {
707 $result['identifier'] = 'DROP VIEW';
709 $prefix = explode('DROP VIEW ', $query);
710 $str = strstr($prefix[1], 'IF EXISTS');
712 if ($str == false ) {
713 $str = $prefix[1];
715 $result['tablename'] = self::getTableName($str);
718 // Parse CREATE DATABASE statement
719 if (! isset($result['identifier']) && substr($query, 0, 15) == 'CREATE DATABASE') {
720 $result['identifier'] = 'CREATE DATABASE';
721 $str = str_replace('CREATE DATABASE', '', $query);
722 $str = str_replace('IF NOT EXISTS', '', $str);
724 $prefix = explode('DEFAULT ', $str);
726 $result['tablename'] = '';
727 $GLOBALS['db'] = self::getTableName($prefix[0]);
730 // Parse ALTER DATABASE statement
731 if (! isset($result['identifier']) && substr($query, 0, 14) == 'ALTER DATABASE') {
732 $result['identifier'] = 'ALTER DATABASE';
733 $result['tablename'] = '';
736 // Parse DROP DATABASE statement
737 if (! isset($result['identifier']) && substr($query, 0, 13) == 'DROP DATABASE') {
738 $result['identifier'] = 'DROP DATABASE';
739 $str = str_replace('DROP DATABASE', '', $query);
740 $str = str_replace('IF EXISTS', '', $str);
741 $GLOBALS['db'] = self::getTableName($str);
742 $result['tablename'] = '';
745 // Parse CREATE TABLE statement
746 if (! isset($result['identifier']) && substr($query, 0, 12) == 'CREATE TABLE' ) {
747 $result['identifier'] = 'CREATE TABLE';
748 $query = str_replace('IF NOT EXISTS', '', $query);
749 $prefix = explode('CREATE TABLE ', $query);
750 $suffix = explode('(', $prefix[1]);
751 $result['tablename'] = self::getTableName($suffix[0]);
754 // Parse ALTER TABLE statement
755 if (! isset($result['identifier']) && substr($query, 0, 12) == 'ALTER TABLE ') {
756 $result['identifier'] = 'ALTER TABLE';
758 $prefix = explode('ALTER TABLE ', $query);
759 $suffix = explode(' ', $prefix[1]);
760 $result['tablename'] = self::getTableName($suffix[0]);
763 // Parse DROP TABLE statement
764 if (! isset($result['identifier']) && substr($query, 0, 11) == 'DROP TABLE ') {
765 $result['identifier'] = 'DROP TABLE';
767 $prefix = explode('DROP TABLE ', $query);
768 $str = strstr($prefix[1], 'IF EXISTS');
770 if ($str == false ) {
771 $str = $prefix[1];
773 $result['tablename'] = self::getTableName($str);
776 // Parse CREATE INDEX statement
777 if (! isset($result['identifier'])
778 && (substr($query, 0, 12) == 'CREATE INDEX'
779 || substr($query, 0, 19) == 'CREATE UNIQUE INDEX'
780 || substr($query, 0, 20) == 'CREATE SPATIAL INDEX')
782 $result['identifier'] = 'CREATE INDEX';
783 $prefix = explode('ON ', $query);
784 $suffix = explode('(', $prefix[1]);
785 $result['tablename'] = self::getTableName($suffix[0]);
788 // Parse DROP INDEX statement
789 if (! isset($result['identifier']) && substr($query, 0, 10) == 'DROP INDEX') {
790 $result['identifier'] = 'DROP INDEX';
791 $prefix = explode('ON ', $query);
792 $result['tablename'] = self::getTableName($prefix[1]);
795 // Parse RENAME TABLE statement
796 if (! isset($result['identifier']) && substr($query, 0, 13) == 'RENAME TABLE ') {
797 $result['identifier'] = 'RENAME TABLE';
798 $prefix = explode('RENAME TABLE ', $query);
799 $names = explode(' TO ', $prefix[1]);
800 $result['tablename'] = self::getTableName($names[0]);
801 $result["tablename_after_rename"] = self::getTableName($names[1]);
805 * DML statements
808 if (! isset($result['identifier'])) {
809 $result["type"] = 'DML';
811 // Parse UPDATE statement
812 if (! isset($result['identifier']) && substr($query, 0, 6) == 'UPDATE') {
813 $result['identifier'] = 'UPDATE';
814 $prefix = explode('UPDATE ', $query);
815 $suffix = explode(' ', $prefix[1]);
816 $result['tablename'] = self::getTableName($suffix[0]);
819 // Parse INSERT INTO statement
820 if (! isset($result['identifier']) && substr($query, 0, 11) == 'INSERT INTO') {
821 $result['identifier'] = 'INSERT';
822 $prefix = explode('INSERT INTO', $query);
823 $suffix = explode('(', $prefix[1]);
824 $result['tablename'] = self::getTableName($suffix[0]);
827 // Parse DELETE statement
828 if (! isset($result['identifier']) && substr($query, 0, 6) == 'DELETE') {
829 $result['identifier'] = 'DELETE';
830 $prefix = explode('FROM ', $query);
831 $suffix = explode(' ', $prefix[1]);
832 $result['tablename'] = self::getTableName($suffix[0]);
835 // Parse TRUNCATE statement
836 if (! isset($result['identifier']) && substr($query, 0, 8) == 'TRUNCATE') {
837 $result['identifier'] = 'TRUNCATE';
838 $prefix = explode('TRUNCATE', $query);
839 $result['tablename'] = self::getTableName($prefix[1]);
842 return $result;
847 * Analyzes a given SQL statement and saves tracking data.
849 * @param string $query a SQL query
851 * @static
853 * @return nothing
855 static public function handleQuery($query)
857 // If query is marked as untouchable, leave
858 if (strstr($query, "/*NOTRACK*/")) {
859 return;
862 if (! (substr($query, -1) == ';')) {
863 $query = $query . ";\n";
865 // Get some information about query
866 $result = self::parseQuery($query);
868 // Get database name
869 $dbname = trim($GLOBALS['db'], '`');
870 // $dbname can be empty, for example when coming from Synchronize
871 // and this is a query for the remote server
872 if (empty($dbname)) {
873 return;
876 // If we found a valid statement
877 if (isset($result['identifier'])) {
878 $version = self::getVersion($dbname, $result['tablename'], $result['identifier']);
880 // If version not exists and auto-creation is enabled
881 if (self::$version_auto_create == true
882 && self::isTracked($dbname, $result['tablename']) == false
883 && $version == -1
885 // Create the version
887 switch ($result['identifier']) {
888 case 'CREATE TABLE':
889 self::createVersion($dbname, $result['tablename'], '1');
890 break;
891 case 'CREATE VIEW':
892 self::createVersion($dbname, $result['tablename'], '1', '', true);
893 break;
894 case 'CREATE DATABASE':
895 self::createDatabaseVersion($dbname, '1', $query);
896 break;
897 } // end switch
900 // If version exists
901 if (self::isTracked($dbname, $result['tablename']) && $version != -1) {
902 if ($result['type'] == 'DDL') {
903 $save_to = 'schema_sql';
904 } elseif ($result['type'] == 'DML') {
905 $save_to = 'data_sql';
906 } else {
907 $save_to = '';
909 $date = date('Y-m-d H:i:s');
911 // Cut off `dbname`. from query
912 $query = preg_replace('/`' . $dbname . '`\s?\./', '', $query);
914 // Add log information
915 $query = self::getLogComment() . $query ;
917 // Mark it as untouchable
918 $sql_query = " /*NOTRACK*/\n" .
919 " UPDATE " . self::$pma_table .
920 " SET " . PMA_backquote($save_to) ." = CONCAT( " . PMA_backquote($save_to) . ",'\n"
921 . PMA_sqlAddSlashes($query) . "') ," . " `date_updated` = '" . $date . "' ";
923 // If table was renamed we have to change the tablename attribute in pma_tracking too
924 if ($result['identifier'] == 'RENAME TABLE') {
925 $sql_query .= ', `table_name` = \'' . PMA_sqlAddSlashes($result['tablename_after_rename']) . '\' ';
928 // Save the tracking information only for
929 // 1. the database
930 // 2. the table / view
931 // 3. the statements
932 // we want to track
933 $sql_query .=
934 " WHERE FIND_IN_SET('" . $result['identifier'] . "',tracking) > 0" .
935 " AND `db_name` = '" . PMA_sqlAddSlashes($dbname) . "' " .
936 " AND `table_name` = '" . PMA_sqlAddSlashes($result['tablename']) . "' " .
937 " AND `version` = '" . PMA_sqlAddSlashes($version) . "' ";
939 $result = PMA_query_as_controluser($sql_query);