Index: branches/pap/ippTools/src/difftool.c
===================================================================
--- branches/pap/ippTools/src/difftool.c	(revision 28179)
+++ branches/pap/ippTools/src/difftool.c	(revision 28484)
@@ -44,4 +44,6 @@
 static bool definewarpwarpMode(pxConfig *config);
 static bool definestackstackMode(pxConfig *config);
+static bool tosummaryMode(pxConfig *config);
+static bool addsummaryMode(pxConfig *config);
 static bool pendingcleanuprunMode(pxConfig *config);
 static bool pendingcleanupskyfileMode(pxConfig *config);
@@ -93,4 +95,6 @@
         MODECASE(DIFFTOOL_MODE_DEFINEWARPWARP,        definewarpwarpMode);
         MODECASE(DIFFTOOL_MODE_DEFINESTACKSTACK,      definestackstackMode);
+	MODECASE(DIFFTOOL_MODE_TOSUMMARY,             tosummaryMode);
+	MODECASE(DIFFTOOL_MODE_ADDSUMMARY,            addsummaryMode);
         MODECASE(DIFFTOOL_MODE_PENDINGCLEANUPRUN,     pendingcleanuprunMode);
         MODECASE(DIFFTOOL_MODE_PENDINGCLEANUPSKYFILE, pendingcleanupskyfileMode);
@@ -2250,4 +2254,135 @@
 }
 
+static bool tosummaryMode(pxConfig *config) {
+  PS_ASSERT_PTR_NON_NULL(config, NULL);
+  
+  psMetadata *where = psMetadataAlloc();
+  PXOPT_COPY_S64(config->args, where, "-warp_id",    "diffSkyfile.warp_id", "==");
+  PXOPT_COPY_STR(config->args, where, "-tess_id",    "diffSkyfile.tess_id", "==");
+  PXOPT_COPY_STR(config->args, where, "-state",      "diffRun.state", "==");
+  PXOPT_COPY_TIME(config->args, where, "-dateobs_begin", "rawExp.dateobs",  ">=");
+  PXOPT_COPY_TIME(config->args, where, "-dateobs_end",   "rawExp.dateobs",  "<=");
+  PXOPT_COPY_STR(config->args, where, "-filter",    "rawExp.filter", "LIKE");
+  PXOPT_COPY_S64(config->args, where, "-magicked", "diffSkyfile.magicked", "==");
+  pxAddLabelSearchArgs (config, where, "-label",   "diffRun.label", "LIKE");
+  pxAddLabelSearchArgs (config, where, "-data_group",   "diffRun.data_group", "LIKE");
+
+  PXOPT_LOOKUP_BOOL(all, config->args, "-all", false);
+
+  PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+  PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+  
+  // find all rawImfiles matching the default query
+  psString query = pxDataGet("difftool_tosummary.sql");
+  if (!query) {
+    psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
+    return false;
+  }
+
+  // generate where strings for arguments that require extra processing
+  // beyond PXOPT_COPY*
+  psString where2 = NULL;
+  if (!pxmagicAddWhere(config, &where2, "diffSkyfile")) {
+    psError(psErrorCodeLast(), false, "pxMagicAddWhere failed");
+    return false;
+  }
+  
+  if (psListLength(where->list)) {
+    psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+    psStringAppend(&query, " AND %s", whereClause);
+    psFree(whereClause);
+  } else if (!all && !where2) {
+    psError(PXTOOLS_ERR_CONFIG, true, "search parameters or -all are required");
+    return false;
+  }
+  
+  if (where2) {
+    if (psListLength(where->list)) {
+      psStringAppend(&query, " %s", where2);
+    } else {
+      psStringAppend(&query, " AND 1 %s", where2);
+    }
+  }
+  psFree(where);
+
+  // treat limit == 0 as "no limit"
+  if (limit) {
+    psString limitString = psDBGenerateLimitSQL(limit);
+    psStringAppend(&query, " %s", limitString);
+    psFree(limitString);
+  }
+  
+  if (!p_psDBRunQuery(config->dbh, query)) {
+    psError(PS_ERR_UNKNOWN, false, "database error");
+    psFree(query);
+    return false;
+  }
+  psFree(query);
+
+  psArray *output = p_psDBFetchResult(config->dbh);
+  if (!output) {
+    psErrorCode err = psErrorCodeLast();
+    switch (err) {
+    case PS_ERR_DB_CLIENT:
+      psError(PXTOOLS_ERR_SYS, false, "database error");
+    case PS_ERR_DB_SERVER:
+      psError(PXTOOLS_ERR_PROG, false, "database error");
+    default:
+      psError(PXTOOLS_ERR_PROG, false, "unknown error");
+    }
+    
+    return false;
+  }
+  if (!psArrayLength(output)) {
+    psTrace("difftool", PS_LOG_INFO, "no rows found");
+    psFree(output);
+    return true;
+  }
+  
+  if (psArrayLength(output)) {
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "diffRun", !simple)) {
+      psError(PS_ERR_UNKNOWN, false, "failed to print array");
+      psFree(output);
+      return false;
+    }
+  }
+  
+  psFree(output);
+  return(true);
+}
+static bool addsummaryMode(pxConfig *config) {
+  PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+  PXOPT_LOOKUP_S64(diff_id, config->args, "-diff_id", true, false);
+  PXOPT_LOOKUP_STR(projection_cell, config->args, "-projection_cell", true, false);
+  PXOPT_LOOKUP_STR(path_base, config->args, "-path_base", true, false);
+
+  psString query = pxDataGet("difftool_addsummary.sql");
+  if (!query) {
+    psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
+    return(false);
+  }
+  if (!p_psDBRunQueryF(config->dbh, query, diff_id, projection_cell, path_base)) {
+    psError(PS_ERR_UNKNOWN, false, "database error");
+    psFree(query);
+    return(false);
+  }
+  psS64 numUpdated = psDBAffectedRows(config->dbh);
+  
+  if (numUpdated != 1) {
+    psError(PS_ERR_UNKNOWN, false, "should have affected 1 row");
+    psFree(query);
+    return false;
+  }
+  
+  psFree(query);
+
+  // Print anything here?
+  
+  return(true);
+}
+
+
 static bool pendingcleanuprunMode(pxConfig *config)
 {
