Advertisement
Guest User

Untitled

a guest
Nov 16th, 2015
77
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 51.76 KB | None | 0 0
  1. <?php
  2. /**
  3. * Mysqldump File Doc Comment
  4. *
  5. * PHP version 5
  6. *
  7. * @category Library
  8. * @package Ifsnop\Mysqldump
  9. * @author Michael J. Calkins <clouddueling@github.com>
  10. * @author Diego Torres <ifsnop@github.com>
  11. * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License
  12. * @link https://github.com/ifsnop/mysqldump-php
  13. *
  14. */
  15.  
  16. namespace Ifsnop\Mysqldump;
  17.  
  18. use Exception;
  19. use PDO;
  20. use PDOException;
  21.  
  22. /**
  23. * Mysqldump Class Doc Comment
  24. *
  25. * @category Library
  26. * @package Ifsnop\Mysqldump
  27. * @author Michael J. Calkins <clouddueling@github.com>
  28. * @author Diego Torres <ifsnop@github.com>
  29. * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License
  30. * @link https://github.com/ifsnop/mysqldump-php
  31. *
  32. */
  33. class Mysqldump
  34. {
  35.  
  36. // Same as mysqldump
  37. const MAXLINESIZE = 1000000;
  38.  
  39. // Available compression methods as constants
  40. const GZIP = 'Gzip';
  41. const BZIP2 = 'Bzip2';
  42. const NONE = 'None';
  43.  
  44. // Available connection strings
  45. const UTF8 = 'utf8';
  46. const UTF8MB4 = 'utf8mb4';
  47.  
  48. /**
  49. * Database username
  50. * @var string
  51. */
  52. public $user;
  53. /**
  54. * Database password
  55. * @var string
  56. */
  57. public $pass;
  58. /**
  59. * Connection string for PDO
  60. * @var string
  61. */
  62. public $dsn;
  63. /**
  64. * Destination filename, defaults to stdout
  65. * @var string
  66. */
  67. public $fileName = 'php://output';
  68.  
  69. // Internal stuff
  70. private $tables = array();
  71. private $views = array();
  72. private $triggers = array();
  73. private $procedures = array();
  74. private $dbHandler;
  75. private $dbType;
  76. private $compressManager;
  77. private $typeAdapter;
  78. private $dumpSettings = array();
  79. private $pdoSettings = array();
  80. private $version;
  81. private $tableColumnTypes = array();
  82. /**
  83. * database name, parsed from dsn
  84. * @var string
  85. */
  86. private $dbName;
  87. /**
  88. * host name, parsed from dsn
  89. * @var string
  90. */
  91. private $host;
  92. /**
  93. * dsn string parsed as an array
  94. * @var array
  95. */
  96. private $dsnArray = array();
  97.  
  98. /**
  99. * Constructor of Mysqldump. Note that in the case of an SQLite database
  100. * connection, the filename must be in the $db parameter.
  101. *
  102. * @param string $dsn PDO DSN connection string
  103. * @param string $user SQL account username
  104. * @param string $pass SQL account password
  105. * @param array $dumpSettings SQL database settings
  106. * @param array $pdoSettings PDO configured attributes
  107. */
  108. public function __construct(
  109. $dsn = '',
  110. $user = '',
  111. $pass = '',
  112. $dumpSettings = array(),
  113. $pdoSettings = array()
  114. ) {
  115. $dumpSettingsDefault = array(
  116. 'include-tables' => array(),
  117. 'exclude-tables' => array(),
  118. 'compress' => Mysqldump::NONE,
  119. 'no-data' => false,
  120. 'add-drop-table' => false,
  121. 'single-transaction' => true,
  122. 'lock-tables' => true,
  123. 'add-locks' => true,
  124. 'extended-insert' => true,
  125. 'disable-keys' => true,
  126. 'where' => '',
  127. 'no-create-info' => false,
  128. 'skip-triggers' => false,
  129. 'add-drop-trigger' => true,
  130. 'routines' => false,
  131. 'hex-blob' => true, /* faster than escaped content */
  132. 'databases' => false,
  133. 'add-drop-database' => false,
  134. 'skip-tz-utc' => false,
  135. 'no-autocommit' => true,
  136. 'default-character-set' => Mysqldump::UTF8,
  137. 'skip-comments' => false,
  138. 'skip-dump-date' => false,
  139. 'init_commands' => array(),
  140. /* deprecated */
  141. 'disable-foreign-keys-check' => true
  142. );
  143.  
  144. $pdoSettingsDefault = array(
  145. PDO::ATTR_PERSISTENT => true,
  146. PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
  147. PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => false
  148. );
  149.  
  150. $this->user = $user;
  151. $this->pass = $pass;
  152. $this->parseDsn($dsn);
  153. $this->pdoSettings = self::array_replace_recursive($pdoSettingsDefault, $pdoSettings);
  154. $this->dumpSettings = self::array_replace_recursive($dumpSettingsDefault, $dumpSettings);
  155.  
  156. $this->dumpSettings['init_commands'][] = "SET NAMES " . $this->dumpSettings['default-character-set'];
  157.  
  158. if (false === $this->dumpSettings['skip-tz-utc']) {
  159. $this->dumpSettings['init_commands'][] = "SET TIME_ZONE='+00:00'";
  160. }
  161.  
  162. $diff = array_diff(array_keys($this->dumpSettings), array_keys($dumpSettingsDefault));
  163. if (count($diff)>0) {
  164. throw new Exception("Unexpected value in dumpSettings: (" . implode(",", $diff) . ")");
  165. }
  166.  
  167. // Create a new compressManager to manage compressed output
  168. $this->compressManager = CompressManagerFactory::create($this->dumpSettings['compress']);
  169. }
  170.  
  171. /**
  172. * Custom array_replace_recursive to be used if PHP < 5.3
  173. * Replaces elements from passed arrays into the first array recursively
  174. *
  175. * @param array $array1 The array in which elements are replaced
  176. * @param array $array2 The array from which elements will be extracted
  177. *
  178. * @return array Returns an array, or NULL if an error occurs.
  179. */
  180. public static function array_replace_recursive($array1, $array2)
  181. {
  182. if (function_exists('array_replace_recursive')) {
  183. return array_replace_recursive($array1, $array2);
  184. }
  185.  
  186. foreach ($array2 as $key => $value) {
  187. if (is_array($value)) {
  188. $array1[$key] = self::array_replace_recursive($array1[$key], $value);
  189. } else {
  190. $array1[$key] = $value;
  191. }
  192. }
  193. return $array1;
  194. }
  195.  
  196. /**
  197. * Parse DSN string and extract dbname value
  198. * Several examples of a DSN string
  199. * mysql:host=localhost;dbname=testdb
  200. * mysql:host=localhost;port=3307;dbname=testdb
  201. * mysql:unix_socket=/tmp/mysql.sock;dbname=testdb
  202. *
  203. * @param string $dsn dsn string to parse
  204. */
  205. private function parseDsn($dsn)
  206. {
  207. if (empty($dsn) || (false === ($pos = strpos($dsn, ":")))) {
  208. throw new Exception("Empty DSN string");
  209. }
  210.  
  211. $this->dsn = $dsn;
  212. $this->dbType = strtolower(substr($dsn, 0, $pos));
  213.  
  214. if (empty($this->dbType)) {
  215. throw new Exception("Missing database type from DSN string");
  216. }
  217.  
  218. $dsn = substr($dsn, $pos + 1);
  219.  
  220. foreach(explode(";", $dsn) as $kvp) {
  221. $kvpArr = explode("=", $kvp);
  222. $this->dsnArray[strtolower($kvpArr[0])] = $kvpArr[1];
  223. }
  224.  
  225. if (empty($this->dsnArray['host']) &&
  226. empty($this->dsnArray['unix_socket'])) {
  227. throw new Exception("Missing host from DSN string");
  228. }
  229. $this->host = (!empty($this->dsnArray['host'])) ?
  230. $this->dsnArray['host'] :
  231. $this->dsnArray['unix_socket'];
  232.  
  233. if (empty($this->dsnArray['dbname'])) {
  234. throw new Exception("Missing database name from DSN string");
  235. }
  236.  
  237. $this->dbName = $this->dsnArray['dbname'];
  238.  
  239. return true;
  240. }
  241.  
  242. /**
  243. * Connect with PDO
  244. *
  245. * @return null
  246. */
  247. private function connect()
  248. {
  249. // Connecting with PDO
  250. try {
  251. switch ($this->dbType) {
  252. case 'sqlite':
  253. $this->dbHandler = @new PDO("sqlite:" . $this->dbName, null, null, $this->pdoSettings);
  254. break;
  255. case 'mysql':
  256. case 'pgsql':
  257. case 'dblib':
  258. $this->dbHandler = @new PDO(
  259. $this->dsn,
  260. $this->user,
  261. $this->pass,
  262. $this->pdoSettings
  263. );
  264. // Execute init commands once connected
  265. foreach($this->dumpSettings['init_commands'] as $stmt) {
  266. $this->dbHandler->exec($stmt);
  267. }
  268. // Store server version
  269. $this->version = $this->dbHandler->getAttribute(PDO::ATTR_SERVER_VERSION);
  270. break;
  271. default:
  272. throw new Exception("Unsupported database type (" . $this->dbType . ")");
  273. }
  274. } catch (PDOException $e) {
  275. throw new Exception(
  276. "Connection to " . $this->dbType . " failed with message: " .
  277. $e->getMessage()
  278. );
  279. }
  280.  
  281. $this->dbHandler->setAttribute(PDO::ATTR_ORACLE_NULLS, PDO::NULL_NATURAL);
  282. $this->typeAdapter = TypeAdapterFactory::create($this->dbType, $this->dbHandler);
  283. }
  284.  
  285. /**
  286. * Main call
  287. *
  288. * @param string $filename Name of file to write sql dump to
  289. * @return null
  290. */
  291. public function start($filename = '')
  292. {
  293. // Output file can be redefined here
  294. if (!empty($filename)) {
  295. $this->fileName = $filename;
  296. }
  297.  
  298. // Connect to database
  299. $this->connect();
  300.  
  301. // Create output file
  302. $this->compressManager->open($this->fileName);
  303.  
  304. // Write some basic info to output file
  305. $this->compressManager->write($this->getDumpFileHeader());
  306.  
  307. // Store server settings and use sanner defaults to dump
  308. $this->compressManager->write(
  309. $this->typeAdapter->backup_parameters($this->dumpSettings)
  310. );
  311.  
  312. if ($this->dumpSettings['databases']) {
  313. $this->compressManager->write(
  314. $this->typeAdapter->getDatabaseHeader($this->dbName)
  315. );
  316. if ($this->dumpSettings['add-drop-database']) {
  317. $this->compressManager->write(
  318. $this->typeAdapter->add_drop_database($this->dbName)
  319. );
  320. }
  321. }
  322.  
  323. // Get table, view and trigger structures from database
  324. $this->getDatabaseStructure();
  325.  
  326. if ($this->dumpSettings['databases']) {
  327. $this->compressManager->write(
  328. $this->typeAdapter->databases($this->dbName)
  329. );
  330. }
  331.  
  332. // If there still are some tables/views in include-tables array,
  333. // that means that some tables or views weren't found.
  334. // Give proper error and exit.
  335. if (0 < count($this->dumpSettings['include-tables'])) {
  336. $name = implode(",", $this->dumpSettings['include-tables']);
  337. throw new Exception("Table or View (" . $name . ") not found in database");
  338. }
  339.  
  340. $this->exportTables();
  341. $this->exportViews();
  342. $this->exportTriggers();
  343. $this->exportProcedures();
  344.  
  345. // Restore saved parameters
  346. $this->compressManager->write(
  347. $this->typeAdapter->restore_parameters($this->dumpSettings)
  348. );
  349. // Write some stats to output file
  350. $this->compressManager->write($this->getDumpFileFooter());
  351. // Close output file
  352. $this->compressManager->close();
  353. }
  354.  
  355. /**
  356. * Returns header for dump file
  357. *
  358. * @return string
  359. */
  360. private function getDumpFileHeader()
  361. {
  362. $header = '';
  363. if (!$this->dumpSettings['skip-comments']) {
  364. // Some info about software, source and time
  365. $header = "-- mysqldump-php https://github.com/ifsnop/mysqldump-php" . PHP_EOL .
  366. "--" . PHP_EOL .
  367. "-- Host: {$this->host}\tDatabase: {$this->dbName}" . PHP_EOL .
  368. "-- ------------------------------------------------------" . PHP_EOL;
  369.  
  370. if (!empty($this->version)) {
  371. $header .= "-- Server version \t" . $this->version . PHP_EOL;
  372. }
  373.  
  374. $header .= "-- Date: " . date('r') . PHP_EOL . PHP_EOL;
  375. }
  376. return $header;
  377. }
  378.  
  379. /**
  380. * Returns footer for dump file
  381. *
  382. * @return string
  383. */
  384. private function getDumpFileFooter()
  385. {
  386. $footer = '';
  387. if (!$this->dumpSettings['skip-comments']) {
  388. $footer .= '-- Dump completed';
  389. if (!$this->dumpSettings['skip-dump-date']) {
  390. $footer .= ' on: ' . date('r');
  391. }
  392. $footer .= PHP_EOL;
  393. }
  394.  
  395. return $footer;
  396. }
  397.  
  398. /**
  399. * Reads table and views names from database.
  400. * Fills $this->tables array so they will be dumped later.
  401. *
  402. * @return null
  403. */
  404. private function getDatabaseStructure()
  405. {
  406. // Listing all tables from database
  407. if (empty($this->dumpSettings['include-tables'])) {
  408. // include all tables for now, blacklisting happens later
  409. foreach ($this->dbHandler->query($this->typeAdapter->show_tables($this->dbName)) as $row) {
  410. array_push($this->tables, current($row));
  411. }
  412. } else {
  413. // include only the tables mentioned in include-tables
  414. foreach ($this->dbHandler->query($this->typeAdapter->show_tables($this->dbName)) as $row) {
  415. if (in_array(current($row), $this->dumpSettings['include-tables'], true)) {
  416. array_push($this->tables, current($row));
  417. $elem = array_search(
  418. current($row),
  419. $this->dumpSettings['include-tables']
  420. );
  421. unset($this->dumpSettings['include-tables'][$elem]);
  422. }
  423. }
  424. }
  425.  
  426. // Listing all views from database
  427. if (empty($this->dumpSettings['include-tables'])) {
  428. // include all views for now, blacklisting happens later
  429. foreach ($this->dbHandler->query($this->typeAdapter->show_views($this->dbName)) as $row) {
  430. array_push($this->views, current($row));
  431. }
  432. } else {
  433. // include only the tables mentioned in include-tables
  434. foreach ($this->dbHandler->query($this->typeAdapter->show_views($this->dbName)) as $row) {
  435. if (in_array(current($row), $this->dumpSettings['include-tables'], true)) {
  436. array_push($this->views, current($row));
  437. $elem = array_search(
  438. current($row),
  439. $this->dumpSettings['include-tables']
  440. );
  441. unset($this->dumpSettings['include-tables'][$elem]);
  442. }
  443. }
  444. }
  445.  
  446. // Listing all triggers from database
  447. if (false === $this->dumpSettings['skip-triggers']) {
  448. foreach ($this->dbHandler->query($this->typeAdapter->show_triggers($this->dbName)) as $row) {
  449. array_push($this->triggers, $row['Trigger']);
  450. }
  451. }
  452.  
  453. // Listing all procedures from database
  454. if ($this->dumpSettings['routines']) {
  455. foreach ($this->dbHandler->query($this->typeAdapter->show_procedures($this->dbName)) as $row) {
  456. array_push($this->procedures, $row['procedure_name']);
  457. }
  458. }
  459. }
  460.  
  461. /**
  462. * Exports all the tables selected from database
  463. *
  464. * @return null
  465. */
  466. private function exportTables()
  467. {
  468. // Exporting tables one by one
  469. foreach ($this->tables as $table) {
  470. if (in_array($table, $this->dumpSettings['exclude-tables'], true)) {
  471. continue;
  472. }
  473. $this->getTableStructure($table);
  474. if (false === $this->dumpSettings['no-data']) {
  475. $this->listValues($table);
  476. }
  477. }
  478. }
  479.  
  480. /**
  481. * Exports all the views found in database
  482. *
  483. * @return null
  484. */
  485. private function exportViews()
  486. {
  487. if (false === $this->dumpSettings['no-create-info']) {
  488. // Exporting views one by one
  489. foreach ($this->views as $view) {
  490. if (in_array($view, $this->dumpSettings['exclude-tables'], true)) {
  491. continue;
  492. }
  493. $this->tableColumnTypes[$view] = $this->getTableColumnTypes($view);
  494. $this->getViewStructureTable($view);
  495. }
  496. foreach ($this->views as $view) {
  497. if (in_array($view, $this->dumpSettings['exclude-tables'], true)) {
  498. continue;
  499. }
  500. $this->getViewStructureView($view);
  501. }
  502. }
  503. }
  504.  
  505. /**
  506. * Exports all the triggers found in database
  507. *
  508. * @return null
  509. */
  510. private function exportTriggers()
  511. {
  512. // Exporting triggers one by one
  513. foreach ($this->triggers as $trigger) {
  514. $this->getTriggerStructure($trigger);
  515. }
  516. }
  517.  
  518. /**
  519. * Exports all the procedures found in database
  520. *
  521. * @return null
  522. */
  523. private function exportProcedures()
  524. {
  525. // Exporting triggers one by one
  526. foreach ($this->procedures as $procedure) {
  527. $this->getProcedureStructure($procedure);
  528. }
  529. }
  530.  
  531. /**
  532. * Table structure extractor
  533. *
  534. * @todo move specific mysql code to typeAdapter
  535. * @param string $tableName Name of table to export
  536. * @return null
  537. */
  538. private function getTableStructure($tableName)
  539. {
  540. if (!$this->dumpSettings['no-create-info']) {
  541. $ret = '';
  542. if (!$this->dumpSettings['skip-comments']) {
  543. $ret = "--" . PHP_EOL .
  544. "-- Table structure for table `$tableName`" . PHP_EOL .
  545. "--" . PHP_EOL . PHP_EOL;
  546. }
  547. $stmt = $this->typeAdapter->show_create_table($tableName);
  548. foreach ($this->dbHandler->query($stmt) as $r) {
  549. $this->compressManager->write($ret);
  550. if ($this->dumpSettings['add-drop-table']) {
  551. $this->compressManager->write(
  552. $this->typeAdapter->drop_table($tableName)
  553. );
  554. }
  555. $this->compressManager->write(
  556. $this->typeAdapter->create_table($r, $this->dumpSettings)
  557. );
  558. break;
  559. }
  560. }
  561. $this->tableColumnTypes[$tableName] = $this->getTableColumnTypes($tableName);
  562. return;
  563. }
  564.  
  565. /**
  566. * Store column types to create data dumps and for Stand-In tables
  567. *
  568. * @param string $tableName Name of table to export
  569. * @return array type column types detailed
  570. */
  571.  
  572. private function getTableColumnTypes($tableName) {
  573. $columnTypes = array();
  574. $columns = $this->dbHandler->query(
  575. $this->typeAdapter->show_columns($tableName)
  576. );
  577. $columns->setFetchMode(PDO::FETCH_ASSOC);
  578.  
  579. foreach($columns as $key => $col) {
  580. $types = $this->typeAdapter->parseColumnType($col);
  581. $columnTypes[$col['Field']] = array(
  582. 'is_numeric'=> $types['is_numeric'],
  583. 'is_blob' => $types['is_blob'],
  584. 'type' => $types['type'],
  585. 'type_sql' => $col['Type']
  586. );
  587. }
  588.  
  589. return $columnTypes;
  590. }
  591.  
  592. /**
  593. * View structure extractor, create table (avoids cyclic references)
  594. *
  595. * @todo move mysql specific code to typeAdapter
  596. * @param string $viewName Name of view to export
  597. * @return null
  598. */
  599. private function getViewStructureTable($viewName)
  600. {
  601. if (!$this->dumpSettings['skip-comments']) {
  602. $ret = "--" . PHP_EOL .
  603. "-- Stand-In structure for view `${viewName}`" . PHP_EOL .
  604. "--" . PHP_EOL . PHP_EOL;
  605. $this->compressManager->write($ret);
  606. }
  607. $stmt = $this->typeAdapter->show_create_view($viewName);
  608.  
  609. // create views as tables, to resolve dependencies
  610. foreach ($this->dbHandler->query($stmt) as $r) {
  611. if ($this->dumpSettings['add-drop-table']) {
  612. $this->compressManager->write(
  613. $this->typeAdapter->drop_view($viewName)
  614. );
  615. }
  616.  
  617. $this->compressManager->write(
  618. $this->createStandInTable($viewName)
  619. );
  620. break;
  621. }
  622. }
  623.  
  624. /**
  625. * Write a create table statement for the table Stand-In, show create
  626. * table would return a create algorithm when used on a view
  627. *
  628. * @param string $viewName Name of view to export
  629. * @return string create statement
  630. */
  631. function createStandInTable($viewName) {
  632. $ret = array();
  633. foreach($this->tableColumnTypes[$viewName] as $k => $v) {
  634. $ret[] = "`${k}` ${v['type_sql']}";
  635. }
  636. $ret = implode(PHP_EOL . ",", $ret);
  637.  
  638. $ret = "CREATE TABLE IF NOT EXISTS `$viewName` (" .
  639. PHP_EOL . $ret . PHP_EOL . ");" . PHP_EOL;
  640.  
  641. return $ret;
  642. }
  643.  
  644. /**
  645. * View structure extractor, create view
  646. *
  647. * @todo move mysql specific code to typeAdapter
  648. * @param string $viewName Name of view to export
  649. * @return null
  650. */
  651. private function getViewStructureView($viewName)
  652. {
  653. if (!$this->dumpSettings['skip-comments']) {
  654. $ret = "--" . PHP_EOL .
  655. "-- View structure for view `${viewName}`" . PHP_EOL .
  656. "--" . PHP_EOL . PHP_EOL;
  657. $this->compressManager->write($ret);
  658. }
  659. $stmt = $this->typeAdapter->show_create_view($viewName);
  660.  
  661. // create views, to resolve dependencies
  662. // replacing tables with views
  663. foreach ($this->dbHandler->query($stmt) as $r) {
  664. // because we must replace table with view, we should delete it
  665. $this->compressManager->write(
  666. $this->typeAdapter->drop_view($viewName)
  667. );
  668. $this->compressManager->write(
  669. $this->typeAdapter->create_view($r)
  670. );
  671. break;
  672. }
  673. }
  674.  
  675. /**
  676. * Trigger structure extractor
  677. *
  678. * @param string $triggerName Name of trigger to export
  679. * @return null
  680. */
  681. private function getTriggerStructure($triggerName)
  682. {
  683. $stmt = $this->typeAdapter->show_create_trigger($triggerName);
  684. foreach ($this->dbHandler->query($stmt) as $r) {
  685. if ($this->dumpSettings['add-drop-trigger']) {
  686. $this->compressManager->write(
  687. $this->typeAdapter->add_drop_trigger($triggerName)
  688. );
  689. }
  690. $this->compressManager->write(
  691. $this->typeAdapter->create_trigger($r)
  692. );
  693. return;
  694. }
  695. }
  696.  
  697. /**
  698. * Procedure structure extractor
  699. *
  700. * @param string $procedureName Name of procedure to export
  701. * @return null
  702. */
  703. private function getProcedureStructure($procedureName)
  704. {
  705. if (!$this->dumpSettings['skip-comments']) {
  706. $ret = "--" . PHP_EOL .
  707. "-- Dumping routines for database '" . $this->dbName . "'" . PHP_EOL .
  708. "--" . PHP_EOL . PHP_EOL;
  709. $this->compressManager->write($ret);
  710. }
  711. $stmt = $this->typeAdapter->show_create_procedure($procedureName);
  712. foreach ($this->dbHandler->query($stmt) as $r) {
  713. $this->compressManager->write(
  714. $this->typeAdapter->create_procedure($r, $this->dumpSettings)
  715. );
  716. return;
  717. }
  718. }
  719.  
  720. /**
  721. * Escape values with quotes when needed
  722. *
  723. * @param string $tableName Name of table which contains rows
  724. * @param array $row Associative array of column names and values to be quoted
  725. *
  726. * @return string
  727. */
  728. private function escape($tableName, $row)
  729. {
  730. $ret = array();
  731. $columnTypes = $this->tableColumnTypes[$tableName];
  732. foreach ($row as $colName => $colValue) {
  733. if (is_null($colValue)) {
  734. $ret[] = "NULL";
  735. } elseif ($this->dumpSettings['hex-blob'] && $columnTypes[$colName]['is_blob']) {
  736. if ($columnTypes[$colName]['type'] == 'bit' || !empty($colValue)) {
  737. $ret[] = "0x${colValue}";
  738. } else {
  739. $ret[] = "''";
  740. }
  741. } elseif ($columnTypes[$colName]['is_numeric']) {
  742. $ret[] = $colValue;
  743. } else {
  744. $ret[] = $this->dbHandler->quote($colValue);
  745. }
  746. }
  747. return $ret;
  748. }
  749.  
  750. /**
  751. * Table rows extractor
  752. *
  753. * @param string $tableName Name of table to export
  754. *
  755. * @return null
  756. */
  757. private function listValues($tableName)
  758. {
  759. $this->prepareListValues($tableName);
  760.  
  761. $onlyOnce = true;
  762. $lineSize = 0;
  763.  
  764. $colStmt = $this->getColumnStmt($tableName);
  765. $stmt = "SELECT $colStmt FROM `$tableName`";
  766.  
  767. if ($this->dumpSettings['where']) {
  768. $stmt .= " WHERE {$this->dumpSettings['where']}";
  769. }
  770. $resultSet = $this->dbHandler->query($stmt);
  771. $resultSet->setFetchMode(PDO::FETCH_ASSOC);
  772.  
  773. foreach ($resultSet as $row) {
  774. $vals = $this->escape($tableName, $row);
  775. if ($onlyOnce || !$this->dumpSettings['extended-insert']) {
  776. $lineSize += $this->compressManager->write(
  777. "INSERT INTO `$tableName` VALUES (" . implode(",", $vals) . ")"
  778. );
  779. $onlyOnce = false;
  780. } else {
  781. $lineSize += $this->compressManager->write(",(" . implode(",", $vals) . ")");
  782. }
  783. if (($lineSize > self::MAXLINESIZE) ||
  784. !$this->dumpSettings['extended-insert']) {
  785. $onlyOnce = true;
  786. $lineSize = $this->compressManager->write(";" . PHP_EOL);
  787. }
  788. }
  789. $resultSet->closeCursor();
  790.  
  791. if (!$onlyOnce) {
  792. $this->compressManager->write(";" . PHP_EOL);
  793. }
  794.  
  795. $this->endListValues($tableName);
  796. }
  797.  
  798. /**
  799. * Table rows extractor, append information prior to dump
  800. *
  801. * @param string $tableName Name of table to export
  802. *
  803. * @return null
  804. */
  805. function prepareListValues($tableName)
  806. {
  807. if (!$this->dumpSettings['skip-comments']) {
  808. $this->compressManager->write(
  809. "--" . PHP_EOL .
  810. "-- Dumping data for table `$tableName`" . PHP_EOL .
  811. "--" . PHP_EOL . PHP_EOL
  812. );
  813. }
  814.  
  815. if ($this->dumpSettings['single-transaction']) {
  816. $this->dbHandler->exec($this->typeAdapter->setup_transaction());
  817. $this->dbHandler->exec($this->typeAdapter->start_transaction());
  818. }
  819.  
  820. if ($this->dumpSettings['lock-tables']) {
  821. $this->typeAdapter->lock_table($tableName);
  822. }
  823.  
  824. if ($this->dumpSettings['add-locks']) {
  825. $this->compressManager->write(
  826. $this->typeAdapter->start_add_lock_table($tableName)
  827. );
  828. }
  829.  
  830. if ($this->dumpSettings['disable-keys']) {
  831. $this->compressManager->write(
  832. $this->typeAdapter->start_add_disable_keys($tableName)
  833. );
  834. }
  835.  
  836. // Disable autocommit for faster reload
  837. if ($this->dumpSettings['no-autocommit']) {
  838. $this->compressManager->write(
  839. $this->typeAdapter->start_disable_autocommit()
  840. );
  841. }
  842.  
  843. return;
  844. }
  845.  
  846. /**
  847. * Table rows extractor, close locks and commits after dump
  848. *
  849. * @param string $tableName Name of table to export
  850. *
  851. * @return null
  852. */
  853. function endListValues($tableName)
  854. {
  855. if ($this->dumpSettings['disable-keys']) {
  856. $this->compressManager->write(
  857. $this->typeAdapter->end_add_disable_keys($tableName)
  858. );
  859. }
  860.  
  861. if ($this->dumpSettings['add-locks']) {
  862. $this->compressManager->write(
  863. $this->typeAdapter->end_add_lock_table($tableName)
  864. );
  865. }
  866.  
  867. if ($this->dumpSettings['single-transaction']) {
  868. $this->dbHandler->exec($this->typeAdapter->commit_transaction());
  869. }
  870.  
  871. if ($this->dumpSettings['lock-tables']) {
  872. $this->typeAdapter->unlock_table($tableName);
  873. }
  874.  
  875. // Commit to enable autocommit
  876. if ($this->dumpSettings['no-autocommit']) {
  877. $this->compressManager->write(
  878. $this->typeAdapter->end_disable_autocommit()
  879. );
  880. }
  881.  
  882. $this->compressManager->write(PHP_EOL);
  883.  
  884. return;
  885. }
  886.  
  887. /**
  888. * Build SQL List of all columns on current table
  889. *
  890. * @param string $tableName Name of table to get columns
  891. *
  892. * @return string SQL sentence with columns
  893. */
  894. function getColumnStmt($tableName)
  895. {
  896. $colStmt = array();
  897. foreach($this->tableColumnTypes[$tableName] as $colName => $colType) {
  898. if ($colType['type'] == 'bit' && $this->dumpSettings['hex-blob']) {
  899. $colStmt[] = "LPAD(HEX(`${colName}`),2,'0') AS `${colName}`";
  900. } else if ($colType['is_blob'] && $this->dumpSettings['hex-blob']) {
  901. $colStmt[] = "HEX(`${colName}`) AS `${colName}`";
  902. } else {
  903. $colStmt[] = "`${colName}`";
  904. }
  905. }
  906. $colStmt = implode($colStmt, ",");
  907.  
  908. return $colStmt;
  909. }
  910. }
  911.  
  912. /**
  913. * Enum with all available compression methods
  914. *
  915. */
  916. abstract class CompressMethod
  917. {
  918. public static $enums = array(
  919. "None",
  920. "Gzip",
  921. "Bzip2"
  922. );
  923.  
  924. /**
  925. * @param string $c
  926. * @return boolean
  927. */
  928. public static function isValid($c)
  929. {
  930. return in_array($c, self::$enums);
  931. }
  932. }
  933.  
  934. abstract class CompressManagerFactory
  935. {
  936. /**
  937. * @param string $c
  938. * @return CompressBzip2|CompressGzip|CompressNone
  939. */
  940. public static function create($c)
  941. {
  942. $c = ucfirst(strtolower($c));
  943. if (! CompressMethod::isValid($c)) {
  944. throw new Exception("Compression method ($c) is not defined yet");
  945. }
  946.  
  947. $method = __NAMESPACE__ . "\\" . "Compress" . $c;
  948.  
  949. return new $method;
  950. }
  951. }
  952.  
  953. class CompressBzip2 extends CompressManagerFactory
  954. {
  955. private $fileHandler = null;
  956.  
  957. public function __construct()
  958. {
  959. if (! function_exists("bzopen")) {
  960. throw new Exception("Compression is enabled, but bzip2 lib is not installed or configured properly");
  961. }
  962. }
  963.  
  964. /**
  965. * @param string $filename
  966. */
  967. public function open($filename)
  968. {
  969. $this->fileHandler = bzopen($filename, "w");
  970. if (false === $this->fileHandler) {
  971. throw new Exception("Output file is not writable");
  972. }
  973.  
  974. return true;
  975. }
  976.  
  977. public function write($str)
  978. {
  979. if (false === ($bytesWritten = bzwrite($this->fileHandler, $str))) {
  980. throw new Exception("Writting to file failed! Probably, there is no more free space left?");
  981. }
  982. return $bytesWritten;
  983. }
  984.  
  985. public function close()
  986. {
  987. return bzclose($this->fileHandler);
  988. }
  989. }
  990.  
  991. class CompressGzip extends CompressManagerFactory
  992. {
  993. private $fileHandler = null;
  994.  
  995. public function __construct()
  996. {
  997. if (! function_exists("gzopen")) {
  998. throw new Exception("Compression is enabled, but gzip lib is not installed or configured properly");
  999. }
  1000. }
  1001.  
  1002. /**
  1003. * @param string $filename
  1004. */
  1005. public function open($filename)
  1006. {
  1007. $this->fileHandler = gzopen($filename, "wb");
  1008. if (false === $this->fileHandler) {
  1009. throw new Exception("Output file is not writable");
  1010. }
  1011.  
  1012. return true;
  1013. }
  1014.  
  1015. public function write($str)
  1016. {
  1017. if (false === ($bytesWritten = gzwrite($this->fileHandler, $str))) {
  1018. throw new Exception("Writting to file failed! Probably, there is no more free space left?");
  1019. }
  1020. return $bytesWritten;
  1021. }
  1022.  
  1023. public function close()
  1024. {
  1025. return gzclose($this->fileHandler);
  1026. }
  1027. }
  1028.  
  1029. class CompressNone extends CompressManagerFactory
  1030. {
  1031. private $fileHandler = null;
  1032.  
  1033. /**
  1034. * @param string $filename
  1035. */
  1036. public function open($filename)
  1037. {
  1038. $this->fileHandler = fopen($filename, "wb");
  1039. if (false === $this->fileHandler) {
  1040. throw new Exception("Output file is not writable");
  1041. }
  1042.  
  1043. return true;
  1044. }
  1045.  
  1046. public function write($str)
  1047. {
  1048. if (false === ($bytesWritten = fwrite($this->fileHandler, $str))) {
  1049. throw new Exception("Writting to file failed! Probably, there is no more free space left?");
  1050. }
  1051. return $bytesWritten;
  1052. }
  1053.  
  1054. public function close()
  1055. {
  1056. return fclose($this->fileHandler);
  1057. }
  1058. }
  1059.  
  1060. /**
  1061. * Enum with all available TypeAdapter implementations
  1062. *
  1063. */
  1064. abstract class TypeAdapter
  1065. {
  1066. public static $enums = array(
  1067. "Sqlite",
  1068. "Mysql"
  1069. );
  1070.  
  1071. /**
  1072. * @param string $c
  1073. * @return boolean
  1074. */
  1075. public static function isValid($c)
  1076. {
  1077. return in_array($c, self::$enums);
  1078. }
  1079. }
  1080.  
  1081. /**
  1082. * TypeAdapter Factory
  1083. *
  1084. */
  1085. abstract class TypeAdapterFactory
  1086. {
  1087. /**
  1088. * @param string $c Type of database factory to create (Mysql, Sqlite,...)
  1089. * @param PDO $dbHandler
  1090. */
  1091. public static function create($c, $dbHandler = null)
  1092. {
  1093. $c = ucfirst(strtolower($c));
  1094. if (! TypeAdapter::isValid($c)) {
  1095. throw new Exception("Database type support for ($c) not yet available");
  1096. }
  1097. $method = __NAMESPACE__ . "\\" . "TypeAdapter" . $c;
  1098. return new $method($dbHandler);
  1099. }
  1100.  
  1101. /**
  1102. * function databases Add sql to create and use database
  1103. * @todo make it do something with sqlite
  1104. */
  1105. public function databases()
  1106. {
  1107. return "";
  1108. }
  1109.  
  1110. public function show_create_table($tableName)
  1111. {
  1112. return "SELECT tbl_name as 'Table', sql as 'Create Table' " .
  1113. "FROM sqlite_master " .
  1114. "WHERE type='table' AND tbl_name='$tableName'";
  1115. }
  1116.  
  1117. /**
  1118. * function create_table Get table creation code from database
  1119. * @todo make it do something with sqlite
  1120. */
  1121. public function create_table($row, $dumpSettings)
  1122. {
  1123. return "";
  1124. }
  1125.  
  1126. public function show_create_view($viewName)
  1127. {
  1128. return "SELECT tbl_name as 'View', sql as 'Create View' " .
  1129. "FROM sqlite_master " .
  1130. "WHERE type='view' AND tbl_name='$viewName'";
  1131. }
  1132.  
  1133. /**
  1134. * function create_view Get view creation code from database
  1135. * @todo make it do something with sqlite
  1136. */
  1137. public function create_view($row)
  1138. {
  1139. return "";
  1140. }
  1141.  
  1142. /**
  1143. * function show_create_trigger Get trigger creation code from database
  1144. * @todo make it do something with sqlite
  1145. */
  1146. public function show_create_trigger($triggerName)
  1147. {
  1148. return "";
  1149. }
  1150.  
  1151. /**
  1152. * function create_trigger Modify trigger code, add delimiters, etc
  1153. * @todo make it do something with sqlite
  1154. */
  1155. public function create_trigger($triggerName)
  1156. {
  1157. return "";
  1158. }
  1159.  
  1160. /**
  1161. * function create_procedure Modify procedure code, add delimiters, etc
  1162. * @todo make it do something with sqlite
  1163. */
  1164. public function create_procedure($procedureName, $dumpSettings)
  1165. {
  1166. return "";
  1167. }
  1168.  
  1169. public function show_tables()
  1170. {
  1171. return "SELECT tbl_name FROM sqlite_master WHERE type='table'";
  1172. }
  1173.  
  1174. public function show_views()
  1175. {
  1176. return "SELECT tbl_name FROM sqlite_master WHERE type='view'";
  1177. }
  1178.  
  1179. public function show_triggers()
  1180. {
  1181. return "SELECT name FROM sqlite_master WHERE type='trigger'";
  1182. }
  1183.  
  1184. public function show_columns()
  1185. {
  1186. if (func_num_args() != 1) {
  1187. return "";
  1188. }
  1189.  
  1190. $args = func_get_args();
  1191.  
  1192. return "pragma table_info(${args[0]})";
  1193. }
  1194.  
  1195. public function show_procedures()
  1196. {
  1197. return "";
  1198. }
  1199.  
  1200. public function setup_transaction()
  1201. {
  1202. return "";
  1203. }
  1204.  
  1205. public function start_transaction()
  1206. {
  1207. return "BEGIN EXCLUSIVE";
  1208. }
  1209.  
  1210. public function commit_transaction()
  1211. {
  1212. return "COMMIT";
  1213. }
  1214.  
  1215. public function lock_table()
  1216. {
  1217. return "";
  1218. }
  1219.  
  1220. public function unlock_table()
  1221. {
  1222. return "";
  1223. }
  1224.  
  1225. public function start_add_lock_table()
  1226. {
  1227. return PHP_EOL;
  1228. }
  1229.  
  1230. public function end_add_lock_table()
  1231. {
  1232. return PHP_EOL;
  1233. }
  1234.  
  1235. public function start_add_disable_keys()
  1236. {
  1237. return PHP_EOL;
  1238. }
  1239.  
  1240. public function end_add_disable_keys()
  1241. {
  1242. return PHP_EOL;
  1243. }
  1244.  
  1245. public function start_disable_foreign_keys_check()
  1246. {
  1247. return PHP_EOL;
  1248. }
  1249.  
  1250. public function end_disable_foreign_keys_check()
  1251. {
  1252. return PHP_EOL;
  1253. }
  1254.  
  1255. public function add_drop_database()
  1256. {
  1257. return PHP_EOL;
  1258. }
  1259.  
  1260. public function add_drop_trigger()
  1261. {
  1262. return PHP_EOL;
  1263. }
  1264.  
  1265. public function drop_table()
  1266. {
  1267. return PHP_EOL;
  1268. }
  1269.  
  1270. public function drop_view()
  1271. {
  1272. return PHP_EOL;
  1273. }
  1274.  
  1275. /**
  1276. * Decode column metadata and fill info structure.
  1277. * type, is_numeric and is_blob will always be available.
  1278. *
  1279. * @param array $colType Array returned from "SHOW COLUMNS FROM tableName"
  1280. * @return array
  1281. */
  1282. public function parseColumnType($colType)
  1283. {
  1284. return array();
  1285. }
  1286.  
  1287. public function backup_parameters()
  1288. {
  1289. return PHP_EOL;
  1290. }
  1291.  
  1292. public function restore_parameters()
  1293. {
  1294. return PHP_EOL;
  1295. }
  1296. }
  1297.  
  1298. class TypeAdapterPgsql extends TypeAdapterFactory
  1299. {
  1300. }
  1301.  
  1302. class TypeAdapterDblib extends TypeAdapterFactory
  1303. {
  1304. }
  1305.  
  1306. class TypeAdapterSqlite extends TypeAdapterFactory
  1307. {
  1308. }
  1309.  
  1310. class TypeAdapterMysql extends TypeAdapterFactory
  1311. {
  1312.  
  1313. private $dbHandler = null;
  1314.  
  1315. // Numerical Mysql types
  1316. public $mysqlTypes = array(
  1317. 'numerical' => array(
  1318. 'bit',
  1319. 'tinyint',
  1320. 'smallint',
  1321. 'mediumint',
  1322. 'int',
  1323. 'integer',
  1324. 'bigint',
  1325. 'real',
  1326. 'double',
  1327. 'float',
  1328. 'decimal',
  1329. 'numeric'
  1330. ),
  1331. 'blob' => array(
  1332. 'tinyblob',
  1333. 'blob',
  1334. 'mediumblob',
  1335. 'longblob',
  1336. 'binary',
  1337. 'varbinary',
  1338. 'bit'
  1339. )
  1340. );
  1341.  
  1342. public function __construct ($dbHandler)
  1343. {
  1344. $this->dbHandler = $dbHandler;
  1345. }
  1346.  
  1347. public function databases()
  1348. {
  1349. $this->check_parameters(func_num_args(), $expected_num_args = 1, __METHOD__);
  1350. $args = func_get_args();
  1351. $databaseName = $args[0];
  1352.  
  1353. $resultSet = $this->dbHandler->query("SHOW VARIABLES LIKE 'character_set_database';");
  1354. $characterSet = $resultSet->fetchColumn(1);
  1355. $resultSet->closeCursor();
  1356.  
  1357. $resultSet = $this->dbHandler->query("SHOW VARIABLES LIKE 'collation_database';");
  1358. $collationDb = $resultSet->fetchColumn(1);
  1359. $resultSet->closeCursor();
  1360. $ret = "";
  1361.  
  1362. $ret .= "CREATE DATABASE /*!32312 IF NOT EXISTS*/ `${databaseName}`".
  1363. " /*!40100 DEFAULT CHARACTER SET ${characterSet} " .
  1364. " COLLATE ${collationDb} */;" . PHP_EOL . PHP_EOL .
  1365. "USE `${databaseName}`;" . PHP_EOL . PHP_EOL;
  1366.  
  1367. return $ret;
  1368. }
  1369.  
  1370. public function show_create_table($tableName)
  1371. {
  1372. return "SHOW CREATE TABLE `$tableName`";
  1373. }
  1374.  
  1375. public function show_create_view($viewName)
  1376. {
  1377. return "SHOW CREATE VIEW `$viewName`";
  1378. }
  1379.  
  1380. public function show_create_trigger($triggerName)
  1381. {
  1382. return "SHOW CREATE TRIGGER `$triggerName`";
  1383. }
  1384.  
  1385. public function show_create_procedure($procedureName)
  1386. {
  1387. return "SHOW CREATE PROCEDURE `$procedureName`";
  1388. }
  1389.  
  1390. public function create_table($row, $dumpSettings)
  1391. {
  1392. if (!isset($row['Create Table'])) {
  1393. throw new Exception("Error getting table code, unknown output");
  1394. }
  1395.  
  1396. $ret = "/*!40101 SET @saved_cs_client = @@character_set_client */;" . PHP_EOL .
  1397. "/*!40101 SET character_set_client = " . $dumpSettings['default-character-set'] . " */;" . PHP_EOL .
  1398. $row['Create Table'] . ";" . PHP_EOL .
  1399. "/*!40101 SET character_set_client = @saved_cs_client */;" . PHP_EOL .
  1400. PHP_EOL;
  1401. return $ret;
  1402. }
  1403.  
  1404. public function create_view($row)
  1405. {
  1406. $ret = "";
  1407. if (!isset($row['Create View'])) {
  1408. throw new Exception("Error getting view structure, unknown output");
  1409. }
  1410.  
  1411. $triggerStmt = $row['Create View'];
  1412.  
  1413. $triggerStmtReplaced1 = str_replace(
  1414. "CREATE ALGORITHM",
  1415. "/*!50001 CREATE ALGORITHM",
  1416. $triggerStmt
  1417. );
  1418. $triggerStmtReplaced2 = str_replace(
  1419. " DEFINER=",
  1420. " */" . PHP_EOL . "/*!50013 DEFINER=",
  1421. $triggerStmtReplaced1
  1422. );
  1423. $triggerStmtReplaced3 = str_replace(
  1424. " VIEW ",
  1425. " */" . PHP_EOL . "/*!50001 VIEW ",
  1426. $triggerStmtReplaced2
  1427. );
  1428. if (false === $triggerStmtReplaced1 ||
  1429. false === $triggerStmtReplaced2 ||
  1430. false === $triggerStmtReplaced3) {
  1431. $triggerStmtReplaced = $triggerStmt;
  1432. } else {
  1433. $triggerStmtReplaced = $triggerStmtReplaced3 . " */;";
  1434. }
  1435.  
  1436. $ret .= $triggerStmtReplaced . PHP_EOL . PHP_EOL;
  1437. return $ret;
  1438. }
  1439.  
  1440. public function create_trigger($row)
  1441. {
  1442. $ret = "";
  1443. if (!isset($row['SQL Original Statement'])) {
  1444. throw new Exception("Error getting trigger code, unknown output");
  1445. }
  1446.  
  1447. $triggerStmt = $row['SQL Original Statement'];
  1448. $triggerStmtReplaced = str_replace(
  1449. "CREATE DEFINER",
  1450. "/*!50003 CREATE*/ /*!50017 DEFINER",
  1451. $triggerStmt
  1452. );
  1453. $triggerStmtReplaced = str_replace(
  1454. " TRIGGER",
  1455. "*/ /*!50003 TRIGGER",
  1456. $triggerStmtReplaced
  1457. );
  1458. if ( false === $triggerStmtReplaced ) {
  1459. $triggerStmtReplaced = $triggerStmt;
  1460. }
  1461.  
  1462. $ret .= "DELIMITER ;;" . PHP_EOL .
  1463. $triggerStmtReplaced . "*/;;" . PHP_EOL .
  1464. "DELIMITER ;" . PHP_EOL . PHP_EOL;
  1465. return $ret;
  1466. }
  1467.  
  1468. public function create_procedure($row, $dumpSettings)
  1469. {
  1470. $ret = "";
  1471. if (!isset($row['Create Procedure'])) {
  1472. throw new Exception("Error getting procedure code, unknown output. " .
  1473. "Please check 'https://bugs.mysql.com/bug.php?id=14564'");
  1474. }
  1475. $procedureStmt = $row['Create Procedure'];
  1476.  
  1477. $ret .= "/*!50003 DROP PROCEDURE IF EXISTS `" .
  1478. $row['Procedure'] . "` */;" . PHP_EOL .
  1479. "/*!40101 SET @saved_cs_client = @@character_set_client */;" . PHP_EOL .
  1480. "/*!40101 SET character_set_client = " . $dumpSettings['default-character-set'] . " */;" . PHP_EOL .
  1481. "DELIMITER ;;" . PHP_EOL .
  1482. $procedureStmt . " ;;" . PHP_EOL .
  1483. "DELIMITER ;" . PHP_EOL .
  1484. "/*!40101 SET character_set_client = @saved_cs_client */;" . PHP_EOL . PHP_EOL;
  1485.  
  1486. return $ret;
  1487. }
  1488.  
  1489. public function show_tables()
  1490. {
  1491. $this->check_parameters(func_num_args(), $expected_num_args = 1, __METHOD__);
  1492. $args = func_get_args();
  1493. return "SELECT TABLE_NAME AS tbl_name " .
  1494. "FROM INFORMATION_SCHEMA.TABLES " .
  1495. "WHERE TABLE_TYPE='BASE TABLE' AND TABLE_SCHEMA='${args[0]}'";
  1496. }
  1497.  
  1498. public function show_views()
  1499. {
  1500. $this->check_parameters(func_num_args(), $expected_num_args = 1, __METHOD__);
  1501. $args = func_get_args();
  1502. return "SELECT TABLE_NAME AS tbl_name " .
  1503. "FROM INFORMATION_SCHEMA.TABLES " .
  1504. "WHERE TABLE_TYPE='VIEW' AND TABLE_SCHEMA='${args[0]}'";
  1505. }
  1506.  
  1507. public function show_triggers()
  1508. {
  1509. $this->check_parameters(func_num_args(), $expected_num_args = 1, __METHOD__);
  1510. $args = func_get_args();
  1511. return "SHOW TRIGGERS FROM `${args[0]}`;";
  1512. }
  1513.  
  1514. public function show_columns()
  1515. {
  1516. $this->check_parameters(func_num_args(), $expected_num_args = 1, __METHOD__);
  1517. $args = func_get_args();
  1518. return "SHOW COLUMNS FROM `${args[0]}`;";
  1519. }
  1520.  
  1521. public function show_procedures()
  1522. {
  1523. $this->check_parameters(func_num_args(), $expected_num_args = 1, __METHOD__);
  1524. $args = func_get_args();
  1525. return "SELECT SPECIFIC_NAME AS procedure_name " .
  1526. "FROM INFORMATION_SCHEMA.ROUTINES " .
  1527. "WHERE ROUTINE_TYPE='PROCEDURE' AND ROUTINE_SCHEMA='${args[0]}'";
  1528. }
  1529.  
  1530. public function setup_transaction()
  1531. {
  1532. return "SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ";
  1533. }
  1534.  
  1535. public function start_transaction()
  1536. {
  1537. return "START TRANSACTION";
  1538. }
  1539.  
  1540. public function commit_transaction()
  1541. {
  1542. return "COMMIT";
  1543. }
  1544.  
  1545. public function lock_table()
  1546. {
  1547. $this->check_parameters(func_num_args(), $expected_num_args = 1, __METHOD__);
  1548. $args = func_get_args();
  1549. return $this->dbHandler->exec("LOCK TABLES `${args[0]}` READ LOCAL");
  1550.  
  1551. }
  1552.  
  1553. public function unlock_table()
  1554. {
  1555. return $this->dbHandler->exec("UNLOCK TABLES");
  1556. }
  1557.  
  1558. public function start_add_lock_table()
  1559. {
  1560. $this->check_parameters(func_num_args(), $expected_num_args = 1, __METHOD__);
  1561. $args = func_get_args();
  1562.  
  1563. return "LOCK TABLES `${args[0]}` WRITE;" . PHP_EOL;
  1564. }
  1565.  
  1566. public function end_add_lock_table()
  1567. {
  1568. return "UNLOCK TABLES;" . PHP_EOL;
  1569. }
  1570.  
  1571. public function start_add_disable_keys()
  1572. {
  1573. $this->check_parameters(func_num_args(), $expected_num_args = 1, __METHOD__);
  1574. $args = func_get_args();
  1575. return "/*!40000 ALTER TABLE `${args[0]}` DISABLE KEYS */;" .
  1576. PHP_EOL;
  1577. }
  1578.  
  1579. public function end_add_disable_keys()
  1580. {
  1581. $this->check_parameters(func_num_args(), $expected_num_args = 1, __METHOD__);
  1582. $args = func_get_args();
  1583. return "/*!40000 ALTER TABLE `${args[0]}` ENABLE KEYS */;" .
  1584. PHP_EOL;
  1585. }
  1586.  
  1587. public function start_disable_autocommit()
  1588. {
  1589. return "SET autocommit=0;" . PHP_EOL;
  1590. }
  1591.  
  1592. public function end_disable_autocommit()
  1593. {
  1594. return "COMMIT;" . PHP_EOL;
  1595. }
  1596.  
  1597. public function add_drop_database()
  1598. {
  1599. $this->check_parameters(func_num_args(), $expected_num_args = 1, __METHOD__);
  1600. $args = func_get_args();
  1601.  
  1602. return "/*!40000 DROP DATABASE IF EXISTS `${args[0]}`*/;" .
  1603. PHP_EOL . PHP_EOL;
  1604. }
  1605.  
  1606. public function add_drop_trigger()
  1607. {
  1608. $this->check_parameters(func_num_args(), $expected_num_args = 1, __METHOD__);
  1609. $args = func_get_args();
  1610. return "DROP TRIGGER IF EXISTS `${args[0]}`;" . PHP_EOL;
  1611. }
  1612.  
  1613. public function drop_table()
  1614. {
  1615. $this->check_parameters(func_num_args(), $expected_num_args = 1, __METHOD__);
  1616. $args = func_get_args();
  1617. return "DROP TABLE IF EXISTS `${args[0]}`;" . PHP_EOL;
  1618. }
  1619.  
  1620. public function drop_view()
  1621. {
  1622. $this->check_parameters(func_num_args(), $expected_num_args = 1, __METHOD__);
  1623. $args = func_get_args();
  1624. return "DROP TABLE IF EXISTS `${args[0]}`;" . PHP_EOL .
  1625. "/*!50001 DROP VIEW IF EXISTS `${args[0]}`*/;" . PHP_EOL;
  1626. }
  1627.  
  1628. public function getDatabaseHeader()
  1629. {
  1630. $this->check_parameters(func_num_args(), $expected_num_args = 1, __METHOD__);
  1631. $args = func_get_args();
  1632. return "--" . PHP_EOL .
  1633. "-- Current Database: `${args[0]}`" . PHP_EOL .
  1634. "--" . PHP_EOL . PHP_EOL;
  1635. }
  1636.  
  1637. /**
  1638. * Decode column metadata and fill info structure.
  1639. * type, is_numeric and is_blob will always be available.
  1640. *
  1641. * @param array $colType Array returned from "SHOW COLUMNS FROM tableName"
  1642. * @return array
  1643. */
  1644. public function parseColumnType($colType)
  1645. {
  1646. $colInfo = array();
  1647. $colParts = explode(" ", $colType['Type']);
  1648.  
  1649. if($fparen = strpos($colParts[0], "("))
  1650. {
  1651. $colInfo['type'] = substr($colParts[0], 0, $fparen);
  1652. $colInfo['length'] = str_replace(")", "", substr($colParts[0], $fparen+1));
  1653. $colInfo['attributes'] = isset($colParts[1]) ? $colParts[1] : NULL;
  1654. }
  1655. else
  1656. {
  1657. $colInfo['type'] = $colParts[0];
  1658. }
  1659. $colInfo['is_numeric'] = in_array($colInfo['type'], $this->mysqlTypes['numerical']);
  1660. $colInfo['is_blob'] = in_array($colInfo['type'], $this->mysqlTypes['blob']);
  1661.  
  1662. return $colInfo;
  1663. }
  1664.  
  1665. public function backup_parameters()
  1666. {
  1667. $this->check_parameters(func_num_args(), $expected_num_args = 1, __METHOD__);
  1668. $args = func_get_args();
  1669. $dumpSettings = $args[0];
  1670. $ret = "/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;" . PHP_EOL .
  1671. "/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;" . PHP_EOL .
  1672. "/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;" . PHP_EOL .
  1673. "/*!40101 SET NAMES " . $dumpSettings['default-character-set'] . " */;" . PHP_EOL;
  1674.  
  1675. if (false === $dumpSettings['skip-tz-utc']) {
  1676. $ret .= "/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;" . PHP_EOL .
  1677. "/*!40103 SET TIME_ZONE='+00:00' */;" . PHP_EOL;
  1678. }
  1679.  
  1680. $ret .= "/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;" . PHP_EOL .
  1681. "/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;" . PHP_EOL .
  1682. "/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;" . PHP_EOL .
  1683. "/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;" . PHP_EOL .PHP_EOL;
  1684.  
  1685. return $ret;
  1686. }
  1687.  
  1688. public function restore_parameters()
  1689. {
  1690. $this->check_parameters(func_num_args(), $expected_num_args = 1, __METHOD__);
  1691. $args = func_get_args();
  1692. $dumpSettings = $args[0];
  1693. $ret = "";
  1694.  
  1695. if (false === $dumpSettings['skip-tz-utc']) {
  1696. $ret .= "/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;" . PHP_EOL;
  1697. }
  1698.  
  1699. $ret .= "/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;" . PHP_EOL .
  1700. "/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;" . PHP_EOL .
  1701. "/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;" . PHP_EOL .
  1702. "/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;" . PHP_EOL .
  1703. "/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;" . PHP_EOL .
  1704. "/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;" . PHP_EOL .
  1705. "/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;" . PHP_EOL . PHP_EOL;
  1706.  
  1707. return $ret;
  1708. }
  1709.  
  1710. private function check_parameters($num_args, $expected_num_args, $method_name)
  1711. {
  1712. if ( $num_args != $expected_num_args ) {
  1713. throw new Exception("Unexpected parameter passed to $method_name");
  1714. }
  1715. return;
  1716. }
  1717. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement