<?php

if (!defined('WPVIVID_PLUGIN_DIR'))
{
    die;
}

use Exception as Exception;

class CompressTest_2
{
    private $fileHandler = null;

    /**
     * @param string $filename
     */
    public function open($filename)
    {
        $this->fileHandler = fopen($filename, "wb");
        if (false === $this->fileHandler) {
            throw new Exception("Output file is not writable");
        }

        return true;
    }

    public function write($str)
    {
        if (false === ($bytesWritten = fwrite($this->fileHandler, $str))) {
            throw new Exception("Writting to file failed! Probably, there is no more free space left?");
        }
        return $bytesWritten;
    }

    public function close()
    {
        return fclose($this->fileHandler);
    }

    public function get_size()
    {
        $fstat = fstat($this->fileHandler);
        return $fstat['size'];
    }
}

class WPvivid_Mysqldump2
{

    // Same as mysqldump
    const MAXLINESIZE = 1000000;

    // Available compression methods as constants
    const GZIP = 'Gzip';
    const BZIP2 = 'Bzip2';
    const NONE = 'None';

    // Available connection strings
    const UTF8 = 'utf8';
    const UTF8MB4 = 'utf8mb4';

    /**
     * Database username
     * @var string
     */
    public $user;
    /**
     * Database password
     * @var string
     */
    public $pass;
    /**
     * Destination filename, defaults to stdout
     * @var string
     */
    public $fileName = 'php://output';

    // Internal stuff
    private $tables = array();
    //private $dbHandler = null;
    private $dbType;
    private $compressManager;
    private $typeAdapter;
    private $dumpSettings = array();
    private $version;
    private $tableColumnTypes = array();
    public $log=false;
    public $task_id='';
    /**
     * database name, parsed from dsn
     * @var string
     */
    private $dbName;
    /**
     * host name, parsed from dsn
     * @var string
     */
    private $host;

    public $last_query_string='';

    public $task = false;
    public $file_index=1;
    public $tmp_file_name='';
    public $current_size=0;
    public $files=array();
    public $backup_tables;
    public $find_zero_date=false;

    public function __construct($task,$dump_setting)
    {
        if(is_a($task, 'WPvivid_Backup_Task_2'))
        {
            $this->task=$task;
        }
        else
        {
            throw new Exception('not as wpvivid task type');
        }

        $dumpSettingsDefault = array(
            'include-tables' => array(),
            'exclude-tables' => array(),
            'compress' => WPvivid_Mysqldump2::NONE,
            'init_commands' => array(),
            'no-data' => array(),
            'reset-auto-increment' => false,
            'add-drop-database' => false,
            'add-drop-table' => true,
            'add-drop-trigger' => true,
            'add-locks' => true,
            'complete-insert' => false,
            'default-character-set' => WPvivid_Mysqldump2::UTF8,
            'disable-keys' => true,
            'extended-insert' => false,
            'events' => false,
            'hex-blob' => true, /* faster than escaped content */
            'net_buffer_length' => self::MAXLINESIZE,
            'no-autocommit' => false,
            'no-create-info' => false,
            'lock-tables' => false,
            'routines' => false,
            'single-transaction' => true,
            'skip-triggers' => false,
            'skip-tz-utc' => false,
            'skip-comments' => false,
            'skip-dump-date' => false,
            'where' => '',

        );

        if(defined('DB_CHARSET'))
        {
            $dumpSettingsDefault['default-character-set']=DB_CHARSET;
        }

        $this->dumpSettings = $this->array_replace_recursive($dumpSettingsDefault, $dump_setting);

        $this->dumpSettings['init_commands'][] = "SET NAMES " . WPvivid_Mysqldump2::UTF8MB4;

        if (false === $this->dumpSettings['skip-tz-utc'])
        {
            $this->dumpSettings['init_commands'][] = "SET TIME_ZONE='+00:00'";
        }

        // Create a new compressManager to manage compressed output
        $this->compressManager = new CompressTest_2();
        $this->backup_tables=0;
    }

    public function connect()
    {
        $dbType=$this->dumpSettings['db_connect_method'];
        $host=$this->dumpSettings['host'];
        $user=$this->dumpSettings['user'];
        $pass=$this->dumpSettings['pass'];
        $database=$this->dumpSettings['database'];

        $this->typeAdapter = WPvividTypeAdapterFactory::create($dbType, null);
        $this->typeAdapter->connect($host,$database,$user,$pass,$this->dumpSettings['init_commands']);

    }

    public function write_header()
    {
        // Write some basic info to output file
        $upload_dir  = wp_upload_dir();

        $site_url=$this->dumpSettings['site_url'];
        $home_url=$this->dumpSettings['home_url'];
        $content_url=$this->dumpSettings['content_url'];
        $upload_url=$upload_dir['baseurl'];

        $this->compressManager->write('/* # site_url: '.$site_url.' */;'.PHP_EOL);
        $this->compressManager->write('/* # home_url: '.$home_url.' */;'.PHP_EOL);
        $this->compressManager->write('/* # content_url: '.$content_url.' */;'.PHP_EOL);
        $this->compressManager->write('/* # upload_url: '.$upload_url.' */;'.PHP_EOL);
        if(isset($this->dumpSettings['prefix']))
        {
            $table_prefix=$this->dumpSettings['prefix'];
            $this->compressManager->write('/* # table_prefix: '.$table_prefix.' */;'.PHP_EOL.PHP_EOL.PHP_EOL);
        }


        // Store server settings and use sanner defaults to dump
        $this->compressManager->write(
            $this->typeAdapter->backup_parameters($this->dumpSettings)
        );
    }

    public function write_footer()
    {
        // Restore saved parameters
        $this->compressManager->write(
            $this->typeAdapter->restore_parameters($this->dumpSettings)
        );
    }

    public function init_job()
    {
        $tables=$this->list_tables();

        if(empty($tables))
        {
            return false;
        }

        usort($tables, function ($a, $b)
        {
            if ($a['size'] == $b['size'])
                return 0;

            if ($a['size'] > $b['size'])
                return 1;
            else
                return -1;
        });

        $jobs=array();

        foreach ($tables as $table)
        {
            $jobs[$table['name']]['index']=0;
            $jobs[$table['name']]['finished']=0;
            $jobs[$table['name']]['created']=0;
            $jobs[$table['name']]['name']=$table['name'];
            $jobs[$table['name']]['size']=$table['size'];
            $jobs[$table['name']]['rows']=$table['rows'];
        }

        $this->task->update_current_sub_job($jobs);
        return $jobs;
    }

    public function start_jobs()
    {
        $this->tables= $this->task->get_current_sub_job();
        return $this->exportTables();
    }

    public function list_tables()
    {
        $tables=array();
        $views=array();

        global $wpdb;
        $resultSet=$wpdb->get_results('SHOW TABLE STATUS', ARRAY_A);

        $resultViews=$wpdb->get_results('SHOW FULL TABLES WHERE table_type = \'VIEW\'', ARRAY_A);
        if(!is_null($resultViews))
        {
            foreach ($resultViews as $view)
            {
                $name = 'Tables_in_'.DB_NAME;
                $views[] = $view[$name];
            }
        }

        if (is_null($resultSet))
        {
           return $tables;
        }

        if(isset($this->dumpSettings['prefix'])&&!empty($this->dumpSettings['prefix']))
        {
            $exclude = array('/^(?!' . $this->dumpSettings['prefix'] . ')/i');
        }
        else
        {
            $exclude=array();
        }
        foreach ($resultSet as $row)
        {
            if(isset($row['Comment']) && $row['Comment'] === 'VIEW')
            {
                continue;
            }

            if ( $this->matches($row['Name'], $this->dumpSettings['include-tables']) )
            {
                $table['name']=$row['Name'];
                $table['size']= ($row["Data_length"] + $row["Index_length"]);
                $table['rows']=$row['Rows'];
                $tables[]=$table;
                continue;
            }

            if(!empty($exclude))
            {
                if ( $this->matches($row['Name'], $exclude) )
                {
                    continue;
                }
            }

            if ( $this->matches($row['Name'], $this->dumpSettings['exclude-tables']) )
            {
                continue;
            }

            if(!empty($views))
            {
                if ( $this->matches($row['Name'], $views) )
                {
                    continue;
                }
            }

            $table['name']=$row['Name'];
            $table['size']= ($row["Data_length"] + $row["Index_length"]);
            $table['rows']=$row['Rows'];
            $tables[]=$table;
        }

        return $tables;
    }
    /**
     * Compare if $table name matches with a definition inside $arr
     * @param $table string
     * @param $arr array with strings or patterns
     * @return bool
     */
    private function matches($table, $arr) {
        $match = false;

        if(empty($arr))
        {
            return false;
        }

        foreach ($arr as $pattern) {
            if ( '/' != $pattern[0] ) {
                continue;
            }
            if ( 1 == preg_match($pattern, $table) ) {
                $match = true;
            }
        }

        return in_array($table, $arr) || $match;
    }

    public function check_tmp_file()
    {
        $max_file_size=$this->dumpSettings['max_file_size'];
        $max_backup_tables=5000;
        if($max_file_size==0)
            return;
        $this->current_size=$this->compressManager->get_size();
        $path=$this->dumpSettings['path'];

        if( $this->current_size>$max_file_size||$this->backup_tables>=$max_backup_tables)
        {
            $this->current_size=0;
            $this->backup_tables=0;
            $this->close_tmp_file();
            $name_file_name=$this->dumpSettings['file_prefix'].'.part'.sprintf('%03d',($this->file_index)).'.sql';
            $this->file_index++;
            rename($this->tmp_file_name,$path.DIRECTORY_SEPARATOR.$name_file_name);
            $this->task->update_current_sub_job($this->tables);
            $this->task->add_mysql_dump_files($name_file_name);
            $this->open_tmp_file();
        }
    }

    public function open_tmp_file($b_delete=false)
    {
        if($b_delete)
            @wp_delete_file( $this->tmp_file_name);
        $this->compressManager->open($this->tmp_file_name);
    }

    public function close_tmp_file()
    {
        $this->compressManager->close();
    }

    private function exportTables()
    {
        global $wpvivid_plugin;
        //tmp_file_name
        $path=$this->dumpSettings['path'];
        $this->tmp_file_name=$path.DIRECTORY_SEPARATOR.$this->dumpSettings['file_prefix'].'_tmp.sql';

        $this->open_tmp_file();
        $this->write_header();
        /*
        if(file_exists($this->tmp_file_name))
        {
            $this->open_tmp_file();
        }
        else
        {
            $this->open_tmp_file();
            $this->write_header();
        }*/

        // Exporting tables one by one
        $this->file_index=$this->task->get_current_mysql_file_index();
        $this->current_size=0;
        $tables=$this->tables;
        $i=0;
        $i_step=0;
        $this->backup_tables=0;
        if($this->task->task_id!=='')
        {
            $size = $this->task->get_backup_jobs();
            if(sizeof($size) > 0)
            {
                $i_step = intval(1 / (sizeof($size)) * 100);
            }
        }
        foreach ($tables as $name=>$table)
        {
            if($this->task->check_cancel_backup())
            {
                die();
            }

            if($table['finished']==1)
            {
                continue;
            }
            $index=$table['index'];
            $table_name=$table['name'];

            $message='Preparing to dump table '.$table_name;
            $wpvivid_plugin->wpvivid_log->WriteLog($message,'notice');

            $this->task->update_sub_task_progress($message);

            if($table['created']==0)
            {
                $this->getTableStructure($table_name);
                $this->tables[$name]['created']=1;
                //$this->task->update_current_sub_job($this->tables);
            }

            $this->tableColumnTypes[$table_name] = $this->getTableColumnTypes($table_name);
            if($this->tableColumnTypes[$table_name]===false)
            {
                continue;
            }

            $this->listValues($table_name,$index);
            $this->check_tmp_file();

            $this->tables[$name]['finished']=1;
            $this->backup_tables++;
            //$this->task->update_current_sub_job($this->tables);
            $i++;
            if($this->task->task_id!=='')
            {
                $i_progress=intval($i/sizeof($this->tables)*$i_step);
                $this->task->update_database_progress($i_progress);
            }
        }

        $this->current_size=$this->compressManager->get_size();
        if($this->current_size>0)
        {
            $this->close_tmp_file();
            $name_file_name=$this->dumpSettings['file_prefix'].'.part'.sprintf('%03d',($this->file_index)).'.sql';
            $this->file_index++;
            rename($this->tmp_file_name,$path.DIRECTORY_SEPARATOR.$name_file_name);
            $this->task->add_mysql_dump_files($name_file_name);
        }
        else
        {
            $this->close_tmp_file();
        }

        $ret['result']='success';
        return $ret;
    }
    /**
     * Table structure extractor
     *
     * @param string $tableName  Name of table to export
     * @return null
     */
    private function getTableStructure($tableName)
    {
        if (!$this->dumpSettings['no-create-info']) {
            $ret = '';
            if (!$this->dumpSettings['skip-comments']) {
                $ret = "--" . PHP_EOL .
                    "-- Table structure for table `$tableName`" . PHP_EOL .
                    "--" . PHP_EOL . PHP_EOL;
            }
            $stmt = $this->typeAdapter->show_create_table($tableName);

            foreach ($this->query($stmt) as $r)
            {
                $this->compressManager->write($ret);
                if ($this->dumpSettings['add-drop-table']) {
                    $this->compressManager->write(
                        $this->typeAdapter->drop_table($tableName)
                    );
                }

                $this->compressManager->write(
                    $this->typeAdapter->create_table($r, $this->dumpSettings)
                );
                break;
            }
        }

        return;
    }

    /**
     * Store column types to create data dumps and for Stand-In tables
     *
     * @param string $tableName  Name of table to export
     * @return array type column types detailed
     */

    private function getTableColumnTypes($tableName) {
        $columnTypes = array();
        $columns = $this->query(
            $this->typeAdapter->show_columns($tableName)
        );
        if($columns===false)
        {
            $error=$this->typeAdapter->errorInfo();
            if(isset($error[2])){
                $error = 'Error: '.$error[2];
            }
            else{
                $error = '';
            }
            $columns = $this->query(
                'DESCRIBE '.$tableName
            );
            if($columns===false)
            {
                $error=$this->typeAdapter->errorInfo();
                if(isset($error[2])){
                    $error = 'Error: '.$error[2];
                }
                else{
                    $error = '';
                }
                return false;
            }
        }

        foreach($columns as $key => $col) {
            $types = $this->typeAdapter->parseColumnType($col);
            $columnTypes[$col['Field']] = array(
                'is_numeric'=> $types['is_numeric'],
                'is_blob' => $types['is_blob'],
                'type' => $types['type'],
                'type_sql' => $col['Type'],
                'is_virtual' => $types['is_virtual']
            );
        }

        return $columnTypes;
    }

    /**
     * Escape values with quotes when needed
     *
     * @param string $tableName Name of table which contains rows
     * @param array $row Associative array of column names and values to be quoted
     *
     * @return array
     */
    private function escape($tableName, $row)
    {
        $ret = array();
        $columnTypes = $this->tableColumnTypes[$tableName];
        foreach ($row as $colName => $colValue) {
            if (is_null($colValue)) {
                $ret[] = "NULL";
            } elseif ($this->dumpSettings['hex-blob'] && $columnTypes[$colName]['is_blob']) {
                if ($columnTypes[$colName]['type'] == 'bit' || !empty($colValue)) {
                    $ret[] = "0x{$colValue}";
                } else {
                    $ret[] = "''";
                }
            } elseif ($columnTypes[$colName]['is_numeric']) {
                $ret[] = $colValue;
            } else {
                $ret[] = $this->typeAdapter->quote($colValue);
            }
        }
        return $ret;
    }


    private function listValues($tableName,$index)
    {
        global $wpvivid_plugin;
        $this->prepareListValues($tableName);

        $onlyOnce = true;
        $lineSize = 0;

        $colStmt = $this->getColumnStmt($tableName);

        global $wpdb;
        $prefix=$wpdb->base_prefix;
        $dbType=$this->dumpSettings['db_connect_method'];

        $start=$index;
        $limit_count=5000;

        //$sum =$wpdb->get_var("SELECT COUNT(1) FROM `{$tableName}`");
        $sum=0;
        $resultSet = $this->query("SELECT COUNT(1) FROM `{$tableName}`");
        foreach ($resultSet as $row)
        {
            $sum=$row['COUNT(1)'];
        }

        $this->typeAdapter->closeCursor($resultSet);

        if($dbType=='wpdb')
        {
            $b_options=false;
            if(substr($tableName, strlen($prefix))=='options')
            {
               $b_options=true;
            }

            $stmt = "SELECT " . implode(",", $colStmt) . " FROM `$tableName`";

            if ($this->dumpSettings['where']) {
                $stmt .= " WHERE {$this->dumpSettings['where']}";
            }

            $i=0;
            $i_check_cancel=0;
            $count=0;

            while($sum > $start)
            {
                $limit = " LIMIT {$limit_count} OFFSET {$start}";

                $query=$stmt.$limit;
                $resultSet = $this->query($query);

                if($resultSet===false)
                {
                    $error=$this->typeAdapter->errorInfo();
                    if(isset($error[2])){
                        $error = 'Error: '.$error[2];
                    }
                    else{
                        $error = '';
                    }
                    $this->endListValues($tableName);
                    return ;
                }

                foreach ($resultSet as $row)
                {
                    $i++;

                    $skip=false;

                    $vals = $this->escape($tableName, $row);

                    foreach($vals as $key => $value)
                    {
                        if($value === '\'0000-00-00 00:00:00\'')
                        {
                            //$vals[$key] = '\'1999-01-01 00:00:00\'';
                            $this->find_zero_date=true;
                        }

                        if($b_options)
                        {
                            if($value=="'wpvivid_task_list'")
                            {
                                $skip=true;
                            }
                        }
                    }

                    if($skip)
                        continue;
                    if ($onlyOnce || !$this->dumpSettings['extended-insert'])
                    {
                        if ($this->dumpSettings['complete-insert'])
                        {
                            $lineSize += $this->compressManager->write(
                                "INSERT INTO `$tableName` (" .
                                implode(", ", $colStmt) .
                                ") VALUES (" . implode(",", $vals) . ")"
                            );
                        } else {
                            $lineSize += $this->compressManager->write(
                                "INSERT INTO `$tableName` VALUES (" . implode(",", $vals) . ")"
                            );
                        }
                        $onlyOnce = false;
                    }
                    else {
                        $lineSize += $this->compressManager->write(",(" . implode(",", $vals) . ")");
                    }
                    if (($lineSize > $this->dumpSettings['net_buffer_length']) ||
                        !$this->dumpSettings['extended-insert']) {
                        $onlyOnce = true;
                        $lineSize = $this->compressManager->write(";" . PHP_EOL);
                    }

                    if($i>=200000)
                    {
                        $count+=$i;
                        $i=0;
                        if($this->task->task_id!=='')
                        {
                            $i_check_cancel++;
                            if($i_check_cancel>5)
                            {
                                $i_check_cancel=0;
                                $this->task->check_cancel_backup();
                            }
                            $message='Dumping table '.$tableName.', rows dumped: '.$count.' rows.';
                            $this->task->update_sub_task_progress($message);
                        }
                    }
                }

                $this->typeAdapter->closeCursor($resultSet);

                $start += $limit_count;
                $this->tables[$tableName]['index']=$start;
                //$this->task->update_current_sub_job($this->tables);
                $this->check_tmp_file();
            }

            if (!$onlyOnce) {
                $this->compressManager->write(";" . PHP_EOL);
            }

            $this->endListValues($tableName);
        }
        else
        {
            $b_options=false;
            if(substr($tableName, strlen($prefix))=='options')
            {
                $b_options=true;
            }

            $stmt = "SELECT " . implode(",", $colStmt) . " FROM `$tableName`";

            if ($this->dumpSettings['where']) {
                $stmt .= " WHERE {$this->dumpSettings['where']}";
            }

            $i=0;
            $i_check_cancel=0;
            $count=0;

            while($sum > $start)
            {
                $limit = " LIMIT {$limit_count} OFFSET {$start}";

                $query=$stmt.$limit;
                $resultSet = $this->query($query);

                if($resultSet===false)
                {
                    $error=$this->typeAdapter->errorInfo();
                    if(isset($error[2])){
                        $error = 'Error: '.$error[2];
                    }
                    else{
                        $error = '';
                    }
                    $this->endListValues($tableName);
                    return ;
                }

                foreach ($resultSet as $row)
                {
                    $skip=false;
                    $vals = $this->escape($tableName, $row);

                    foreach($vals as $key => $value)
                    {
                        if($value === '\'0000-00-00 00:00:00\'')
                        {
                            //$vals[$key] = '\'1999-01-01 00:00:00\'';
                            $this->find_zero_date=true;
                        }

                        if($b_options)
                        {
                            if($value=="'wpvivid_task_list'")
                            {
                                $skip=true;
                            }
                        }
                    }

                    if($skip)
                        continue;

                    if ($onlyOnce || !$this->dumpSettings['extended-insert'])
                    {
                        if ($this->dumpSettings['complete-insert'])
                        {
                            var_dump('test1');
                            $lineSize += $this->compressManager->write(
                                "INSERT INTO `$tableName` (" .
                                implode(", ", $colStmt) .
                                ") VALUES (" . implode(",", $vals) . ")"
                            );
                        } else {
                            $lineSize += $this->compressManager->write(
                                "INSERT INTO `$tableName` VALUES (" . implode(",", $vals) . ")"
                            );
                        }
                        $onlyOnce = false;
                    }
                    else {
                        $lineSize += $this->compressManager->write(",(" . implode(",", $vals) . ")");
                    }
                    if (($lineSize > $this->dumpSettings['net_buffer_length']) ||
                        !$this->dumpSettings['extended-insert']) {
                        $onlyOnce = true;
                        $lineSize = $this->compressManager->write(";" . PHP_EOL);
                    }

                    if($i>=200000)
                    {
                        $count+=$i;
                        $i=0;
                        if($this->task->task_id!=='')
                        {
                            $i_check_cancel++;
                            if($i_check_cancel>5)
                            {
                                $i_check_cancel=0;
                                $this->task->check_cancel_backup();
                            }
                            $message='Dumping table '.$tableName.', rows dumped: '.$count.' rows.';
                            $this->task->update_sub_task_progress($message);
                        }
                    }
                }

                $this->typeAdapter->closeCursor($resultSet);

                $start += $limit_count;
                $this->tables[$tableName]['index']=$start;
                //$this->task->update_current_sub_job($this->tables);
                $this->check_tmp_file();
            }

            if (!$onlyOnce) {
                $this->compressManager->write(";" . PHP_EOL);
            }

            $this->endListValues($tableName);
        }

        //$this->current_size+=$table['size'];
    }

    /**
     * Table rows extractor, append information prior to dump
     *
     * @param string $tableName  Name of table to export
     *
     * @return null
     */
    function prepareListValues($tableName)
    {
        if (!$this->dumpSettings['skip-comments']) {
            $this->compressManager->write(
                "--" . PHP_EOL .
                "-- Dumping data for table `$tableName`" .  PHP_EOL .
                "--" . PHP_EOL . PHP_EOL
            );
        }

        if ($this->dumpSettings['single-transaction']) {
            $this->exec($this->typeAdapter->setup_transaction());
            $this->exec($this->typeAdapter->start_transaction());
        }

        if ($this->dumpSettings['lock-tables'])
        {
            $this->typeAdapter->lock_table($tableName);

            //if($this -> privileges['LOCK TABLES'] == 0)
            //{
            //global $wpvivid_plugin;
            //    $wpvivid_plugin->wpvivid_log->WriteLog('The lack of LOCK TABLES privilege, the backup will skip lock_tables() to continue.','notice');
            //}else{
            //    $this->typeAdapter->lock_table($tableName);
            //}
        }

        if ($this->dumpSettings['add-locks']) {
            $this->compressManager->write(
                $this->typeAdapter->start_add_lock_table($tableName)
            );
        }

        if ($this->dumpSettings['disable-keys']) {
            $this->compressManager->write(
                $this->typeAdapter->start_add_disable_keys($tableName)
            );
        }

        // Disable autocommit for faster reload
        if ($this->dumpSettings['no-autocommit']) {
            $this->compressManager->write(
                $this->typeAdapter->start_disable_autocommit()
            );
        }

        return;
    }

