I have developed a new module, inspired by the devel module but with some convenient features for logging all "action" queries -- that is, all insert/update/delete queries.

This becomes very useful when you are performing a configuration task on your "staging" or "development" site and then want to propagate those changes to the live site...

Please give it a try. I am currently trying to get a cvs account so I can upload this to drupal.org properly.

Code follows...

qrecorder.module

<?php
// $Id: qrecorder.module,v 0.1 2006/11/25 00:00:00 chud Exp $

/**
* Implementation of hook_help().
*/
function qrecorder_help($section) {
  switch (
$section) {
    case
'admin/modules#description':
      return
t('Records all insert/update/delete queries... makes it easy to tranfer changes from one version of a site to another.');
    case
'admin/settings/qrecorder':
      return
'<p>'. t('Settings for the Query Recorder.'). '</p>';
  }
}

/**
* Implementation of hook_menu().
*/
function qrecorder_menu($may_cache) {
 
$items = array();

  if (
$may_cache) {
   
$items[] = array('path' => 'qrecorder/start',
     
'title' => t('start recording'),
     
'callback' => 'qrecorder_start',
     
'access' => user_access('use query recorder'),
     
'type' => MENU_CALLBACK,
    );
   
$items[] = array('path' => 'qrecorder/stop',
     
'title' => t('stop recording'),
     
'callback' => 'qrecorder_stop',
     
'access' => user_access('use query recorder'),
     
'type' => MENU_CALLBACK,
    );
   
$items[] = array('path' => 'qrecorder/empty',
     
'title' => t('empty query log'),
     
'callback' => 'qrecorder_empty',
     
'access' => user_access('use query recorder'),
     
'type' => MENU_CALLBACK,
    );
   
$items[] = array('path' => 'qrecorder/qview',
     
'title' => t('view query log'),
     
'callback' => 'qrecorder_qview',
     
'access' => user_access('use query recorder'),
     
'type' => MENU_CALLBACK,
    );
  }

  return
$items;
}

function
qrecorder_start() {
  global
$base_url;
 
variable_set("dev_query", 1);
 
variable_set("qrecorder_state", 1);
 
drupal_set_message('query recorder started').
 
$referer = referer_uri();
 
header('Location: '. ($referer ? $referer : $base_url));
  exit();
}

function
qrecorder_stop() {
  global
$base_url;
 
variable_set("qrecorder_state", 0);
 
drupal_set_message('query recorder stopped').
 
$referer = referer_uri();
 
header('Location: '. ($referer ? $referer : $base_url));
  exit();
}

function
qrecorder_empty() {
  global
$base_url;
 
db_query('DELETE FROM {qrecorder_queries}');
 
drupal_set_message('query log emptied').
 
$referer = referer_uri();
 
header('Location: '. ($referer ? $referer : $base_url));
  exit();
}

function
qrecorder_qview() {
 
$result = db_query("SELECT query FROM {qrecorder_queries} ORDER BY qid;");
  while (
$row = db_fetch_object($result)) {
     
$output .= $row->query . "\n";
  }
 
$form['qlog'] = array(
       
'#type' => 'textarea',
   
'#title' => t('queries'),
   
'#attributes' => array('wrap' => 'off'),
   
'#default_value' => $output,
   
'#rows' => 15,
  );
 
$output = drupal_get_form('qlog', $form);
  return
$output;
}

/**
* Implementation of hook_perm().
*/
function qrecorder_perm() {
  return array(
'use query recorder');
}

/**
* Implementation of hook_block().
*/
function qrecorder_block($op = 'list', $delta = 0) {
  if (
$op == 'list') {
   
$blocks[0]['info'] = t('Query Recorder');
   
   
// Auto-enable the qrecorder blocks for fresh installations.
   
$blocks[0]['status'] = 1;

    return
$blocks;
  }
  else if (
$op == 'view') {
    switch (
$delta) {
      case
0:
          if (
user_access('use query recorder')) {
             
$block['subject'] = t('query recorder');
             
$block['content'] = theme_qrecorder_block();
          }
    }

    return
$block;
  }
}


function
theme_qrecorder_block() {
   
$output = '<p>';
   
$output .= l('start recording', 'qrecorder/start');
   
$output .= " | ";
   
$output .= l('stop recording', 'qrecorder/stop');
   
$output .= '</p>';
   
$output .= '<p>';
   
$output .= l('empty query log', 'qrecorder/empty');
   
$output .= " | ";
   
$output .= l('view query log', 'qrecorder/qview');
   
$output .= '</p>';
   
$output .= '<p>';
   
$output .= '<b>' . t('current status: ') . '</b>';
   
$output .= variable_get('qrecorder_state',0) ? t('active') : t('inactive');
   
$output .= '</p>';
    return
$output;
}


function
qrecorder_log_queries($queries) {
   
$pos = array();
//    print_a($queries, "new");
//    die();
   
foreach ($queries as $query) {
   
$ar = explode("\n", $query[0]);
   
$function=array_shift($ar);
   
$pos[0] = strpos(strtolower($ar[0]), "insert into");
       
$pos[1] = strpos(strtolower($ar[0]), "update");
       
$pos[2] = strpos(strtolower($ar[0]), "delete");
        if (
in_array(0, $pos, TRUE)) { // we found an action query
           
db_query("INSERT INTO {qrecorder_queries} (query, function, created) VALUES ('%s', '%s', %d)", $ar[0], $function, time());
        }
  }

}

function
qrecorder_exit($destination = NULL) {
  global
$queries;   
    if (
$queries) {
       
// print_a($queries,"new2");
     
if (variable_get('qrecorder_state', 0)) {
           
qrecorder_log_queries($queries);
      }
    }
}
?>

qrecorder.install

<?php
<?php
// $Id: qrecorder.install,v 0.1 2006/11/25 00:00:00 chud Exp $
/**
* Implementation of hook_install()
*/
function qrecorder_install() {
 
// New module weights in core: put qrecorder as the very last in the chain.
 
db_query("UPDATE {system} SET weight = 10 WHERE name = 'qrecorder'");

  switch (
$GLOBALS['db_type']) {
    case
'mysqli':
    case
'mysql':
     
$sql = "CREATE TABLE {qrecorder_queries} (
        qid int(10) NOT NULL auto_increment,
        function varchar(255) NOT NULL default '',
        query text NOT NULL,
        created int(11) NOT NULL,
        PRIMARY KEY (`qid`)
        ) /*!40100 DEFAULT CHARACTER SET utf8 */;"
;
     
db_query($sql);
      break;
  }

 
// Enable the blocks automatically at install.
 
_block_rehash();
}
?>

Comments

ooooo, you should update

ooooo, you should update this for 5.x (or maybe 6.0 instead). this sounds quite useful, but doesn't work... and i can't find anything else like this elsewhere