? 170583.patch
? includes/Drush Database Layer
? includes/table.inc
Index: commands/core/watchdog.drush.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/commands/core/watchdog.drush.inc,v
retrieving revision 1.4
diff -u -r1.4 watchdog.drush.inc
--- commands/core/watchdog.drush.inc	16 Feb 2010 16:01:40 -0000	1.4
+++ commands/core/watchdog.drush.inc	20 Feb 2010 11:50:06 -0000
@@ -1,130 +1,286 @@
 <?php
 
+/**
+ * Implementation of hook_drush_help().
+ */
 function watchdog_drush_help($section) {
   switch ($section)  {
+    case 'drush:watchdog-list':
+      return dt("Show watchdog severity levels and message types.");
     case 'drush:watchdog-show':
-      return dt("Show recent watchdog messages.");
+      return dt("Show watchdog messages. Arguments and options can be combined to configure which messages to show.");
     case 'drush:watchdog-delete':
-      return dt("Delete watchdog messages.");
+      return dt("Delete watchdog messages. Arguments or options must be provided to specify which messages to delete.");
   }
 }
 
+/**
+ * Implementation of hook_drush_command().
+ */
 function watchdog_drush_command() {
+  $items['watchdog-list'] = array(
+    'description' => 'Show watchdog severity levels and message types.',
+    'drupal dependencies' => drush_drupal_major_version() >= 6 ? array('dblog') : array('watchdog'),
+    'aliases' => array('wd-list'),
+  );
   $items['watchdog-show'] = array(
-    'description' => 'Shows recent watchdog log messages. Optionally filter for a specific type.',
+    'description' => 'Show watchdog messages.',
     'drupal dependencies' => drush_drupal_major_version() >= 6 ? array('dblog') : array('watchdog'),
     'arguments' => array(
-      'type' => 'The type of messages to show. Defaults to all.',
+      'wid' => 'Optional id of a watchdog message to show in detail. If not provided, a listing of most recent 10 messages will be displayed. Alternatively if a string is provided, watchdog messages will be filtered by it.',
     ),
     'options' => array(
-      '--limit' => 'The number of messages to show. Defaults to 10.',
-      '--severity' => 'Restrict to a given severity level. Error=0, Warning=4.',
+      '--count' => 'The number of messages to show. Defaults to 10.',
+      '--severity' => 'Restrict to messages of a given severity level.',
+      '--type' => 'Restrict to messages of a given type.',
     ),
     'examples' => array(
-      'watchdog-show cron' => 'Show recent cron watchdog messages.',
-      'watchdog-show --severity=0' => 'Show recent error messages.',
-      'watchdog-show --limit=50' => 'Show 50 recent watchdog messages.',
+      'watchdog-show' => 'Show a listing of most recent 10 messages.',
+      'watchdog-show 64' => 'Show in detail message with id 64.',
+      'watchdog-show "cron run succesful"' => 'Show a listing of most recent 10 messages containing the string "cron run succesful".',
+      'watchdog-show --count=46' => 'Show a listing of most recent 46 messages.',
+      'watchdog-show --severity=notice' => 'Show a listing of most recent 10 messages with a severity of notice.',
+      'watchdog-show --type=php' => 'Show a listing of most recent 10 messages of type php.',
     ),
-    'aliases' => array('ws'),
+    'aliases' => array('wd-show'),
+    'deprecated-aliases' => array('ws'),
   );
   $items['watchdog-delete'] = array(
-    'description' => 'Delete all messages or only those of a specified type.',
+    'description' => 'Delete watchdog messages.',
+    'drupal dependencies' => drush_drupal_major_version() >= 6 ? array('dblog') : array('watchdog'),
     'arguments' => array(
-      'type' => 'The type of messages to delete. Use \'all.\' to do a complete wipe.',
+      '--count' => 'The number of messages to *not* delete.',
+      '--severity' => 'Delete messages of a given severity level.',
+      '--type' => 'Delete messages of a given type.',
     ),
-    'drupal dependencies' => drush_drupal_major_version() >= 6 ? array('dblog') : array('watchdog'),
     'examples' => array(
-      'watchdog-delete all' => 'Delete all watchdog messages.',
-      'watchdog-delete cron' => 'Delete all cron watchdog messages.',
+      'watchdog-delete all' => 'Delete all messages.',
+      'watchdog-delete 64' => 'Delete message with id 64.',
+      'watchdog-delete "cron run succesful"' => 'Show 10 messages containing the string "cron run succesful".',
+      'watchdog-delete --count=46' => 'Delete all messages but 46 recent ones.',
+      'watchdog-delete --severity=notice' => 'Delete all messages with a severity of notice.',
+      'watchdog-delete --type=cron' => 'Delete all messages of type cron.',
     ),
-    'aliases' => array('wd'),
+    'aliases' => array('wd-del', 'wd-delete'),
+    'deprecated-aliases' => array('wd'),
   );
   return $items;
 }
 
 /**
- * Displays the most recent watchdog log messages (default: 10 messages).
+ * Command callback.
+ */
+function drush_core_watchdog_list() {
+  drush_print("Severity levels:");
+  foreach (core_watchdog_severity_levels() as $key => $value) {
+     drush_print("$key: $value", 2);
+  }
+  drush_print("Message types:");
+  foreach (core_watchdog_message_types() as $type) {
+     drush_print($type, 2);
+  }
+}
+
+/**
+ * Helper function to obtain the message types based on drupal version.
+ *
+ * @return
+ *   Array of watchdog message types.
+ */
+function core_watchdog_message_types() {
+  if (drush_drupal_major_version() == 5) {
+    return _watchdog_get_message_types();
+  }
+  else {
+    return _dblog_get_message_types();
+  }
+}
+
+/**
+ * Helper function to obtain the severity levels based on drupal version.
+ *
+ * @return
+ *   Array of watchdog severity levels.
  */
