Index: branches/tap_branches/ippTools/src/difftool.c
===================================================================
--- branches/tap_branches/ippTools/src/difftool.c	(revision 25900)
+++ branches/tap_branches/ippTools/src/difftool.c	(revision 27838)
@@ -43,4 +43,5 @@
 static bool definewarpstackMode(pxConfig *config);
 static bool definewarpwarpMode(pxConfig *config);
+static bool definestackstackMode(pxConfig *config);
 static bool pendingcleanuprunMode(pxConfig *config);
 static bool pendingcleanupskyfileMode(pxConfig *config);
@@ -55,4 +56,7 @@
 static bool topurgedskyfileMode(pxConfig *config);
 static bool toscrubbedskyfileMode(pxConfig *config);
+static bool tofullskyfileMode(pxConfig *config);
+static bool listrunMode(pxConfig *config);
+static bool setskyfiletoupdateMode(pxConfig *config);
 
 
@@ -88,4 +92,5 @@
         MODECASE(DIFFTOOL_MODE_DEFINEWARPSTACK,       definewarpstackMode);
         MODECASE(DIFFTOOL_MODE_DEFINEWARPWARP,        definewarpwarpMode);
+        MODECASE(DIFFTOOL_MODE_DEFINESTACKSTACK,      definestackstackMode);
         MODECASE(DIFFTOOL_MODE_PENDINGCLEANUPRUN,     pendingcleanuprunMode);
         MODECASE(DIFFTOOL_MODE_PENDINGCLEANUPSKYFILE, pendingcleanupskyfileMode);
@@ -94,7 +99,10 @@
         MODECASE(DIFFTOOL_MODE_EXPORTRUN,             exportrunMode);
         MODECASE(DIFFTOOL_MODE_IMPORTRUN,             importrunMode);
-        MODECASE(DIFFTOOL_MODE_TOCLEANEDSKYFILE,   tocleanedskyfileMode);
-	MODECASE(DIFFTOOL_MODE_TOPURGEDSKYFILE,    topurgedskyfileMode);
-	MODECASE(DIFFTOOL_MODE_TOSCRUBBEDSKYFILE,  toscrubbedskyfileMode);
+        MODECASE(DIFFTOOL_MODE_TOCLEANEDSKYFILE,      tocleanedskyfileMode);
+        MODECASE(DIFFTOOL_MODE_TOPURGEDSKYFILE,       topurgedskyfileMode);
+        MODECASE(DIFFTOOL_MODE_TOSCRUBBEDSKYFILE,     toscrubbedskyfileMode);
+        MODECASE(DIFFTOOL_MODE_TOFULLSKYFILE,         tofullskyfileMode);
+        MODECASE(DIFFTOOL_MODE_LISTRUN,               listrunMode);
+        MODECASE(DIFFTOOL_MODE_SETSKYFILETOUPDATE,    setskyfiletoupdateMode);
 
         default:
@@ -132,5 +140,6 @@
     PXOPT_LOOKUP_STR(data_group, config->args, "-set_data_group", false, false);
     PXOPT_LOOKUP_STR(dist_group, config->args, "-set_dist_group", false, false);
-    PXOPT_LOOKUP_STR(reduction, config->args, "-rset_eduction", false, false);
+    PXOPT_LOOKUP_STR(reduction, config->args, "-set_reduction", false, false);
+    PXOPT_LOOKUP_S16(diff_mode, config->args, "-set_diff_mode", false, false);
     PXOPT_LOOKUP_STR(note, config->args, "-set_note", false, false);
 
@@ -153,4 +162,5 @@
             exposure,
             false,
+            diff_mode,
             note
     );
@@ -186,10 +196,11 @@
     psMetadata *where = psMetadataAlloc();
 
-    PXOPT_COPY_S64(config->args, where, "-diff_id",  "stack_id",   "==");
+    PXOPT_COPY_S64(config->args, where, "-diff_id",  "diff_id",   "==");
     PXOPT_COPY_STR(config->args, where, "-label",     "label",     "==");
+    PXOPT_COPY_STR(config->args, where, "-data_group","data_group",     "==");
     PXOPT_COPY_STR(config->args, where, "-state",     "state",     "==");
     if (!psListLength(where->list)) {
         psFree(where);
-        psError(PXTOOLS_ERR_DATA, false, "search parameters are required");
+        psError(PXTOOLS_ERR_CONFIG, false, "search parameters are required");
         return false;
     }
@@ -198,5 +209,5 @@
 
     // pxUpdateRun gets parameters from config->args and updates
-    bool result = pxUpdateRun(config, where, &query, "diffRun", true);
+    bool result = pxUpdateRun(config, where, &query, "diffRun", "diff_id", "diffSkyfile", true);
 
     psFree(query);
@@ -204,25 +215,4 @@
 
     return result;
-
-#ifdef notdef
-    // required options
-    PXOPT_LOOKUP_S64(diff_id, config->args, "-diff_id", false, false);
-    PXOPT_LOOKUP_STR(state, config->args, "-state", true, false);
-    PXOPT_LOOKUP_STR(label, config->args, "-label", false, false);
-    
-    // Copy of my hacky work around from stacktool.c
-    if ((state)&&(diff_id)) {
-        // set detRun.state to state
-        return setdiffRunState(config, diff_id, state, false);
-    }
-
-    if ((state)&&(label)) {
-      return setdiffRunStateByLabel(config, label, state);
-    }
-
-    psError(PS_ERR_UNKNOWN, false, "Required options not found.");
-
-    return false;
-#endif
 }
 
@@ -379,27 +369,23 @@
     psString query = pxDataGet("difftool_inputskyfile.sql");
     if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    psString whereClause = NULL;
+        psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    psString whereClause = psStringCopy("");
     if (psListLength(where->list)) {
         whereClause = psDBGenerateWhereConditionSQL(where, NULL);
-        psStringPrepend(&whereClause, "\n AND ");
+        psStringPrepend(&whereClause, "\n WHERE ");
     }
     psFree(where);
 
     // Add condition to get only templates or only inputs
