Index: database_mysql_dump.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/demo/database_mysql_dump.inc,v retrieving revision 1.5.2.6 diff -u -p -r1.5.2.6 database_mysql_dump.inc --- database_mysql_dump.inc 17 May 2009 13:25:01 -0000 1.5.2.6 +++ database_mysql_dump.inc 30 Jul 2009 16:20:06 -0000 @@ -8,8 +8,13 @@ if (!defined('MYSQLI_BINARY_FLAG')) { /** * Dump active database. + * + * @param $filename + * Output filename. + * @param $options + * Snapshot options. */ -function demo_dump_db($filename, $exclude = array()) { +function demo_dump_db($filename, $options = array()) { // Make sure we have permission to save our backup file. $directory = dirname($filename); if (!file_check_directory($directory, FILE_CREATE_DIRECTORY)) { @@ -28,13 +33,12 @@ function demo_dump_db($filename, $exclud $header .= "SET FOREIGN_KEY_CHECKS = 0;\n"; fwrite($fp, $header); - foreach (demo_enum_tables() as $table) { - // Always export structure to allow creating a new site - // from a database dump - fwrite($fp, _demo_dump_table_structure($table)); - - if (!in_array($table, $exclude)) { - fwrite($fp, _demo_dump_table_data($table)); + foreach ($options['tables'] as $table => $dump_options) { + if ($dump_options['schema']) { + _demo_dump_table_schema($fp, $table); + } + if ($dump_options['data']) { + _demo_dump_table_data($fp, $table); } } @@ -49,7 +53,7 @@ function demo_dump_db($filename, $exclud } /** - * Returns the name of the active database. + * Return the name of the active database. */ function _demo_get_database() { $database = array_keys(db_fetch_array(db_query('SHOW TABLES'))); @@ -58,9 +62,21 @@ function _demo_get_database() { } /** - * Dump table structure. + * Enumerate database tables. */ -function _demo_dump_table_structure($table) { +function _demo_enum_tables() { + return db_query("SHOW TABLES"); +} + +/** + * Dump table schema. + * + * @param $fp + * Output file handle. + * @param $table + * Table name to export schema for. + */ +function _demo_dump_table_schema($fp, $table) { $output = "\n"; $output .= "--\n"; $output .= "-- Table structure for table '$table'\n"; @@ -69,21 +85,26 @@ function _demo_dump_table_structure($tab $data = db_fetch_array(db_query("SHOW CREATE TABLE %s", $table)); $output .= preg_replace('/^CREATE TABLE/', 'CREATE TABLE IF NOT EXISTS', $data['Create Table']) . ";\n"; - return $output; + fwrite($fp, $output); } /** * Dump table data. * * This code has largely been stolen from the phpMyAdmin project. + * + * @param $fp + * Output file handle. + * @param $table + * Table name to export data for. */ -function _demo_dump_table_data($table) { +function _demo_dump_table_data($fp, $table) { $output = "\n"; $output .= "--\n"; $output .= "-- Dumping data for table '$table'\n"; $output .= "--\n\n"; - // Dump table data + // Dump table data. $result = db_query("SELECT * FROM %s", $table); // Get table fields. @@ -142,7 +163,9 @@ function _demo_dump_table_data($table) { else { $insert_buffer = '(' . implode(', ', $values) . ')'; if ($query_size + strlen($insert_buffer) > 50000) { - $output .= ";\n"; + // Flush buffer to disc. + fwrite($fp, $output . ";\n"); + $output = ''; $current_row = 1; $query_size = 0; $insert_buffer = $insert_cmd . $insert_buffer; @@ -161,7 +184,7 @@ function _demo_dump_table_data($table) { $output .= "/*!40000 ALTER TABLE $table ENABLE KEYS */;\n"; } - return $output; + fwrite($fp, $output); } /** Index: demo.admin.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/demo/demo.admin.inc,v retrieving revision 1.1.2.15 diff -u -p -r1.1.2.15 demo.admin.inc --- demo.admin.inc 17 Jul 2009 15:38:27 -0000 1.1.2.15 +++ demo.admin.inc 30 Jul 2009 16:22:58 -0000 @@ -77,7 +77,10 @@ function demo_admin_settings_submit($for drupal_set_message(t('The configuration options have been saved.')); } -function demo_manage() { +/** + * Menu callback to display manage snapshots form. + */ +function demo_manage_form() { $form['dump'] = array( '#type' => 'fieldset', '#title' => t('Available snapshots'), @@ -95,7 +98,7 @@ function demo_manage() { return $form; } -function demo_manage_submit($form, &$form_state) { +function demo_manage_form_submit($form, &$form_state) { demo_set_default($form_state['values']['filename']); } @@ -124,7 +127,10 @@ function demo_delete_confirm_submit($for $form_state['redirect'] = 'admin/build/demo/manage'; } -function demo_dump() { +/** + * Menu callback to render the create snapshot form. + */ +function demo_dump_form() { $form = array(); $form['dump']['filename'] = array( '#title' => t('File name'), @@ -144,60 +150,62 @@ function demo_dump() { '#rows' => 2, '#description' => t('Optionally enter a description for this snapshot here. If no description is given and a snapshot with the same filename already exists, the previous description is used.'), ); + $form['dump']['tables'] = array('#type' => 'value', '#value' => demo_enum_tables()); return confirm_form($form, t('Are you sure you want to create a new snapshot?'), 'admin/build/demo', t('If the above filename already exists, creating a new snapshot will overwrite the existing snapshot. This action cannot be undone.'), t('Create'), t('Cancel')); } -function demo_dump_submit($form, &$form_state) { - global $db_type; +function demo_dump_form_submit($form, &$form_state) { + if ($fileconfig = demo_dump($form_state['values'])) { + drupal_set_message(t('Successfully created snapshot %filename.', array('%filename' => $fileconfig['sqlfile']))); + } + $form_state['redirect'] = 'admin/build/demo/manage'; +} - // Generate info file. - $info = demo_set_info($form_state['values']); +/** + * Create a new snapshot. + * + * @param $options + * A structured array of snapshot options: + * - filename: The base output filename, without extension. + * - default: Whether to set this dump as new default snapshot. + * - description: A description for the snapshot. If a snapshot with the same + * name already exists and this is left blank, the new snapshot will reuse + * the existing description. + * - tables: An array of tables to dump, keyed by table name (including table + * prefix, if any). The value is an array of dump options: + * - schema: Whether to dump the table schema. + * - data: Whether to dump the table data. + */ +function demo_dump($options) { + // Increase PHP's max_execution_time for large dumps. + @set_time_limit(600); + + // Allow other modules to alter the submitted option values. + drupal_alter('demo_dump', $options); + + // Generate the info file. + $info = demo_set_info($options); if (!$info) { return FALSE; } - // Include database specific functions. - $engine = ($db_type == 'mysqli' ? 'mysql' : $db_type); - $inc_file = drupal_get_path('module', 'demo') . '/database_' . $engine . '_dump.inc'; - if (file_exists($inc_file)) { - require_once $inc_file; - - if (!empty($form_state['values']['default'])) { - // Set new default snapshot. - demo_set_default($info['filename']); - } - - // Increase PHP's max_execution_time for large dumps. - @set_time_limit(600); - - // Perform dump. - $fileconfig = demo_get_fileconfig($info['filename']); - $exclude = array( - '{cache}', - '{cache_admin_menu}', - '{cache_block}', - '{cache_content}', - '{cache_filter}', - '{cache_form}', - '{cache_menu}', - '{cache_page}', - '{cache_views}', - '{ctools_object_cache}', - '{panels_object_cache}', - '{views_object_cache}', - '{watchdog}', - ); - $exclude = array_map('db_prefix_tables', $exclude); - demo_dump_db($fileconfig['sqlfile'], $exclude); - drupal_set_message(t('Successfully created snapshot %filename.', array('%filename' => $fileconfig['sqlfile']))); + // Set as new default snapshot. + if (!empty($options['default'])) { + demo_set_default($info['filename']); } - else { - drupal_set_message(t('@engine support not implemented yet.', array('@engine' => ucfirst($engine))), 'error'); + + // Perform database dump. + $fileconfig = demo_get_fileconfig($info['filename']); + if (!demo_dump_db($fileconfig['sqlfile'], $options)) { + return FALSE; } - $form_state['redirect'] = 'admin/build/demo/manage'; + return $fileconfig; } +/** + * Menu callback to display snapshot selection form. + */ function demo_reset_confirm() { $form['dump'] = array( '#type' => 'fieldset', @@ -209,18 +217,29 @@ function demo_reset_confirm() { } function demo_reset_confirm_submit($form, &$form_state) { - // Increase PHP's max_execution_time for large dumps. - @set_time_limit(600); - // Reset site to chosen snapshot. demo_reset($form_state['values']['filename']); - // Save time of last reset. - variable_set('demo_reset_last', time()); $form_state['redirect'] = isset($form_state['values']['redirect']) ? $form_state['values']['redirect'] : 'admin/build/demo'; } -function demo_reset($filename = 'demo_site', $verbose = TRUE) { +/** + * Reset site using snapshot. + * + * @param $filename + * Base snapshot filename, without extension. + * @param $verbose + * Whether to output status messages. + */ +function demo_reset($filename, $verbose = TRUE) { + // Increase PHP's max_execution_time for large dumps. + @set_time_limit(600); + + // Load database specific functions. + if (!demo_load_include()) { + return FALSE; + } + $fileconfig = demo_get_fileconfig($filename); if (!file_exists($fileconfig['sqlfile']) || !($fp = fopen($fileconfig['sqlfile'], 'r'))) { if ($verbose) { @@ -235,11 +254,11 @@ function demo_reset($filename = 'demo_si $version = demo_get_info($fileconfig['infofile'], 'version'); $is_version_1_0_dump = version_compare($version, '1.1', '<'); - // Drop tables - $dt_watchdog = db_prefix_tables('{watchdog}'); - foreach (demo_enum_tables() as $table) { + // Drop tables. + $watchdog = db_prefix_tables('{watchdog}'); + foreach (demo_enum_tables() as $table => $dump_options) { // Skip watchdog, except for legacy dumps that included the watchdog table - if ($table != $dt_watchdog || $is_version_1_0_dump) { + if ($table != $watchdog || $is_version_1_0_dump) { db_query("DROP TABLE %s", $table); } } @@ -298,6 +317,8 @@ function demo_reset($filename = 'demo_si // Reset default dump to load on cron. variable_set('demo_dump_cron', $demo_dump_cron); + // Save time of last reset. + variable_set('demo_reset_last', $_SERVER['REQUEST_TIME']); return $success; } @@ -342,6 +363,24 @@ function demo_get_fileconfig($filename = return $fileconfig; } +/** + * Load database specific functions. + */ +function demo_load_include() { + global $db_type; + + $engine = ($db_type == 'mysqli' ? 'mysql' : $db_type); + $inc_file = drupal_get_path('module', 'demo') . '/database_' . $engine . '_dump.inc'; + if (!file_exists($inc_file)) { + drupal_set_message(t('@engine support not implemented yet.', array('@engine' => ucfirst($engine))), 'error'); + return FALSE; + } + + require_once $inc_file; + + return TRUE; +} + function demo_get_dumps() { $fileconfig = demo_get_fileconfig(); @@ -484,25 +523,21 @@ function demo_enum_tables() { $tables = array(); + // Load database specific functions. + if (!demo_load_include()) { + return FALSE; + } + + // Create a regex that matches the table prefix(es). if (is_array($db_prefix)) { - // Create a regular expression for table prefix matching. $rx = '/^' . implode('|', array_filter($db_prefix)) . '/'; } else if ($db_prefix != '') { $rx = '/^' . $db_prefix . '/'; } - switch ($GLOBALS['db_type']) { - case 'mysql': - case 'mysqli': - $result = db_query("SHOW TABLES"); - break; - - case 'pgsql': - $result = db_query("SELECT table_name FROM information_schema.tables WHERE table_schema = '%s'", 'public'); - break; - } - + // Query the database engine for the table list. + $result = _demo_enum_tables(); while ($table = db_fetch_array($result)) { $table = reset($table); if (is_array($db_prefix)) { @@ -511,17 +546,46 @@ function demo_enum_tables() { $table_prefix = $matches[0]; $plain_table = substr($table, strlen($table_prefix)); if ($db_prefix[$plain_table] == $table_prefix || $db_prefix['default'] == $table_prefix) { - $tables[] = $table; + $tables[$table] = array('schema' => TRUE, 'data' => TRUE); } } } else if ($db_prefix != '') { if (preg_match($rx, $table)) { - $tables[] = $table; + $tables[$table] = array('schema' => TRUE, 'data' => TRUE); } } else { - $tables[] = $table; + $tables[$table] = array('schema' => TRUE, 'data' => TRUE); + } + } + + // Apply default exclude list. + $excludes = array( + // Core + '{cache}', + '{cache_block}', + '{cache_content}', + '{cache_filter}', + '{cache_form}', + '{cache_menu}', + '{cache_page}', + '{cache_update}', + '{watchdog}', + // CTools + '{ctools_object_cache}', + // Drupal Administration Menu + '{cache_admin_menu}', + // Panels + '{panels_object_cache}', + // Views + '{cache_views}', + '{cache_views_data}', + '{views_object_cache}', + ); + foreach (array_map('db_prefix_tables', $excludes) as $table) { + if (isset($tables[$table])) { + $tables[$table]['data'] = FALSE; } } Index: demo.api.php =================================================================== RCS file: demo.api.php diff -N demo.api.php --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ demo.api.php 30 Jul 2009 16:10:33 -0000 @@ -0,0 +1,48 @@ + $dump_options) { + // Test if the table name starts with 'unrelated_'. + if (strncmp($table, 'unrelated_', 10) == 0) { + unset($options['tables'][$table]); + } + } +} + +/** + * @} End of "addtogroup hooks". + */ Index: demo.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/demo/demo.module,v retrieving revision 1.19.2.13 diff -u -p -r1.19.2.13 demo.module --- demo.module 12 Jul 2009 00:09:48 -0000 1.19.2.13 +++ demo.module 30 Jul 2009 16:18:18 -0000 @@ -36,7 +36,7 @@ function demo_menu() { $items['admin/build/demo/manage'] = array( 'title' => 'Manage snapshots', 'page callback' => 'drupal_get_form', - 'page arguments' => array('demo_manage'), + 'page arguments' => array('demo_manage_form'), 'access arguments' => $admin_access, 'file' => 'demo.admin.inc', 'type' => MENU_LOCAL_TASK, @@ -45,7 +45,7 @@ function demo_menu() { $items['admin/build/demo/dump'] = array( 'title' => 'Create snapshot', 'page callback' => 'drupal_get_form', - 'page arguments' => array('demo_dump'), + 'page arguments' => array('demo_dump_form'), 'access arguments' => $admin_access, 'file' => 'demo.admin.inc', 'type' => MENU_LOCAL_TASK, @@ -137,7 +137,6 @@ function demo_cron() { if (($time - $interval) >= variable_get('demo_reset_last', 0)) { module_load_include('inc', 'demo', 'demo.admin'); demo_reset(variable_get('demo_dump_cron', 'demo_site'), FALSE); - variable_set('demo_reset_last', $time); } } }