diff --git a/commands/sql/sql.drush.inc b/commands/sql/sql.drush.inc
index 05866fd..bc6b117 100644
--- a/commands/sql/sql.drush.inc
+++ b/commands/sql/sql.drush.inc
@@ -355,6 +355,83 @@ function drush_sql_get_table_selection() {
   return array('skip' => $skip_tables, 'structure' => $structure_tables, 'tables' => $tables);
 }
 
+function drush_sql_expand_table_selection($table_selection, $db_spec, $site_record = NULL) {
+  if (isset($table_selection['skip'])) {
+    $table_selection['skip'] = drush_sql_expand_wildcard_tables($table_selection['skip'], $db_spec, $site_record);
+  }
+  if (isset($table_selection['structure'])) {
+    $table_selection['structure'] = drush_sql_expand_wildcard_tables($table_selection['structure'], $db_spec, $site_record);
+  }
+  if (isset($table_selection['tables'])) {
+    $table_selection['tables'] = drush_sql_expand_wildcard_tables($table_selection['tables'], $db_spec, $site_record);
+  }
+  return $table_selection;
+}
+
+function drush_sql_get_expanded_table_selection($db_spec, $site_record = NULL) {
+  return drush_sql_expand_table_selection(drush_sql_get_table_selection(), $db_spec, $site_record);
+}
+
+/**
+ * Expand wildcard tables.
+ * 
+ * @param array $tables
+ *   An array of table names, some of which may contain wildcards (`*`).
+ * @param $db_spec
+ *   For D5/D6, a $db_url. For D7+, a target in the default DB connection.
+ * @param $site_record
+ * @return
+ *   An array with the corresponding expanded tables names, all of which actually
+ *   exist in the database, none of which still contains a wildcard (`*`).
+ */
+function drush_sql_expand_wildcard_tables($tables, $db_spec, $site_record = NULL) {
+  // Get the existing table names contained in the given database.
+  $db_tables = _drush_sql_get_db_table_list($db_spec, $site_record);
+  
+  // table name expansion based on `*` wildcard.
+  $expanded_db_tables = array();
+  foreach ($tables as $k => $table) {
+    // only deal with table names containing a wildcard.
+    if (strpos($table, '*') !== FALSE) {
+      $pattern = '/^' . str_replace('*', '.*', $table) . '$/i';
+      // Merge those existing tables which match the pattern with the rest of
+      // the expanded table names.
+      $expanded_db_tables += preg_grep($pattern, $db_tables);
+    }
+  }
+  $tables += $expanded_db_tables;
+  $tables = drush_sql_validate_tables($tables, $db_spec);
+  $tables = array_unique($tables);
+  sort($tables);
+  
+  return $tables;
+}
+
+/**
+ * Validates tables
+ * 
+ * @param array $tables
+ *   An array of table names to validate.
+ * @param $db_spec
+ *   For D5/D6, a $db_url. For D7+, a target in the default DB connection.
+ * @return
+ *   An array with only valid table names (i.e. all of which actually exist in
+ *   the database).
+ */
+function drush_sql_validate_tables($tables, $db_spec, $site_record = NULL) {
+  // Get the existing table names contained in the current database.
+  $db_tables = _drush_sql_get_db_table_list($db_spec, $site_record);
+  
+  // Ensure all the tables actually exist in the database.
+  foreach ($tables as $k => $table) {
+    if (!in_array($table, $db_tables)) {
+      unset($tables[$k]);
+    }
+  }
+  
+  return $tables;
+}
+
 /**
  * Build a mysqldump/pg_dump/sqlite statement.
  *
@@ -366,7 +443,10 @@ function drush_sql_get_table_selection() {
  *     2. The filepath where the dump will be saved.
  */
 function drush_sql_dump($db_spec = NULL) {
-  return drush_sql_build_dump_command(drush_sql_get_table_selection(), $db_spec, drush_get_option('result-file', FALSE));
+  if (is_null($db_spec)) {
+    $db_spec = _drush_sql_get_db_spec();
+  }
+  return drush_sql_build_dump_command(drush_sql_get_expanded_table_selection($db_spec), $db_spec, drush_get_option('result-file', FALSE));
 }
 
 /**
@@ -395,10 +475,6 @@ function drush_sql_build_dump_command($table_selection, $db_spec = NULL, $file =
   // @todo add documention once a hook for drush_get_option_help() is available.
   // @see drush_get_option_help() in drush.inc
   $ordered_dump = drush_get_option('ordered-dump');
-
-  if (is_null($db_spec)) {
-    $db_spec = _drush_sql_get_db_spec();
-  }
   $database = $db_spec['database'];
 
   // $file is passed in to us usually via --result-file.  If the user
@@ -594,6 +670,95 @@ function _drush_sql_get_table_list($option_name) {
 }
 
 /**
+ * Extract the name of all existing tables in the given database.
+ * 
+ * @param $db_spec
+ *   For D5/D6, a $db_url. For D7, a target in the default DB connection.
+ * @param $site_record
+ *   Necessary for remote database.
+ * @return array
+ *   An array of table names which exist in the current database.
+ */
+function _drush_sql_get_db_table_list($db_spec, $site_record = NULL) {
+  $db_tables = drush_get_context('DRUSH_SQL_DB_TABLES', array());
+  $cache_key = serialize($db_spec);
+  if (isset($db_tables[$cache_key])) {
+    return $db_tables[$cache_key];
+  }
+  
+  $suffix = '';
+  $scheme = _drush_sql_get_scheme($db_spec);
+  switch ($scheme) {
+    case 'pgsql':
+      $query = drush_sql_show_tables_pgsql();
+      break;
+    case 'sqlite':
+      $query = '.tables';
+      break;
+    case 'sqlsrv':
+      $query = 'SELECT TABLE_NAME FROM information_schema.tables';
+      break;
+    case 'oracle':
+      $query = "SELECT TABLE_NAME FROM USER_TABLES WHERE TABLE_NAME NOT IN ('BLOBS','LONG_IDENTIFIERS')";
+      $suffix = '.sql';
+      break;
+    default:
+      $query = 'SHOW TABLES';
+      break;
+  }
+  
+  $target_site = '@self';
+  // Remote
+  if (isset($db_spec['remote-host'])) {
+    if (is_null($site_record)) {
+      drush_log(dt('Retrieving the table list for a remote DB, but the site record is missing.'), 'error');
+      exit;
+    }
+    $target_site = $site_record;
+  }
+  $result = drush_invoke_process($target_site, 'sqlq', array($query), array(), array('override-simulated' => TRUE, 'integrate' => FALSE));
+  $tables_raw = explode("\n", rtrim($result['output']));
+  // Shift off the "Calling system(…);" line at the top of the output.
+  array_shift($tables_raw);
+  
+  $tables = array();
+  if (!empty($tables_raw)) {
+    if ($scheme === 'sqlite') {
+      // SQLite's '.tables' command always outputs the table names in a column
+      // format, like this:
+      // table_alpha    table_charlie    table_echo
+      // table_bravo    table_delta      table_foxtrot
+      // …and there doesn't seem to be a way to fix that. So we need to do some
+      // clean-up.
+      foreach ($tables_raw as $line) {
+        preg_match_all('/[^\s]+/', $line, $matches);
+        if (!empty($matches[0])) {
+          foreach ($matches[0] as $match) {
+            $tables[] = $match;
+          }
+        }
+      }
+    }
+    elseif ($scheme === 'sqlsrv') {
+      // Shift off the header of the column of data returned.
+      array_pop($tables_raw);
+      array_pop($tables_raw);
+      $tables = $tables_raw;
+    }
+    else {
+      // Shift off the header of the column of data returned.
+      array_shift($tables_raw);
+      $tables = $tables_raw;
+    }
+  }
+
+  $db_tables[$cache_key] = $tables;
+  drush_set_context('DRUSH_SQL_DB_TABLES', $db_tables);
+  
+  return $db_tables[$cache_key];
+}
+
+/**
  * Command callback. Executes the given SQL query on the Drupal database.
  */
 
@@ -687,56 +852,15 @@ function drush_sql_drop() {
 // is rewritten to also use that technique, it should maintain
 // the drop tables code here as a fallback.
 function _drush_sql_drop($db_spec = NULL) {
-  // TODO: integrate with _drush_sql_get_table_list?
-
-  $suffix = '';
+  $tables = _drush_sql_get_table_list($db_spec);
   $scheme = _drush_sql_get_scheme($db_spec);
-  switch ($scheme) {
-    case 'pgsql':
-      $query = drush_sql_show_tables_pgsql();
-      break;
-    case 'sqlite':
-      $query = '.tables';
-      break;
-    case 'sqlsrv':
-      $query = 'SELECT TABLE_NAME FROM information_schema.tables';
-      break;
-    case 'oracle':
-      $query = "SELECT TABLE_NAME FROM USER_TABLES WHERE TABLE_NAME NOT IN ('BLOBS','LONG_IDENTIFIERS')";
-      $suffix = '.sql';
-      break;
-    default:
-      $query = 'SHOW TABLES;';
-  }
-
-  $filename = drush_save_data_to_temp_file($query, $suffix);
-  $exec = drush_sql_build_exec($db_spec, $filename);
-
-  // Actually run this prep query no matter if in SIMULATE.
-  $old = drush_get_context('DRUSH_SIMULATE');
-  drush_set_context('DRUSH_SIMULATE', FALSE);
-  drush_shell_exec($exec);
-  drush_set_context('DRUSH_SIMULATE', $old);
-  if ($tables = drush_shell_exec_output()) {
+  if (count($tables)) {
     if ($scheme === 'sqlite') {
-      // SQLite's '.tables' command always outputs the table names in a column
-      // format, like this:
-      // table_alpha    table_charlie    table_echo
-      // table_bravo    table_delta      table_foxtrot
-      // …and there doesn't seem to be a way to fix that. So we need to do some
-      // clean-up.
-      // Since we're already doing iteration here, might as well build the SQL
-      // too, since SQLite only wants one table per DROP TABLE command (so we have
-      // to do "DROP TABLE foo; DROP TABLE bar;" instead of
-      // "DROP TABLE foo, bar;").
       $sql = '';
-      foreach ($tables as $line) {
-        preg_match_all('/[^\s]+/', $line, $matches);
-        if (!empty($matches[0])) {
-          foreach ($matches[0] as $match) {
-            $sql .= "DROP TABLE {$match};";
-          }
-        }
+      // SQLite only wants one table per DROP TABLE command (so we have to do
+      // "DROP TABLE foo; DROP TABLE bar;" instead of "DROP TABLE foo, bar;").
+      foreach ($tables as $table) {
+        $sql .= "DROP TABLE {$match};";
       }
       // We can't use drush_op('db_query', $sql) because it will only perform one
       // SQL command and we're technically performing several.
@@ -744,16 +868,7 @@ function _drush_sql_drop($db_spec = NULL) {
       $exec .= " '{$sql}'";
       return drush_op_system($exec) == 0;
     }
-    elseif ($scheme === 'sqlsrv') {
-      // Shift off the header of the column of data returned.
-      array_pop($tables);
-      array_pop($tables);
-      $sql = 'DROP TABLE '. implode(', ', $tables);
-      return _drush_sql_query($sql, $db_spec);
-    }
     else {
-      // Shift off the header of the column of data returned.
-      array_shift($tables);
       $sql = 'DROP TABLE '. implode(', ', $tables);
       return _drush_sql_query($sql, $db_spec);
     }
diff --git a/examples/example.drushrc.php b/examples/example.drushrc.php
index 4e120ee..bf0eeaa 100644
--- a/examples/example.drushrc.php
+++ b/examples/example.drushrc.php
@@ -263,7 +263,7 @@
  * commands when the "--structure-tables-key=common" option is provided.
  * You may add specific tables to the existing array or add a new element.
  */
-# $options['structure-tables']['common'] = array('cache', 'cache_filter', 'cache_menu', 'cache_page', 'history', 'sessions', 'watchdog');
+# $options['structure-tables']['common'] = array('cache', 'cache_*', 'history', 'search_*', 'sessions', 'watchdog');
 
 /**
  * List of tables to be omitted entirely from SQL dumps made by the 'sql-dump'
diff --git a/includes/drush.inc b/includes/drush.inc
index 0ed75fd..485a9e7 100644
--- a/includes/drush.inc
+++ b/includes/drush.inc
@@ -320,7 +320,7 @@ function drush_get_global_options($brief = FALSE) {
   $options['debug']              = array('short-form' => 'd', 'context' => 'DRUSH_DEBUG', 'description' => 'Display even more information, including internal messages.');
   $options['yes']                = array('short-form' => 'y', 'context' => 'DRUSH_AFFIRMATIVE', 'description' => "Assume 'yes' as answer to all prompts.");
   $options['no']                 = array('short-form' => 'n', 'context' => 'DRUSH_NEGATIVE', 'description' => "Assume 'no' as answer to all prompts.");
-  $options['simulate']           = array('short-form' => 's', 'context' => 'DRUSH_SIMULATE', 'description' => "Simulate all relevant actions (don't actually change the system).");
+  $options['simulate']           = array('short-form' => 's', 'context' => 'DRUSH_SIMULATE', 'never-propagate' => TRUE, 'description' => "Simulate all relevant actions (don't actually change the system).");
   $options['pipe']               = array('short-form' => 'p', 'hidden' => TRUE, 'description' => "Emit a compact representation of the command for scripting.");
   $options['help']               = array('short-form' => 'h', 'description' => "This help system.");
   $options['version']            = array('description' => "Show drush version.");