+    psString templateClause = psStringCopy("");
     {
-        psString templateClause = NULL;
         if (template) {
-            psStringAppend(&templateClause, " %s", " template != 0");
+            psStringAppend(&templateClause, "\n WHERE %s", " template != 0");
         } else if (input) {
-            psStringAppend(&templateClause, " %s", " template = 0");
-        }
-        if (templateClause) {
-            psStringAppend(&whereClause, "\n AND %s", templateClause);
-        }
-        psFree(templateClause);
+            psStringAppend(&templateClause, "\n WHERE %s", " template = 0");
+        }
     }
 
@@ -412,10 +398,12 @@
     }
 
-    if (!p_psDBRunQueryF(config->dbh, query, whereClause, whereClause, whereClause, whereClause)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
+    if (!p_psDBRunQueryF(config->dbh, query, whereClause, whereClause, whereClause, whereClause, templateClause)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(templateClause);
         psFree(whereClause);
         psFree(query);
         return false;
     }
+    psFree(templateClause);
     psFree(whereClause);
     psFree(query);
@@ -469,5 +457,5 @@
     psString query = pxDataGet("difftool_todiffskyfile.sql");
     if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
         return false;
     }
@@ -626,5 +614,5 @@
     psString query = pxDataGet("difftool_completed_runs.sql");
     if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
         return false;
     }
@@ -717,5 +705,7 @@
     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(pstamp_order, config->args, "-pstamp_order", false);
     PXOPT_LOOKUP_BOOL(template, config->args, "-template", false);
     if (!template) {
@@ -725,5 +715,5 @@
         PXOPT_COPY_TIME(config->args, where, "-dateobs_begin", "rawInput.dateobs",  ">=");
         PXOPT_COPY_TIME(config->args, where, "-dateobs_end",   "rawInput.dateobs",  "<=");
-        PXOPT_COPY_STR(config->args, where, "-filter",     "rawInput.filter", "==");
+        PXOPT_COPY_STR(config->args, where, "-filter",     "rawInput.filter", "LIKE");
     } else {
         PXOPT_COPY_S64(config->args, where, "-exp_id", "rawTemplate.exp_id", "==");
@@ -732,5 +722,5 @@
         PXOPT_COPY_TIME(config->args, where, "-dateobs_begin", "rawTemplate.dateobs",  ">=");
         PXOPT_COPY_TIME(config->args, where, "-dateobs_end",   "rawTemplate.dateobs",  "<=");
-        PXOPT_COPY_STR(config->args, where, "-filter",     "rawTemplate.filter", "==");
+        PXOPT_COPY_STR(config->args, where, "-filter",     "rawTemplate.filter", "LIKE");
     }
 
@@ -745,5 +735,5 @@
     psString query = pxDataGet("difftool_skyfile.sql");
     if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
         return false;
     }
@@ -756,9 +746,17 @@
         psStringAppend(&query, " WHERE diffRun.diff_id is not null %s", where2);
     } else if (!all) {
-        psError(PXTOOLS_ERR_DATA, true, "search parameters or -all are required");
+        psError(PXTOOLS_ERR_CONFIG, true, "search parameters or -all are required");
         return false;
     }
     psFree(where);
 
+    if (pstamp_order) {
+        if (template) {
+            psStringAppend(&query, " ORDER BY rawTemplate.exp_id, diff_id DESC");
+        } else {
+            psStringAppend(&query, " ORDER BY rawInput.exp_id, diff_id DESC");
+        }
+    }
+            
     // treat limit == 0 as "no limit"
     if (limit) {
@@ -816,27 +814,23 @@
     psMetadata *where = psMetadataAlloc();
     PXOPT_COPY_S64(config->args, where,  "-diff_id", "diffSkyfile.diff_id", "==");
-    PXOPT_COPY_STR(config->args, where,  "-label", "diffRun.label", "==");
+    PXOPT_COPY_STR(config->args, where,  "-skycell_id", "diffSkyfile.skycell_id", "==");
+    pxAddLabelSearchArgs(config, where, "-label", "diffRun.label", "==");
     PXOPT_COPY_S16(config->args, where, "-fault",     "fault", "==");
 
     if (!psListLength(where->list) && !psMetadataLookupBool(NULL, config->args, "-all")) {
         psFree(where);
-        psError(PXTOOLS_ERR_DATA, false, "search parameters are required");
-        return false;
-    }
-
-    if (!psDBTransaction(config->dbh)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(where);
-        return false;
-    }
-
-    // Update state to 'new'
+        psError(PXTOOLS_ERR_CONFIG, false, "search parameters are required");
+        return false;
+    }
+
     {
-        psString query = pxDataGet("difftool_revertdiffskyfile_update.sql");
+        psString query = pxDataGet("difftool_revertdiffskyfile_delete.sql");
         if (!query) {
-            psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-            if (!psDBRollback(config->dbh)) {
-                psError(PS_ERR_UNKNOWN, false, "database error");
-            }
+            psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
+            return false;
+        }
+        psString query_updated = pxDataGet("difftool_revertdiffskyfile_updated.sql");
+        if (!query_updated) {
+            psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
             return false;
         }
@@ -845,4 +839,5 @@
             psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
             psStringAppend(&query, " AND %s", whereClause);
+            psStringAppend(&query_updated, " AND %s", whereClause);
             psFree(whereClause);
         }
@@ -851,50 +846,21 @@
             psError(PS_ERR_UNKNOWN, false, "database error");
             psFree(query);
-            if (!psDBRollback(config->dbh)) {
-                psError(PS_ERR_UNKNOWN, false, "database error");
-            }
             return false;
         }
         psFree(query);
+        psLogMsg("difftool", PS_LOG_INFO, "Deleted %" PRIu64 " rows", psDBAffectedRows(config->dbh));
+
+        if (!p_psDBRunQuery(config->dbh, query_updated)) {
+            psError(PS_ERR_UNKNOWN, false, "database error");
+            psFree(query_updated);
+            return false;
+        }
+        psFree(query_updated);
 
         psLogMsg("difftool", PS_LOG_INFO, "Updated %" PRIu64 " rows", psDBAffectedRows(config->dbh));
     }
 
