Upgraded phpmyadmin to 4.0.4 (All Languages) - No modifications yet
[openemr.git] / phpmyadmin / libraries / plugins / export / ExportSql.class.php
blob4481013721911e1a26892e393764b82f34df1d01
1 <?php
2 /* vim: set expandtab sw=4 ts=4 sts=4: */
3 /**
4 * Set of functions used to build SQL dumps of tables
6 * @package PhpMyAdmin-Export
7 * @subpackage SQL
8 */
9 if (! defined('PHPMYADMIN')) {
10 exit;
13 /* Get the export interface */
14 require_once 'libraries/plugins/ExportPlugin.class.php';
16 /**
17 * Handles the export for the SQL class
19 * @package PhpMyAdmin-Export
20 * @subpackage SQL
22 class ExportSql extends ExportPlugin
24 /**
25 * Constructor
27 public function __construct()
29 $this->setProperties();
31 // Avoids undefined variables, use NULL so isset() returns false
32 if (! isset($GLOBALS['sql_backquotes'])) {
33 $GLOBALS['sql_backquotes'] = null;
37 /**
38 * Sets the export SQL properties
40 * @return void
42 protected function setProperties()
44 global $plugin_param;
46 $hide_sql = false;
47 $hide_structure = false;
48 if ($plugin_param['export_type'] == 'table'
49 && ! $plugin_param['single_table']
50 ) {
51 $hide_structure = true;
52 $hide_sql = true;
55 if (! $hide_sql) {
56 $props = 'libraries/properties/';
57 include_once "$props/plugins/ExportPluginProperties.class.php";
58 include_once "$props/options/groups/OptionsPropertyRootGroup.class.php";
59 include_once "$props/options/groups/OptionsPropertyMainGroup.class.php";
60 include_once "$props/options/groups/OptionsPropertySubgroup.class.php";
61 include_once "$props/options/items/BoolPropertyItem.class.php";
62 include_once "$props/options/items/MessageOnlyPropertyItem.class.php";
63 include_once "$props/options/items/RadioPropertyItem.class.php";
64 include_once "$props/options/items/SelectPropertyItem.class.php";
65 include_once "$props/options/items/TextPropertyItem.class.php";
67 $exportPluginProperties = new ExportPluginProperties();
68 $exportPluginProperties->setText('SQL');
69 $exportPluginProperties->setExtension('sql');
70 $exportPluginProperties->setMimeType('text/x-sql');
71 $exportPluginProperties->setOptionsText(__('Options'));
73 // create the root group that will be the options field for
74 // $exportPluginProperties
75 // this will be shown as "Format specific options"
76 $exportSpecificOptions = new OptionsPropertyRootGroup();
77 $exportSpecificOptions->setName("Format Specific Options");
79 // general options main group
80 $generalOptions = new OptionsPropertyMainGroup();
81 $generalOptions->setName("general_opts");
83 // comments
84 $subgroup = new OptionsPropertySubgroup();
85 $subgroup->setName("include_comments");
86 $leaf = new BoolPropertyItem();
87 $leaf->setName('include_comments');
88 $leaf->setText(
89 __(
90 'Display comments <i>(includes info such as export'
91 . ' timestamp, PHP version, and server version)</i>'
94 $subgroup->setSubgroupHeader($leaf);
96 $leaf = new TextPropertyItem();
97 $leaf->setName('header_comment');
98 $leaf->setText(
99 __('Additional custom header comment (\n splits lines):')
101 $subgroup->addProperty($leaf);
102 $leaf = new BoolPropertyItem();
103 $leaf->setName('dates');
104 $leaf->setText(
106 'Include a timestamp of when databases were created, last'
107 . ' updated, and last checked'
110 $subgroup->addProperty($leaf);
111 if (! empty($GLOBALS['cfgRelation']['relation'])) {
112 $leaf = new BoolPropertyItem();
113 $leaf->setName('relation');
114 $leaf->setText(__('Display foreign key relationships'));
115 $subgroup->addProperty($leaf);
117 if (! empty($GLOBALS['cfgRelation']['mimework'])) {
118 $leaf = new BoolPropertyItem();
119 $leaf->setName('mime');
120 $leaf->setText(__('Display MIME types'));
121 $subgroup->addProperty($leaf);
123 $generalOptions->addProperty($subgroup);
125 // enclose in a transaction
126 $leaf = new BoolPropertyItem();
127 $leaf->setName("use_transaction");
128 $leaf->setText(__('Enclose export in a transaction'));
129 $leaf->setDoc(
130 array(
131 'programs',
132 'mysqldump',
133 'option_mysqldump_single-transaction'
136 $generalOptions->addProperty($leaf);
138 // disable foreign key checks
139 $leaf = new BoolPropertyItem();
140 $leaf->setName("disable_fk");
141 $leaf->setText(__('Disable foreign key checks'));
142 $leaf->setDoc(
143 array(
144 'manual_MySQL_Database_Administration',
145 'server-system-variables',
146 'sysvar_foreign_key_checks'
149 $generalOptions->addProperty($leaf);
151 // compatibility maximization
152 $compats = PMA_DBI_getCompatibilities();
153 if (count($compats) > 0) {
154 $values = array();
155 foreach ($compats as $val) {
156 $values[$val] = $val;
159 $leaf = new SelectPropertyItem();
160 $leaf->setName("compatibility");
161 $leaf->setText(
163 'Database system or older MySQL server to maximize output'
164 . ' compatibility with:'
167 $leaf->setValues($values);
168 $leaf->setDoc(
169 array(
170 'manual_MySQL_Database_Administration',
171 'Server_SQL_mode'
174 $generalOptions->addProperty($leaf);
176 unset($values);
179 // server export options
180 if ($plugin_param['export_type'] == 'server') {
181 $leaf = new BoolPropertyItem();
182 $leaf->setName("drop_database");
183 $leaf->setText(
184 sprintf(__('Add %s statement'), '<code>DROP DATABASE</code>')
186 $generalOptions->addProperty($leaf);
189 // what to dump (structure/data/both)
190 $subgroup = new OptionsPropertySubgroup();
191 $subgroup->setName("dump_table");
192 $subgroup->setText("Dump table");
193 $leaf = new RadioPropertyItem();
194 $leaf->setName('structure_or_data');
195 $leaf->setValues(
196 array(
197 'structure' => __('structure'),
198 'data' => __('data'),
199 'structure_and_data' => __('structure and data')
202 $subgroup->setSubgroupHeader($leaf);
203 $generalOptions->addProperty($subgroup);
205 // add the main group to the root group
206 $exportSpecificOptions->addProperty($generalOptions);
209 // structure options main group
210 if (! $hide_structure) {
211 $structureOptions = new OptionsPropertyMainGroup();
212 $structureOptions->setName("structure");
213 $structureOptions->setText(__('Object creation options'));
214 $structureOptions->setForce('data');
216 // begin SQL Statements
217 $subgroup = new OptionsPropertySubgroup();
218 $leaf = new MessageOnlyPropertyItem();
219 $leaf->setName('add_statements');
220 $leaf->setText(__('Add statements:'));
221 $subgroup->setSubgroupHeader($leaf);
222 if ($plugin_param['export_type'] == 'table') {
223 if (PMA_Table::isView($GLOBALS['db'], $GLOBALS['table'])) {
224 $drop_clause = '<code>DROP VIEW</code>';
225 } else {
226 $drop_clause = '<code>DROP TABLE</code>';
228 } else {
229 if (PMA_DRIZZLE) {
230 $drop_clause = '<code>DROP TABLE</code>';
231 } else {
232 $drop_clause = '<code>DROP TABLE / VIEW / PROCEDURE'
233 . ' / FUNCTION</code>';
234 if (PMA_MYSQL_INT_VERSION > 50100) {
235 $drop_clause .= '<code> / EVENT</code>';
239 $leaf = new BoolPropertyItem();
240 $leaf->setName('drop_table');
241 $leaf->setText(sprintf(__('Add %s statement'), $drop_clause));
242 $subgroup->addProperty($leaf);
243 // Drizzle doesn't support procedures and functions
244 if (! PMA_DRIZZLE) {
245 $leaf = new BoolPropertyItem();
246 $leaf->setName('procedure_function');
247 $leaf->setText(
248 sprintf(
249 __('Add %s statement'),
250 '<code>CREATE PROCEDURE / FUNCTION'
251 . (PMA_MYSQL_INT_VERSION > 50100
252 ? ' / EVENT</code>' : '</code>')
255 $subgroup->addProperty($leaf);
258 // begin CREATE TABLE statements
259 $subgroup_create_table = new OptionsPropertySubgroup();
260 $leaf = new BoolPropertyItem();
261 $leaf->setName('create_table_statements');
262 $leaf->setText(__('<code>CREATE TABLE</code> options:'));
263 $subgroup_create_table->setSubgroupHeader($leaf);
264 $leaf = new BoolPropertyItem();
265 $leaf->setName('if_not_exists');
266 $leaf->setText('<code>IF NOT EXISTS</code>');
267 $subgroup_create_table->addProperty($leaf);
268 $leaf = new BoolPropertyItem();
269 $leaf->setName('auto_increment');
270 $leaf->setText('<code>AUTO_INCREMENT</code>');
271 $subgroup_create_table->addProperty($leaf);
272 $subgroup->addProperty($subgroup_create_table);
273 $structureOptions->addProperty($subgroup);
275 $leaf = new BoolPropertyItem();
276 $leaf->setName("backquotes");
277 $leaf->setText(
279 'Enclose table and column names with backquotes '
280 . '<i>(Protects column and table names formed with'
281 . ' special characters or keywords)</i>'
285 $structureOptions->addProperty($leaf);
287 // add the main group to the root group
288 $exportSpecificOptions->addProperty($structureOptions);
292 // begin Data options
293 $dataOptions = new OptionsPropertyMainGroup();
294 $dataOptions->setName("data");
295 $dataOptions->setText(__('Data creation options'));
296 $dataOptions->setForce('structure');
297 $leaf = new BoolPropertyItem();
298 $leaf->setName("truncate");
299 $leaf->setText(__('Truncate table before insert'));
300 $dataOptions->addProperty($leaf);
302 // begin SQL Statements
303 $subgroup = new OptionsPropertySubgroup();
304 $leaf = new MessageOnlyPropertyItem();
305 $leaf->setText(__('Instead of <code>INSERT</code> statements, use:'));
306 $subgroup->setSubgroupHeader($leaf);
307 // Not supported in Drizzle
308 if (! PMA_DRIZZLE) {
309 $leaf = new BoolPropertyItem();
310 $leaf->setName("delayed");
311 $leaf->setText(__('<code>INSERT DELAYED</code> statements'));
312 $leaf->setDoc(
313 array(
314 'manual_MySQL_Database_Administration',
315 'insert_delayed'
318 $subgroup->addProperty($leaf);
320 $leaf = new BoolPropertyItem();
321 $leaf->setName("ignore");
322 $leaf->setText(__('<code>INSERT IGNORE</code> statements'));
323 $leaf->setDoc(
324 array(
325 'manual_MySQL_Database_Administration',
326 'insert'
329 $subgroup->addProperty($leaf);
330 $dataOptions->addProperty($subgroup);
332 // Function to use when dumping dat
333 $leaf = new SelectPropertyItem();
334 $leaf->setName("type");
335 $leaf->setText(__('Function to use when dumping data:'));
336 $leaf->setValues(
337 array(
338 'INSERT' => 'INSERT',
339 'UPDATE' => 'UPDATE',
340 'REPLACE' => 'REPLACE'
343 $dataOptions->addProperty($leaf);
345 /* Syntax to use when inserting data */
346 $subgroup = new OptionsPropertySubgroup();
347 $leaf = new MessageOnlyPropertyItem();
348 $leaf->setText(__('Syntax to use when inserting data:'));
349 $subgroup->setSubgroupHeader($leaf);
350 $leaf = new RadioPropertyItem();
351 $leaf->setName("insert_syntax");
352 $leaf->setText(__('<code>INSERT IGNORE</code> statements'));
353 $leaf->setValues(
354 array(
355 'complete' => __(
356 'include column names in every <code>INSERT</code> statement'
357 . ' <br /> &nbsp; &nbsp; &nbsp; Example: <code>INSERT INTO'
358 . ' tbl_name (col_A,col_B,col_C) VALUES (1,2,3)</code>'
360 'extended' => __(
361 'insert multiple rows in every <code>INSERT</code> statement'
362 . '<br /> &nbsp; &nbsp; &nbsp; Example: <code>INSERT INTO'
363 . ' tbl_name VALUES (1,2,3), (4,5,6), (7,8,9)</code>'
365 'both' => __(
366 'both of the above<br /> &nbsp; &nbsp; &nbsp; Example:'
367 . ' <code>INSERT INTO tbl_name (col_A,col_B) VALUES (1,2,3),'
368 . ' (4,5,6), (7,8,9)</code>'
370 'none' => __(
371 'neither of the above<br /> &nbsp; &nbsp; &nbsp; Example:'
372 . ' <code>INSERT INTO tbl_name VALUES (1,2,3)</code>'
376 $subgroup->addProperty($leaf);
377 $dataOptions->addProperty($subgroup);
379 // Max length of query
380 $leaf = new TextPropertyItem();
381 $leaf->setName("max_query_size");
382 $leaf->setText(__('Maximal length of created query'));
383 $dataOptions->addProperty($leaf);
385 // Dump binary columns in hexadecimal
386 $leaf = new BoolPropertyItem();
387 $leaf->setName("hex_for_blob");
388 $leaf->setText(
390 'Dump binary columns in hexadecimal notation'
391 . ' <i>(for example, "abc" becomes 0x616263)</i>'
394 $dataOptions->addProperty($leaf);
396 // Drizzle works only with UTC timezone
397 if (! PMA_DRIZZLE) {
398 // Dump time in UTC
399 $leaf = new BoolPropertyItem();
400 $leaf->setName("utc_time");
401 $leaf->setText(
403 'Dump TIMESTAMP columns in UTC <i>(enables TIMESTAMP columns'
404 . ' to be dumped and reloaded between servers in different'
405 . ' time zones)</i>'
408 $dataOptions->addProperty($leaf);
411 // add the main group to the root group
412 $exportSpecificOptions->addProperty($dataOptions);
414 // set the options for the export plugin property item
415 $exportPluginProperties->setOptions($exportSpecificOptions);
416 $this->properties = $exportPluginProperties;
421 * This method is called when any PluginManager to which the observer
422 * is attached calls PluginManager::notify()
424 * @param SplSubject $subject The PluginManager notifying the observer
425 * of an update.
427 * @return void
429 public function update (SplSubject $subject)
434 * Exports routines (procedures and functions)
436 * @param string $db Database
438 * @return bool Whether it succeeded
440 public function exportRoutines($db)
442 global $crlf;
444 $text = '';
445 $delimiter = '$$';
447 $procedure_names = PMA_DBI_get_procedures_or_functions($db, 'PROCEDURE');
448 $function_names = PMA_DBI_get_procedures_or_functions($db, 'FUNCTION');
450 if ($procedure_names || $function_names) {
451 $text .= $crlf
452 . 'DELIMITER ' . $delimiter . $crlf;
455 if ($procedure_names) {
456 $text .=
457 $this->_exportComment()
458 . $this->_exportComment(__('Procedures'))
459 . $this->_exportComment();
461 foreach ($procedure_names as $procedure_name) {
462 if (! empty($GLOBALS['sql_drop_table'])) {
463 $text .= 'DROP PROCEDURE IF EXISTS '
464 . PMA_Util::backquote($procedure_name)
465 . $delimiter . $crlf;
467 $text .= PMA_DBI_get_definition($db, 'PROCEDURE', $procedure_name)
468 . $delimiter . $crlf . $crlf;
472 if ($function_names) {
473 $text .=
474 $this->_exportComment()
475 . $this->_exportComment(__('Functions'))
476 . $this->_exportComment();
478 foreach ($function_names as $function_name) {
479 if (! empty($GLOBALS['sql_drop_table'])) {
480 $text .= 'DROP FUNCTION IF EXISTS '
481 . PMA_Util::backquote($function_name)
482 . $delimiter . $crlf;
484 $text .= PMA_DBI_get_definition($db, 'FUNCTION', $function_name)
485 . $delimiter . $crlf . $crlf;
489 if ($procedure_names || $function_names) {
490 $text .= 'DELIMITER ;' . $crlf;
493 if (! empty($text)) {
494 return PMA_exportOutputHandler($text);
495 } else {
496 return false;
501 * Possibly outputs comment
503 * @param string $text Text of comment
505 * @return string The formatted comment
507 private function _exportComment($text = '')
509 if (isset($GLOBALS['sql_include_comments'])
510 && $GLOBALS['sql_include_comments']
512 // see http://dev.mysql.com/doc/refman/5.0/en/ansi-diff-comments.html
513 return '--' . (empty($text) ? '' : ' ') . $text . $GLOBALS['crlf'];
514 } else {
515 return '';
520 * Possibly outputs CRLF
522 * @return string $crlf or nothing
524 private function _possibleCRLF()
526 if (isset($GLOBALS['sql_include_comments'])
527 && $GLOBALS['sql_include_comments']
529 return $GLOBALS['crlf'];
530 } else {
531 return '';
536 * Outputs export footer
538 * @return bool Whether it succeeded
540 public function exportFooter()
542 global $crlf, $mysql_charset_map;
544 $foot = '';
546 if (isset($GLOBALS['sql_disable_fk'])) {
547 $foot .= 'SET FOREIGN_KEY_CHECKS=1;' . $crlf;
550 if (isset($GLOBALS['sql_use_transaction'])) {
551 $foot .= 'COMMIT;' . $crlf;
554 // restore connection settings
555 $charset_of_file = isset($GLOBALS['charset_of_file'])
556 ? $GLOBALS['charset_of_file'] : '';
557 if (! empty($GLOBALS['asfile'])
558 && isset($mysql_charset_map[$charset_of_file])
559 && ! PMA_DRIZZLE
561 $foot .= $crlf
562 . '/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;'
563 . $crlf
564 . '/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;'
565 . $crlf
566 . '/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;'
567 . $crlf;
570 /* Restore timezone */
571 if (isset($GLOBALS['sql_utc_time']) && $GLOBALS['sql_utc_time']) {
572 PMA_DBI_query('SET time_zone = "' . $GLOBALS['old_tz'] . '"');
575 return PMA_exportOutputHandler($foot);
579 * Outputs export header. It is the first method to be called, so all
580 * the required variables are initialized here.
582 * @return bool Whether it succeeded
584 public function exportHeader()
586 global $crlf, $cfg;
587 global $mysql_charset_map;
589 if (isset($GLOBALS['sql_compatibility'])) {
590 $tmp_compat = $GLOBALS['sql_compatibility'];
591 if ($tmp_compat == 'NONE') {
592 $tmp_compat = '';
594 PMA_DBI_try_query('SET SQL_MODE="' . $tmp_compat . '"');
595 unset($tmp_compat);
597 $head = $this->_exportComment('phpMyAdmin SQL Dump')
598 . $this->_exportComment('version ' . PMA_VERSION)
599 . $this->_exportComment('http://www.phpmyadmin.net')
600 . $this->_exportComment();
601 $host_string = __('Host') . ': ' . $cfg['Server']['host'];
602 if (! empty($cfg['Server']['port'])) {
603 $host_string .= ':' . $cfg['Server']['port'];
605 $head .= $this->_exportComment($host_string);
606 $head .=
607 $this->_exportComment(
608 __('Generation Time') . ': '
609 . PMA_Util::localisedDate()
611 . $this->_exportComment(
612 __('Server version') . ': ' . PMA_MYSQL_STR_VERSION
614 . $this->_exportComment(__('PHP Version') . ': ' . phpversion())
615 . $this->_possibleCRLF();
617 if (isset($GLOBALS['sql_header_comment'])
618 && ! empty($GLOBALS['sql_header_comment'])
620 // '\n' is not a newline (like "\n" would be), it's the characters
621 // backslash and n, as explained on the export interface
622 $lines = explode('\n', $GLOBALS['sql_header_comment']);
623 $head .= $this->_exportComment();
624 foreach ($lines as $one_line) {
625 $head .= $this->_exportComment($one_line);
627 $head .= $this->_exportComment();
630 if (isset($GLOBALS['sql_disable_fk'])) {
631 $head .= 'SET FOREIGN_KEY_CHECKS=0;' . $crlf;
634 // We want exported AUTO_INCREMENT columns to have still same value,
635 // do this only for recent MySQL exports
636 if ((! isset($GLOBALS['sql_compatibility'])
637 || $GLOBALS['sql_compatibility'] == 'NONE')
638 && ! PMA_DRIZZLE
640 $head .= 'SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";' . $crlf;
643 if (isset($GLOBALS['sql_use_transaction'])) {
644 $head .= 'SET AUTOCOMMIT = 0;' . $crlf
645 . 'START TRANSACTION;' . $crlf;
648 /* Change timezone if we should export timestamps in UTC */
649 if (isset($GLOBALS['sql_utc_time']) && $GLOBALS['sql_utc_time']) {
650 $head .= 'SET time_zone = "+00:00";' . $crlf;
651 $GLOBALS['old_tz'] = PMA_DBI_fetch_value('SELECT @@session.time_zone');
652 PMA_DBI_query('SET time_zone = "+00:00"');
655 $head .= $this->_possibleCRLF();
657 if (! empty($GLOBALS['asfile']) && ! PMA_DRIZZLE) {
658 // we are saving as file, therefore we provide charset information
659 // so that a utility like the mysql client can interpret
660 // the file correctly
661 if (isset($GLOBALS['charset_of_file'])
662 && isset($mysql_charset_map[$GLOBALS['charset_of_file']])
664 // we got a charset from the export dialog
665 $set_names = $mysql_charset_map[$GLOBALS['charset_of_file']];
666 } else {
667 // by default we use the connection charset
668 $set_names = $mysql_charset_map['utf-8'];
670 $head .= $crlf
671 . '/*!40101 SET @OLD_CHARACTER_SET_CLIENT='
672 . '@@CHARACTER_SET_CLIENT */;' . $crlf
673 . '/*!40101 SET @OLD_CHARACTER_SET_RESULTS='
674 . '@@CHARACTER_SET_RESULTS */;' . $crlf
675 . '/*!40101 SET @OLD_COLLATION_CONNECTION='
676 . '@@COLLATION_CONNECTION */;'. $crlf
677 . '/*!40101 SET NAMES ' . $set_names . ' */;' . $crlf . $crlf;
680 return PMA_exportOutputHandler($head);
684 * Outputs CREATE DATABASE statement
686 * @param string $db Database name
688 * @return bool Whether it succeeded
690 public function exportDBCreate($db)
692 global $crlf;
694 if (isset($GLOBALS['sql_compatibility'])) {
695 $compat = $GLOBALS['sql_compatibility'];
696 } else {
697 $compat = 'NONE';
699 if (isset($GLOBALS['sql_drop_database'])) {
700 if (! PMA_exportOutputHandler(
701 'DROP DATABASE '
702 . (isset($GLOBALS['sql_backquotes'])
703 ? PMA_Util::backquoteCompat($db, $compat) : $db)
704 . ';' . $crlf
705 )) {
706 return false;
709 $create_query = 'CREATE DATABASE IF NOT EXISTS '
710 . (isset($GLOBALS['sql_backquotes'])
711 ? PMA_Util::backquoteCompat($db, $compat) : $db);
712 $collation = PMA_getDbCollation($db);
713 if (PMA_DRIZZLE) {
714 $create_query .= ' COLLATE ' . $collation;
715 } else {
716 if (strpos($collation, '_')) {
717 $create_query .= ' DEFAULT CHARACTER SET '
718 . substr($collation, 0, strpos($collation, '_'))
719 . ' COLLATE ' . $collation;
720 } else {
721 $create_query .= ' DEFAULT CHARACTER SET ' . $collation;
724 $create_query .= ';' . $crlf;
725 if (! PMA_exportOutputHandler($create_query)) {
726 return false;
728 if (isset($GLOBALS['sql_backquotes'])
729 && ((isset($GLOBALS['sql_compatibility'])
730 && $GLOBALS['sql_compatibility'] == 'NONE')
731 || PMA_DRIZZLE)
733 $result = PMA_exportOutputHandler(
734 'USE ' . PMA_Util::backquoteCompat($db, $compat)
735 . ';' . $crlf
737 } else {
738 $result = PMA_exportOutputHandler('USE ' . $db . ';' . $crlf);
741 return $result;
745 * Outputs database header
747 * @param string $db Database name
749 * @return bool Whether it succeeded
751 public function exportDBHeader($db)
753 if (isset($GLOBALS['sql_compatibility'])) {
754 $compat = $GLOBALS['sql_compatibility'];
755 } else {
756 $compat = 'NONE';
758 $head = $this->_exportComment()
759 . $this->_exportComment(
760 __('Database') . ': '
761 . (isset($GLOBALS['sql_backquotes'])
762 ? PMA_Util::backquoteCompat($db, $compat)
763 : '\'' . $db . '\'')
765 . $this->_exportComment();
766 return PMA_exportOutputHandler($head);
770 * Outputs database footer
772 * @param string $db Database name
774 * @return bool Whether it succeeded
776 public function exportDBFooter($db)
778 global $crlf;
780 $result = true;
781 if (isset($GLOBALS['sql_constraints'])) {
782 $result = PMA_exportOutputHandler($GLOBALS['sql_constraints']);
783 unset($GLOBALS['sql_constraints']);
786 if (($GLOBALS['sql_structure_or_data'] == 'structure'
787 || $GLOBALS['sql_structure_or_data'] == 'structure_and_data')
788 && isset($GLOBALS['sql_procedure_function'])
790 $text = '';
791 $delimiter = '$$';
793 if (PMA_MYSQL_INT_VERSION > 50100) {
794 $event_names = PMA_DBI_fetch_result(
795 'SELECT EVENT_NAME FROM information_schema.EVENTS WHERE'
796 . ' EVENT_SCHEMA= \''
797 . PMA_Util::sqlAddSlashes($db, true)
798 . '\';'
800 } else {
801 $event_names = array();
804 if ($event_names) {
805 $text .= $crlf
806 . 'DELIMITER ' . $delimiter . $crlf;
808 $text .=
809 $this->_exportComment()
810 . $this->_exportComment(__('Events'))
811 . $this->_exportComment();
813 foreach ($event_names as $event_name) {
814 if (! empty($GLOBALS['sql_drop_table'])) {
815 $text .= 'DROP EVENT '
816 . PMA_Util::backquote($event_name)
817 . $delimiter . $crlf;
819 $text .= PMA_DBI_get_definition($db, 'EVENT', $event_name)
820 . $delimiter . $crlf . $crlf;
823 $text .= 'DELIMITER ;' . $crlf;
826 if (! empty($text)) {
827 $result = PMA_exportOutputHandler($text);
830 return $result;
834 * Returns a stand-in CREATE definition to resolve view dependencies
836 * @param string $db the database name
837 * @param string $view the view name
838 * @param string $crlf the end of line sequence
840 * @return string resulting definition
842 public function getTableDefStandIn($db, $view, $crlf)
844 $create_query = '';
845 if (! empty($GLOBALS['sql_drop_table'])) {
846 $create_query .= 'DROP VIEW IF EXISTS '
847 . PMA_Util::backquote($view)
848 . ';' . $crlf;
851 $create_query .= 'CREATE TABLE ';
853 if (isset($GLOBALS['sql_if_not_exists'])
854 && $GLOBALS['sql_if_not_exists']
856 $create_query .= 'IF NOT EXISTS ';
858 $create_query .= PMA_Util::backquote($view) . ' (' . $crlf;
859 $tmp = array();
860 $columns = PMA_DBI_get_columns_full($db, $view);
861 foreach ($columns as $column_name => $definition) {
862 $tmp[] = PMA_Util::backquote($column_name) . ' ' .
863 $definition['Type'] . $crlf;
865 $create_query .= implode(',', $tmp) . ');';
866 return($create_query);
870 * Returns $table's CREATE definition
872 * @param string $db the database name
873 * @param string $table the table name
874 * @param string $crlf the end of line sequence
875 * @param string $error_url the url to go back in case of error
876 * @param bool $show_dates whether to include creation/update/check
877 * dates
878 * @param bool $add_semicolon whether to add semicolon and end-of-line at
879 * the end
880 * @param bool $view whether we're handling a view
882 * @return string resulting schema
884 public function getTableDef(
885 $db,
886 $table,
887 $crlf,
888 $error_url,
889 $show_dates = false,
890 $add_semicolon = true,
891 $view = false
893 global $sql_drop_table, $sql_backquotes, $sql_constraints,
894 $sql_constraints_query, $sql_drop_foreign_keys;
896 $schema_create = '';
897 $auto_increment = '';
898 $new_crlf = $crlf;
900 if (isset($GLOBALS['sql_compatibility'])) {
901 $compat = $GLOBALS['sql_compatibility'];
902 } else {
903 $compat = 'NONE';
906 // need to use PMA_DBI_QUERY_STORE with PMA_DBI_num_rows() in mysqli
907 $result = PMA_DBI_query(
908 'SHOW TABLE STATUS FROM ' . PMA_Util::backquote($db)
909 . ' LIKE \'' . PMA_Util::sqlAddSlashes($table, true) . '\'',
910 null,
911 PMA_DBI_QUERY_STORE
913 if ($result != false) {
914 if (PMA_DBI_num_rows($result) > 0) {
915 $tmpres = PMA_DBI_fetch_assoc($result);
916 if (PMA_DRIZZLE && $show_dates) {
917 // Drizzle doesn't give Create_time and Update_time in
918 // SHOW TABLE STATUS, add it
919 $sql ="SELECT
920 TABLE_CREATION_TIME AS Create_time,
921 TABLE_UPDATE_TIME AS Update_time
922 FROM data_dictionary.TABLES
923 WHERE TABLE_SCHEMA = '"
924 . PMA_Util::sqlAddSlashes($db) . "'
925 AND TABLE_NAME = '"
926 . PMA_Util::sqlAddSlashes($table) . "'";
927 $tmpres = array_merge(PMA_DBI_fetch_single_row($sql), $tmpres);
929 // Here we optionally add the AUTO_INCREMENT next value,
930 // but starting with MySQL 5.0.24, the clause is already included
931 // in SHOW CREATE TABLE so we'll remove it below
932 // It's required for Drizzle because SHOW CREATE TABLE uses
933 // the value from table's creation time
934 if (isset($GLOBALS['sql_auto_increment'])
935 && ! empty($tmpres['Auto_increment'])
937 $auto_increment .= ' AUTO_INCREMENT='
938 . $tmpres['Auto_increment'] . ' ';
941 if ($show_dates
942 && isset($tmpres['Create_time'])
943 && ! empty($tmpres['Create_time'])
945 $schema_create .= $this->_exportComment(
946 __('Creation') . ': '
947 . PMA_Util::localisedDate(
948 strtotime($tmpres['Create_time'])
951 $new_crlf = $this->_exportComment() . $crlf;
954 if ($show_dates
955 && isset($tmpres['Update_time'])
956 && ! empty($tmpres['Update_time'])
958 $schema_create .= $this->_exportComment(
959 __('Last update') . ': '
960 . PMA_Util::localisedDate(
961 strtotime($tmpres['Update_time'])
964 $new_crlf = $this->_exportComment() . $crlf;
967 if ($show_dates
968 && isset($tmpres['Check_time'])
969 && ! empty($tmpres['Check_time'])
971 $schema_create .= $this->_exportComment(
972 __('Last check') . ': '
973 . PMA_Util::localisedDate(
974 strtotime($tmpres['Check_time'])
977 $new_crlf = $this->_exportComment() . $crlf;
980 PMA_DBI_free_result($result);
983 $schema_create .= $new_crlf;
985 // no need to generate a DROP VIEW here, it was done earlier
986 if (! empty($sql_drop_table) && ! PMA_Table::isView($db, $table)) {
987 $schema_create .= 'DROP TABLE IF EXISTS '
988 . PMA_Util::backquote($table, $sql_backquotes) . ';'
989 . $crlf;
992 // Complete table dump,
993 // Whether to quote table and column names or not
994 // Drizzle always quotes names
995 if (! PMA_DRIZZLE) {
996 if ($sql_backquotes) {
997 PMA_DBI_query('SET SQL_QUOTE_SHOW_CREATE = 1');
998 } else {
999 PMA_DBI_query('SET SQL_QUOTE_SHOW_CREATE = 0');
1003 // I don't see the reason why this unbuffered query could cause problems,
1004 // because SHOW CREATE TABLE returns only one row, and we free the
1005 // results below. Nonetheless, we got 2 user reports about this
1006 // (see bug 1562533) so I removed the unbuffered mode.
1007 // $result = PMA_DBI_query('SHOW CREATE TABLE ' . backquote($db)
1008 // . '.' . backquote($table), null, PMA_DBI_QUERY_UNBUFFERED);
1010 // Note: SHOW CREATE TABLE, at least in MySQL 5.1.23, does not
1011 // produce a displayable result for the default value of a BIT
1012 // column, nor does the mysqldump command. See MySQL bug 35796
1013 $result = PMA_DBI_try_query(
1014 'SHOW CREATE TABLE ' . PMA_Util::backquote($db) . '.'
1015 . PMA_Util::backquote($table)
1017 // an error can happen, for example the table is crashed
1018 $tmp_error = PMA_DBI_getError();
1019 if ($tmp_error) {
1020 return $this->_exportComment(__('in use') . '(' . $tmp_error . ')');
1023 if ($result != false && ($row = PMA_DBI_fetch_row($result))) {
1024 $create_query = $row[1];
1025 unset($row);
1027 // Convert end of line chars to one that we want (note that MySQL
1028 // doesn't return query it will accept in all cases)
1029 if (strpos($create_query, "(\r\n ")) {
1030 $create_query = str_replace("\r\n", $crlf, $create_query);
1031 } elseif (strpos($create_query, "(\n ")) {
1032 $create_query = str_replace("\n", $crlf, $create_query);
1033 } elseif (strpos($create_query, "(\r ")) {
1034 $create_query = str_replace("\r", $crlf, $create_query);
1038 * Drop database name from VIEW creation.
1040 * This is a bit tricky, but we need to issue SHOW CREATE TABLE with
1041 * database name, but we don't want name to show up in CREATE VIEW
1042 * statement.
1044 if ($view) {
1045 $create_query = preg_replace(
1046 '/' . PMA_Util::backquote($db) . '\./',
1048 $create_query
1052 // Should we use IF NOT EXISTS?
1053 // It always must be OFF for MSSQL compatibility mode
1054 if (isset($GLOBALS['sql_if_not_exists']) && $compat != 'MSSQL') {
1055 $create_query = preg_replace(
1056 '/^CREATE TABLE/',
1057 'CREATE TABLE IF NOT EXISTS',
1058 $create_query
1062 // In MSSQL
1063 // 1. DATE field doesn't exists, we will use DATETIME instead
1064 // 2. UNSIGNED attribute doesn't exist
1065 // 3. No length on INT, TINYINT, SMALLINT, BIGINT and no precision on
1066 // FLOAT fields
1067 // 4. No KEY and INDEX inside CREATE TABLE
1068 // 5. DOUBLE field doesn't exists, we will use FLOAT instead
1069 if ($compat == 'MSSQL') {
1070 // first we need to replace all lines ended with '" DATE ...,\n'
1071 // last preg_replace preserve us from situation with date text
1072 // inside DEFAULT field value
1073 $create_query = preg_replace(
1074 "/\" date DEFAULT NULL(,)?\n/",
1075 '" datetime DEFAULT NULL$1' . "\n",
1076 $create_query
1078 $create_query = preg_replace(
1079 "/\" date NOT NULL(,)?\n/",
1080 '" datetime NOT NULL$1' . "\n",
1081 $create_query
1083 $create_query = preg_replace(
1084 '/" date NOT NULL DEFAULT \'([^\'])/',
1085 '" datetime NOT NULL DEFAULT \'$1',
1086 $create_query
1089 // next we need to replace all lines ended with ') UNSIGNED ...,'
1090 // last preg_replace preserve us from situation with unsigned text
1091 // inside DEFAULT field value
1092 $create_query = preg_replace(
1093 "/\) unsigned NOT NULL(,)?\n/",
1094 ') NOT NULL$1' . "\n",
1095 $create_query
1097 $create_query = preg_replace(
1098 "/\) unsigned DEFAULT NULL(,)?\n/",
1099 ') DEFAULT NULL$1' . "\n",
1100 $create_query
1102 $create_query = preg_replace(
1103 '/\) unsigned NOT NULL DEFAULT \'([^\'])/',
1104 ') NOT NULL DEFAULT \'$1',
1105 $create_query
1108 // we need to replace all lines ended with
1109 // '" INT|TINYINT([0-9]{1,}) ...,' last preg_replace preserve us
1110 // from situation with int([0-9]{1,}) text inside DEFAULT field
1111 // value
1112 $create_query = preg_replace(
1113 '/" (int|tinyint|smallint|bigint)\([0-9]+\) DEFAULT NULL(,)?\n/',
1114 '" $1 DEFAULT NULL$2' . "\n",
1115 $create_query
1117 $create_query = preg_replace(
1118 '/" (int|tinyint|smallint|bigint)\([0-9]+\) NOT NULL(,)?\n/',
1119 '" $1 NOT NULL$2' . "\n",
1120 $create_query
1122 $create_query = preg_replace(
1123 '/" (int|tinyint|smallint|bigint)\([0-9]+\) NOT NULL DEFAULT \'([^\'])/',
1124 '" $1 NOT NULL DEFAULT \'$2',
1125 $create_query
1128 // we need to replace all lines ended with
1129 // '" FLOAT|DOUBLE([0-9,]{1,}) ...,'
1130 // last preg_replace preserve us from situation with
1131 // float([0-9,]{1,}) text inside DEFAULT field value
1132 $create_query = preg_replace(
1133 '/" (float|double)(\([0-9]+,[0-9,]+\))? DEFAULT NULL(,)?\n/',
1134 '" float DEFAULT NULL$3' . "\n",
1135 $create_query
1137 $create_query = preg_replace(
1138 '/" (float|double)(\([0-9,]+,[0-9,]+\))? NOT NULL(,)?\n/',
1139 '" float NOT NULL$3' . "\n",
1140 $create_query
1142 $create_query = preg_replace(
1143 '/" (float|double)(\([0-9,]+,[0-9,]+\))? NOT NULL DEFAULT \'([^\'])/',
1144 '" float NOT NULL DEFAULT \'$3',
1145 $create_query
1148 // @todo remove indexes from CREATE TABLE
1151 // Drizzle (checked on 2011.03.13) returns ROW_FORMAT surrounded
1152 // with quotes, which is not accepted by parser
1153 if (PMA_DRIZZLE) {
1154 $create_query = preg_replace(
1155 '/ROW_FORMAT=\'(\S+)\'/',
1156 'ROW_FORMAT=$1',
1157 $create_query
1161 // are there any constraints to cut out?
1162 if (preg_match('@CONSTRAINT|FOREIGN[\s]+KEY@', $create_query)) {
1164 // Split the query into lines, so we can easily handle it.
1165 // We know lines are separated by $crlf (done few lines above).
1166 $sql_lines = explode($crlf, $create_query);
1167 $sql_count = count($sql_lines);
1169 // lets find first line with constraints
1170 for ($i = 0; $i < $sql_count; $i++) {
1171 if (preg_match(
1172 '@^[\s]*(CONSTRAINT|FOREIGN[\s]+KEY)@',
1173 $sql_lines[$i]
1174 )) {
1175 break;
1179 // If we really found a constraint
1180 if ($i != $sql_count) {
1182 // remove, from the end of create statement
1183 $sql_lines[$i - 1] = preg_replace(
1184 '@,$@',
1186 $sql_lines[$i - 1]
1189 // prepare variable for constraints
1190 if (! isset($sql_constraints)) {
1191 if (isset($GLOBALS['no_constraints_comments'])) {
1192 $sql_constraints = '';
1193 } else {
1194 $sql_constraints = $crlf
1195 . $this->_exportComment()
1196 . $this->_exportComment(
1197 __('Constraints for dumped tables')
1199 . $this->_exportComment();
1203 // comments for current table
1204 if (! isset($GLOBALS['no_constraints_comments'])) {
1205 $sql_constraints .= $crlf
1206 . $this->_exportComment()
1207 . $this->_exportComment(
1208 __('Constraints for table')
1209 . ' '
1210 . PMA_Util::backquoteCompat($table, $compat)
1212 . $this->_exportComment();
1215 // let's do the work
1216 $sql_constraints_query .= 'ALTER TABLE '
1217 . PMA_Util::backquoteCompat($table, $compat)
1218 . $crlf;
1219 $sql_constraints .= 'ALTER TABLE '
1220 . PMA_Util::backquoteCompat($table, $compat)
1221 . $crlf;
1222 $sql_drop_foreign_keys .= 'ALTER TABLE '
1223 . PMA_Util::backquoteCompat($db, $compat) . '.'
1224 . PMA_Util::backquoteCompat($table, $compat)
1225 . $crlf;
1227 $first = true;
1228 for ($j = $i; $j < $sql_count; $j++) {
1229 if (preg_match(
1230 '@CONSTRAINT|FOREIGN[\s]+KEY@',
1231 $sql_lines[$j]
1232 )) {
1233 if (! $first) {
1234 $sql_constraints .= $crlf;
1236 if (strpos($sql_lines[$j], 'CONSTRAINT') === false) {
1237 $tmp_str = preg_replace(
1238 '/(FOREIGN[\s]+KEY)/',
1239 'ADD \1',
1240 $sql_lines[$j]
1242 $sql_constraints_query .= $tmp_str;
1243 $sql_constraints .= $tmp_str;
1244 } else {
1245 $tmp_str = preg_replace(
1246 '/(CONSTRAINT)/',
1247 'ADD \1',
1248 $sql_lines[$j]
1250 $sql_constraints_query .= $tmp_str;
1251 $sql_constraints .= $tmp_str;
1252 preg_match(
1253 '/(CONSTRAINT)([\s])([\S]*)([\s])/',
1254 $sql_lines[$j],
1255 $matches
1257 if (! $first) {
1258 $sql_drop_foreign_keys .= ', ';
1260 $sql_drop_foreign_keys .= 'DROP FOREIGN KEY '
1261 . $matches[3];
1263 $first = false;
1264 } else {
1265 break;
1268 $sql_constraints .= ';' . $crlf;
1269 $sql_constraints_query .= ';';
1271 $create_query = implode(
1272 $crlf,
1273 array_slice($sql_lines, 0, $i)
1275 . $crlf
1276 . implode(
1277 $crlf,
1278 array_slice($sql_lines, $j, $sql_count - 1)
1280 unset($sql_lines);
1283 $schema_create .= $create_query;
1286 // remove a possible "AUTO_INCREMENT = value" clause
1287 // that could be there starting with MySQL 5.0.24
1288 // in Drizzle it's useless as it contains the value given at table
1289 // creation time
1290 $schema_create = preg_replace(
1291 '/AUTO_INCREMENT\s*=\s*([0-9])+/',
1293 $schema_create
1296 $schema_create .= ($compat != 'MSSQL') ? $auto_increment : '';
1298 PMA_DBI_free_result($result);
1299 return $schema_create . ($add_semicolon ? ';' . $crlf : '');
1300 } // end of the 'getTableDef()' function
1303 * Returns $table's comments, relations etc.
1305 * @param string $db database name
1306 * @param string $table table name
1307 * @param string $crlf end of line sequence
1308 * @param bool $do_relation whether to include relation comments
1309 * @param bool $do_mime whether to include mime comments
1311 * @return string resulting comments
1313 private function _getTableComments(
1314 $db,
1315 $table,
1316 $crlf,
1317 $do_relation = false,
1318 $do_mime = false
1320 global $cfgRelation, $sql_backquotes;
1322 $schema_create = '';
1324 // Check if we can use Relations
1325 if ($do_relation && ! empty($cfgRelation['relation'])) {
1326 // Find which tables are related with the current one and write it in
1327 // an array
1328 $res_rel = PMA_getForeigners($db, $table);
1330 if ($res_rel && count($res_rel) > 0) {
1331 $have_rel = true;
1332 } else {
1333 $have_rel = false;
1335 } else {
1336 $have_rel = false;
1337 } // end if
1339 if ($do_mime && $cfgRelation['mimework']) {
1340 if (! ($mime_map = PMA_getMIME($db, $table, true))) {
1341 unset($mime_map);
1345 if (isset($mime_map) && count($mime_map) > 0) {
1346 $schema_create .= $this->_possibleCRLF()
1347 . $this->_exportComment()
1348 . $this->_exportComment(
1349 __('MIME TYPES FOR TABLE'). ' '
1350 . PMA_Util::backquote($table, $sql_backquotes) . ':'
1352 @reset($mime_map);
1353 foreach ($mime_map AS $mime_field => $mime) {
1354 $schema_create .=
1355 $this->_exportComment(
1357 . PMA_Util::backquote($mime_field, $sql_backquotes)
1359 . $this->_exportComment(
1361 . PMA_Util::backquote(
1362 $mime['mimetype'],
1363 $sql_backquotes
1367 $schema_create .= $this->_exportComment();
1370 if ($have_rel) {
1371 $schema_create .= $this->_possibleCRLF()
1372 . $this->_exportComment()
1373 . $this->_exportComment(
1374 __('RELATIONS FOR TABLE') . ' '
1375 . PMA_Util::backquote($table, $sql_backquotes)
1376 . ':'
1378 foreach ($res_rel AS $rel_field => $rel) {
1379 $schema_create .=
1380 $this->_exportComment(
1382 . PMA_Util::backquote($rel_field, $sql_backquotes)
1384 . $this->_exportComment(
1386 . PMA_Util::backquote(
1387 $rel['foreign_table'],
1388 $sql_backquotes
1390 . ' -> '
1391 . PMA_Util::backquote(
1392 $rel['foreign_field'],
1393 $sql_backquotes
1397 $schema_create .= $this->_exportComment();
1400 return $schema_create;
1402 } // end of the '_getTableComments()' function
1405 * Outputs table's structure
1407 * @param string $db database name
1408 * @param string $table table name
1409 * @param string $crlf the end of line sequence
1410 * @param string $error_url the url to go back in case of error
1411 * @param string $export_mode 'create_table','triggers','create_view',
1412 * 'stand_in'
1413 * @param string $export_type 'server', 'database', 'table'
1414 * @param bool $relation whether to include relation comments
1415 * @param bool $comments whether to include the pmadb-style column
1416 * comments as comments in the structure; this is
1417 * deprecated but the parameter is left here
1418 * because export.php calls exportStructure()
1419 * also for other export types which use this
1420 * parameter
1421 * @param bool $mime whether to include mime comments
1422 * @param bool $dates whether to include creation/update/check dates
1424 * @return bool Whether it succeeded
1426 public function exportStructure(
1427 $db,
1428 $table,
1429 $crlf,
1430 $error_url,
1431 $export_mode,
1432 $export_type,
1433 $relation = false,
1434 $comments = false,
1435 $mime = false,
1436 $dates = false
1438 if (isset($GLOBALS['sql_compatibility'])) {
1439 $compat = $GLOBALS['sql_compatibility'];
1440 } else {
1441 $compat = 'NONE';
1444 $formatted_table_name = (isset($GLOBALS['sql_backquotes']))
1445 ? PMA_Util::backquoteCompat($table, $compat)
1446 : '\'' . $table . '\'';
1447 $dump = $this->_possibleCRLF()
1448 . $this->_exportComment(str_repeat('-', 56))
1449 . $this->_possibleCRLF()
1450 . $this->_exportComment();
1452 switch($export_mode) {
1453 case 'create_table':
1454 $dump .= $this->_exportComment(
1455 __('Table structure for table') . ' '. $formatted_table_name
1457 $dump .= $this->_exportComment();
1458 $dump .= $this->getTableDef($db, $table, $crlf, $error_url, $dates);
1459 $dump .= $this->_getTableComments($db, $table, $crlf, $relation, $mime);
1460 break;
1461 case 'triggers':
1462 $dump = '';
1463 $triggers = PMA_DBI_get_triggers($db, $table);
1464 if ($triggers) {
1465 $dump .= $this->_possibleCRLF()
1466 . $this->_exportComment()
1467 . $this->_exportComment(
1468 __('Triggers') . ' ' . $formatted_table_name
1470 . $this->_exportComment();
1471 $delimiter = '//';
1472 foreach ($triggers as $trigger) {
1473 $dump .= $trigger['drop'] . ';' . $crlf;
1474 $dump .= 'DELIMITER ' . $delimiter . $crlf;
1475 $dump .= $trigger['create'];
1476 $dump .= 'DELIMITER ;' . $crlf;
1479 break;
1480 case 'create_view':
1481 $dump .=
1482 $this->_exportComment(
1483 __('Structure for view')
1484 . ' '
1485 . $formatted_table_name
1487 . $this->_exportComment();
1488 // delete the stand-in table previously created (if any)
1489 if ($export_type != 'table') {
1490 $dump .= 'DROP TABLE IF EXISTS '
1491 . PMA_Util::backquote($table) . ';' . $crlf;
1493 $dump .= $this->getTableDef(
1494 $db, $table, $crlf, $error_url, $dates, true, true
1496 break;
1497 case 'stand_in':
1498 $dump .=
1499 $this->_exportComment(
1500 __('Stand-in structure for view') . ' ' . $formatted_table_name
1502 . $this->_exportComment();
1503 // export a stand-in definition to resolve view dependencies
1504 $dump .= $this->getTableDefStandIn($db, $table, $crlf);
1505 } // end switch
1507 // this one is built by getTableDef() to use in table copy/move
1508 // but not in the case of export
1509 unset($GLOBALS['sql_constraints_query']);
1511 return PMA_exportOutputHandler($dump);
1515 * Outputs the content of a table in SQL format
1517 * @param string $db database name
1518 * @param string $table table name
1519 * @param string $crlf the end of line sequence
1520 * @param string $error_url the url to go back in case of error
1521 * @param string $sql_query SQL query for obtaining data
1523 * @return bool Whether it succeeded
1525 public function exportData($db, $table, $crlf, $error_url, $sql_query)
1527 global $current_row, $sql_backquotes;
1529 if (isset($GLOBALS['sql_compatibility'])) {
1530 $compat = $GLOBALS['sql_compatibility'];
1531 } else {
1532 $compat = 'NONE';
1535 $formatted_table_name = (isset($GLOBALS['sql_backquotes']))
1536 ? PMA_Util::backquoteCompat($table, $compat)
1537 : '\'' . $table . '\'';
1539 // Do not export data for a VIEW
1540 // (For a VIEW, this is called only when exporting a single VIEW)
1541 if (PMA_Table::isView($db, $table)) {
1542 $head = $this->_possibleCRLF()
1543 . $this->_exportComment()
1544 . $this->_exportComment('VIEW ' . ' ' . $formatted_table_name)
1545 . $this->_exportComment(__('Data') . ': ' . __('None'))
1546 . $this->_exportComment()
1547 . $this->_possibleCRLF();
1549 if (! PMA_exportOutputHandler($head)) {
1550 return false;
1552 return true;
1555 // analyze the query to get the true column names, not the aliases
1556 // (this fixes an undefined index, also if Complete inserts
1557 // are used, we did not get the true column name in case of aliases)
1558 $analyzed_sql = PMA_SQP_analyze(PMA_SQP_parse($sql_query));
1560 $result = PMA_DBI_try_query($sql_query, null, PMA_DBI_QUERY_UNBUFFERED);
1561 // a possible error: the table has crashed
1562 $tmp_error = PMA_DBI_getError();
1563 if ($tmp_error) {
1564 return PMA_exportOutputHandler(
1565 $this->_exportComment(
1566 __('Error reading data:') . ' (' . $tmp_error . ')'
1571 if ($result != false) {
1572 $fields_cnt = PMA_DBI_num_fields($result);
1574 // Get field information
1575 $fields_meta = PMA_DBI_get_fields_meta($result);
1576 $field_flags = array();
1577 for ($j = 0; $j < $fields_cnt; $j++) {
1578 $field_flags[$j] = PMA_DBI_field_flags($result, $j);
1581 for ($j = 0; $j < $fields_cnt; $j++) {
1582 if (isset($analyzed_sql[0]['select_expr'][$j]['column'])) {
1583 $field_set[$j] = PMA_Util::backquoteCompat(
1584 $analyzed_sql[0]['select_expr'][$j]['column'],
1585 $compat,
1586 $sql_backquotes
1588 } else {
1589 $field_set[$j] = PMA_Util::backquoteCompat(
1590 $fields_meta[$j]->name,
1591 $compat,
1592 $sql_backquotes
1597 if (isset($GLOBALS['sql_type'])
1598 && $GLOBALS['sql_type'] == 'UPDATE'
1600 // update
1601 $schema_insert = 'UPDATE ';
1602 if (isset($GLOBALS['sql_ignore'])) {
1603 $schema_insert .= 'IGNORE ';
1605 // avoid EOL blank
1606 $schema_insert .= PMA_Util::backquoteCompat(
1607 $table,
1608 $compat,
1609 $sql_backquotes
1610 ) . ' SET';
1611 } else {
1612 // insert or replace
1613 if (isset($GLOBALS['sql_type'])
1614 && $GLOBALS['sql_type'] == 'REPLACE'
1616 $sql_command = 'REPLACE';
1617 } else {
1618 $sql_command = 'INSERT';
1621 // delayed inserts?
1622 if (isset($GLOBALS['sql_delayed'])) {
1623 $insert_delayed = ' DELAYED';
1624 } else {
1625 $insert_delayed = '';
1628 // insert ignore?
1629 if (isset($GLOBALS['sql_type'])
1630 && $GLOBALS['sql_type'] == 'INSERT'
1631 && isset($GLOBALS['sql_ignore'])
1633 $insert_delayed .= ' IGNORE';
1635 //truncate table before insert
1636 if (isset($GLOBALS['sql_truncate'])
1637 && $GLOBALS['sql_truncate']
1638 && $sql_command == 'INSERT'
1640 $truncate = 'TRUNCATE TABLE '
1641 . PMA_Util::backquoteCompat(
1642 $table,
1643 $compat,
1644 $sql_backquotes
1645 ) . ";";
1646 $truncatehead = $this->_possibleCRLF()
1647 . $this->_exportComment()
1648 . $this->_exportComment(
1649 __('Truncate table before insert') . ' '
1650 . $formatted_table_name
1652 . $this->_exportComment()
1653 . $crlf;
1654 PMA_exportOutputHandler($truncatehead);
1655 PMA_exportOutputHandler($truncate);
1656 } else {
1657 $truncate = '';
1660 // scheme for inserting fields
1661 if ($GLOBALS['sql_insert_syntax'] == 'complete'
1662 || $GLOBALS['sql_insert_syntax'] == 'both'
1664 $fields = implode(', ', $field_set);
1665 $schema_insert = $sql_command . $insert_delayed .' INTO '
1666 . PMA_Util::backquoteCompat(
1667 $table,
1668 $compat,
1669 $sql_backquotes
1671 // avoid EOL blank
1672 . ' (' . $fields . ') VALUES';
1673 } else {
1674 $schema_insert = $sql_command . $insert_delayed .' INTO '
1675 . PMA_Util::backquoteCompat(
1676 $table,
1677 $compat,
1678 $sql_backquotes
1680 . ' VALUES';
1684 //\x08\\x09, not required
1685 $search = array("\x00", "\x0a", "\x0d", "\x1a");
1686 $replace = array('\0', '\n', '\r', '\Z');
1687 $current_row = 0;
1688 $query_size = 0;
1689 if (($GLOBALS['sql_insert_syntax'] == 'extended'
1690 || $GLOBALS['sql_insert_syntax'] == 'both')
1691 && (! isset($GLOBALS['sql_type'])
1692 || $GLOBALS['sql_type'] != 'UPDATE')
1694 $separator = ',';
1695 $schema_insert .= $crlf;
1696 } else {
1697 $separator = ';';
1700 while ($row = PMA_DBI_fetch_row($result)) {
1701 if ($current_row == 0) {
1702 $head = $this->_possibleCRLF()
1703 . $this->_exportComment()
1704 . $this->_exportComment(
1705 __('Dumping data for table') . ' '
1706 . $formatted_table_name
1708 . $this->_exportComment()
1709 . $crlf;
1710 if (! PMA_exportOutputHandler($head)) {
1711 return false;
1714 // We need to SET IDENTITY_INSERT ON for MSSQL
1715 if (isset($GLOBALS['sql_compatibility'])
1716 && $GLOBALS['sql_compatibility'] == 'MSSQL'
1717 && $current_row == 0
1719 if (! PMA_exportOutputHandler(
1720 'SET IDENTITY_INSERT '
1721 . PMA_Util::backquoteCompat(
1722 $table,
1723 $compat
1725 . ' ON ;'.$crlf
1726 )) {
1727 return false;
1730 $current_row++;
1731 for ($j = 0; $j < $fields_cnt; $j++) {
1732 // NULL
1733 if (! isset($row[$j]) || is_null($row[$j])) {
1734 $values[] = 'NULL';
1735 } elseif ($fields_meta[$j]->numeric
1736 && $fields_meta[$j]->type != 'timestamp'
1737 && ! $fields_meta[$j]->blob
1739 // a number
1740 // timestamp is numeric on some MySQL 4.1, BLOBs are
1741 // sometimes numeric
1742 $values[] = $row[$j];
1743 } elseif (stristr($field_flags[$j], 'BINARY')
1744 && $fields_meta[$j]->blob
1745 && isset($GLOBALS['sql_hex_for_blob'])
1747 // a true BLOB
1748 // - mysqldump only generates hex data when the --hex-blob
1749 // option is used, for fields having the binary attribute
1750 // no hex is generated
1751 // - a TEXT field returns type blob but a real blob
1752 // returns also the 'binary' flag
1754 // empty blobs need to be different, but '0' is also empty
1755 // :-(
1756 if (empty($row[$j]) && $row[$j] != '0') {
1757 $values[] = '\'\'';
1758 } else {
1759 $values[] = '0x' . bin2hex($row[$j]);
1761 } elseif ($fields_meta[$j]->type == 'bit') {
1762 // detection of 'bit' works only on mysqli extension
1763 $values[] = "b'" . PMA_Util::sqlAddSlashes(
1764 PMA_Util::printableBitValue(
1765 $row[$j], $fields_meta[$j]->length
1768 . "'";
1769 } else {
1770 // something else -> treat as a string
1771 $values[] = '\''
1772 . str_replace(
1773 $search, $replace,
1774 PMA_Util::sqlAddSlashes($row[$j])
1776 . '\'';
1777 } // end if
1778 } // end for
1780 // should we make update?
1781 if (isset($GLOBALS['sql_type'])
1782 && $GLOBALS['sql_type'] == 'UPDATE'
1785 $insert_line = $schema_insert;
1786 for ($i = 0; $i < $fields_cnt; $i++) {
1787 if (0 == $i) {
1788 $insert_line .= ' ';
1790 if ($i > 0) {
1791 // avoid EOL blank
1792 $insert_line .= ',';
1794 $insert_line .= $field_set[$i] . ' = ' . $values[$i];
1797 list($tmp_unique_condition, $tmp_clause_is_unique)
1798 = PMA_Util::getUniqueCondition(
1799 $result,
1800 $fields_cnt,
1801 $fields_meta,
1802 $row
1804 $insert_line .= ' WHERE ' . $tmp_unique_condition;
1805 unset($tmp_unique_condition, $tmp_clause_is_unique);
1807 } else {
1809 // Extended inserts case
1810 if ($GLOBALS['sql_insert_syntax'] == 'extended'
1811 || $GLOBALS['sql_insert_syntax'] == 'both'
1813 if ($current_row == 1) {
1814 $insert_line = $schema_insert . '('
1815 . implode(', ', $values) . ')';
1816 } else {
1817 $insert_line = '(' . implode(', ', $values) . ')';
1818 $sql_max_size = $GLOBALS['sql_max_query_size'];
1819 if (isset($sql_max_size)
1820 && $sql_max_size > 0
1821 && $query_size + strlen($insert_line) > $sql_max_size
1823 if (! PMA_exportOutputHandler(';' . $crlf)) {
1824 return false;
1826 $query_size = 0;
1827 $current_row = 1;
1828 $insert_line = $schema_insert . $insert_line;
1831 $query_size += strlen($insert_line);
1832 // Other inserts case
1833 } else {
1834 $insert_line = $schema_insert
1835 . '('
1836 . implode(', ', $values)
1837 . ')';
1840 unset($values);
1842 if (! PMA_exportOutputHandler(
1843 ($current_row == 1 ? '' : $separator . $crlf)
1844 . $insert_line
1845 )) {
1846 return false;
1849 } // end while
1851 if ($current_row > 0) {
1852 if (! PMA_exportOutputHandler(';' . $crlf)) {
1853 return false;
1857 // We need to SET IDENTITY_INSERT OFF for MSSQL
1858 if (isset($GLOBALS['sql_compatibility'])
1859 && $GLOBALS['sql_compatibility'] == 'MSSQL'
1860 && $current_row > 0
1862 $outputSucceeded = PMA_exportOutputHandler(
1863 $crlf . 'SET IDENTITY_INSERT '
1864 . PMA_Util::backquoteCompat($table, $compat)
1865 . ' OFF;' . $crlf
1867 if (! $outputSucceeded) {
1868 return false;
1871 } // end if ($result != false)
1872 PMA_DBI_free_result($result);
1874 return true;
1875 } // end of the 'exportData()' function