Gangabass has asked for the wisdom of the Perl Monks concerning the following question:

Hi, monks!

I need to upload dump file to remote MySQL server from client machine. So i can't execute mysqldump command on remote server course i just connect to it's 3306 port :-(

All i have is MySQL user password for remote MySQL server and MySQL dump file created via PHPMyAdmin. Here is example of the dump:

/*!40101 SET SQL_MODE=''*/; create database if not exists `nexusscars`; USE `nexusscars`; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY +_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO +' */; /*Table structure for table `bids` */ DROP TABLE IF EXISTS `bids`; CREATE TABLE `bids` ( `id` int(11) NOT NULL auto_increment, `site_id` int(11) NOT NULL, `target` int(11) NOT NULL, `bid_num` int(11) NOT NULL, `model_id` int(11) NOT NULL, `body` varchar(50) default NULL, `color_id` int(11) NOT NULL, `year` int(11) NOT NULL, `mileage` int(11) default NULL, `transmission` varchar(10) NOT NULL, `displacement` int(11) default NULL, `grade` varchar(50) default NULL, `inspection` varchar(50) default NULL, `score_id` int(11) NOT NULL, `trade_date` date NOT NULL, `start` int(11) default NULL, `final` int(11) default NULL, `result_id` int(11) NOT NULL, `front_image` tinyint(1) default NULL, `back_image` tinyint(1) default NULL, `auction_list_image` tinyint(1) default NULL, `aircondition` tinyint(1) default NULL, `powerwindow` tinyint(1) default NULL, `powersteering` tinyint(1) default NULL, `aluminiumwheels` tinyint(1) default NULL, `sunroof` tinyint(1) default NULL, `leather` tinyint(1) default NULL, `tv` tinyint(1) default NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; /*Data for the table `sites` */ insert into `sites`(`id`,`name`,`kaijo`,`day_of_week`,`delivery_price +`,`image_field_size`) values (70,'Ryuutsu','RA',7,0,5),(71,'Sapporo', +'SP',4,25000,5),(72,'Gunma','GM',7,0,4),(73,'R_Nagoya','NR',2,20000,5 +),(74,'Yokohama','YK',3,0,5),(75,'Kobe','KB',3,20000,5),(76,'Tohoku', +'TH',4,25000,4),(77,'Fukuoka','KF',4,50000,4),(78,'Tokyo','TK',5,0,5) +,(79,'R_Tokyo','TR',5,0,5),(80,'Nishi Tokyo','WT',6,0,4),(81,'Nagoya' +,'NG',6,20000,5),(82,'Osaka','OS',6,20000,5),(83,'Shizuoka','SZ',7,20 +000,5),(84,'Okayama','OK',7,40000,4),(85,'Kyushu','KG',7,50000,5),(86 +,'Hokuriku','HK',6,50000,5),(87,'BCN','BC',3,0,5),(88,'Niigata','NT', +4,0,5),(89,'Ju Hiroshima','JH',0,5,0),(90,'LAA Kansai','LK',5,0,5),(9 +1,'BCN','BC',0,0,5),(92,'JU Nagano','JN',3,0,5),(93,'ZiP Osaka','ZO', +5,0,5),(94,'Hanaten','HM',0,0,5),(95,'JU Gifu','JG',0,0,5),(96,'JU Ai +chi','JA',0,0,5),(97,'BAY AUC','BA',4,0,5),(98,'KCAA Fukuoka','KCAA', +0,5,0); /*!40101 SET SQL_MODE=@OLD_SQL_MODE */;

I think about parsing SQL and executing it via $dbh->do(). What you think about this? I'm looking into SQL::Statement now but can't find a way how it can help me...

So my main question now is there any modules that can parse SQL dump file into single SQL commands (so i can execute it via DBI)?

Replies are listed 'Best First'.
Re: Importing MySQL dump file remotely
by igelkott (Priest) on Aug 09, 2008 at 08:57 UTC

    A simple, non-perl solution would be to use the local mysql client:

    mysql -hserver -p < dump.sql
    The password should be set in your .my.cnf (or equiv). Specify the database for loading single db dumps.

    If the mysql client isn't available locally, install it; it's worth the small effort.

Re: Importing MySQL dump file remotely
by Corion (Patriarch) on Aug 09, 2008 at 08:40 UTC

    If you have a real MySQLDump file, the easy way is to just set $/ = ";\n";, because mysqldump will never output a newline as SQL data. It will output CREATE TABLE statements over multiple lines, but these will end with a semicolon as well.

    If you need to do some munging, do it after having splitted...

Re: Importing MySQL dump file remotely
by pjotrik (Friar) on Aug 09, 2008 at 12:10 UTC
    I got into similar problems in my old PHP days - I only had FTP access and ability to run PHP; dump import in PHPMyAdmin was failing because of the execution time limit.

    I wrote a simple script that basically read the dump statement by statement and ended with a refresh header while remembering the offset, when getting too close to execution limit. It's definitely not 100 percent errorproof, but it worked for the dumps I needed it for.

    I hope I'm not gonna get lynched for posting PHP code here :-)

    <?php define('CUSHION', 5); define('FILENAME', 'dump.sql'); define('BLOCK_SIZE', 4000); define('LINE_SEP', "\n"); define('STMT_SEP', ";\n"); define('COMMENT', "--"); error_reporting(E_ALL); ini_set('display_errors', 1); $time_to_end = time() + intval(ini_get('max_execution_time')) - CUSHIO +N; $db = mysql_connect('localhost', 'username', 'passwd'); mysql_select_db('dbname', $db); mysql_query('SET NAMES utf8'); mysql_query('SET CHARACTER SET utf8'); $file = fopen(FILENAME, 'r'); $offset = (empty($_GET['o']) ? 0 : $_GET['o']); fseek($file, $offset, SEEK_SET); $counter = 0; $block = ''; $chopped = ''; $errors = array(); while (time() < $time_to_end) { $block .= fread($file, BLOCK_SIZE); $start = 0; while(($end = strpos($block, STMT_SEP, $start)) !== false) { $stmt = $chopped . substr($block, $start, $end-$start); $start = $end + 2; while (strpos($stmt, COMMENT) === 0) { $new_start = strpos($stmt, LINE_SEP); $stmt = substr($stmt, $new_start + 1); } if (mysql_query($stmt, $db)) { $counter++; $chopped = ''; } else { $errors[] = mysql_error(); $errors[] = $stmt; if (!mysql_ping()) { $offset = ftell($file) - STMT_SEP + $start - 2 - strlen($stmt) +; header('Refresh: 0; URL=loader.php?o='.$offset); include('header.inc'); echo 'Connection to db was interrupted, couldn\'t finish state +ment: '.$stmt; include('footer.inc'); exit; } $chopped = $stmt . STMT_SEP; } } $block = substr($block, $start); } $offset = ftell($file) - strlen($block) - strlen($chopped); if (!feof($file)) header('Refresh: 0; URL=loader.php?o='.$offset); include('header.inc'); echo 'Successfully executed ' . $counter . ' statements, execution end +ed at position ' . $offset; if (!empty($errors)) echo '<br>There were errors:<br>' . implode('<br>', $errors); if (feof($file)) echo '<br>And it\'s finished.'; include('footer.inc'); ?>
    header.inc and footer.inc are generic HTML fragments. I hope no error sneaked in when I translated the names and texts into english.

      AH! PHP CODE! Lynch him! :P

      <(^.^-<) <(-^.^<) <(-^.^-)> (>^.^-)> (>-^.^)>