    /**
     * Table rows extractor, close locks and commits after dump
     *
     * @param string $tableName  Name of table to export
     *
     * @return null
     */
    function endListValues($tableName)
    {
        if ($this->dumpSettings['disable-keys']) {
            $this->compressManager->write(
                $this->typeAdapter->end_add_disable_keys($tableName)
            );
        }

        if ($this->dumpSettings['add-locks']) {
            $this->compressManager->write(
                $this->typeAdapter->end_add_lock_table($tableName)
            );
        }

        if ($this->dumpSettings['single-transaction']) {
            $this->exec($this->typeAdapter->commit_transaction());
        }

        if ($this->dumpSettings['lock-tables']) {
            $this->typeAdapter->unlock_table($tableName);
        }

        // Commit to enable autocommit
        if ($this->dumpSettings['no-autocommit']) {
            $this->compressManager->write(
                $this->typeAdapter->end_disable_autocommit()
            );
        }

        $this->compressManager->write(PHP_EOL);

        return;
    }

    /**
     * Build SQL List of all columns on current table
     *
     * @param string $tableName  Name of table to get columns
     *
     * @return string SQL sentence with columns
     */
    function getColumnStmt($tableName)
    {
        $colStmt = array();
        foreach($this->tableColumnTypes[$tableName] as $colName => $colType) {
            if ($colType['type'] == 'bit' && $this->dumpSettings['hex-blob']) {
                $colStmt[] = "LPAD(HEX(`{$colName}`),2,'0') AS `{$colName}`";
            } else if ($colType['is_blob'] && $this->dumpSettings['hex-blob']) {
                $colStmt[] = "HEX(`{$colName}`) AS `{$colName}`";
            } else if ($colType['is_virtual']) {
                $this->dumpSettings['complete-insert'] = true;
                continue;
            } else {
                $colStmt[] = "`{$colName}`";
            }
        }

        return $colStmt;
    }

    /**
     * Custom array_replace_recursive to be used if PHP < 5.3
     * Replaces elements from passed arrays into the first array recursively
     *
     * @param array $array1 The array in which elements are replaced
     * @param array $array2 The array from which elements will be extracted
     *
     * @return array Returns an array, or NULL if an error occurs.
     */
    public function array_replace_recursive($array1, $array2)
    {
        if (function_exists('array_replace_recursive')) {
            return array_replace_recursive($array1, $array2);
        }

        foreach ($array2 as $key => $value) {
            if (is_array($value)) {
                $array1[$key] = $this->array_replace_recursive($array1[$key], $value);
            } else {
                $array1[$key] = $value;
            }
        }
        return $array1;
    }

    public function query($query_string)
    {
        $this->last_query_string=$query_string;
        return  $this->typeAdapter->query($query_string);
    }

    private function exec($query_string)
    {
        $this->last_query_string=$query_string;
        return  $this->typeAdapter->query($query_string);
    }

    public function is_has_zero_date()
    {
        if($this->find_zero_date)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}