Improve translation.
[phpmyadmin/crack.git] / libraries / Table.class.php
blob82cc43c68bd6cda581b4c903c82fa9a11f774fe9
1 <?php
2 /* vim: set expandtab sw=4 ts=4 sts=4: */
3 /**
5 * @version $Id$
6 */
8 /**
9 * @todo make use of PMA_Message and PMA_Error
11 class PMA_Table {
13 /**
14 * @var string table name
16 var $name = '';
18 /**
19 * @var string database name
21 var $db_name = '';
23 /**
24 * @var string engine (innodb, myisam, bdb, ...)
26 var $engine = '';
28 /**
29 * @var string type (view, base table, system view)
31 var $type = '';
33 /**
34 * @var array settings
36 var $settings = array();
38 /**
39 * @var array errors occured
41 var $errors = array();
43 /**
44 * @var array messages
46 var $messages = array();
48 /**
49 * Constructor
51 * @param string $table_name table name
52 * @param string $db_name database name
54 function __construct($table_name, $db_name)
56 $this->setName($table_name);
57 $this->setDbName($db_name);
60 /**
61 * @see PMA_Table::getName()
63 function __toString()
65 return $this->getName();
68 function getLastError()
70 return end($this->errors);
73 function getLastMessage()
75 return end($this->messages);
78 /**
79 * sets table anme
81 * @uses $this->name to set it
82 * @param string $table_name new table name
84 function setName($table_name)
86 $this->name = $table_name;
89 /**
90 * returns table name
92 * @uses $this->name as return value
93 * @param boolean wether to quote name with backticks ``
94 * @return string table name
96 function getName($quoted = false)
98 if ($quoted) {
99 return PMA_backquote($this->name);
101 return $this->name;
105 * sets database name for this table
107 * @uses $this->db_name to set it
108 * @param string $db_name
110 function setDbName($db_name)
112 $this->db_name = $db_name;
116 * returns database name for this table
118 * @uses $this->db_name as return value
119 * @param boolean wether to quote name with backticks ``
120 * @return string database name for this table
122 function getDbName($quoted = false)
124 if ($quoted) {
125 return PMA_backquote($this->db_name);
127 return $this->db_name;
131 * returns full name for table, including database name
133 * @param boolean wether to quote name with backticks ``
135 function getFullName($quoted = false)
137 return $this->getDbName($quoted) . '.' . $this->getName($quoted);
140 static public function isView($db = null, $table = null)
142 if (strlen($db) && strlen($table)) {
143 return PMA_Table::_isView($db, $table);
146 if (isset($this) && strpos($this->get('TABLE TYPE'), 'VIEW')) {
147 return true;
150 return false;
154 * sets given $value for given $param
156 * @uses $this->settings to add or change value
157 * @param string param name
158 * @param mixed param value
160 function set($param, $value)
162 $this->settings[$param] = $value;
166 * returns value for given setting/param
168 * @uses $this->settings to return value
169 * @param string name for value to return
170 * @return mixed value for $param
172 function get($param)
174 if (isset($this->settings[$param])) {
175 return $this->settings[$param];
178 return null;
182 * loads structure data
184 function loadStructure()
186 $table_info = PMA_DBI_get_tables_full($this->getDbName(), $this->getName());
188 if (false === $table_info) {
189 return false;
192 $this->settings = $table_info;
194 if ($this->get('TABLE_ROWS') === null) {
195 $this->set('TABLE_ROWS', PMA_Table::countRecords($this->getDbName(),
196 $this->getName(), true, true));
199 $create_options = explode(' ', $this->get('TABLE_ROWS'));
201 // export create options by its name as variables into gloabel namespace
202 // f.e. pack_keys=1 becomes available as $pack_keys with value of '1'
203 foreach ($create_options as $each_create_option) {
204 $each_create_option = explode('=', $each_create_option);
205 if (isset($each_create_option[1])) {
206 $this->set($$each_create_option[0], $each_create_option[1]);
212 * Checks if this "table" is a view
214 * @deprecated
215 * @todo see what we could do with the possible existence of $table_is_view
216 * @param string the database name
217 * @param string the table name
219 * @return boolean whether this is a view
221 * @access public
223 static protected function _isView($db, $table)
225 // maybe we already know if the table is a view
226 if (isset($GLOBALS['tbl_is_view']) && $GLOBALS['tbl_is_view']) {
227 return true;
230 // This would be the correct way of doing the check but at least in
231 // MySQL 5.0.33 it's too slow when there are hundreds of databases
232 // and/or tables (more than 3 minutes for 400 tables)
233 /*if (false === PMA_DBI_fetch_value('SELECT TABLE_NAME FROM `information_schema`.`VIEWS` WHERE `TABLE_SCHEMA` = \'' . $db . '\' AND `TABLE_NAME` = \'' . $table . '\';')) {
234 return false;
235 } else {
236 return true;
237 } */
238 // A more complete verification would be to check if all columns
239 // from the result set are NULL except Name and Comment.
240 // MySQL from 5.0.0 to 5.0.12 returns 'view',
241 // from 5.0.13 returns 'VIEW'.
242 $comment = strtoupper(PMA_DBI_fetch_value('SHOW TABLE STATUS FROM ' . PMA_backquote($db) . ' LIKE \'' . $table . '\'', 0, 'Comment'));
243 // use substr() because the comment might contain something like:
244 // (VIEW 'BASE2.VTEST' REFERENCES INVALID TABLE(S) OR COLUMN(S) OR FUNCTION)
245 return (substr($comment, 0, 4) == 'VIEW');
249 * generates column/field specification for ALTER or CREATE TABLE syntax
251 * @todo move into class PMA_Column
252 * @todo on the interface, some js to clear the default value when the default
253 * current_timestamp is checked
254 * @static
255 * @param string $name name
256 * @param string $type type ('INT', 'VARCHAR', 'BIT', ...)
257 * @param string $length length ('2', '5,2', '', ...)
258 * @param string $attribute
259 * @param string $collation
260 * @param string $null with 'NULL' or 'NOT NULL'
261 * @param string $default default value
262 * @param boolean $default_current_timestamp whether default value is
263 * CURRENT_TIMESTAMP or not
264 * this overrides $default value
265 * @param string $extra 'AUTO_INCREMENT'
266 * @param string $comment field comment
267 * @param array &$field_primary list of fields for PRIMARY KEY
268 * @param string $index
269 * @param string $default_orig
270 * @return string field specification
272 static function generateFieldSpec($name, $type, $length = '', $attribute = '',
273 $collation = '', $null = false, $default = '',
274 $default_current_timestamp = false, $extra = '', $comment = '',
275 &$field_primary, $index, $default_orig = false)
278 $is_timestamp = strpos(' ' . strtoupper($type), 'TIMESTAMP') == 1;
280 // $default_current_timestamp has priority over $default
283 * @todo include db-name
285 $query = PMA_backquote($name) . ' ' . $type;
287 if ($length != ''
288 && !preg_match('@^(DATE|DATETIME|TIME|TINYBLOB|TINYTEXT|BLOB|TEXT|MEDIUMBLOB|MEDIUMTEXT|LONGBLOB|LONGTEXT)$@i', $type)) {
289 $query .= '(' . $length . ')';
292 if ($attribute != '') {
293 $query .= ' ' . $attribute;
296 if (!empty($collation) && $collation != 'NULL'
297 && preg_match('@^(TINYTEXT|TEXT|MEDIUMTEXT|LONGTEXT|VARCHAR|CHAR|ENUM|SET)$@i', $type)) {
298 $query .= PMA_generateCharsetQueryPart($collation);
301 if ($null !== false) {
302 if (!empty($null)) {
303 $query .= ' NOT NULL';
304 } else {
305 $query .= ' NULL';
309 if ($default_current_timestamp && $is_timestamp) {
310 $query .= ' DEFAULT CURRENT_TIMESTAMP';
311 // auto_increment field cannot have a default value
312 } elseif ($extra !== 'AUTO_INCREMENT'
313 && (strlen($default) || $default != $default_orig)) {
314 if (strtoupper($default) == 'NULL') {
315 $query .= ' DEFAULT NULL';
316 } else {
317 if (strlen($default)) {
318 if ($is_timestamp && $default == '0') {
319 // a TIMESTAMP does not accept DEFAULT '0'
320 // but DEFAULT 0 works
321 $query .= ' DEFAULT ' . PMA_sqlAddslashes($default);
322 } elseif ($default && $type == 'BIT') {
323 $query .= ' DEFAULT b\'' . preg_replace('/[^01]/', '0', $default) . '\'';
324 } else {
325 $query .= ' DEFAULT \'' . PMA_sqlAddslashes($default) . '\'';
331 if (!empty($extra)) {
332 $query .= ' ' . $extra;
333 // Force an auto_increment field to be part of the primary key
334 // even if user did not tick the PK box;
335 // but the PK could contain other columns so do not append
336 // a PRIMARY KEY clause, just add a member to $field_primary
337 if ($extra == 'AUTO_INCREMENT') {
338 $primary_cnt = count($field_primary);
339 $found_in_pk = false;
340 for ($j = 0; $j < $primary_cnt; $j++) {
341 if ($field_primary[$j] == $index) {
342 $found_in_pk = true;
343 break;
345 } // end for
346 if (! $found_in_pk) {
347 $field_primary[] = $index;
349 } // end if (auto_increment)
351 if (!empty($comment)) {
352 $query .= " COMMENT '" . PMA_sqlAddslashes($comment) . "'";
354 return $query;
355 } // end function
358 * Counts and returns (or displays) the number of records in a table
360 * Revision 13 July 2001: Patch for limiting dump size from
361 * vinay@sanisoft.com & girish@sanisoft.com
363 * @param string the current database name
364 * @param string the current table name
365 * @param boolean whether to retain or to displays the result
366 * @param boolean whether to force an exact count
368 * @return mixed the number of records if retain is required, true else
370 * @access public
372 static public function countRecords($db, $table, $ret = false, $force_exact = false)
374 $row_count = false;
376 if (! $force_exact) {
377 $row_count = PMA_DBI_fetch_value(
378 'SHOW TABLE STATUS FROM ' . PMA_backquote($db) . ' LIKE \''
379 . PMA_sqlAddslashes($table, true) . '\';',
380 0, 'Rows');
383 $tbl_is_view = PMA_Table::isView($db, $table);
385 // for a VIEW, $row_count is always false at this point
386 if (false === $row_count || $row_count < $GLOBALS['cfg']['MaxExactCount']) {
387 if (! $tbl_is_view) {
388 $row_count = PMA_DBI_fetch_value(
389 'SELECT COUNT(*) FROM ' . PMA_backquote($db) . '.'
390 . PMA_backquote($table));
391 } else {
392 // For complex views, even trying to get a partial record
393 // count could bring down a server, so we offer an
394 // alternative: setting MaxExactCountViews to 0 will bypass
395 // completely the record counting for views
397 if ($GLOBALS['cfg']['MaxExactCountViews'] == 0) {
398 $row_count = 0;
399 } else {
400 // Counting all rows of a VIEW could be too long, so use
401 // a LIMIT clause.
402 // Use try_query because it can fail (a VIEW is based on
403 // a table that no longer exists)
404 $result = PMA_DBI_try_query(
405 'SELECT 1 FROM ' . PMA_backquote($db) . '.'
406 . PMA_backquote($table) . ' LIMIT '
407 . $GLOBALS['cfg']['MaxExactCountViews'],
408 null, PMA_DBI_QUERY_STORE);
409 if (!PMA_DBI_getError()) {
410 $row_count = PMA_DBI_num_rows($result);
411 PMA_DBI_free_result($result);
417 if ($ret) {
418 return $row_count;
422 * @deprecated at the moment nowhere is $return = false used
424 // Note: as of PMA 2.8.0, we no longer seem to be using
425 // PMA_Table::countRecords() in display mode.
426 echo PMA_formatNumber($row_count, 0);
427 if ($tbl_is_view) {
428 echo '&nbsp;'
429 . sprintf($GLOBALS['strViewMaxExactCount'],
430 $GLOBALS['cfg']['MaxExactCount'],
431 '[a@./Documentation.html#cfg_MaxExactCount@_blank]', '[/a]');
433 } // end of the 'PMA_Table::countRecords()' function
436 * @todo add documentation
438 static public function generateAlter($oldcol, $newcol, $type, $length,
439 $attribute, $collation, $null, $default, $default_current_timestamp,
440 $extra, $comment='', $default_orig)
442 $empty_a = array();
443 return PMA_backquote($oldcol) . ' '
444 . PMA_Table::generateFieldSpec($newcol, $type, $length, $attribute,
445 $collation, $null, $default, $default_current_timestamp, $extra,
446 $comment, $empty_a, -1, $default_orig);
447 } // end function
450 * Inserts existing entries in a PMA_* table by reading a value from an old entry
452 * @param string The array index, which Relation feature to check
453 * ('relwork', 'commwork', ...)
454 * @param string The array index, which PMA-table to update
455 * ('bookmark', 'relation', ...)
456 * @param array Which fields will be SELECT'ed from the old entry
457 * @param array Which fields will be used for the WHERE query
458 * (array('FIELDNAME' => 'FIELDVALUE'))
459 * @param array Which fields will be used as new VALUES. These are the important
460 * keys which differ from the old entry.
461 * (array('FIELDNAME' => 'NEW FIELDVALUE'))
463 * @global string relation variable
465 * @author Garvin Hicking <me@supergarv.de>
467 static public function duplicateInfo($work, $pma_table, $get_fields, $where_fields,
468 $new_fields)
470 $last_id = -1;
472 if (isset($GLOBALS['cfgRelation']) && $GLOBALS['cfgRelation'][$work]) {
473 $select_parts = array();
474 $row_fields = array();
475 foreach ($get_fields as $get_field) {
476 $select_parts[] = PMA_backquote($get_field);
477 $row_fields[$get_field] = 'cc';
480 $where_parts = array();
481 foreach ($where_fields as $_where => $_value) {
482 $where_parts[] = PMA_backquote($_where) . ' = \''
483 . PMA_sqlAddslashes($_value) . '\'';
486 $new_parts = array();
487 $new_value_parts = array();
488 foreach ($new_fields as $_where => $_value) {
489 $new_parts[] = PMA_backquote($_where);
490 $new_value_parts[] = PMA_sqlAddslashes($_value);
493 $table_copy_query = '
494 SELECT ' . implode(', ', $select_parts) . '
495 FROM ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.'
496 . PMA_backquote($GLOBALS['cfgRelation'][$pma_table]) . '
497 WHERE ' . implode(' AND ', $where_parts);
499 // must use PMA_DBI_QUERY_STORE here, since we execute another
500 // query inside the loop
501 $table_copy_rs = PMA_query_as_cu($table_copy_query, true,
502 PMA_DBI_QUERY_STORE);
504 while ($table_copy_row = @PMA_DBI_fetch_assoc($table_copy_rs)) {
505 $value_parts = array();
506 foreach ($table_copy_row as $_key => $_val) {
507 if (isset($row_fields[$_key]) && $row_fields[$_key] == 'cc') {
508 $value_parts[] = PMA_sqlAddslashes($_val);
512 $new_table_query = '
513 INSERT IGNORE INTO ' . PMA_backquote($GLOBALS['cfgRelation']['db'])
514 . '.' . PMA_backquote($GLOBALS['cfgRelation'][$pma_table]) . '
515 (' . implode(', ', $select_parts) . ',
516 ' . implode(', ', $new_parts) . ')
517 VALUES
518 (\'' . implode('\', \'', $value_parts) . '\',
519 \'' . implode('\', \'', $new_value_parts) . '\')';
521 PMA_query_as_cu($new_table_query);
522 $last_id = PMA_DBI_insert_id();
523 } // end while
525 PMA_DBI_free_result($table_copy_rs);
527 return $last_id;
530 return true;
531 } // end of 'PMA_Table::duplicateInfo()' function
535 * Copies or renames table
536 * @todo use RENAME for move operations
537 * - would work only if the databases are on the same filesystem,
538 * how can we check that? try the operation and
539 * catch an error?
540 * - for views, only if MYSQL > 50013
541 * - still have to handle pmadb synch.
543 * @author Michal Cihar <michal@cihar.com>
545 static public function moveCopy($source_db, $source_table, $target_db, $target_table, $what, $move, $mode)
547 global $err_url;
549 // set export settings we need
550 $GLOBALS['sql_backquotes'] = 1;
551 $GLOBALS['asfile'] = 1;
553 // Ensure the target is valid
554 if (! $GLOBALS['PMA_List_Database']->exists($source_db, $target_db)) {
555 if (! $GLOBALS['PMA_List_Database']->exists($source_db)) {
556 $GLOBALS['message'] = PMA_Message::rawError('source database `'
557 . htmlspecialchars($source_db) . '` not found');
559 if (! $GLOBALS['PMA_List_Database']->exists($target_db)) {
560 $GLOBALS['message'] = PMA_Message::rawError('target database `'
561 . htmlspecialchars($target_db) . '` not found');
563 return false;
566 $source = PMA_backquote($source_db) . '.' . PMA_backquote($source_table);
567 if (! isset($target_db) || ! strlen($target_db)) {
568 $target_db = $source_db;
571 // Doing a select_db could avoid some problems with replicated databases,
572 // when moving table from replicated one to not replicated one
573 PMA_DBI_select_db($target_db);
575 $target = PMA_backquote($target_db) . '.' . PMA_backquote($target_table);
577 // do not create the table if dataonly
578 if ($what != 'dataonly') {
579 require_once './libraries/export/sql.php';
581 $no_constraints_comments = true;
582 $GLOBALS['sql_constraints_query'] = '';
584 $sql_structure = PMA_getTableDef($source_db, $source_table, "\n", $err_url);
585 unset($no_constraints_comments);
586 $parsed_sql = PMA_SQP_parse($sql_structure);
587 $analyzed_sql = PMA_SQP_analyze($parsed_sql);
588 $i = 0;
589 if (empty($analyzed_sql[0]['create_table_fields'])) {
590 // this is not a CREATE TABLE, so find the first VIEW
591 $target_for_view = PMA_backquote($target_db);
592 while (true) {
593 if ($parsed_sql[$i]['type'] == 'alpha_reservedWord' && $parsed_sql[$i]['data'] == 'VIEW') {
594 break;
596 $i++;
599 unset($analyzed_sql);
601 /* nijel: Find table name in query and replace it */
602 while ($parsed_sql[$i]['type'] != 'quote_backtick') {
603 $i++;
606 /* no need to PMA_backquote() */
607 if (isset($target_for_view)) {
608 // this a view definition; we just found the first db name
609 // that follows DEFINER VIEW
610 // so change it for the new db name
611 $parsed_sql[$i]['data'] = $target_for_view;
612 // then we have to find all references to the source db
613 // and change them to the target db, ensuring we stay into
614 // the $parsed_sql limits
615 $last = $parsed_sql['len'] - 1;
616 $backquoted_source_db = PMA_backquote($source_db);
617 for (++$i; $i <= $last; $i++) {
618 if ($parsed_sql[$i]['type'] == 'quote_backtick' && $parsed_sql[$i]['data'] == $backquoted_source_db) {
619 $parsed_sql[$i]['data'] = $target_for_view;
622 unset($last,$backquoted_source_db);
623 } else {
624 $parsed_sql[$i]['data'] = $target;
627 /* Generate query back */
628 $sql_structure = PMA_SQP_formatHtml($parsed_sql, 'query_only');
629 // If table exists, and 'add drop table' is selected: Drop it!
630 $drop_query = '';
631 if (isset($GLOBALS['drop_if_exists'])
632 && $GLOBALS['drop_if_exists'] == 'true') {
633 if (PMA_Table::_isView($target_db,$target_table)) {
634 $drop_query = 'DROP VIEW';
635 } else {
636 $drop_query = 'DROP TABLE';
638 $drop_query .= ' IF EXISTS '
639 . PMA_backquote($target_db) . '.'
640 . PMA_backquote($target_table);
641 PMA_DBI_query($drop_query);
643 $GLOBALS['sql_query'] .= "\n" . $drop_query . ';';
645 // garvin: If an existing table gets deleted, maintain any
646 // entries for the PMA_* tables
647 $maintain_relations = true;
650 @PMA_DBI_query($sql_structure);
651 $GLOBALS['sql_query'] .= "\n" . $sql_structure . ';';
653 if (($move || isset($GLOBALS['add_constraints']))
654 && !empty($GLOBALS['sql_constraints_query'])) {
655 $parsed_sql = PMA_SQP_parse($GLOBALS['sql_constraints_query']);
656 $i = 0;
658 // find the first quote_backtick, it must be the source table name
659 while ($parsed_sql[$i]['type'] != 'quote_backtick') {
660 $i++;
661 // maybe someday we should guard against going over limit
662 //if ($i == $parsed_sql['len']) {
663 // break;
667 // replace it by the target table name, no need to PMA_backquote()
668 $parsed_sql[$i]['data'] = $target;
670 // now we must remove all quote_backtick that follow a CONSTRAINT
671 // keyword, because a constraint name must be unique in a db
673 $cnt = $parsed_sql['len'] - 1;
675 for ($j = $i; $j < $cnt; $j++) {
676 if ($parsed_sql[$j]['type'] == 'alpha_reservedWord'
677 && strtoupper($parsed_sql[$j]['data']) == 'CONSTRAINT') {
678 if ($parsed_sql[$j+1]['type'] == 'quote_backtick') {
679 $parsed_sql[$j+1]['data'] = '';
684 // Generate query back
685 $GLOBALS['sql_constraints_query'] = PMA_SQP_formatHtml($parsed_sql,
686 'query_only');
687 if ($mode == 'one_table') {
688 PMA_DBI_query($GLOBALS['sql_constraints_query']);
690 $GLOBALS['sql_query'] .= "\n" . $GLOBALS['sql_constraints_query'];
691 if ($mode == 'one_table') {
692 unset($GLOBALS['sql_constraints_query']);
695 } else {
696 $GLOBALS['sql_query'] = '';
699 // Copy the data unless this is a VIEW
700 if (($what == 'data' || $what == 'dataonly') && ! PMA_Table::_isView($target_db,$target_table)) {
701 $sql_insert_data =
702 'INSERT INTO ' . $target . ' SELECT * FROM ' . $source;
703 PMA_DBI_query($sql_insert_data);
704 $GLOBALS['sql_query'] .= "\n\n" . $sql_insert_data . ';';
707 require_once './libraries/relation.lib.php';
708 $GLOBALS['cfgRelation'] = PMA_getRelationsParam();
710 // Drops old table if the user has requested to move it
711 if ($move) {
713 // This could avoid some problems with replicated databases, when
714 // moving table from replicated one to not replicated one
715 PMA_DBI_select_db($source_db);
717 if (PMA_Table::_isView($source_db,$source_table)) {
718 $sql_drop_query = 'DROP VIEW';
719 } else {
720 $sql_drop_query = 'DROP TABLE';
722 $sql_drop_query .= ' ' . $source;
723 PMA_DBI_query($sql_drop_query);
725 // garvin: Move old entries from PMA-DBs to new table
726 if ($GLOBALS['cfgRelation']['commwork']) {
727 $remove_query = 'UPDATE ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.' . PMA_backquote($GLOBALS['cfgRelation']['column_info'])
728 . ' SET table_name = \'' . PMA_sqlAddslashes($target_table) . '\', '
729 . ' db_name = \'' . PMA_sqlAddslashes($target_db) . '\''
730 . ' WHERE db_name = \'' . PMA_sqlAddslashes($source_db) . '\''
731 . ' AND table_name = \'' . PMA_sqlAddslashes($source_table) . '\'';
732 PMA_query_as_cu($remove_query);
733 unset($remove_query);
736 // garvin: updating bookmarks is not possible since only a single table is moved,
737 // and not the whole DB.
739 if ($GLOBALS['cfgRelation']['displaywork']) {
740 $table_query = 'UPDATE ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.' . PMA_backquote($GLOBALS['cfgRelation']['table_info'])
741 . ' SET db_name = \'' . PMA_sqlAddslashes($target_db) . '\', '
742 . ' table_name = \'' . PMA_sqlAddslashes($target_table) . '\''
743 . ' WHERE db_name = \'' . PMA_sqlAddslashes($source_db) . '\''
744 . ' AND table_name = \'' . PMA_sqlAddslashes($source_table) . '\'';
745 PMA_query_as_cu($table_query);
746 unset($table_query);
749 if ($GLOBALS['cfgRelation']['relwork']) {
750 $table_query = 'UPDATE ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.' . PMA_backquote($GLOBALS['cfgRelation']['relation'])
751 . ' SET foreign_table = \'' . PMA_sqlAddslashes($target_table) . '\','
752 . ' foreign_db = \'' . PMA_sqlAddslashes($target_db) . '\''
753 . ' WHERE foreign_db = \'' . PMA_sqlAddslashes($source_db) . '\''
754 . ' AND foreign_table = \'' . PMA_sqlAddslashes($source_table) . '\'';
755 PMA_query_as_cu($table_query);
756 unset($table_query);
758 $table_query = 'UPDATE ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.' . PMA_backquote($GLOBALS['cfgRelation']['relation'])
759 . ' SET master_table = \'' . PMA_sqlAddslashes($target_table) . '\','
760 . ' master_db = \'' . PMA_sqlAddslashes($target_db) . '\''
761 . ' WHERE master_db = \'' . PMA_sqlAddslashes($source_db) . '\''
762 . ' AND master_table = \'' . PMA_sqlAddslashes($source_table) . '\'';
763 PMA_query_as_cu($table_query);
764 unset($table_query);
768 * @todo garvin: Can't get moving PDFs the right way. The page numbers
769 * always get screwed up independently from duplication because the
770 * numbers do not seem to be stored on a per-database basis. Would
771 * the author of pdf support please have a look at it?
774 if ($GLOBALS['cfgRelation']['pdfwork']) {
775 $table_query = 'UPDATE ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.' . PMA_backquote($GLOBALS['cfgRelation']['table_coords'])
776 . ' SET table_name = \'' . PMA_sqlAddslashes($target_table) . '\','
777 . ' db_name = \'' . PMA_sqlAddslashes($target_db) . '\''
778 . ' WHERE db_name = \'' . PMA_sqlAddslashes($source_db) . '\''
779 . ' AND table_name = \'' . PMA_sqlAddslashes($source_table) . '\'';
780 PMA_query_as_cu($table_query);
781 unset($table_query);
783 $pdf_query = 'SELECT pdf_page_number '
784 . ' FROM ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.' . PMA_backquote($GLOBALS['cfgRelation']['table_coords'])
785 . ' WHERE db_name = \'' . PMA_sqlAddslashes($target_db) . '\''
786 . ' AND table_name = \'' . PMA_sqlAddslashes($target_table) . '\'';
787 $pdf_rs = PMA_query_as_cu($pdf_query);
789 while ($pdf_copy_row = PMA_DBI_fetch_assoc($pdf_rs)) {
790 $table_query = 'UPDATE ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.' . PMA_backquote($GLOBALS['cfgRelation']['pdf_pages'])
791 . ' SET db_name = \'' . PMA_sqlAddslashes($target_db) . '\''
792 . ' WHERE db_name = \'' . PMA_sqlAddslashes($source_db) . '\''
793 . ' AND page_nr = \'' . PMA_sqlAddslashes($pdf_copy_row['pdf_page_number']) . '\'';
794 $tb_rs = PMA_query_as_cu($table_query);
795 unset($table_query);
796 unset($tb_rs);
801 if ($GLOBALS['cfgRelation']['designerwork']) {
802 $table_query = 'UPDATE ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.' . PMA_backquote($GLOBALS['cfgRelation']['designer_coords'])
803 . ' SET table_name = \'' . PMA_sqlAddslashes($target_table) . '\','
804 . ' db_name = \'' . PMA_sqlAddslashes($target_db) . '\''
805 . ' WHERE db_name = \'' . PMA_sqlAddslashes($source_db) . '\''
806 . ' AND table_name = \'' . PMA_sqlAddslashes($source_table) . '\'';
807 PMA_query_as_cu($table_query);
808 unset($table_query);
811 $GLOBALS['sql_query'] .= "\n\n" . $sql_drop_query . ';';
812 // end if ($move)
813 } else {
814 // we are copying
815 // garvin: Create new entries as duplicates from old PMA DBs
816 if ($what != 'dataonly' && !isset($maintain_relations)) {
817 if ($GLOBALS['cfgRelation']['commwork']) {
818 // Get all comments and MIME-Types for current table
819 $comments_copy_query = 'SELECT
820 column_name, ' . PMA_backquote('comment') . ($GLOBALS['cfgRelation']['mimework'] ? ', mimetype, transformation, transformation_options' : '') . '
821 FROM ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.' . PMA_backquote($GLOBALS['cfgRelation']['column_info']) . '
822 WHERE
823 db_name = \'' . PMA_sqlAddslashes($source_db) . '\' AND
824 table_name = \'' . PMA_sqlAddslashes($source_table) . '\'';
825 $comments_copy_rs = PMA_query_as_cu($comments_copy_query);
827 // Write every comment as new copied entry. [MIME]
828 while ($comments_copy_row = PMA_DBI_fetch_assoc($comments_copy_rs)) {
829 $new_comment_query = 'REPLACE INTO ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.' . PMA_backquote($GLOBALS['cfgRelation']['column_info'])
830 . ' (db_name, table_name, column_name, ' . PMA_backquote('comment') . ($GLOBALS['cfgRelation']['mimework'] ? ', mimetype, transformation, transformation_options' : '') . ') '
831 . ' VALUES('
832 . '\'' . PMA_sqlAddslashes($target_db) . '\','
833 . '\'' . PMA_sqlAddslashes($target_table) . '\','
834 . '\'' . PMA_sqlAddslashes($comments_copy_row['column_name']) . '\''
835 . ($GLOBALS['cfgRelation']['mimework'] ? ',\'' . PMA_sqlAddslashes($comments_copy_row['comment']) . '\','
836 . '\'' . PMA_sqlAddslashes($comments_copy_row['mimetype']) . '\','
837 . '\'' . PMA_sqlAddslashes($comments_copy_row['transformation']) . '\','
838 . '\'' . PMA_sqlAddslashes($comments_copy_row['transformation_options']) . '\'' : '')
839 . ')';
840 PMA_query_as_cu($new_comment_query);
841 } // end while
842 PMA_DBI_free_result($comments_copy_rs);
843 unset($comments_copy_rs);
846 // duplicating the bookmarks must not be done here, but
847 // just once per db
849 $get_fields = array('display_field');
850 $where_fields = array('db_name' => $source_db, 'table_name' => $source_table);
851 $new_fields = array('db_name' => $target_db, 'table_name' => $target_table);
852 PMA_Table::duplicateInfo('displaywork', 'table_info', $get_fields, $where_fields, $new_fields);
856 * @todo revise this code when we support cross-db relations
858 $get_fields = array('master_field', 'foreign_table', 'foreign_field');
859 $where_fields = array('master_db' => $source_db, 'master_table' => $source_table);
860 $new_fields = array('master_db' => $target_db, 'foreign_db' => $target_db, 'master_table' => $target_table);
861 PMA_Table::duplicateInfo('relwork', 'relation', $get_fields, $where_fields, $new_fields);
864 $get_fields = array('foreign_field', 'master_table', 'master_field');
865 $where_fields = array('foreign_db' => $source_db, 'foreign_table' => $source_table);
866 $new_fields = array('master_db' => $target_db, 'foreign_db' => $target_db, 'foreign_table' => $target_table);
867 PMA_Table::duplicateInfo('relwork', 'relation', $get_fields, $where_fields, $new_fields);
870 $get_fields = array('x', 'y', 'v', 'h');
871 $where_fields = array('db_name' => $source_db, 'table_name' => $source_table);
872 $new_fields = array('db_name' => $target_db, 'table_name' => $target_table);
873 PMA_Table::duplicateInfo('designerwork', 'designer_coords', $get_fields, $where_fields, $new_fields);
876 * @todo garvin: Can't get duplicating PDFs the right way. The
877 * page numbers always get screwed up independently from
878 * duplication because the numbers do not seem to be stored on a
879 * per-database basis. Would the author of pdf support please
880 * have a look at it?
882 $get_fields = array('page_descr');
883 $where_fields = array('db_name' => $source_db);
884 $new_fields = array('db_name' => $target_db);
885 $last_id = PMA_Table::duplicateInfo('pdfwork', 'pdf_pages', $get_fields, $where_fields, $new_fields);
887 if (isset($last_id) && $last_id >= 0) {
888 $get_fields = array('x', 'y');
889 $where_fields = array('db_name' => $source_db, 'table_name' => $source_table);
890 $new_fields = array('db_name' => $target_db, 'table_name' => $target_table, 'pdf_page_number' => $last_id);
891 PMA_Table::duplicateInfo('pdfwork', 'table_coords', $get_fields, $where_fields, $new_fields);
896 return true;
900 * checks if given name is a valid table name,
901 * currently if not empty, trailing spaces, '.', '/' and '\'
903 * @todo add check for valid chars in filename on current system/os
904 * @see http://dev.mysql.com/doc/refman/5.0/en/legal-names.html
905 * @param string $table_name name to check
906 * @return boolean whether the string is valid or not
908 function isValidName($table_name)
910 if ($table_name !== trim($table_name)) {
911 // trailing spaces
912 return false;
915 if (! strlen($table_name)) {
916 // zero length
917 return false;
920 if (preg_match('/[.\/\\\\]+/i', $table_name)) {
921 // illegal char . / \
922 return false;
925 return true;
929 * renames table
931 * @param string new table name
932 * @param string new database name
933 * @return boolean success
935 function rename($new_name, $new_db = null)
937 if (null !== $new_db && $new_db !== $this->getDbName()) {
938 // Ensure the target is valid
939 if (! $GLOBALS['PMA_List_Database']->exists($new_db)) {
940 $this->errors[] = $GLOBALS['strInvalidDatabase'] . ': ' . $new_db;
941 return false;
943 } else {
944 $new_db = $this->getDbName();
947 $new_table = new PMA_Table($new_name, $new_db);
949 if ($this->getFullName() === $new_table->getFullName()) {
950 return true;
953 if (! PMA_Table::isValidName($new_name)) {
954 $this->errors[] = $GLOBALS['strInvalidTableName'] . ': ' . $new_table->getFullName();
955 return false;
958 $GLOBALS['sql_query'] = '
959 RENAME TABLE ' . $this->getFullName(true) . '
960 TO ' . $new_table->getFullName(true) . ';';
961 if (! PMA_DBI_query($GLOBALS['sql_query'])) {
962 $this->errors[] = sprintf($GLOBALS['strErrorRenamingTable'], $this->getFullName(), $new_table->getFullName());
963 return false;
966 $old_name = $this->getName();
967 $old_db = $this->getDbName();
968 $this->setName($new_name);
969 $this->setDbName($new_db);
972 * @todo move into extra function PMA_Relation::renameTable($new_name, $old_name, $new_db, $old_db)
974 // garvin: Move old entries from comments to new table
975 require_once './libraries/relation.lib.php';
976 $GLOBALS['cfgRelation'] = PMA_getRelationsParam();
977 if ($GLOBALS['cfgRelation']['commwork']) {
978 $remove_query = '
979 UPDATE ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.'
980 . PMA_backquote($GLOBALS['cfgRelation']['column_info']) . '
981 SET `db_name` = \'' . PMA_sqlAddslashes($new_db) . '\',
982 `table_name` = \'' . PMA_sqlAddslashes($new_name) . '\'
983 WHERE `db_name` = \'' . PMA_sqlAddslashes($old_db) . '\'
984 AND `table_name` = \'' . PMA_sqlAddslashes($old_name) . '\'';
985 PMA_query_as_cu($remove_query);
986 unset($remove_query);
989 if ($GLOBALS['cfgRelation']['displaywork']) {
990 $table_query = '
991 UPDATE ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.'
992 . PMA_backquote($GLOBALS['cfgRelation']['table_info']) . '
993 SET `db_name` = \'' . PMA_sqlAddslashes($new_db) . '\',
994 `table_name` = \'' . PMA_sqlAddslashes($new_name) . '\'
995 WHERE `db_name` = \'' . PMA_sqlAddslashes($old_db) . '\'
996 AND `table_name` = \'' . PMA_sqlAddslashes($old_name) . '\'';
997 PMA_query_as_cu($table_query);
998 unset($table_query);
1001 if ($GLOBALS['cfgRelation']['relwork']) {
1002 $table_query = '
1003 UPDATE ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.'
1004 . PMA_backquote($GLOBALS['cfgRelation']['relation']) . '
1005 SET `foreign_db` = \'' . PMA_sqlAddslashes($new_db) . '\',
1006 `foreign_table` = \'' . PMA_sqlAddslashes($new_name) . '\'
1007 WHERE `foreign_db` = \'' . PMA_sqlAddslashes($old_db) . '\'
1008 AND `foreign_table` = \'' . PMA_sqlAddslashes($old_name) . '\'';
1009 PMA_query_as_cu($table_query);
1011 $table_query = '
1012 UPDATE ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.'
1013 . PMA_backquote($GLOBALS['cfgRelation']['relation']) . '
1014 SET `master_db` = \'' . PMA_sqlAddslashes($new_db) . '\',
1015 `master_table` = \'' . PMA_sqlAddslashes($new_name) . '\'
1016 WHERE `master_db` = \'' . PMA_sqlAddslashes($old_db) . '\'
1017 AND `master_table` = \'' . PMA_sqlAddslashes($old_name) . '\'';
1018 PMA_query_as_cu($table_query);
1019 unset($table_query);
1022 if ($GLOBALS['cfgRelation']['pdfwork']) {
1023 $table_query = '
1024 UPDATE ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.'
1025 . PMA_backquote($GLOBALS['cfgRelation']['table_coords']) . '
1026 SET `db_name` = \'' . PMA_sqlAddslashes($new_db) . '\',
1027 `table_name` = \'' . PMA_sqlAddslashes($new_name) . '\'
1028 WHERE `db_name` = \'' . PMA_sqlAddslashes($old_db) . '\'
1029 AND `table_name` = \'' . PMA_sqlAddslashes($old_name) . '\'';
1030 PMA_query_as_cu($table_query);
1031 unset($table_query);
1034 if ($GLOBALS['cfgRelation']['designerwork']) {
1035 $table_query = '
1036 UPDATE ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.'
1037 . PMA_backquote($GLOBALS['cfgRelation']['designer_coords']) . '
1038 SET `db_name` = \'' . PMA_sqlAddslashes($new_db) . '\',
1039 `table_name` = \'' . PMA_sqlAddslashes($new_name) . '\'
1040 WHERE `db_name` = \'' . PMA_sqlAddslashes($old_db) . '\'
1041 AND `table_name` = \'' . PMA_sqlAddslashes($old_name) . '\'';
1042 PMA_query_as_cu($table_query);
1043 unset($table_query);
1046 $this->messages[] = sprintf($GLOBALS['strRenameTableOK'],
1047 htmlspecialchars($old_name), htmlspecialchars($new_name));
1048 return true;