-function drush_core_watchdog_show($type = NULL) {
-  $limit = drush_get_option('limit') ? drush_get_option('limit') : 10;
+function core_watchdog_severity_levels() {
+  if (drush_drupal_major_version() == 5) {
+    return array(WATCHDOG_NOTICE => dt('notice'), WATCHDOG_WARNING => dt('warning'), WATCHDOG_ERROR => dt('error'));
+  }
+  else {
+    return watchdog_severity_levels();
+  }
+}
+
+/**
+ * Command callback.
+ */
+function drush_core_watchdog_show($arg = NULL) {
+  if (is_numeric($arg)) {
+    drush_core_watchdog_show_one($arg);
+  }
+  else {
+    drush_core_watchdog_show_many($arg);
+  }
+}
+
+/**
+ * Print a watchdog message.
+ *
+ * @param $wid
+ *    The id of the message to show.
+ */
+function drush_core_watchdog_show_one($wid) {
+  $rs = drush_db_select('watchdog', '*', 'wid = :wid', array(':wid' => $wid), 0, 1);
+  $result = drush_db_fetch_object($rs);
+  $result = core_watchdog_format_result($result);
+  drush_print_table(drush_key_value_to_array_table($result));
+  print "\n";
+}
+
+/**
+ * Print a table of watchdog messages.
+ *
+ * @param    $filter
+ *    String to filter the message's text by.
+ */
+function drush_core_watchdog_show_many($filter = NULL) {
+  $count = drush_get_option('count', 10);
+  $type = drush_get_option('type');
   $severity = drush_get_option('severity');
 
-  switch (drush_drupal_major_version()) {
-    case 5:
-    case 6:
-      if ($type) {
-        $where[] = "w.type = '%s'";
-        $placeholders[] = $type;
-      }
-      if ($severity) {
-        $where[] = "w.severity = %d";
-        $placeholders[] = $severity;
-      }
-      $criteria = empty($where) ? '' : ' WHERE ' . implode(' AND ', $where);
-      $sql = 'SELECT w.*, u.name, u.uid FROM {watchdog} w INNER JOIN {users} u ON w.uid = u.uid  ';
-      $sort = ' ORDER BY w.wid DESC';
-      $result = db_query_range($sql . $criteria . $sort, $placeholders, 0, $limit);
-      while ($watchdog = db_fetch_object($result)) {
-        $rows[] = core_watchdog_format_row($watchdog);
-      }
-      break;
-    default:
-      $query = db_select('watchdog', 'w')
-                ->fields('w')
-                ->fields('u', array('name', 'uid'))
-                ->orderBy('w.wid', 'DESC')
-                ->range(0, $limit);
-      $query->join('users', 'u', 'w.uid = u.uid');
-      if ($type) {
-        $query->condition('w.type', $type);
-      }
-      if ($severity) {
-        $query->condition('w.severity', $severity);
-      }
-      $results = $query->execute();
-      $watchdogs = $results->fetchAllAssoc('wid');
-      foreach ($watchdogs as $watchdog) {
-        $rows[] = core_watchdog_format_row($watchdog);
-      }
+  $rs = core_watchdog_query('select', $count, $type, $severity, $filter);
+  if ($rs === FALSE) {
+    return drush_log(dt('Aborting.'));
+  }
+  $table[] = array(dt('Id'), dt('Date'), dt('Severity'), dt('Type'), dt('Message'), dt('User'));
+  while ($result = drush_db_fetch_object($rs)) {
+    $row = core_watchdog_format_result($result);
+    $table[] = array($row->wid, $row->timestamp, $row->severity, $row->type, $row->message, $row->uid);
   }
 
-  if (empty($rows)) {
-    return drush_log('No log messages available.', 'ok');
+  if (count($table) == 1) {
+    return drush_log(dt('No log messages available.'), 'ok');
   }
   else {
-    drush_log(dt('Last !count watchdog log messages:', array('!count' => $limit)));
+    drush_log(dt('Most recent !count watchdog log messages:', array('!count' => $count)));
+    drush_print_table($table, TRUE);
+    print "\n";
+  }
+}
+
 
-    array_unshift($rows, array(dt('Date'), dt('Severity'), dt('Type'), dt('Message'), dt('User')));
-    drush_print_table($rows, TRUE);
+/**
+ * Format a watchdog database row.
+ *
+ * @param $result
+ *   Array a database result object.
+ * @return
+ *   Array 
+ */
+function core_watchdog_format_result($result) {
+  // severity
+  $severities = core_watchdog_severity_levels();
+  $result->severity = $severities[$result->severity];
+  
+  // timestamp
+  $result->timestamp = format_date($result->timestamp, 'small');
+
+  // message
+  if (drush_drupal_major_version() > 5) {
+    $variables = unserialize($result->variables);
+    $result->message = strtr($result->message, $variables);
+    unset($result->variables); 
   }
+  $result->message = strip_tags(decode_entities($result->message));
+
+  // user
+  $result->uid = $result->uid ? strip_tags(theme('username', (array)$result)) : dt('Anonymous');
+  
+  return $result;
 }
 
-function core_watchdog_format_row($watchdog) {
-  $severities = watchdog_severity_levels();
-  return array(
-    format_date($watchdog->timestamp, 'custom', 'Y.n.j G.i.s'),
-    $severities[$watchdog->severity],
-    dt($watchdog->type),
-    truncate_utf8(drush_watchdog_format_message($watchdog), 188, FALSE, FALSE),
-    $watchdog->uid ? strip_tags(theme('username', (array)$watchdog)) : dt('Anon'),
-  );
+/**
+ * Build a select statement for the watchdog table and query the database.
+ *
+ * @return
+ *   False or database resource.
+ */
+function core_watchdog_query($op, $count, $type = NULL, $severity = NULL, $filter = NULL) {
+  $args = array();
+  $conditions = array();
+  if ($type) {
+    $types = core_watchdog_message_types();
+    if (array_search($type, $types) === FALSE) {
+      $msg = 'Unknown message type: !type. Valid types are: !types';
+      drush_log(dt($msg, array('!type' => $type, '!types' => implode(', ', $types))), 'error');
+      return FALSE;
+    }
+    $conditions[] = "type = :type";
+    $args[':type'] = $type;
+  }
+  if (!is_null($severity)) {
+    if (!is_numeric($severity)) {
+      $severities = core_watchdog_severity_levels();
+      if (($key = array_search($severity, $severities)) === FALSE) {
+        $msg = 'Unknown severity level: !severity. Valid severity levels are: !severities';
+        drush_log(dt($msg, array('!severity' => $severity, '!severities' => implode(', ', $severities))), 'error');
+        return FALSE;
+      }
+      $severity = $key;
+    }
+    $conditions[] = "severity = :severity";
+    $args[':severity'] = $severity;
+  }
+  if ($filter) {
+    $conditions[] = "message LIKE :filter";
+    $args[':filter'] = '%'.$filter.'%';
+  }
+
+  $where = implode(' AND ', $conditions);
+
+  if ($op == 'select') {
+    return drush_db_select('watchdog', '*', $where, $args, 0, $count, 'wid', 'DESC');
+  }
+  else { // ($op == 'delete')
+  // what does $count mean in this context? => delete all but most recent $count... ORDER wid ASC,LIMIT $total - $count
+  //  return drush_db_delete('watchdog', $where, $args, 0, $count, 'wid', 'ASC');
+  }
 }
 
 /**
- * Deletes all log messages of a certain type from the watchdog log
- * (default: all).
+ * Command callback.
+ * 
+ * @param $arg
+ *    The id of the message to delete or 'all'.
  */
-function drush_core_watchdog_delete($type = NULL) {
-  if ($type == "all") {
-    // D7: ought to be a dynamic query.
-    drush_op('db_query', 'DELETE FROM {watchdog}'); // Indiscriminately delete all
-    drush_log(dt('Deleted all rows.'), 'ok');
-  }
-  elseif (!empty($type)) {
-    drush_op('db_query', 'DELETE FROM {watchdog} WHERE type = \'%s\'', $type);
-    drush_log(dt('Deleted all rows.'), 'ok');
+function drush_core_watchdog_delete($arg) {
+  if ($arg == 'all') {
+    db_query('DELETE FROM {watchdog}');
+    drush_log(dt('All watchdog messages has been deleted.'), 'ok');
+  }
+  else if (is_numeric($arg)) {
+    drush_print(dt("Watchdog message #!wid will be deleted.", array('!wid' => $arg)));
+    if(!drush_confirm(dt('Do you really want to continue?'))) {
+      return drush_log(dt('Aborting.'));
+    }
+    db_query('DELETE FROM {watchdog} WHERE wid = %d', array($arg));
+    drush_log(dt('Watchdog message #!wid has been deleted.', array('!wid' => $arg)), 'ok');
+  }
+  else if (is_null($arg)) {
+    $count = drush_get_option('count', 10);
+    $type = drush_get_option('type');
+    $severity = drush_get_option('severity');
+    // TODO: build the log string
+    drush_print(dt("", array()));
+    if(!drush_confirm(dt('Do you really want to continue?'))) {
+      return drush_log(dt('Aborting.'));
+    }
+    core_watchdog_db_delete('delete', $count, $type, $severity, $filter);
+    // TODO: build the log string
+    drush_log(dt('Watchdog messages of type=|severity=| has been deleted.'));
   }
   else {
-    drush_set_error(dt('Please specify a message type, or "all" to delete all messages.'));
+    return drush_set_error(dt("Please specify a message type, or 'all' to delete all messages."));
   }
 }
+
Index: includes/drush.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/includes/drush.inc,v
retrieving revision 1.85
diff -u -r1.85 drush.inc
--- includes/drush.inc	7 Feb 2010 14:39:45 -0000	1.85
+++ includes/drush.inc	20 Feb 2010 11:50:06 -0000
@@ -243,6 +243,88 @@
 }
 
 /**
+ *
+ */
+function _drush_replace_query_placeholders($where, $args) {
+  foreach ($args as $key => $data) {
+    if (!is_numeric($data)) {
+      $args[$key] = '"'.$data.'"';
+    }
+    else if (is_array($data)) {
+      $new_keys = array();
+      foreach ($data as $i => $value) {
+        $new_keys[$key . '_' . $i] = $value;
+      }
+      $where = preg_replace('#' . $key . '\b#', implode(', ', array_keys($new_keys)), $query);
+      unset($args[$key]);
+      $args += $new_keys;
+    }
+  }
+
+  foreach ($args as $key => $data) {
+    $where = str_replace($key, $data, $where);
+  }
+
+  return $where;
+}
+
+/**
+ * A db_select() that works for any version of Drupal.
+ *
+ * @param $table
+ * @param $fields
+ * @param $where
+ * @param $args
+ * @param $start
+ * @param $length
+ * @param $order_by_field
+ * @param $order_by_direction
+ * 
+ */
+function drush_db_select($table, $fields = '*', $where = NULL, $args = NULL, $start = NULL, $length = NULL, $order_by_field = NULL, $order_by_direction = 'ASC') {
+
+  if (drush_drupal_major_version() >= 7) {
+    if ($fields == '*') {
+      $fields = array();
+    }
+    $query = db_select($table, $table)
+      ->fields($table, $fields);
+    if (!empty($where)) {
+      $query = $query->where($where, $args);
+    }
+    if (!is_null($order_by_field)) {
+      $query = $query->orderBy($order_by_field, $order_by_direction);
+    }
+    if (!is_null($length)) {
+      $query = $query->range($start, $length);
+    }
+    return $query->execute();
+  }
+  else {
+    if ($fields != '*') {
+      $fields = implode('","', $fields);
+    }
+    $query = "SELECT $fields FROM {$table}";
+    if (!empty($where)) {
+      $where = _drush_replace_query_placeholders($where, $args);
+      $query .= " WHERE ".$where;
+    }
+    if (!is_null($order_by_field)) {
+      $query .= " ORDER BY $order_by_field $order_by_direction";
+    }
+    if (!is_null($length)) {
+      $limit = " LIMIT $length";
+      if (!is_null($start)) {
+        $limit .= " OFFSET $start";
+      }
+      $query .= $limit;
+    }
+
+    return db_query($query, $args);
+  }
+}
+
+/**
  * A db_result() that works for any version of Drupal.
  *
  * @param