-    // Delete product
-    {
-        psString query = pxDataGet("difftool_revertdiffskyfile_delete.sql");
-        if (!query) {
-            psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-            if (!psDBRollback(config->dbh)) {
-                psError(PS_ERR_UNKNOWN, false, "database error");
-            }
-            return false;
-        }
-
-        if (psListLength(where->list)) {
-            psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
-            psStringAppend(&query, " AND %s", whereClause);
-            psFree(whereClause);
-        }
-
-        if (!p_psDBRunQuery(config->dbh, query)) {
-            psError(PS_ERR_UNKNOWN, false, "database error");
-            psFree(query);
-            if (!psDBRollback(config->dbh)) {
-                psError(PS_ERR_UNKNOWN, false, "database error");
-            }
-            return false;
-        }
-        psFree(query);
-
-        psLogMsg("difftool", PS_LOG_INFO, "Deleted %" PRIu64 " rows", psDBAffectedRows(config->dbh));
-    }
-
     psFree(where);
 
-    if (!psDBCommit(config->dbh)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
 
     return true;
@@ -914,5 +880,5 @@
     if (magicked) {
       char *query = "UPDATE diffRun SET state = '%s', magicked = %" PRId64 " WHERE diff_id = %"PRId64;
-      
+
       if (!p_psDBRunQueryF(config->dbh, query, state, magicked, diff_id)) {
         psError(PS_ERR_UNKNOWN, false,
@@ -923,5 +889,5 @@
     else {
       char *query = "UPDATE diffRun SET state = '%s' WHERE diff_id = %"PRId64;
-      
+
       if (!p_psDBRunQueryF(config->dbh, query, state, diff_id)) {
         psError(PS_ERR_UNKNOWN, false,
@@ -930,5 +896,5 @@
       }
     }
-    
+
     return true;
 }
@@ -948,5 +914,5 @@
   if (!p_psDBRunQueryF(config->dbh,query,state,label)) {
     psError(PS_ERR_UNKNOWN, false,
-	    "failed to change state for label %s", label);
+            "failed to change state for label %s", label);
     return(false);
   }
@@ -986,4 +952,18 @@
         return false;
     }
+    psS16 diff_mode = IPP_DIFF_MODE_UNDEFINED;
+    if ((input_warp_id != PS_MAX_S64) && (template_warp_id != PS_MAX_S64)) {
+      diff_mode = IPP_DIFF_MODE_WARP_WARP;
+    }
+    else if ((input_warp_id != PS_MAX_S64) && (template_stack_id != PS_MAX_S64)) {
+      diff_mode = IPP_DIFF_MODE_WARP_STACK;
+    }
+    else if ((input_stack_id != PS_MAX_S64) && (template_warp_id != PS_MAX_S64)) {
+      diff_mode = IPP_DIFF_MODE_STACK_WARP;
+    }
+    else if ((input_stack_id != PS_MAX_S64) && (template_stack_id != PS_MAX_S64)) {
+      diff_mode = IPP_DIFF_MODE_STACK_STACK;
+    }
+
 
     // default
@@ -1005,4 +985,5 @@
             false,
             0,       // magicked
+            diff_mode, // diff_mode
             note
     );
@@ -1110,5 +1091,5 @@
 
     psArray *list = psArrayAllocEmpty(16); // List of runs, to print
-
+    // Populated Run will generate the diff_mode value
     if (!populatedrun(list, workdir, skycell_id, tess_id, label, data_group ? data_group : label, dist_group, reduction, note,
                       input_warp_id ? input_warp_id : PS_MAX_S64,
@@ -1138,14 +1119,21 @@
 
     psMetadata *expWhere = psMetadataAlloc();
-    psMetadata *warpWhere = psMetadataAlloc();
+    psMetadata *warp1Where = psMetadataAlloc(); // First set of restrictions on warp
+    psMetadata *warp2Where = psMetadataAlloc(); // Second set of restriction on warp
     psMetadata *stackWhere = psMetadataAlloc();
 
     PXOPT_COPY_S64(config->args, expWhere, "-exp_id", "exp_id", "==");
     PXOPT_COPY_STR(config->args, expWhere, "-filter", "filter", "==");
-    PXOPT_COPY_S64(config->args, warpWhere, "-warp_id", "warpRun.warp_id", "==");
-    PXOPT_COPY_STR(config->args, warpWhere, "-skycell_id", "warpSkyfile.skycell_id", "==");
-    PXOPT_COPY_STR(config->args, warpWhere, "-tess_id", "warpRun.tess_id", "==");
-    PXOPT_COPY_STR(config->args, warpWhere, "-warp_label", "warpRun.label", "==");
-    PXOPT_COPY_F32(config->args, warpWhere,  "-good_frac", "warpSkyfile.good_frac", ">=");
+    PXOPT_COPY_STR(config->args, expWhere, "-comment", "comment", "LIKE");
+    PXOPT_COPY_S64(config->args, warp1Where, "-warp_id", "warpRun.warp_id", "==");
+    PXOPT_COPY_STR(config->args, warp1Where, "-warp_label", "warpRun.label", "==");
+    PXOPT_COPY_STR(config->args, warp1Where, "-tess_id", "warpRun.tess_id", "==");
+    PXOPT_COPY_STR(config->args, warp1Where, "-data_group", "warpRun.data_group", "==");
+    PXOPT_COPY_S64(config->args, warp2Where, "-warp_id", "warpRun.warp_id", "==");
+    PXOPT_COPY_STR(config->args, warp2Where, "-tess_id", "warpRun.tess_id", "==");
+    PXOPT_COPY_STR(config->args, warp2Where, "-data_group", "warpRun.data_group", "==");
+    PXOPT_COPY_STR(config->args, warp2Where, "-skycell_id", "warpSkyfile.skycell_id", "==");
+    PXOPT_COPY_STR(config->args, warp2Where, "-warp_label", "warpRun.label", "==");
+    PXOPT_COPY_F32(config->args, warp2Where,  "-good_frac", "warpSkyfile.good_frac", ">=");
     PXOPT_COPY_STR(config->args, stackWhere, "-stack_label", "stackRun.label", "==");
 
@@ -1167,9 +1155,10 @@
     psString query = pxDataGet("difftool_definewarpstack_part1.sql");
     if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    psString warpQuery = NULL;
+        psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    psString warp1Query = NULL;
+    psString warp2Query = NULL;
     psString stackQuery = NULL;
     psString expQuery = NULL;
@@ -1183,17 +1172,20 @@
     }
     psFree(expWhere);
-    if (psListLength(warpWhere->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(warpWhere, NULL);
-        psStringAppend(&warpQuery, "\n AND %s", whereClause);
+    if (psListLength(warp1Where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(warp1Where, NULL);
+        psStringAppend(&warp1Query, "\n AND %s", whereClause);
         psFree(whereClause);
     } else {
-        warpQuery = psStringCopy("\n");
-    }
-    psFree(warpWhere);
-
-    if (!available) {
-        // diff what's available, even if warp run has some faults and is incomplete
-        psStringAppend(&warpQuery, " AND warpRun.state = 'full'");
-    }
+        warp1Query = psStringCopy("\n");
+    }
+    psFree(warp1Where);
+    if (psListLength(warp2Where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(warp2Where, NULL);
+        psStringAppend(&warp2Query, "\n AND %s", whereClause);
+        psFree(whereClause);
+    } else {
+        warp2Query = psStringCopy("\n");
+    }
+    psFree(warp2Where);
 
     // don't queue for exposures that have already been diff'd unless requested
@@ -1214,5 +1206,5 @@
     psFree(stackWhere);
 
-    psTrace("difftool", 1, query, warpQuery, diffQuery, expQuery, stackQuery);
+    psTrace("difftool", 1, query, warp1Query, warp2Query, diffQuery, expQuery, stackQuery);
 
     if (!psDBTransaction(config->dbh)) {
@@ -1221,5 +1213,5 @@
     }
 
-    if (!p_psDBRunQueryF(config->dbh, query, warpQuery, expQuery, diffQuery)) {
+    if (!p_psDBRunQueryF(config->dbh, query, warp1Query, warp2Query, expQuery, diffQuery)) {
         psError(PS_ERR_UNKNOWN, false, "database error");
         psFree(query);
@@ -1281,4 +1273,5 @@
         return false;
     }
+    psFree(warp1Query);
     psFree(query);
     query = NULL;
@@ -1312,5 +1305,5 @@
         if (!p_psDBRunQuery(config->dbh, "DELETE FROM skycellsToDiff")) {
             psError(PS_ERR_UNKNOWN, false, "database error");
-            psFree(warpQuery);
+            psFree(warp2Query);
             psFree(stackQuery);
             psFree(skycell_query);
@@ -1323,5 +1316,5 @@
         if (!mdok) {
             psError(PXTOOLS_ERR_PROG, false, "warp_id not found --- ignoring row %ld", i);
-            psFree(warpQuery);
+            psFree(warp2Query);
             psFree(stackQuery);
             psFree(skycell_query);
@@ -1334,5 +1327,5 @@
         if (!mdok) {
             psError(PXTOOLS_ERR_PROG, false, "skycell_count not found");
-            psFree(warpQuery);
+            psFree(warp2Query);
             psFree(stackQuery);
             psFree(skycell_query);
@@ -1345,5 +1338,5 @@
         if (!mdok) {
             psError(PXTOOLS_ERR_PROG, false, "tess_id not found");
-            psFree(warpQuery);
+            psFree(warp2Query);
             psFree(stackQuery);
             psFree(skycell_query);
@@ -1353,8 +1346,9 @@
             return false;
         }
+
         psString filter = psMetadataLookupStr(&mdok, row, "filter");
         if (!mdok) {
             psError(PXTOOLS_ERR_PROG, false, "filter not found");
-            psFree(warpQuery);
+            psFree(warp2Query);
             psFree(stackQuery);
             psFree(skycell_query);
@@ -1364,7 +1358,23 @@
             return false;
         }
-        if (!p_psDBRunQueryF(config->dbh, skycell_query, stackQuery, warp_id, filter, warpQuery)) {
-            psError(PS_ERR_UNKNOWN, false, "database error");
-            psFree(warpQuery);
+
+	psString warp_data_group = psMetadataLookupStr(&mdok, row, "data_group");
+	if (!mdok) {
+	  psError(PXTOOLS_ERR_PROG, false, "warp data_group not found");
+	  psFree(warp2Query);
+	  psFree(stackQuery);
+	  psFree(skycell_query);
+	  if (!psDBRollback(config->dbh)) {
+	    psError(PS_ERR_UNKNOWN, false, "database error");
+	  }
+	  return false;
+	}
+	if (warp_data_group) {
+	  data_group = warp_data_group;
+	}
+	
+        if (!p_psDBRunQueryF(config->dbh, skycell_query, stackQuery, warp_id, filter, warp2Query)) {
+            psError(PS_ERR_UNKNOWN, false, "database error");
+            psFree(warp2Query);
             psFree(stackQuery);
             psFree(skycell_query);
@@ -1377,5 +1387,5 @@
 
         if (num == 0) {
-            psTrace("difftool", PS_LOG_INFO, "no skycells with stack found for %" PRId64, warp_id);
+            psTrace("difftool", PS_LOG_INFO, "no skycells with stack found for warp_id %" PRId64, warp_id);
             continue;
         }
@@ -1383,5 +1393,5 @@
         if (!available && (num != skycell_count)) {
             psTrace("difftool", PS_LOG_INFO, "%" PRId64 " skyfiles with stack found for warp_id %" PRId64
-                    " need %" PRId64, num, warp_id, skycell_count);
+                    " but need %" PRId64, num, warp_id, skycell_count);
             continue;
         }
@@ -1402,4 +1412,5 @@
                 true,                   // exposure
                 0,       // magicked
+                IPP_DIFF_MODE_WARP_STACK,
                 note
         );
@@ -1418,5 +1429,5 @@
         if (!p_psDBRunQuery(config->dbh, query)) {
             psError(PS_ERR_UNKNOWN, false, "database error");
-            psFree(warpQuery);
+            psFree(warp2Query);
             psFree(stackQuery);
             psFree(skycell_query);
@@ -1432,5 +1443,5 @@
         if (!p_psDBRunQuery(config->dbh, query)) {
             psError(PS_ERR_UNKNOWN, false, "database error");
-            psFree(warpQuery);
+            psFree(warp2Query);
             psFree(stackQuery);
             psFree(skycell_query);
@@ -1447,5 +1458,5 @@
             psError(PS_ERR_UNKNOWN, false, "failed to change diffRun.state for diff_id: %" PRId64,
                 run->diff_id);
-            psFree(warpQuery);
+            psFree(warp2Query);
             psFree(stackQuery);
             psFree(skycell_query);
@@ -1461,5 +1472,5 @@
     }
     psFree(output);
-    psFree(warpQuery);
+    psFree(warp2Query);
     psFree(stackQuery);
     psFree(skycell_query);
@@ -1549,5 +1560,4 @@
     // Additional controls
     PXOPT_LOOKUP_BOOL(rerun, config->args, "-rerun", false);
-    PXOPT_LOOKUP_BOOL(available, config->args, "-available", false);
 
     // Settings to apply to defined run
@@ -1574,5 +1584,5 @@
         psString tempCreate = pxDataGet("difftool_definewarpwarp_temp_create.sql"); // Create temp table SQL
         if (!tempCreate) {
-            psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+            psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
             psFree(selectWhere);
             psFree(insertWhere);
@@ -1597,5 +1607,5 @@
         psString tempInsert = pxDataGet("difftool_definewarpwarp_temp_insert.sql"); // Insert to temp table
         if (!tempInsert) {
-            psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+            psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
             psFree(selectWhere);
             psFree(insertWhere);
@@ -1629,5 +1639,5 @@
     psString select = pxDataGet("difftool_definewarpwarp_select.sql");
     if (!select) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
         psFree(selectWhere);
         psFree(insertWhere);
@@ -1642,18 +1652,11 @@
     if (psListLength(selectWhere->list)) {
         psString new = psDBGenerateWhereConditionSQL(selectWhere, NULL);
-        psStringAppend(&whereClause, "\n%s %s", whereClause ? "AND" : "WHERE", new);
+        psStringAppend(&whereClause, "\nAND %s", new);
         psFree(new);
     }
     psFree(selectWhere);
 
-    if (!available) {
-        psStringAppend(&whereClause,
-                       "\n%s inputWarpRun.state = 'full'"
-                       "AND templateWarpRun.state = 'full'",
-                       whereClause ? "AND" : "WHERE");
-    }
-
     if (!rerun) {
-        psStringAppend(&whereClause, "\n%s diffs.diff_id IS NULL", whereClause ? "AND" : "WHERE");
+        psStringAppend(&whereClause, "\nAND diffs.diff_id IS NULL");
     }
 
@@ -1732,4 +1735,9 @@
         const char *template = psMetadataLookupStr(NULL, row, "template_warp_id");
         const char *tess_id = psMetadataLookupStr(NULL, row, "tess_id");
+	psString input_data_group = psMetadataLookupStr(NULL, row, "input_data_group");
+	if (input_data_group) {
+	  data_group = input_data_group;
+	}
+
         if (!input_id || !template || !tess_id) {
             psError(PXTOOLS_ERR_PROG, false, "Identifiers not found");
@@ -1742,7 +1750,20 @@
             return false;
         }
-
-        diffRunRow *run = diffRunRowAlloc(0, "reg", workdir, label, data_group ? data_group : label, dist_group, reduction, NULL, registered,
-                                          tess_id, true, true, false, note); // Run to insert
+	
+        diffRunRow *run = diffRunRowAlloc(0,
+                                          "reg",
+                                          workdir,
+                                          label,
+                                          data_group ? data_group : label,
+                                          dist_group,
+                                          reduction,
+                                          NULL,  // dvodb
+                                          registered,
+                                          tess_id,
+                                          true,  // bothways
+                                          true,  // exposure
+                                          false, // magicked
+                                          IPP_DIFF_MODE_WARP_WARP,
+                                          note); // Run to insert
         if (!diffRunInsertObject(config->dbh, run)) {
             psError(PS_ERR_UNKNOWN, false, "database error");
@@ -1816,4 +1837,303 @@
 }
 
+static bool definestackstackMode(pxConfig *config) {
+  PS_ASSERT_PTR_NON_NULL(config, false);
+
+  psMetadata *stack1Where = psMetadataAlloc();
+  psMetadata *stack2Where = psMetadataAlloc();
+
+  PXOPT_COPY_STR(config->args, stack1Where, "-tess_id", "stackRun.tess_id", "==");
+  PXOPT_COPY_STR(config->args, stack2Where, "-tess_id", "stackRun.tess_id", "==");
+  PXOPT_COPY_STR(config->args, stack1Where, "-filter", "stackRun.filter", "==");
+  PXOPT_COPY_STR(config->args, stack2Where, "-filter", "stackRun.filter", "==");
+  PXOPT_COPY_STR(config->args, stack1Where, "-skycell_id", "stackRun.skycell_id", "==");
+  PXOPT_COPY_STR(config->args, stack2Where, "-skycell_id", "stackRun.skycell_id", "==");
+  PXOPT_COPY_STR(config->args, stack1Where, "-input_label", "stackRun.label","==");
+  PXOPT_COPY_STR(config->args, stack2Where, "-template_label", "stackRun.label","==");
+  PXOPT_COPY_F32(config->args, stack1Where, "-good_frac", "stackSumSkyfile.good_frac", ">=");
+  PXOPT_COPY_F32(config->args, stack2Where, "-good_frac", "stackSumSkyfile.good_frac", ">=");
+
+  PXOPT_LOOKUP_STR(workdir, config->args, "-set_workdir", true, false); // required option
+  PXOPT_LOOKUP_STR(label, config->args, "-set_label", false, false); // option
+  PXOPT_LOOKUP_STR(reduction, config->args, "-set_reduction", false, false); // option
+  PXOPT_LOOKUP_TIME(registered, config->args, "-set_registered", false, false);
+  PXOPT_LOOKUP_STR(data_group, config->args, "-set_data_group", false, false);
+  PXOPT_LOOKUP_STR(dist_group, config->args, "-set_dist_group", false, false);
+  PXOPT_LOOKUP_STR(note, config->args, "-set_note", false, false);
+
+  PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+  PXOPT_LOOKUP_BOOL(reRun, config->args, "-rerun", false);
+  PXOPT_LOOKUP_BOOL(newTemplates,config->args,"-new-templates", false);
+
+  PXOPT_LOOKUP_BOOL(available, config->args, "-available", false);
+  PXOPT_LOOKUP_BOOL(pretend, config->args, "-pretend", false);
+
+  if (!(label)) {
+    PXOPT_LOOKUP_STR(label,config->args, "-input_label",true,false);
+  }
+
+  // Organize the config information into queries.
+  psString stack1Query = NULL;
+  psString stack2Query = NULL;
+
+  if (psListLength(stack1Where->list)) {
+    psString whereClause = psDBGenerateWhereConditionSQL(stack1Where, NULL);
+    psStringAppend(&stack1Query, "\n AND %s", whereClause);
+    psFree(whereClause);
+  } else {
+    stack1Query = psStringCopy("\n");
+  }
+  psFree(stack1Where);
+
+  if (psListLength(stack2Where->list)) {
+    psString whereClause = psDBGenerateWhereConditionSQL(stack2Where, NULL);
+    psStringAppend(&stack2Query, "\n AND %s", whereClause);
+    psFree(whereClause);
+  } else {
+    stack2Query = psStringCopy("\n");
+  }
+  psFree(stack2Where);
+
+  // don't queue for stacks that have already been diffed unless requested
+  psString diffQuery = NULL;
+  if (! (reRun || newTemplates) ) {
+    psStringAppend(&diffQuery, "\n AND diffExp.diff_id IS NULL");
+  } else {
+    diffQuery = psStringCopy("\n");
+  }
+
+  // find the distinct set of data_groups and filters
+  psString query = pxDataGet("difftool_definestackstack_part0.sql");
+  if (!query) {
+    psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
+    return(false);
+  }
+  psTrace("difftool",1,query,stack2Query,stack1Query,diffQuery,stack1Query);
+/*   exit(10); */
+
+  if (!psDBTransaction(config->dbh)) {
+    psError(PS_ERR_UNKNOWN, false, "database error");
+    return(false);
+  }
+
+  if (!p_psDBRunQueryF(config->dbh, query, stack2Query, stack1Query, diffQuery, stack1Query)) {
+    psError(PS_ERR_UNKNOWN, false, "database error");
+    psFree(query);
+    if (!psDBRollback(config->dbh)) {
+      psError(PS_ERR_UNKNOWN, false, "database error");
+    }
+    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");
+      break;
+    case PS_ERR_DB_SERVER:
+      psError(PXTOOLS_ERR_PROG, false, "database error");
+      break;
+    default:
+      psError(PXTOOLS_ERR_PROG, false, "unknown error");
+      break;
+    }
+    if (!psDBRollback(config->dbh)) {
+      psError(PS_ERR_UNKNOWN, false, "database error");
+    }
+    return false;
+  }
+  if (!psArrayLength(output)) {
+    psTrace("difftool", PS_LOG_INFO, "no rows found");
+    psFree(output);
+    if (!psDBCommit(config->dbh)) {
+      psError(PS_ERR_UNKNOWN, false, "database error");
+      return false;
+    }
+    return true;
+  }
+
+  query = pxDataGet("difftool_definestackstack_part1.sql");
+  if (pretend) {
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "diffRunTemp", !simple)) {
+      psError(PS_ERR_UNKNOWN, false, "failed to print array");
+      psFree(output);
+      return false;
+    }
+    psFree(output);
+    return true;
+  }
+
+  psArray *list = psArrayAllocEmpty(16); // List of runs defined, to print
+  for (long i = 0; i < output->n; i++) {
+    psMetadata *row = output->data[i]; // Output row from query
+    bool mdok;                      // Status of MD lookup
+
+    psString tess_id = psMetadataLookupStr(&mdok,row,"INPUT_tess_id");
+    psString this_data_group = psMetadataLookupStr(&mdok,row,"INPUT_data_group");
+    psString this_dist_group = psMetadataLookupStr(&mdok,row,"INPUT_dist_group");
+    psString this_label = psMetadataLookupStr(&mdok,row,"INPUT_label");
+
+    psString this_stack1Query = psStringCopy(stack1Query);
+
+    psString thisWhere = psDBGenerateWhereConditionSQL(row,NULL);
+    psStringSubstitute(&thisWhere,"stackRun.","INPUT_");
+    psStringAppend(&this_stack1Query,"\n AND %s", thisWhere);
+    psFree(thisWhere);
+
+    psTrace("difftool",1, query,stack2Query,this_stack1Query,diffQuery,this_stack1Query);
+    if (!psDBTransaction(config->dbh)) {
+      psError(PS_ERR_UNKNOWN, false, "database error");
+      return(false);
+    }
+
+    if (!p_psDBRunQueryF(config->dbh, query, stack2Query, this_stack1Query, diffQuery, this_stack1Query)) {
+      psError(PS_ERR_UNKNOWN, false, "database error");
+      psFree(query);
+      if (!psDBRollback(config->dbh)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+      }
+      return false;
+    }
+    psFree(this_stack1Query);
+
+    psArray *diff_id_output = p_psDBFetchResult(config->dbh);
+    if (!diff_id_output) {
+      psErrorCode err = psErrorCodeLast();
+      switch (err) {
+      case PS_ERR_DB_CLIENT:
+        psError(PXTOOLS_ERR_SYS, false, "database error");
+        break;
+      case PS_ERR_DB_SERVER:
+        psError(PXTOOLS_ERR_PROG, false, "database error");
+        break;
+      default:
+        psError(PXTOOLS_ERR_PROG, false, "unknown error");
+        break;
+      }
+      if (!psDBRollback(config->dbh)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+      }
+      return false;
+    }
+    if (!psArrayLength(diff_id_output)) {
+      psTrace("difftool", PS_LOG_INFO, "no rows found");
+      psFree(diff_id_output);
+      if (!psDBCommit(config->dbh)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+      }
+      return true;
+    }
+
+    // ok we've got one create the diffRun
+    diffRunRow *run = diffRunRowAlloc(
+                                      0,          // ID
+                                      "reg",      // state
+                                      workdir,
+                                      label ? label : this_label,
+                                      data_group ? data_group : this_data_group,
+                                      dist_group ? dist_group : this_dist_group,
+                                      reduction,
+                                      NULL,       // dvodb
+                                      registered,
+                                      tess_id,
+                                      false,                 // bothways
+                                      false,                 // exposure
+                                      0,       // magicked
+                                      IPP_DIFF_MODE_STACK_STACK, // diff_mode
+                                      note
+                                      );
+    // Commit to database
+    if (!diffRunInsertObject(config->dbh, run)) {
+      psError(PS_ERR_UNKNOWN, false, "database error");
+      psFree(run);
+      if (!psDBRollback(config->dbh)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+      }
+      return false;
+    }
+/*     diffRunPrintObject(stdout,run,1); */
+    run->diff_id = psDBLastInsertID(config->dbh);
+    for (long j = 0; j < diff_id_output->n; j++) {
+      psMetadata *input_row = diff_id_output->data[j]; // Output row from query
+      bool mdok;
+      psString in_skycell_id  = psMetadataLookupStr(&mdok,input_row,"skycell_id");
+      psS64 in_input_stack_id = psMetadataLookupS64(&mdok,input_row,"stack_id");
+      psS64 in_template_stack_id = psMetadataLookupS64(&mdok,input_row,"max_stack_id");
+      psString in_tess_id = psMetadataLookupStr(&mdok,input_row,"tess_id");
+      psTrace("difftool",1,"%s %" PRId64 " %" PRId64 " %s\n",
+              in_skycell_id, in_input_stack_id, in_template_stack_id, in_tess_id);
+      diffInputSkyfileRow *input = diffInputSkyfileRowAlloc(
+                                                            run->diff_id,   // ID
+                                                            in_skycell_id,
+                                                            PS_MAX_S64, // warp1_id -> NULL
+                                                            in_input_stack_id, // stack1
+                                                            PS_MAX_S64, // warp2_id -> NULL
+                                                            in_template_stack_id, // stack2
+                                                            in_tess_id,
+                                                            0 // diff_skyfile_id
+                                                            );
+      // Commit to database the input
+      if (!diffInputSkyfileInsertObject(config->dbh, input)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(input);
+        if (!psDBRollback(config->dbh)) {
+          psError(PS_ERR_UNKNOWN, false, "database error");
+        }
+        return false;
+      }
+
+/*       diffInputSkyfilePrintObject(stdout,input,1); */
+      psFree(input);
+    }
+
+    if (!setdiffRunState(config, run->diff_id, "new", false)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to change diffRun.state for diff_id: %" PRId64, run->diff_id);
+        psFree(stack1Query);
+        psFree(stack2Query);
+        psFree(diffQuery);
+        psFree(run);
+        psFree(list);
+        if (!psDBRollback(config->dbh)) {
+            psError(PS_ERR_UNKNOWN, false, "database error");
+        }
+        return false;
+    }
+    psArrayAdd(list, list->n, run);
+    psFree(run);
+  }
+
+  if (!psDBCommit(config->dbh)) {
+    psError(PS_ERR_UNKNOWN, false, "database error");
+    psFree(list);
+    return false;
+  }
+
+  if (!diffRunPrintObjects(stdout, list, !simple)) {
+    psError(PS_ERR_UNKNOWN, false, "failed to print object");
+    psFree(list);
+    return false;
+  }
+
+  psFree(query);
+  psFree(stack1Query);
+  psFree(stack2Query);
+  psFree(diffQuery);
+  psFree(output);
+  psFree(list);
+
+    if (!psDBCommit(config->dbh)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(list);
+        return false;
+    }
+
+  return(true);
+}
 
 static bool pendingcleanuprunMode(pxConfig *config)
@@ -1825,16 +2145,24 @@
 
     psMetadata *where = psMetadataAlloc();
-    pxAddLabelSearchArgs (config, where, "-label", "label", "==");
+    pxAddLabelSearchArgs (config, where, "-label", "diffRun.label", "==");
 
     psString query = pxDataGet("difftool_pendingcleanuprun.sql");
     if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
+        psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
+        return false;
+    }
+    // pxDataGet/psStringSubstitute workaround
+    psString queryCopy = psStringCopy(query);
+    psFree(query);
+    query = queryCopy;
 
     if (where && psListLength(where->list)) {
         psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
-        psStringAppend(&query, " AND %s", whereClause);
+        psStringAppend(&whereClause, " AND ");
+        psStringSubstitute(&query,whereClause,"@INNERCONSTRAINT@");
         psFree(whereClause);
+    }
+    else {
+      psStringSubstitute(&query,NULL,"@INNERCONSTRAINT@");
     }
     psFree(where);
@@ -1846,6 +2174,7 @@
         psFree(limitString);
     }
-
     //    fprintf(stderr,"%s",query);
+
+    //fprintf(stderr,"%s",query);
     if (!p_psDBRunQuery(config->dbh, query)) {
         psError(PS_ERR_UNKNOWN, false, "database error");
@@ -1895,5 +2224,5 @@
     psString query = pxDataGet("difftool_pendingcleanupskyfile.sql");
     if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
         return false;
     }
@@ -1955,5 +2284,5 @@
     psString query = pxDataGet("difftool_donecleanup.sql");
     if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
         return false;
     }
@@ -2010,4 +2339,5 @@
     psMetadata *where = psMetadataAlloc();
     PXOPT_COPY_S64(config->args, where, "-diff_id",   "diff_id",   "==");
+    PXOPT_COPY_STR(config->args, where, "-skycell_id", "skycell_id",   "==");
 
     if (!pxSetFaultCode(config->dbh, "diffSkyfile", where, fault)) {
@@ -2027,4 +2357,11 @@
   PXOPT_LOOKUP_S64(diff_id, config->args, "-diff_id", true, false);
   PXOPT_LOOKUP_STR(skycell_id, config->args, "-skycell_id", true, false);
+
+
+  psS64 magicked = 0;
+  if (!strcmp(data_state, "full")) {
+      PXOPT_LOOKUP_S64(set_magicked, config->args, "-magicked", 0, false);
+      magicked = set_magicked;
+  }
 
   psString query = pxDataGet("difftool_change_skyfile_data_state.sql");
@@ -2035,7 +2372,18 @@
   }
 
+  psString set_magicked_skyfile = psStringCopy("");
+  psString set_magicked_run = psStringCopy("");
+  if (magicked != 0 && !strcmp(data_state, "full")) {
+    psStringAppend(&set_magicked_skyfile,  "\n , diffSkyfile.magicked = %" PRId64, magicked);
+    psStringAppend(&set_magicked_run,      "\n , diffRun.magicked = %" PRId64, magicked);
+
+  } else if (!strcmp(data_state, "cleaned") || !strcmp(data_state, "purged")) {
+    psStringAppend(&set_magicked_skyfile, "\n, diffSkyfile.magicked = IF(diffSkyfile.magicked = 0, 0, -1)");
+    psStringAppend(&set_magicked_run, "\n, diffRun.magicked = IF(diffRun.magicked = 0, 0, -1)");
+  }
+
   // Uses the unconstrained (diffRun.state [NEED NOT EQUAL] run_state) version from warptool.c
 
-  if (!p_psDBRunQueryF(config->dbh, query, data_state, diff_id, skycell_id)) {
+  if (!p_psDBRunQueryF(config->dbh, query, data_state, set_magicked_skyfile, diff_id, skycell_id)) {
     psError(PS_ERR_UNKNOWN, false, "database error");
     // rollback
@@ -2044,10 +2392,12 @@
     }
     psError(PS_ERR_UNKNOWN, false, "database error");
+    psFree(set_magicked_skyfile);
     return(false);
   }
+  psFree(set_magicked_skyfile);
   psFree(query);
 
   query = pxDataGet("difftool_change_run_state.sql");
-  if (!p_psDBRunQueryF(config->dbh, query, data_state, diff_id, data_state)) {
+  if (!p_psDBRunQueryF(config->dbh, query, data_state, set_magicked_run, diff_id, data_state)) {
     // rollback
     if (!psDBRollback(config->dbh)) {
@@ -2055,4 +2405,5 @@
     }
     psError(PS_ERR_UNKNOWN, false, "database error");
+    psFree(set_magicked_run);
     return(false);
   }
@@ -2060,7 +2411,9 @@
   if (!psDBCommit(config->dbh)) {
     psError(PS_ERR_UNKNOWN, false, "database error");
+    psFree(set_magicked_run);
     return(false);
   }
-  
+  psFree(set_magicked_run);
+
   return(true);
 }
@@ -2074,4 +2427,7 @@
 static bool toscrubbedskyfileMode(pxConfig *config) {
   return change_skyfile_data_state(config, "scrubbed", "goto_scrubbed");
+}
+static bool tofullskyfileMode(pxConfig *config) {
+  return change_skyfile_data_state(config, "full", "update");
 }
 
@@ -2115,5 +2471,5 @@
     psString query = pxDataGet(tables[i].sqlFilename);
     if (!query) {
-      psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+      psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
       return false;
     }
@@ -2252,2 +2608,148 @@
   return true;
 }
+
+static bool listrunMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where,  "-diff_id", "diffRun.diff_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-tess_id", "diffRun.tess_id", "==");
+    PXOPT_COPY_S64(config->args, where,  "-magicked", "diffRun.magicked", "==");
+    pxAddLabelSearchArgs (config, where, "-label", "diffRun.label", "LIKE");
+    pxAddLabelSearchArgs (config, where, "-data_group", "diffRun.data_group", "LIKE");
+    pxAddLabelSearchArgs (config, where, "-dist_group", "diffRun.dist_group", "LIKE");
+
+    PXOPT_LOOKUP_BOOL(template, config->args, "-template", false);
+    if (!template) {
+        PXOPT_COPY_S64(config->args, where, "-exp_id", "rawInput.exp_id", "==");
+        PXOPT_COPY_STR(config->args, where, "-exp_name", "rawInput.exp_name", "==");
+        PXOPT_COPY_STR(config->args, where, "-warp_id", "warpInput.warp_id", "==");
+        PXOPT_COPY_TIME(config->args, where, "-dateobs_begin", "rawInput.dateobs",  ">=");
+        PXOPT_COPY_TIME(config->args, where, "-dateobs_end",   "rawInput.dateobs",  "<=");
+        PXOPT_COPY_STR(config->args, where, "-filter",     "rawInput.filter", "LIKE");
+    } else {
+        PXOPT_COPY_S64(config->args, where, "-exp_id", "rawTemplate.exp_id", "==");
+        PXOPT_COPY_STR(config->args, where, "-exp_name", "rawTemplate.exp_name", "==");
+        PXOPT_COPY_STR(config->args, where, "-warp_id", "warpTemplate.warp_id", "==");
+        PXOPT_COPY_TIME(config->args, where, "-dateobs_begin", "rawTemplate.dateobs",  ">=");
+        PXOPT_COPY_TIME(config->args, where, "-dateobs_end",   "rawTemplate.dateobs",  "<=");
+        PXOPT_COPY_STR(config->args, where, "-filter",     "rawTemplate.filter", "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);
+    PXOPT_LOOKUP_BOOL(pstamp_order, config->args, "-pstamp_order", false);
+
+
+    psString where2 = NULL;
+    pxmagicAddWhere(config, &where2, "diffRun");
+    pxspaceAddWhere(config, &where2, template ? "rawTemplate" : "rawInput");
+    psString query = pxDataGet("difftool_listrun.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " WHERE %s", whereClause);
+        psFree(whereClause);
+    } else if (where2) {
+        psStringAppend(&query, " WHERE diffRun.diff_id is not null %s", where2);
+    } else if (!all) {
+        psError(PXTOOLS_ERR_CONFIG, true, "search parameters or -all are required");
+        return false;
+    }
+    psFree(where);
+
+    if (pstamp_order) {
+        if (template) {
+            psStringAppend(&query, " ORDER BY rawTemplate.exp_id, diff_id DESC");
+        } else {
+            psStringAppend(&query, " ORDER BY rawInput.exp_id, diff_id DESC");
+        }
+    }
+            
+    // 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;
+}
+// a very specfic function to queue a cleaned warpSkyfile to be updated
+static bool setskyfiletoupdateMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_S64(diff_id, config->args, "-diff_id", true, false);
+    PXOPT_LOOKUP_STR(skycell_id, config->args, "-skycell_id", false, false);
+    PXOPT_LOOKUP_STR(label, config->args, "-set_label", false, false);
+
+    psString query = pxDataGet("difftool_setskyfiletoupdate.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    psString setHook = psStringCopy("");
+    if (label) {
+        psStringAppend(&setHook, "\n , diffRun.label = '%s'", label);
+    }
+
+    if (skycell_id) {
+        psStringAppend(&query, " AND (diffSkyfile.skycell_id = '%s')", skycell_id);
+    }
+
+    if (!p_psDBRunQueryF(config->dbh, query, setHook, diff_id)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+
+    psFree(setHook);
+    psFree(query);
+
+    return true;
+}
