Romanian update
[phpmyadmin/arisferyanto.git] / libraries / Table.class.php
blob7122733e3b60db7ff27f35af2b1de84ee051ef9e
1 <?php
2 /* vim: set expandtab sw=4 ts=4 sts=4: */
3 /**
5 * @version $Id$
6 */
8 /**
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 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 * old PHP 4style constructor
214 * @see PMA_Table::__construct()
216 function PMA_Table($table_name, $db_name)
218 $this->__construct($table_name, $db_name);
222 * Checks if this "table" is a view
224 * @deprecated
225 * @todo see what we could do with the possible existence of $table_is_view
226 * @param string the database name
227 * @param string the table name
229 * @return boolean whether this is a view
231 * @access public
233 function _isView($db, $table) {
234 // maybe we already know if the table is a view
235 if (isset($GLOBALS['tbl_is_view']) && $GLOBALS['tbl_is_view']) {
236 return true;
238 // old MySQL version: no view
239 if (PMA_MYSQL_INT_VERSION < 50000) {
240 return false;
242 // This would be the correct way of doing the check but at least in
243 // MySQL 5.0.33 it's too slow when there are hundreds of databases
244 // and/or tables (more than 3 minutes for 400 tables)
245 /*if (false === PMA_DBI_fetch_value('SELECT TABLE_NAME FROM `information_schema`.`VIEWS` WHERE `TABLE_SCHEMA` = \'' . $db . '\' AND `TABLE_NAME` = \'' . $table . '\';')) {
246 return false;
247 } else {
248 return true;
249 } */
250 // A more complete verification would be to check if all columns
251 // from the result set are NULL except Name and Comment.
252 // MySQL from 5.0.0 to 5.0.12 returns 'view',
253 // from 5.0.13 returns 'VIEW'.
254 $comment = strtoupper(PMA_DBI_fetch_value('SHOW TABLE STATUS FROM ' . PMA_backquote($db) . ' LIKE \'' . $table . '\'', 0, 'Comment'));
255 // use substr() because the comment might contain something like:
256 // (VIEW 'BASE2.VTEST' REFERENCES INVALID TABLE(S) OR COLUMN(S) OR FUNCTION)
257 return (substr($comment, 0, 4) == 'VIEW');
261 * generates column/field specification for ALTER or CREATE TABLE syntax
263 * @todo move into class PMA_Column
264 * @todo on the interface, some js to clear the default value when the default
265 * current_timestamp is checked
266 * @static
267 * @param string $name name
268 * @param string $type type ('INT', 'VARCHAR', 'BIT', ...)
269 * @param string $length length ('2', '5,2', '', ...)
270 * @param string $attribute
271 * @param string $collation
272 * @param string $null with 'NULL' or 'NOT NULL'
273 * @param string $default default value
274 * @param boolean $default_current_timestamp whether default value is
275 * CURRENT_TIMESTAMP or not
276 * this overrides $default value
277 * @param string $extra 'AUTO_INCREMENT'
278 * @param string $comment field comment
279 * @param array &$field_primary list of fields for PRIMARY KEY
280 * @param string $index
281 * @param string $default_orig
282 * @return string field specification
284 function generateFieldSpec($name, $type, $length = '', $attribute = '',
285 $collation = '', $null = false, $default = '',
286 $default_current_timestamp = false, $extra = '', $comment = '',
287 &$field_primary, $index, $default_orig = false)
290 $is_timestamp = strpos(' ' . strtoupper($type), 'TIMESTAMP') == 1;
292 // $default_current_timestamp has priority over $default
295 * @todo include db-name
297 $query = PMA_backquote($name) . ' ' . $type;
299 if ($length != ''
300 && !preg_match('@^(DATE|DATETIME|TIME|TINYBLOB|TINYTEXT|BLOB|TEXT|MEDIUMBLOB|MEDIUMTEXT|LONGBLOB|LONGTEXT)$@i', $type)) {
301 $query .= '(' . $length . ')';
304 if ($attribute != '') {
305 $query .= ' ' . $attribute;
308 if (PMA_MYSQL_INT_VERSION >= 40100 && !empty($collation)
309 && $collation != 'NULL'
310 && preg_match('@^(TINYTEXT|TEXT|MEDIUMTEXT|LONGTEXT|VARCHAR|CHAR|ENUM|SET)$@i', $type)) {
311 $query .= PMA_generateCharsetQueryPart($collation);
314 if ($null !== false) {
315 if (!empty($null)) {
316 $query .= ' NOT NULL';
317 } else {
318 $query .= ' NULL';
322 if ($default_current_timestamp && $is_timestamp) {
323 $query .= ' DEFAULT CURRENT_TIMESTAMP';
324 // auto_increment field cannot have a default value
325 } elseif ($extra !== 'AUTO_INCREMENT'
326 && (strlen($default) || $default != $default_orig)) {
327 if (strtoupper($default) == 'NULL') {
328 $query .= ' DEFAULT NULL';
329 } else {
330 if (strlen($default)) {
331 if ($is_timestamp && $default == '0') {
332 // a TIMESTAMP does not accept DEFAULT '0'
333 // but DEFAULT 0 works
334 $query .= ' DEFAULT ' . PMA_sqlAddslashes($default);
335 } elseif ($default && $type == 'BIT') {
336 $query .= ' DEFAULT b\'' . preg_replace('/[^01]/', '0', $default) . '\'';
337 } else {
338 $query .= ' DEFAULT \'' . PMA_sqlAddslashes($default) . '\'';
344 if (!empty($extra)) {
345 $query .= ' ' . $extra;
346 // Force an auto_increment field to be part of the primary key
347 // even if user did not tick the PK box;
348 // but the PK could contain other columns so do not append
349 // a PRIMARY KEY clause, just add a member to $field_primary
350 if ($extra == 'AUTO_INCREMENT') {
351 $primary_cnt = count($field_primary);
352 $found_in_pk = false;
353 for ($j = 0; $j < $primary_cnt; $j++) {
354 if ($field_primary[$j] == $index) {
355 $found_in_pk = true;
356 break;
358 } // end for
359 if (! $found_in_pk) {
360 $field_primary[] = $index;
362 } // end if (auto_increment)
364 if (PMA_MYSQL_INT_VERSION >= 40100 && !empty($comment)) {
365 $query .= " COMMENT '" . PMA_sqlAddslashes($comment) . "'";
367 return $query;
368 } // end function
371 * Counts and returns (or displays) the number of records in a table
373 * Revision 13 July 2001: Patch for limiting dump size from
374 * vinay@sanisoft.com & girish@sanisoft.com
376 * @param string the current database name
377 * @param string the current table name
378 * @param boolean whether to retain or to displays the result
379 * @param boolean whether to force an exact count
381 * @return mixed the number of records if retain is required, true else
383 * @access public
385 function countRecords($db, $table, $ret = false, $force_exact = false)
387 $row_count = false;
389 if (! $force_exact) {
390 $row_count = PMA_DBI_fetch_value(
391 'SHOW TABLE STATUS FROM ' . PMA_backquote($db) . ' LIKE \''
392 . PMA_sqlAddslashes($table, true) . '\';',
393 0, 'Rows');
396 $tbl_is_view = PMA_Table::isView($db, $table);
398 // for a VIEW, $row_count is always false at this point
399 if (false === $row_count || $row_count < $GLOBALS['cfg']['MaxExactCount']) {
400 if (! $tbl_is_view) {
401 $row_count = PMA_DBI_fetch_value(
402 'SELECT COUNT(*) FROM ' . PMA_backquote($db) . '.'
403 . PMA_backquote($table));
404 } else {
405 // For complex views, even trying to get a partial record
406 // count could bring down a server, so we offer an
407 // alternative: setting MaxExactCountViews to 0 will bypass
408 // completely the record counting for views
410 if ($GLOBALS['cfg']['MaxExactCountViews'] == 0) {
411 $row_count = 0;
412 } else {
413 // Counting all rows of a VIEW could be too long, so use
414 // a LIMIT clause.
415 // Use try_query because it can fail (a VIEW is based on
416 // a table that no longer exists)
417 $result = PMA_DBI_try_query(
418 'SELECT 1 FROM ' . PMA_backquote($db) . '.'
419 . PMA_backquote($table) . ' LIMIT '
420 . $GLOBALS['cfg']['MaxExactCountViews'],
421 null, PMA_DBI_QUERY_STORE);
422 if (!PMA_DBI_getError()) {
423 $row_count = PMA_DBI_num_rows($result);
424 PMA_DBI_free_result($result);
430 if ($ret) {
431 return $row_count;
435 * @deprecated at the moment nowhere is $return = false used
437 // Note: as of PMA 2.8.0, we no longer seem to be using
438 // PMA_Table::countRecords() in display mode.
439 echo PMA_formatNumber($row_count, 0);
440 if ($tbl_is_view) {
441 echo '&nbsp;'
442 . sprintf($GLOBALS['strViewMaxExactCount'],
443 $GLOBALS['cfg']['MaxExactCount'],
444 '[a@./Documentation.html#cfg_MaxExactCount@_blank]', '[/a]');
446 } // end of the 'PMA_Table::countRecords()' function
449 * @todo add documentation
451 function generateAlter($oldcol, $newcol, $type, $length,
452 $attribute, $collation, $null, $default, $default_current_timestamp,
453 $extra, $comment='', $default_orig)
455 $empty_a = array();
456 return PMA_backquote($oldcol) . ' '
457 . PMA_Table::generateFieldSpec($newcol, $type, $length, $attribute,
458 $collation, $null, $default, $default_current_timestamp, $extra,
459 $comment, $empty_a, -1, $default_orig);
460 } // end function
463 * Inserts existing entries in a PMA_* table by reading a value from an old entry
465 * @param string The array index, which Relation feature to check
466 * ('relwork', 'commwork', ...)
467 * @param string The array index, which PMA-table to update
468 * ('bookmark', 'relation', ...)
469 * @param array Which fields will be SELECT'ed from the old entry
470 * @param array Which fields will be used for the WHERE query
471 * (array('FIELDNAME' => 'FIELDVALUE'))
472 * @param array Which fields will be used as new VALUES. These are the important
473 * keys which differ from the old entry.
474 * (array('FIELDNAME' => 'NEW FIELDVALUE'))
476 * @global string relation variable
478 * @author Garvin Hicking <me@supergarv.de>
480 function duplicateInfo($work, $pma_table, $get_fields, $where_fields,
481 $new_fields)
483 $last_id = -1;
485 if (isset($GLOBALS['cfgRelation']) && $GLOBALS['cfgRelation'][$work]) {
486 $select_parts = array();
487 $row_fields = array();
488 foreach ($get_fields as $get_field) {
489 $select_parts[] = PMA_backquote($get_field);
490 $row_fields[$get_field] = 'cc';
493 $where_parts = array();
494 foreach ($where_fields as $_where => $_value) {
495 $where_parts[] = PMA_backquote($_where) . ' = \''
496 . PMA_sqlAddslashes($_value) . '\'';
499 $new_parts = array();
500 $new_value_parts = array();
501 foreach ($new_fields as $_where => $_value) {
502 $new_parts[] = PMA_backquote($_where);
503 $new_value_parts[] = PMA_sqlAddslashes($_value);
506 $table_copy_query = '
507 SELECT ' . implode(', ', $select_parts) . '
508 FROM ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.'
509 . PMA_backquote($GLOBALS['cfgRelation'][$pma_table]) . '
510 WHERE ' . implode(' AND ', $where_parts);
512 // must use PMA_DBI_QUERY_STORE here, since we execute another
513 // query inside the loop
514 $table_copy_rs = PMA_query_as_cu($table_copy_query, true,
515 PMA_DBI_QUERY_STORE);
517 while ($table_copy_row = @PMA_DBI_fetch_assoc($table_copy_rs)) {
518 $value_parts = array();
519 foreach ($table_copy_row as $_key => $_val) {
520 if (isset($row_fields[$_key]) && $row_fields[$_key] == 'cc') {
521 $value_parts[] = PMA_sqlAddslashes($_val);
525 $new_table_query = '
526 INSERT IGNORE INTO ' . PMA_backquote($GLOBALS['cfgRelation']['db'])
527 . '.' . PMA_backquote($GLOBALS['cfgRelation'][$pma_table]) . '
528 (' . implode(', ', $select_parts) . ',
529 ' . implode(', ', $new_parts) . ')
530 VALUES
531 (\'' . implode('\', \'', $value_parts) . '\',
532 \'' . implode('\', \'', $new_value_parts) . '\')';
534 PMA_query_as_cu($new_table_query);
535 $last_id = PMA_DBI_insert_id();
536 } // end while
538 PMA_DBI_free_result($table_copy_rs);
540 return $last_id;
543 return true;
544 } // end of 'PMA_Table::duplicateInfo()' function
548 * Copies or renames table
549 * @todo use RENAME for move operations
550 * - would work only if the databases are on the same filesystem,
551 * how can we check that? try the operation and
552 * catch an error?
553 * - for views, only if MYSQL > 50013
554 * - still have to handle pmadb synch.
556 * @author Michal Cihar <michal@cihar.com>
558 function moveCopy($source_db, $source_table, $target_db, $target_table, $what, $move, $mode)
560 global $err_url;
562 // set export settings we need
563 $GLOBALS['sql_backquotes'] = 1;
564 $GLOBALS['asfile'] = 1;
566 // Ensure the target is valid
567 if (! $GLOBALS['PMA_List_Database']->exists($source_db, $target_db)) {
569 * @todo exit really needed here? or just a return?
571 exit;
574 $source = PMA_backquote($source_db) . '.' . PMA_backquote($source_table);
575 if (! isset($target_db) || ! strlen($target_db)) {
576 $target_db = $source_db;
579 // Doing a select_db could avoid some problems with replicated databases,
580 // when moving table from replicated one to not replicated one
581 PMA_DBI_select_db($target_db);
583 $target = PMA_backquote($target_db) . '.' . PMA_backquote($target_table);
585 // do not create the table if dataonly
586 if ($what != 'dataonly') {
587 require_once './libraries/export/sql.php';
589 $no_constraints_comments = true;
590 $GLOBALS['sql_constraints_query'] = '';
592 $sql_structure = PMA_getTableDef($source_db, $source_table, "\n", $err_url);
593 unset($no_constraints_comments);
594 $parsed_sql = PMA_SQP_parse($sql_structure);
595 $analyzed_sql = PMA_SQP_analyze($parsed_sql);
596 $i = 0;
597 if (empty($analyzed_sql[0]['create_table_fields'])) {
598 // this is not a CREATE TABLE, so find the first VIEW
599 $target_for_view = PMA_backquote($target_db);
600 while (true) {
601 if ($parsed_sql[$i]['type'] == 'alpha_reservedWord' && $parsed_sql[$i]['data'] == 'VIEW') {
602 break;
604 $i++;
607 unset($analyzed_sql);
608 $server_sql_mode = PMA_DBI_fetch_value("SHOW VARIABLES LIKE 'sql_mode'", 0, 1);
609 if ('ANSI_QUOTES' == $server_sql_mode) {
610 $table_delimiter = 'quote_double';
611 } else {
612 $table_delimiter = 'quote_backtick';
614 unset($server_sql_mode);
616 /* nijel: Find table name in query and replace it */
617 while ($parsed_sql[$i]['type'] != $table_delimiter) {
618 $i++;
621 /* no need to PMA_backquote() */
622 if (isset($target_for_view)) {
623 // this a view definition; we just found the first db name
624 // that follows DEFINER VIEW
625 // so change it for the new db name
626 $parsed_sql[$i]['data'] = $target_for_view;
627 // then we have to find all references to the source db
628 // and change them to the target db, ensuring we stay into
629 // the $parsed_sql limits
630 $last = $parsed_sql['len'] - 1;
631 $backquoted_source_db = PMA_backquote($source_db);
632 for (++$i; $i <= $last; $i++) {
633 if ($parsed_sql[$i]['type'] == $table_delimiter && $parsed_sql[$i]['data'] == $backquoted_source_db) {
634 $parsed_sql[$i]['data'] = $target_for_view;
637 unset($last,$backquoted_source_db);
638 } else {
639 $parsed_sql[$i]['data'] = $target;
642 /* Generate query back */
643 $sql_structure = PMA_SQP_formatHtml($parsed_sql, 'query_only');
644 // If table exists, and 'add drop table' is selected: Drop it!
645 $drop_query = '';
646 if (isset($GLOBALS['drop_if_exists'])
647 && $GLOBALS['drop_if_exists'] == 'true') {
648 if (PMA_Table::_isView($target_db,$target_table)) {
649 $drop_query = 'DROP VIEW';
650 } else {
651 $drop_query = 'DROP TABLE';
653 $drop_query .= ' IF EXISTS '
654 . PMA_backquote($target_db) . '.'
655 . PMA_backquote($target_table);
656 PMA_DBI_query($drop_query);
658 $GLOBALS['sql_query'] .= "\n" . $drop_query . ';';
660 // garvin: If an existing table gets deleted, maintain any
661 // entries for the PMA_* tables
662 $maintain_relations = true;
665 @PMA_DBI_query($sql_structure);
666 $GLOBALS['sql_query'] .= "\n" . $sql_structure . ';';
668 if (($move || isset($GLOBALS['add_constraints']))
669 && !empty($GLOBALS['sql_constraints_query'])) {
670 $parsed_sql = PMA_SQP_parse($GLOBALS['sql_constraints_query']);
671 $i = 0;
673 // find the first $table_delimiter, it must be the source table name
674 while ($parsed_sql[$i]['type'] != $table_delimiter) {
675 $i++;
676 // maybe someday we should guard against going over limit
677 //if ($i == $parsed_sql['len']) {
678 // break;
682 // replace it by the target table name, no need to PMA_backquote()
683 $parsed_sql[$i]['data'] = $target;
685 // now we must remove all $table_delimiter that follow a CONSTRAINT
686 // keyword, because a constraint name must be unique in a db
688 $cnt = $parsed_sql['len'] - 1;
690 for ($j = $i; $j < $cnt; $j++) {
691 if ($parsed_sql[$j]['type'] == 'alpha_reservedWord'
692 && strtoupper($parsed_sql[$j]['data']) == 'CONSTRAINT') {
693 if ($parsed_sql[$j+1]['type'] == $table_delimiter) {
694 $parsed_sql[$j+1]['data'] = '';
699 // Generate query back
700 $GLOBALS['sql_constraints_query'] = PMA_SQP_formatHtml($parsed_sql,
701 'query_only');
702 if ($mode == 'one_table') {
703 PMA_DBI_query($GLOBALS['sql_constraints_query']);
705 $GLOBALS['sql_query'] .= "\n" . $GLOBALS['sql_constraints_query'];
706 if ($mode == 'one_table') {
707 unset($GLOBALS['sql_constraints_query']);
710 } else {
711 $GLOBALS['sql_query'] = '';
714 // Copy the data unless this is a VIEW
715 if (($what == 'data' || $what == 'dataonly') && ! PMA_Table::_isView($target_db,$target_table)) {
716 $sql_insert_data =
717 'INSERT INTO ' . $target . ' SELECT * FROM ' . $source;
718 PMA_DBI_query($sql_insert_data);
719 $GLOBALS['sql_query'] .= "\n\n" . $sql_insert_data . ';';
722 require_once './libraries/relation.lib.php';
723 $GLOBALS['cfgRelation'] = PMA_getRelationsParam();
725 // Drops old table if the user has requested to move it
726 if ($move) {
728 // This could avoid some problems with replicated databases, when
729 // moving table from replicated one to not replicated one
730 PMA_DBI_select_db($source_db);
732 if (PMA_Table::_isView($source_db,$source_table)) {
733 $sql_drop_query = 'DROP VIEW';
734 } else {
735 $sql_drop_query = 'DROP TABLE';
737 $sql_drop_query .= ' ' . $source;
738 PMA_DBI_query($sql_drop_query);
740 // garvin: Move old entries from PMA-DBs to new table
741 if ($GLOBALS['cfgRelation']['commwork']) {
742 $remove_query = 'UPDATE ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.' . PMA_backquote($GLOBALS['cfgRelation']['column_info'])
743 . ' SET table_name = \'' . PMA_sqlAddslashes($target_table) . '\', '
744 . ' db_name = \'' . PMA_sqlAddslashes($target_db) . '\''
745 . ' WHERE db_name = \'' . PMA_sqlAddslashes($source_db) . '\''
746 . ' AND table_name = \'' . PMA_sqlAddslashes($source_table) . '\'';
747 PMA_query_as_cu($remove_query);
748 unset($remove_query);
751 // garvin: updating bookmarks is not possible since only a single table is moved,
752 // and not the whole DB.
754 if ($GLOBALS['cfgRelation']['displaywork']) {
755 $table_query = 'UPDATE ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.' . PMA_backquote($GLOBALS['cfgRelation']['table_info'])
756 . ' SET db_name = \'' . PMA_sqlAddslashes($target_db) . '\', '
757 . ' table_name = \'' . PMA_sqlAddslashes($target_table) . '\''
758 . ' WHERE db_name = \'' . PMA_sqlAddslashes($source_db) . '\''
759 . ' AND table_name = \'' . PMA_sqlAddslashes($source_table) . '\'';
760 PMA_query_as_cu($table_query);
761 unset($table_query);
764 if ($GLOBALS['cfgRelation']['relwork']) {
765 $table_query = 'UPDATE ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.' . PMA_backquote($GLOBALS['cfgRelation']['relation'])
766 . ' SET foreign_table = \'' . PMA_sqlAddslashes($target_table) . '\','
767 . ' foreign_db = \'' . PMA_sqlAddslashes($target_db) . '\''
768 . ' WHERE foreign_db = \'' . PMA_sqlAddslashes($source_db) . '\''
769 . ' AND foreign_table = \'' . PMA_sqlAddslashes($source_table) . '\'';
770 PMA_query_as_cu($table_query);
771 unset($table_query);
773 $table_query = 'UPDATE ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.' . PMA_backquote($GLOBALS['cfgRelation']['relation'])
774 . ' SET master_table = \'' . PMA_sqlAddslashes($target_table) . '\','
775 . ' master_db = \'' . PMA_sqlAddslashes($target_db) . '\''
776 . ' WHERE master_db = \'' . PMA_sqlAddslashes($source_db) . '\''
777 . ' AND master_table = \'' . PMA_sqlAddslashes($source_table) . '\'';
778 PMA_query_as_cu($table_query);
779 unset($table_query);
783 * @todo garvin: Can't get moving PDFs the right way. The page numbers
784 * always get screwed up independently from duplication because the
785 * numbers do not seem to be stored on a per-database basis. Would
786 * the author of pdf support please have a look at it?
789 if ($GLOBALS['cfgRelation']['pdfwork']) {
790 $table_query = 'UPDATE ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.' . PMA_backquote($GLOBALS['cfgRelation']['table_coords'])
791 . ' SET table_name = \'' . PMA_sqlAddslashes($target_table) . '\','
792 . ' db_name = \'' . PMA_sqlAddslashes($target_db) . '\''
793 . ' WHERE db_name = \'' . PMA_sqlAddslashes($source_db) . '\''
794 . ' AND table_name = \'' . PMA_sqlAddslashes($source_table) . '\'';
795 PMA_query_as_cu($table_query);
796 unset($table_query);
798 $pdf_query = 'SELECT pdf_page_number '
799 . ' FROM ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.' . PMA_backquote($GLOBALS['cfgRelation']['table_coords'])
800 . ' WHERE db_name = \'' . PMA_sqlAddslashes($target_db) . '\''
801 . ' AND table_name = \'' . PMA_sqlAddslashes($target_table) . '\'';
802 $pdf_rs = PMA_query_as_cu($pdf_query);
804 while ($pdf_copy_row = PMA_DBI_fetch_assoc($pdf_rs)) {
805 $table_query = 'UPDATE ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.' . PMA_backquote($GLOBALS['cfgRelation']['pdf_pages'])
806 . ' SET db_name = \'' . PMA_sqlAddslashes($target_db) . '\''
807 . ' WHERE db_name = \'' . PMA_sqlAddslashes($source_db) . '\''
808 . ' AND page_nr = \'' . PMA_sqlAddslashes($pdf_copy_row['pdf_page_number']) . '\'';
809 $tb_rs = PMA_query_as_cu($table_query);
810 unset($table_query);
811 unset($tb_rs);
816 if ($GLOBALS['cfgRelation']['designerwork']) {
817 $table_query = 'UPDATE ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.' . PMA_backquote($GLOBALS['cfgRelation']['designer_coords'])
818 . ' SET table_name = \'' . PMA_sqlAddslashes($target_table) . '\','
819 . ' db_name = \'' . PMA_sqlAddslashes($target_db) . '\''
820 . ' WHERE db_name = \'' . PMA_sqlAddslashes($source_db) . '\''
821 . ' AND table_name = \'' . PMA_sqlAddslashes($source_table) . '\'';
822 PMA_query_as_cu($table_query);
823 unset($table_query);
825 $GLOBALS['sql_query'] .= "\n\n" . $sql_drop_query . ';';
826 // end if ($move)
827 } else {
828 // we are copying
829 // garvin: Create new entries as duplicates from old PMA DBs
830 if ($what != 'dataonly' && !isset($maintain_relations)) {
831 if ($GLOBALS['cfgRelation']['commwork']) {
832 // Get all comments and MIME-Types for current table
833 $comments_copy_query = 'SELECT
834 column_name, ' . PMA_backquote('comment') . ($GLOBALS['cfgRelation']['mimework'] ? ', mimetype, transformation, transformation_options' : '') . '
835 FROM ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.' . PMA_backquote($GLOBALS['cfgRelation']['column_info']) . '
836 WHERE
837 db_name = \'' . PMA_sqlAddslashes($source_db) . '\' AND
838 table_name = \'' . PMA_sqlAddslashes($source_table) . '\'';
839 $comments_copy_rs = PMA_query_as_cu($comments_copy_query);
841 // Write every comment as new copied entry. [MIME]
842 while ($comments_copy_row = PMA_DBI_fetch_assoc($comments_copy_rs)) {
843 $new_comment_query = 'REPLACE INTO ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.' . PMA_backquote($GLOBALS['cfgRelation']['column_info'])
844 . ' (db_name, table_name, column_name, ' . PMA_backquote('comment') . ($GLOBALS['cfgRelation']['mimework'] ? ', mimetype, transformation, transformation_options' : '') . ') '
845 . ' VALUES('
846 . '\'' . PMA_sqlAddslashes($target_db) . '\','
847 . '\'' . PMA_sqlAddslashes($target_table) . '\','
848 . '\'' . PMA_sqlAddslashes($comments_copy_row['column_name']) . '\''
849 . ($GLOBALS['cfgRelation']['mimework'] ? ',\'' . PMA_sqlAddslashes($comments_copy_row['comment']) . '\','
850 . '\'' . PMA_sqlAddslashes($comments_copy_row['mimetype']) . '\','
851 . '\'' . PMA_sqlAddslashes($comments_copy_row['transformation']) . '\','
852 . '\'' . PMA_sqlAddslashes($comments_copy_row['transformation_options']) . '\'' : '')
853 . ')';
854 PMA_query_as_cu($new_comment_query);
855 } // end while
856 PMA_DBI_free_result($comments_copy_rs);
857 unset($comments_copy_rs);
860 // duplicating the bookmarks must not be done here, but
861 // just once per db
863 $get_fields = array('display_field');
864 $where_fields = array('db_name' => $source_db, 'table_name' => $source_table);
865 $new_fields = array('db_name' => $target_db, 'table_name' => $target_table);
866 PMA_Table::duplicateInfo('displaywork', 'table_info', $get_fields, $where_fields, $new_fields);
870 * @todo revise this code when we support cross-db relations
872 $get_fields = array('master_field', 'foreign_table', 'foreign_field');
873 $where_fields = array('master_db' => $source_db, 'master_table' => $source_table);
874 $new_fields = array('master_db' => $target_db, 'foreign_db' => $target_db, 'master_table' => $target_table);
875 PMA_Table::duplicateInfo('relwork', 'relation', $get_fields, $where_fields, $new_fields);
878 $get_fields = array('foreign_field', 'master_table', 'master_field');
879 $where_fields = array('foreign_db' => $source_db, 'foreign_table' => $source_table);
880 $new_fields = array('master_db' => $target_db, 'foreign_db' => $target_db, 'foreign_table' => $target_table);
881 PMA_Table::duplicateInfo('relwork', 'relation', $get_fields, $where_fields, $new_fields);
884 $get_fields = array('x', 'y', 'v', 'h');
885 $where_fields = array('db_name' => $source_db, 'table_name' => $source_table);
886 $new_fields = array('db_name' => $target_db, 'table_name' => $target_table);
887 PMA_Table::duplicateInfo('designerwork', 'designer_coords', $get_fields, $where_fields, $new_fields);
890 * @todo garvin: Can't get duplicating PDFs the right way. The
891 * page numbers always get screwed up independently from
892 * duplication because the numbers do not seem to be stored on a
893 * per-database basis. Would the author of pdf support please
894 * have a look at it?
896 $get_fields = array('page_descr');
897 $where_fields = array('db_name' => $source_db);
898 $new_fields = array('db_name' => $target_db);
899 $last_id = PMA_Table::duplicateInfo('pdfwork', 'pdf_pages', $get_fields, $where_fields, $new_fields);
901 if (isset($last_id) && $last_id >= 0) {
902 $get_fields = array('x', 'y');
903 $where_fields = array('db_name' => $source_db, 'table_name' => $source_table);
904 $new_fields = array('db_name' => $target_db, 'table_name' => $target_table, 'pdf_page_number' => $last_id);
905 PMA_Table::duplicateInfo('pdfwork', 'table_coords', $get_fields, $where_fields, $new_fields);
914 * checks if given name is a valid table name,
915 * currently if not empty, trailing spaces, '.', '/' and '\'
917 * @todo add check for valid chars in filename on current system/os
918 * @see http://dev.mysql.com/doc/refman/5.0/en/legal-names.html
919 * @param string $table_name name to check
920 * @return boolean whether the string is valid or not
922 function isValidName($table_name)
924 if ($table_name !== trim($table_name)) {
925 // trailing spaces
926 return false;
929 if (! strlen($table_name)) {
930 // zero length
931 return false;
934 if (preg_match('/[.\/\\\\]+/i', $table_name)) {
935 // illegal char . / \
936 return false;
939 return true;
943 * renames table
945 * @param string new table name
946 * @param string new database name
947 * @return boolean success
949 function rename($new_name, $new_db = null)
951 if (null !== $new_db && $new_db !== $this->getDbName()) {
952 // Ensure the target is valid
953 if (! $GLOBALS['PMA_List_Database']->exists($new_db)) {
954 $this->errors[] = $GLOBALS['strInvalidDatabase'] . ': ' . $new_db;
955 return false;
957 } else {
958 $new_db = $this->getDbName();
961 $new_table = new PMA_Table($new_name, $new_db);
963 if ($this->getFullName() === $new_table->getFullName()) {
964 return true;
967 if (! PMA_Table::isValidName($new_name)) {
968 $this->errors[] = $GLOBALS['strInvalidTableName'] . ': ' . $new_table->getFullName();
969 return false;
972 $GLOBALS['sql_query'] = '
973 RENAME TABLE ' . $this->getFullName(true) . '
974 TO ' . $new_table->getFullName(true) . ';';
975 if (! PMA_DBI_query($GLOBALS['sql_query'])) {
976 $this->errors[] = sprintf($GLOBALS['strErrorRenamingTable'], $this->getFullName(), $new_table->getFullName());
977 return false;
980 $old_name = $this->getName();
981 $old_db = $this->getDbName();
982 $this->setName($new_name);
983 $this->setDbName($new_db);
986 * @todo move into extra function PMA_Relation::renameTable($new_name, $old_name, $new_db, $old_db)
988 // garvin: Move old entries from comments to new table
989 require_once './libraries/relation.lib.php';
990 $GLOBALS['cfgRelation'] = PMA_getRelationsParam();
991 if ($GLOBALS['cfgRelation']['commwork']) {
992 $remove_query = '
993 UPDATE ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.'
994 . PMA_backquote($GLOBALS['cfgRelation']['column_info']) . '
995 SET `db_name` = \'' . PMA_sqlAddslashes($new_db) . '\',
996 `table_name` = \'' . PMA_sqlAddslashes($new_name) . '\'
997 WHERE `db_name` = \'' . PMA_sqlAddslashes($old_db) . '\'
998 AND `table_name` = \'' . PMA_sqlAddslashes($old_name) . '\'';
999 PMA_query_as_cu($remove_query);
1000 unset($remove_query);
1003 if ($GLOBALS['cfgRelation']['displaywork']) {
1004 $table_query = '
1005 UPDATE ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.'
1006 . PMA_backquote($GLOBALS['cfgRelation']['table_info']) . '
1007 SET `db_name` = \'' . PMA_sqlAddslashes($new_db) . '\',
1008 `table_name` = \'' . PMA_sqlAddslashes($new_name) . '\'
1009 WHERE `db_name` = \'' . PMA_sqlAddslashes($old_db) . '\'
1010 AND `table_name` = \'' . PMA_sqlAddslashes($old_name) . '\'';
1011 PMA_query_as_cu($table_query);
1012 unset($table_query);
1015 if ($GLOBALS['cfgRelation']['relwork']) {
1016 $table_query = '
1017 UPDATE ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.'
1018 . PMA_backquote($GLOBALS['cfgRelation']['relation']) . '
1019 SET `foreign_db` = \'' . PMA_sqlAddslashes($new_db) . '\',
1020 `foreign_table` = \'' . PMA_sqlAddslashes($new_name) . '\'
1021 WHERE `foreign_db` = \'' . PMA_sqlAddslashes($old_db) . '\'
1022 AND `foreign_table` = \'' . PMA_sqlAddslashes($old_name) . '\'';
1023 PMA_query_as_cu($table_query);
1025 $table_query = '
1026 UPDATE ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.'
1027 . PMA_backquote($GLOBALS['cfgRelation']['relation']) . '
1028 SET `master_db` = \'' . PMA_sqlAddslashes($new_db) . '\',
1029 `master_table` = \'' . PMA_sqlAddslashes($new_name) . '\'
1030 WHERE `master_db` = \'' . PMA_sqlAddslashes($old_db) . '\'
1031 AND `master_table` = \'' . PMA_sqlAddslashes($old_name) . '\'';
1032 PMA_query_as_cu($table_query);
1033 unset($table_query);
1036 if ($GLOBALS['cfgRelation']['pdfwork']) {
1037 $table_query = '
1038 UPDATE ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.'
1039 . PMA_backquote($GLOBALS['cfgRelation']['table_coords']) . '
1040 SET `db_name` = \'' . PMA_sqlAddslashes($new_db) . '\',
1041 `table_name` = \'' . PMA_sqlAddslashes($new_name) . '\'
1042 WHERE `db_name` = \'' . PMA_sqlAddslashes($old_db) . '\'
1043 AND `table_name` = \'' . PMA_sqlAddslashes($old_name) . '\'';
1044 PMA_query_as_cu($table_query);
1045 unset($table_query);
1048 if ($GLOBALS['cfgRelation']['designerwork']) {
1049 $table_query = '
1050 UPDATE ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.'
1051 . PMA_backquote($GLOBALS['cfgRelation']['designer_coords']) . '
1052 SET `db_name` = \'' . PMA_sqlAddslashes($new_db) . '\',
1053 `table_name` = \'' . PMA_sqlAddslashes($new_name) . '\'
1054 WHERE `db_name` = \'' . PMA_sqlAddslashes($old_db) . '\'
1055 AND `table_name` = \'' . PMA_sqlAddslashes($old_name) . '\'';
1056 PMA_query_as_cu($table_query);
1057 unset($table_query);
1060 $this->messages[] = sprintf($GLOBALS['strRenameTableOK'],
1061 htmlspecialchars($old_name), htmlspecialchars($new_name));
1062 return true;