Index: trunk/ippTools/src/difftool.c
===================================================================
--- trunk/ippTools/src/difftool.c	(revision 28373)
+++ trunk/ippTools/src/difftool.c	(revision 28375)
@@ -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)
 {
Index: trunk/ippTools/src/difftool.h
===================================================================
--- trunk/ippTools/src/difftool.h	(revision 28373)
+++ trunk/ippTools/src/difftool.h	(revision 28375)
@@ -32,4 +32,6 @@
     DIFFTOOL_MODE_ADDDIFFSKYFILE,
     DIFFTOOL_MODE_ADVANCE,
+    DIFFTOOL_MODE_TOSUMMARY,
+    DIFFTOOL_MODE_ADDSUMMARY,
     DIFFTOOL_MODE_DIFFSKYFILE,
     DIFFTOOL_MODE_REVERTDIFFSKYFILE,
Index: trunk/ippTools/src/difftoolConfig.c
===================================================================
--- trunk/ippTools/src/difftoolConfig.c	(revision 28373)
+++ trunk/ippTools/src/difftoolConfig.c	(revision 28375)
@@ -323,4 +323,33 @@
     psMetadataAddU64(pendingcleanuprunArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
 
+    // -tosummary
+    psMetadata *tosummaryArgs = psMetadataAlloc();
+    psMetadataAddS64(tosummaryArgs, PS_LIST_TAIL,  "-diff_id", 0,           "search by diff ID", 0);
+    psMetadataAddStr(tosummaryArgs, PS_LIST_TAIL,  "-tess_id",  0,          "search by tessellation ID", NULL);
+    psMetadataAddStr(tosummaryArgs, PS_LIST_TAIL, "-state",  0,            "search by state", NULL);
+    psMetadataAddS64(tosummaryArgs, PS_LIST_TAIL,  "-exp_id",  0,           "search by exposure ID", 0);
+    psMetadataAddStr(tosummaryArgs , PS_LIST_TAIL, "-exp_name",  0,        "search by exposure name", NULL);
+    psMetadataAddS64(tosummaryArgs, PS_LIST_TAIL, "-warp_id", 0,         "search by warp ID", 0);
+    
+    psMetadataAddTime(tosummaryArgs, PS_LIST_TAIL, "-dateobs_begin", 0,    "search for exposures by time (>=)", NULL);
+    psMetadataAddTime(tosummaryArgs, PS_LIST_TAIL, "-dateobs_end", 0,      "search for exposures by time (<=)", NULL);
+    psMetadataAddStr(tosummaryArgs, PS_LIST_TAIL,  "-filter", 0,           "search for filter", NULL);
+    psMetadataAddS64(tosummaryArgs, PS_LIST_TAIL,  "-magicked", 0,         "search by magic id", 0);
+    psMetadataAddStr(tosummaryArgs,  PS_LIST_TAIL, "-label",  PS_META_DUPLICATE_OK, "search by diffRun label (LIKE comparison)", NULL);
+    psMetadataAddStr(tosummaryArgs,  PS_LIST_TAIL, "-data_group",  PS_META_DUPLICATE_OK, "search by diffRun data_group (LIKE comparison)", NULL);
+    psMetadataAddStr(tosummaryArgs,  PS_LIST_TAIL, "-dist_group",  PS_META_DUPLICATE_OK, "search by diffRun dist_group (LIKE comparison)", NULL);
+    psMetadataAddBool(tosummaryArgs, PS_LIST_TAIL,  "-destreaked", 0, "search for runs that have been destreaked", false);
+    psMetadataAddBool(tosummaryArgs, PS_LIST_TAIL,  "-not_destreaked", 0, "search for runs that have not been destreaked", false);
+    
+    psMetadataAddBool(tosummaryArgs, PS_LIST_TAIL, "-all",  0,             "search without arguments", false);
+    psMetadataAddU64(tosummaryArgs, PS_LIST_TAIL,  "-limit",  0,            "limit result set to N items", 0);
+    psMetadataAddBool(tosummaryArgs, PS_LIST_TAIL, "-simple",  0,          "use the simple output format", false);
+    
+    // -addsummary
+    psMetadata *addsummaryArgs = psMetadataAlloc();
+    psMetadataAddS64(addsummaryArgs, PS_LIST_TAIL,  "-diff_id", 0,           "search by diff ID", 0);
+    psMetadataAddStr(addsummaryArgs, PS_LIST_TAIL, "-projection_cell", 0, "set projection cell", NULL);
+    psMetadataAddStr(addsummaryArgs, PS_LIST_TAIL, "-path_base", 0, "set summary path base", NULL);
+
     // -pendingcleanupskyfile
     psMetadata *pendingcleanupskyfileArgs = psMetadataAlloc();
@@ -380,5 +409,4 @@
     psMetadata *importrunArgs = psMetadataAlloc();
     psMetadataAddStr(importrunArgs, PS_LIST_TAIL, "-infile",  0,          "import from this file (required)", NULL);
-
 
 
@@ -415,4 +443,6 @@
     PXOPT_ADD_MODE("-toscrubbedskyfile", "set skyfile as scrubbed", DIFFTOOL_MODE_TOSCRUBBEDSKYFILE, toscrubbedskyfileArgs);
     PXOPT_ADD_MODE("-tofullskyfile", "set skyfile as full", DIFFTOOL_MODE_TOFULLSKYFILE, tofullskyfileArgs);
+    PXOPT_ADD_MODE("-tosummary",            "show runs that can be summarized", DIFFTOOL_MODE_TOSUMMARY, tosummaryArgs);
+    PXOPT_ADD_MODE("-addsummary",           "add entry to the summary table", DIFFTOOL_MODE_ADDSUMMARY, addsummaryArgs);
 
     if (!pxGetOptions(stderr, argc, argv, config, modes, argSets)) {
Index: trunk/ippTools/src/stacktool.c
===================================================================
--- trunk/ippTools/src/stacktool.c	(revision 28373)
+++ trunk/ippTools/src/stacktool.c	(revision 28375)
@@ -39,5 +39,8 @@
 static bool addsumskyfileMode(pxConfig *config);
 static bool sumskyfileMode(pxConfig *config);
+static bool sassskyfileMode(pxConfig *config);
 static bool revertsumskyfileMode(pxConfig *config);
+static bool tosummaryMode(pxConfig *config);
+static bool addsummaryMode(pxConfig *config);
 static bool pendingcleanuprunMode(pxConfig *config);
 static bool pendingcleanupskyfileMode(pxConfig *config);
@@ -75,5 +78,8 @@
         MODECASE(STACKTOOL_MODE_ADDSUMSKYFILE,         addsumskyfileMode);
         MODECASE(STACKTOOL_MODE_SUMSKYFILE,            sumskyfileMode);
+	MODECASE(STACKTOOL_MODE_SASSSKYFILE,            sassskyfileMode);
         MODECASE(STACKTOOL_MODE_REVERTSUMSKYFILE,      revertsumskyfileMode);
+	MODECASE(STACKTOOL_MODE_TOSUMMARY,             tosummaryMode);
+	MODECASE(STACKTOOL_MODE_ADDSUMMARY,            addsummaryMode);
         MODECASE(STACKTOOL_MODE_PENDINGCLEANUPRUN,     pendingcleanuprunMode);
         MODECASE(STACKTOOL_MODE_PENDINGCLEANUPSKYFILE, pendingcleanupskyfileMode);
@@ -102,4 +108,84 @@
     exit(exit_status);
 }
+//stackAssociationRow *association = pxStackAssociationDefine(data_group,tess_id,filter,skycell_id);
+stackAssociationRow *pxStackAssociationDefine(pxConfig *config, psS64 stack_id) {
+  psString select = pxDataGet("stacktool_associationdefine_select.sql");
+  if (!select) {
+    psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
+    return false;
+  }
+
+  psString idString = NULL;
+  psStringAppend(&idString, "%" PRId64, stack_id);
+  // Copy string to get around the issue with psStringSubstitute not believing
+  // that select is a psString.
+  psString rep = psStringCopy(select);
+  psFree(select);
+  select = rep;
+  psStringSubstitute(&select, idString, "@STACK_ID@");
+  psFree(idString);
+
+  if (!p_psDBRunQuery(config->dbh, select)) {
+    psError(PS_ERR_UNKNOWN,false, "database error");
+    psFree(select);
+    return(NULL);
+  }
+  psFree(select);
+  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(NULL);
+  }
+  if (psArrayLength(output) != 1) {
+    psWarning("stacktool: incorrect number of rows found");
+    psFree(output);
+    return(NULL);
+  }
+  psMetadata *outrow = psMetadataAlloc();
+  for (long i = 0; i < output->n; i++) {
+    psMetadata *row = output->data[i];
+
+    printf("%" PRId64 " %s %s %s %s\n",psMetadataLookupS64(NULL,row,"sass_id"),
+	   psMetadataLookupStr(NULL,row,"data_group"),
+	   psMetadataLookupStr(NULL,row,"tess_id"),
+	   psMetadataLookupStr(NULL,row,"filter"),
+	   psMetadataLookupStr(NULL,row,"projection_cell"));
+
+    if (psMetadataLookupS64(NULL,row,"sass_id") == PS_MAX_S64) {
+      psMetadataAddS64(outrow,PS_LIST_TAIL,"sass_id",PS_META_REPLACE,"",0);
+    }
+    else {
+      psMetadataAddS64(outrow,PS_LIST_TAIL,"sass_id",PS_META_REPLACE,"",psMetadataLookupS64(NULL,row,"sass_id"));
+    }
+    psMetadataAddStr(outrow,PS_LIST_TAIL,"data_group",PS_META_REPLACE,"",psMetadataLookupStr(NULL,row,"data_group"));
+    psMetadataAddStr(outrow,PS_LIST_TAIL,"tess_id",PS_META_REPLACE,"",psMetadataLookupStr(NULL,row,"tess_id"));
+    psMetadataAddStr(outrow,PS_LIST_TAIL,"filter",PS_META_REPLACE,"",psMetadataLookupStr(NULL,row,"filter"));
+    psMetadataAddStr(outrow,PS_LIST_TAIL,"projection_cell",PS_META_REPLACE,"",
+		     psMetadataLookupStr(NULL,row,"projection_cell"));
+  }
+  printf("%" PRId64 " %s %s %s %s\n",psMetadataLookupS64(NULL,outrow,"sass_id"),
+	 psMetadataLookupStr(NULL,outrow,"data_group"),
+	 psMetadataLookupStr(NULL,outrow,"tess_id"),
+	 psMetadataLookupStr(NULL,outrow,"filter"),
+	 psMetadataLookupStr(NULL,outrow,"projection_cell"));
+  
+
+  psFree(output);
+  stackAssociationRow *sassRow = stackAssociationObjectFromMetadata(outrow);
+  psFree(outrow);
+  return(sassRow);
+}
+      
+      
+  
+					      
 
 
@@ -395,4 +481,48 @@
         psFree(run);
 
+	//CZW Add an association entry here.
+	// Define the requested association, and insert it if it doesn't already exist
+	stackAssociationRow *association = pxStackAssociationDefine(config,stack_id);
+	psS64 sass_id;
+	if (!association->sass_id) {
+	  psTrace("stacktool.association",2,"No required Association found. Adding.");
+
+	  if (!stackAssociationInsertObject(config->dbh,association)) {
+	    if (!psDBRollback(config->dbh)) {
+	      psError(PS_ERR_UNKNOWN, false, "database error");
+	    }
+	    psError(PS_ERR_UNKNOWN, false, "database error");
+	    psFree(output);
+	    psFree(run);
+	    psFree(insert);
+	    psFree(list);
+	    psFree(association);
+	    if (!psDBRollback(config->dbh)) {
+	      psError(PS_ERR_UNKNOWN, false, "database error");
+	    }
+	    return(false);
+	  }
+	  sass_id = psDBLastInsertID(config->dbh);
+	  association->sass_id = sass_id;
+	}
+	// Insert the map entry for this row.
+	stackAssociationMapRow *maprow = stackAssociationMapRowAlloc(sass_id,stack_id);
+	if (!stackAssociationMapInsertObject(config->dbh,maprow)) {
+	  if (!psDBRollback(config->dbh)) {
+	    psError(PS_ERR_UNKNOWN, false, "database error");
+	  }
+	  psError(PS_ERR_UNKNOWN, false, "database error");
+	  psFree(output);
+	  psFree(run);
+	  psFree(insert);
+	  psFree(list);
+	  psFree(association);
+	  if (!psDBRollback(config->dbh)) {
+	    psError(PS_ERR_UNKNOWN, false, "database error");
+	  }
+	  return(false);
+	}
+	
+	
         // Create a suitable insertion query for this run
         psString thisInsert = psStringCopy(insert);
@@ -552,4 +682,6 @@
     run->stack_id = psDBLastInsertID(config->dbh);
 
+    //CZW Add an association entry here.
+    
     // insert the stackInputSkyfile rows
     psListIterator *iter = psListIteratorAlloc(warp_ids->data.list, 0, false);
@@ -603,7 +735,8 @@
 #endif
     psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_S64(config->args, where, "-stack_id",  "stack_id",   "==");
-    PXOPT_COPY_STR(config->args, where, "-label",     "label",     "==");
-    PXOPT_COPY_STR(config->args, where, "-state",     "state",     "==");
+    PXOPT_COPY_S64(config->args, where, "-stack_id",  "stackRun.stack_id",   "==");
+    PXOPT_COPY_STR(config->args, where, "-label",     "stackRun.label",     "==");
+    PXOPT_COPY_STR(config->args, where, "-state",     "stackRun.state",     "==");
+    PXOPT_COPY_STR(config->args, where, "-sass_id",   "stackAssociationMap.sass_id",  "==");
     if (!psListLength(where->list)) {
         psFree(where);
@@ -612,4 +745,5 @@
     }
 
+    //CZW join against stackAssociationMap
     psString query = psStringCopy("UPDATE stackRun");
 
@@ -1038,23 +1172,27 @@
 }
 
-
-static bool revertsumskyfileMode(pxConfig *config)
+static bool sassskyfileMode(pxConfig *config)
 {
     PS_ASSERT_PTR_NON_NULL(config, false);
 
     psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_S64(config->args, where, "-stack_id", "stackSumSkyfile.stack_id", "==");
-    pxAddLabelSearchArgs(config, where, "-label", "stackRun.label", "==");
-    PXOPT_COPY_S16(config->args, where, "-fault", "stackSumSkyfile.fault", "==");
-
-    if (!psListLength(where->list) && !psMetadataLookupBool(NULL, config->args, "-all")) {
-        psFree(where);
-        psError(PXTOOLS_ERR_CONFIG, false, "search parameters are required");
-        return false;
-    }
-
-    // Delete product
-    psString delete = pxDataGet("stacktool_revertsumskyfile_delete.sql");
-    if (!delete) {
+    PXOPT_COPY_S64(config->args, where, "-sass_id", "stackAssociation.sass_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-tess_id", "stackAssociation.tess_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-projection_cell", "stackAssociation.projection_cell", "==");
+    PXOPT_COPY_STR(config->args, where, "-filter", "stackAssociation.filter", "LIKE");
+    PXOPT_COPY_STR(config->args, where, "-data_group", "stackAssociation.data_group", "LIKE");
+
+//  The following three selectors are incompatible with the sql so omit them
+//    PXOPT_COPY_S64(config->args, where, "-warp_id", "warpRun.warp_id", "==");
+//     PXOPT_COPY_S64(config->args, where, "-exp_id", "rawExp.exp_id", "==");
+//    PXOPT_COPY_STR(config->args, where, "-exp_name", "rawExp.exp_name", "==");
+
+    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);
+
+    psString query = pxDataGet("stacktool_sassskyfile.sql");
+    if (!query) {
         psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
         return false;
@@ -1063,88 +1201,11 @@
     if (psListLength(where->list)) {
         psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
-        psStringAppend(&delete, " AND %s", whereClause);
+        psStringAppend(&query, " WHERE %s", whereClause);
         psFree(whereClause);
-    }
-
-    if (!p_psDBRunQuery(config->dbh, delete)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(delete);
-        psFree(where);
-        return false;
-    }
-    psFree(delete);
-
-    int numRows = psDBAffectedRows(config->dbh); // Number of row affected
-    psLogMsg("stacktool", PS_LOG_INFO, "Deleted %d rows", numRows);
-
-    psFree(where);
-
-    return true;
-}
-
-
-static bool setstackRunState(pxConfig *config, psS64 stack_id, const char *state)
-{
-    PS_ASSERT_PTR_NON_NULL(state, false);
-
-    // check that state is a valid string value
-    if (!pxIsValidState(state)) {
-        psError(PS_ERR_UNKNOWN, false, "invalid stackRun state: %s", state);
-        return false;
-    }
-
-    char *query = "UPDATE stackRun SET state = '%s' WHERE stack_id = %"PRId64;
-    if (!p_psDBRunQueryF(config->dbh, query, state, stack_id)) {
-        psError(PS_ERR_UNKNOWN, false,
-                "failed to change state for stack_id %"PRId64, stack_id);
-        return false;
-    }
-
-    return true;
-}
-
-#ifdef notdef
-static bool setstackRunStateByLabel(pxConfig *config, const char *label, const char *state)
-{
-    PS_ASSERT_PTR_NON_NULL(state, false);
-
-    // check that state is a valid string value
-    if (!pxIsValidState(state)) {
-        psError(PS_ERR_UNKNOWN, false, "invalid stackRun state: %s", state);
-        return false;
-    }
-
-    char *query = "UPDATE stackRun SET state = '%s' WHERE label = '%s'";
-    if (!p_psDBRunQueryF(config->dbh, query, state, label)) {
-        psError(PS_ERR_UNKNOWN, false,
-                "failed to change state for label %s", label);
-        return false;
-    }
-
-    return true;
-}
-#endif
-
-static bool pendingcleanuprunMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, NULL);
-
-    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
-    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-
-    psMetadata *where = psMetadataAlloc();
-    pxAddLabelSearchArgs (config, where, "-label", "stackRun.label", "==");
-
-    psString query = pxDataGet("stacktool_pendingcleanuprun.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    if (where && psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
-        psStringAppend(&query, " AND %s", whereClause);
-        psFree(whereClause);
-    }
+    } else if (!all) {
+        psError(PXTOOLS_ERR_CONFIG, true, "search parameters or -all are required");
+        return false;
+    }
+
     psFree(where);
 
@@ -1165,5 +1226,14 @@
     psArray *output = p_psDBFetchResult(config->dbh);
     if (!output) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
+        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;
     }
@@ -1174,31 +1244,233 @@
     }
 
+    if (psArrayLength(output)) {
+        if (!ippdbPrintMetadatas(stdout, output, "stackSumSkyfile", !simple)) {
+            psError(PS_ERR_UNKNOWN, false, "failed to print array");
+            psFree(output);
+            return false;
+        }
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+
+static bool revertsumskyfileMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-stack_id", "stackSumSkyfile.stack_id", "==");
+    pxAddLabelSearchArgs(config, where, "-label", "stackRun.label", "==");
+    PXOPT_COPY_S16(config->args, where, "-fault", "stackSumSkyfile.fault", "==");
+
+    if (!psListLength(where->list) && !psMetadataLookupBool(NULL, config->args, "-all")) {
+        psFree(where);
+        psError(PXTOOLS_ERR_CONFIG, false, "search parameters are required");
+        return false;
+    }
+
+    // Delete product
+    psString delete = pxDataGet("stacktool_revertsumskyfile_delete.sql");
+    if (!delete) {
+        psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&delete, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, delete)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(delete);
+        psFree(where);
+        return false;
+    }
+    psFree(delete);
+
+    int numRows = psDBAffectedRows(config->dbh); // Number of row affected
+    psLogMsg("stacktool", PS_LOG_INFO, "Deleted %d rows", numRows);
+
+    psFree(where);
+
+    return true;
+}
+
+
+static bool setstackRunState(pxConfig *config, psS64 stack_id, const char *state)
+{
+    PS_ASSERT_PTR_NON_NULL(state, false);
+
+    // check that state is a valid string value
+    if (!pxIsValidState(state)) {
+        psError(PS_ERR_UNKNOWN, false, "invalid stackRun state: %s", state);
+        return false;
+    }
+
+    char *query = "UPDATE stackRun SET state = '%s' WHERE stack_id = %"PRId64;
+    if (!p_psDBRunQueryF(config->dbh, query, state, stack_id)) {
+        psError(PS_ERR_UNKNOWN, false,
+                "failed to change state for stack_id %"PRId64, stack_id);
+        return false;
+    }
+
+    return true;
+}
+
+#ifdef notdef
+static bool setstackRunStateByLabel(pxConfig *config, const char *label, const char *state)
+{
+    PS_ASSERT_PTR_NON_NULL(state, false);
+
+    // check that state is a valid string value
+    if (!pxIsValidState(state)) {
+        psError(PS_ERR_UNKNOWN, false, "invalid stackRun state: %s", state);
+        return false;
+    }
+
+    char *query = "UPDATE stackRun SET state = '%s' WHERE label = '%s'";
+    if (!p_psDBRunQueryF(config->dbh, query, state, label)) {
+        psError(PS_ERR_UNKNOWN, false,
+                "failed to change state for label %s", label);
+        return false;
+    }
+
+    return true;
+}
+#endif
+static bool tosummaryMode(pxConfig *config) {
+  PS_ASSERT_PTR_NON_NULL(config, NULL);
+  
+  psMetadata *where = psMetadataAlloc();
+  PXOPT_COPY_S64(config->args, where, "-stack_id",    "stackSumSkyfile.warp_id", "==");
+  PXOPT_COPY_S64(config->args, where, "-sass_id",     "stackAssociationMap.sass_id", "==");
+  PXOPT_COPY_STR(config->args, where, "-tess_id",    "stackSumSkyfile.tess_id", "==");
+  PXOPT_COPY_STR(config->args, where, "-state",      "stackRun.state", "==");
+  PXOPT_COPY_STR(config->args, where, "-filter",    "stackRun.filter", "LIKE");
+  pxAddLabelSearchArgs (config, where, "-label",   "stackRun.label", "LIKE");
+  pxAddLabelSearchArgs (config, where, "-data_group",   "stackRun.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("stacktool_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*
+  if (psListLength(where->list)) {
+    psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+    psStringAppend(&query, " AND %s", whereClause);
+    psFree(whereClause);
+  } else if (!all) {
+    psError(PXTOOLS_ERR_CONFIG, true, "search parameters or -all are required");
+    return false;
+  }
+  
+  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("stacktool", PS_LOG_INFO, "no rows found");
+    psFree(output);
+    return true;
+  }
+  
+  if (psArrayLength(output)) {
     // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "stackPendingCleanupRun", !simple)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print array");
-        psFree(output);
-        return false;
-    }
-
-    psFree(output);
-
-    return true;
-}
-
-static bool pendingcleanupskyfileMode(pxConfig *config)
+    if (!ippdbPrintMetadatas(stdout, output, "stackRun", !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(sass_id, config->args, "-sass_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("stacktool_addsummary.sql");
+  if (!query) {
+    psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
+    return(false);
+  }
+  if (!p_psDBRunQueryF(config->dbh, query, sass_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)
 {
     PS_ASSERT_PTR_NON_NULL(config, NULL);
 
-    PXOPT_LOOKUP_S64(stack_id, config->args, "-stack_id", false, false);
     PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
     PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
 
     psMetadata *where = psMetadataAlloc();
-    if (stack_id) {
-        PXOPT_COPY_S64(config->args, where, "-stack_id", "stack_id", "==");
-    }
+    PXOPT_COPY_S64(config->args, where, "-stack_id", "stackRun.stack_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-sass_id", "stackAssociationMap.sass_id", "==");
+    
     pxAddLabelSearchArgs (config, where, "-label", "stackRun.label", "==");
 
-    psString query = pxDataGet("stacktool_pendingcleanupskyfile.sql");
+    psString query = pxDataGet("stacktool_pendingcleanuprun.sql");
     if (!query) {
         psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
@@ -1239,5 +1511,5 @@
 
     // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "stackPendingCleanupSkyfile", !simple)) {
+    if (!ippdbPrintMetadatas(stdout, output, "stackPendingCleanupRun", !simple)) {
         psError(PS_ERR_UNKNOWN, false, "failed to print array");
         psFree(output);
@@ -1250,16 +1522,19 @@
 }
 
-
-static bool donecleanupMode(pxConfig *config)
+static bool pendingcleanupskyfileMode(pxConfig *config)
 {
     PS_ASSERT_PTR_NON_NULL(config, NULL);
 
+    PXOPT_LOOKUP_S64(stack_id, config->args, "-stack_id", false, false);
     PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
     PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
 
     psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-label", "label", "==");
-
-    psString query = pxDataGet("stacktool_donecleanup.sql");
+    if (stack_id) {
+        PXOPT_COPY_S64(config->args, where, "-stack_id", "stack_id", "==");
+    }
+    pxAddLabelSearchArgs (config, where, "-label", "stackRun.label", "==");
+
+    psString query = pxDataGet("stacktool_pendingcleanupskyfile.sql");
     if (!query) {
         psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
@@ -1300,4 +1575,66 @@
 
     // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "stackPendingCleanupSkyfile", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+
+static bool donecleanupMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_STR(config->args, where, "-label", "label", "==");
+    PXOPT_COPY_STR(config->args, where, "-sass_id", "sass_id", "==");
+
+    psString query = pxDataGet("stacktool_donecleanup.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    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) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("stacktool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
     if (!ippdbPrintMetadatas(stdout, output, "stackDoneCleanup", !simple)) {
         psError(PS_ERR_UNKNOWN, false, "failed to print array");
@@ -1329,4 +1666,5 @@
 }
 
+//CZW I have not added sass information to the export/import run modes yet.
 bool exportrunMode(pxConfig *config)
 {
Index: trunk/ippTools/src/stacktool.h
===================================================================
--- trunk/ippTools/src/stacktool.h	(revision 28373)
+++ trunk/ippTools/src/stacktool.h	(revision 28375)
@@ -33,5 +33,8 @@
     STACKTOOL_MODE_ADDSUMSKYFILE,
     STACKTOOL_MODE_SUMSKYFILE,
+    STACKTOOL_MODE_SASSSKYFILE,
     STACKTOOL_MODE_REVERTSUMSKYFILE,
+    STACKTOOL_MODE_TOSUMMARY,
+    STACKTOOL_MODE_ADDSUMMARY,
     STACKTOOL_MODE_PENDINGCLEANUPRUN,
     STACKTOOL_MODE_PENDINGCLEANUPSKYFILE,
Index: trunk/ippTools/src/stacktoolConfig.c
===================================================================
--- trunk/ippTools/src/stacktoolConfig.c	(revision 28373)
+++ trunk/ippTools/src/stacktoolConfig.c	(revision 28375)
@@ -197,4 +197,16 @@
     psMetadataAddBool(sumskyfileArgs, PS_LIST_TAIL, "-all",  0,            "enable search without arguments", false);
 
+    // -sassskyfile
+    psMetadata *sassskyfileArgs = psMetadataAlloc();
+    psMetadataAddS64(sassskyfileArgs, PS_LIST_TAIL, "-sass_id", 0,           "search by stack association ID", 0);
+    psMetadataAddStr(sassskyfileArgs, PS_LIST_TAIL, "-tess_id", 0,            "search by tess ID", 0);
+    psMetadataAddStr(sassskyfileArgs, PS_LIST_TAIL, "-projection_cell", 0,         "search by projection cell", 0);
+
+    psMetadataAddStr(sassskyfileArgs, PS_LIST_TAIL, "-data_group", 0,        "search by stackAssociation.data_group (LIKE comparison)", NULL);
+    psMetadataAddStr(sassskyfileArgs, PS_LIST_TAIL, "-filter", 0,            "search by filter (LIKE comparison)", NULL);
+    psMetadataAddU64(sassskyfileArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
+    psMetadataAddBool(sassskyfileArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddBool(sassskyfileArgs, PS_LIST_TAIL, "-all",  0,            "enable search without arguments", false);
+
     // -revertsumskyfile
     psMetadata *revertsumskyfileArgs= psMetadataAlloc();
@@ -204,4 +216,25 @@
     psMetadataAddBool(revertsumskyfileArgs, PS_LIST_TAIL, "-all",  0, "allow no search terms", 0);
 
+    // -tosummary
+    psMetadata *tosummaryArgs = psMetadataAlloc();
+    psMetadataAddS64(tosummaryArgs, PS_LIST_TAIL, "-stack_id", 0,  "search by stack ID", 0);
+    psMetadataAddS64(tosummaryArgs, PS_LIST_TAIL, "-sass_id", 0,  "search by stack association ID", 0);
+    psMetadataAddStr(tosummaryArgs, PS_LIST_TAIL, "-tess_id", 0,   "search by tessellation ID", NULL);
+    psMetadataAddStr(tosummaryArgs, PS_LIST_TAIL, "-state", 0,     "search by state", NULL);
+    psMetadataAddStr(tosummaryArgs, PS_LIST_TAIL, "-filter", 0,    "search by filter", NULL);
+    psMetadataAddStr(tosummaryArgs, PS_LIST_TAIL, "-label", PS_META_DUPLICATE_OK, "search by stackRun label (LIKE comparison)", NULL);
+    psMetadataAddStr(tosummaryArgs, PS_LIST_TAIL, "-data_group", PS_META_DUPLICATE_OK, "search by stackRun data_group (LIKE comparison)", NULL);
+    psMetadataAddStr(tosummaryArgs, PS_LIST_TAIL, "-dist_group", PS_META_DUPLICATE_OK, "search by stackRun dist_group (LIKE comparison)", NULL);
+
+    psMetadataAddBool(tosummaryArgs, PS_LIST_TAIL, "-all",  0,             "search without arguments", false);
+    psMetadataAddU64(tosummaryArgs, PS_LIST_TAIL,  "-limit",  0,            "limit result set to N items", 0);
+    psMetadataAddBool(tosummaryArgs, PS_LIST_TAIL, "-simple",  0,          "use the simple output format", false);
+
+    // -addsummary
+    psMetadata *addsummaryArgs = psMetadataAlloc();
+    psMetadataAddS64(addsummaryArgs, PS_LIST_TAIL, "-sass_id", 0,      "set stack Association ID", 0);
+    psMetadataAddStr(addsummaryArgs, PS_LIST_TAIL, "-projection_cell", 0, "set projection cell", NULL);
+    psMetadataAddStr(addsummaryArgs, PS_LIST_TAIL, "-path_base", 0,     "set summary path base", NULL);		     
+    
     // -pendingcleanuprun
     psMetadata *pendingcleanuprunArgs = psMetadataAlloc();
@@ -252,4 +285,5 @@
     PXOPT_ADD_MODE("-addsumskyfile",   "", STACKTOOL_MODE_ADDSUMSKYFILE,   addsumskyfileArgs);
     PXOPT_ADD_MODE("-sumskyfile",      "list results of stackRun", STACKTOOL_MODE_SUMSKYFILE,      sumskyfileArgs);
+    PXOPT_ADD_MODE("-sassskyfile",      "list results of stackAssociation", STACKTOOL_MODE_SASSSKYFILE,      sassskyfileArgs);
     PXOPT_ADD_MODE("-revertsumskyfile","", STACKTOOL_MODE_REVERTSUMSKYFILE,      revertsumskyfileArgs);
     PXOPT_ADD_MODE("-pendingcleanuprun",     "show runs that need to be cleaned up", STACKTOOL_MODE_PENDINGCLEANUPRUN,    pendingcleanuprunArgs);
@@ -257,4 +291,6 @@
     PXOPT_ADD_MODE("-donecleanup",           "show runs that have been cleaned",     STACKTOOL_MODE_DONECLEANUP,          donecleanupArgs);
     PXOPT_ADD_MODE("-updatesumskyfile",      "update fault code for sumskyfile",     STACKTOOL_MODE_UPDATESUMSKYFILE,          updatesumskyfileArgs);
+    PXOPT_ADD_MODE("-tosummary",            "show runs that can be summarized", STACKTOOL_MODE_TOSUMMARY, tosummaryArgs);
+    PXOPT_ADD_MODE("-addsummary",           "add entry to the summary table", STACKTOOL_MODE_ADDSUMMARY, addsummaryArgs);
     PXOPT_ADD_MODE("-exportrun",            "export run for import on other database", STACKTOOL_MODE_EXPORTRUN, exportrunArgs);
     PXOPT_ADD_MODE("-importrun",            "import run from metadata file",           STACKTOOL_MODE_IMPORTRUN, importrunArgs);
Index: trunk/ippTools/src/warptool.c
===================================================================
--- trunk/ippTools/src/warptool.c	(revision 28373)
+++ trunk/ippTools/src/warptool.c	(revision 28375)
@@ -48,4 +48,6 @@
 static bool maskedMode(pxConfig *config);
 static bool unblockMode(pxConfig *config);
+static bool tosummaryMode(pxConfig *config);
+static bool addsummaryMode(pxConfig *config);
 static bool pendingcleanuprunMode(pxConfig *config);
 static bool pendingcleanupwarpMode(pxConfig *config);
@@ -101,4 +103,6 @@
         MODECASE(WARPTOOL_MODE_MASKED,             maskedMode);
         MODECASE(WARPTOOL_MODE_UNBLOCK,            unblockMode);
+	MODECASE(WARPTOOL_MODE_TOSUMMARY,          tosummaryMode);
+	MODECASE(WARPTOOL_MODE_ADDSUMMARY,         addsummaryMode);
         MODECASE(WARPTOOL_MODE_PENDINGCLEANUPRUN,  pendingcleanuprunMode);
         MODECASE(WARPTOOL_MODE_PENDINGCLEANUPSKYFILE, pendingcleanupwarpMode);
@@ -1548,4 +1552,133 @@
 }
 
+static bool tosummaryMode(pxConfig *config) {
+  PS_ASSERT_PTR_NON_NULL(config, NULL);
+  
+  psMetadata *where = psMetadataAlloc();
+  PXOPT_COPY_S64(config->args, where, "-warp_id",    "warpSkyfile.warp_id", "==");
+  PXOPT_COPY_STR(config->args, where, "-tess_id",    "warpSkyfile.tess_id", "==");
+  PXOPT_COPY_STR(config->args, where, "-state",      "warpRun.state", "==");
+  PXOPT_COPY_S64(config->args, where, "-exp_id",     "rawExp.exp_id", "==");
+  PXOPT_COPY_STR(config->args, where, "-exp_name",   "rawExp.exp_name", "==");
+  PXOPT_COPY_S64(config->args, where, "-fake_id",    "fakeRun.fake_id", "==");
+  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", "warpSkyfile.magicked", "==");
+  pxAddLabelSearchArgs (config, where, "-label",   "warpRun.label", "LIKE");
+  pxAddLabelSearchArgs (config, where, "-data_group",   "warpRun.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("warptool_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, "warpSkyfile")) {
+    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) {
+    psStringAppend(&query, " %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("warptool", PS_LOG_INFO, "no rows found");
+    psFree(output);
+    return true;
+  }
+  
+  if (psArrayLength(output)) {
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "warpRun", !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(warp_id, config->args, "-warp_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("warptool_addsummary.sql");
+  if (!query) {
+    psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
+    return(false);
+  }
+  if (!p_psDBRunQueryF(config->dbh, query, warp_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)
 {
Index: trunk/ippTools/src/warptool.h
===================================================================
--- trunk/ippTools/src/warptool.h	(revision 28373)
+++ trunk/ippTools/src/warptool.h	(revision 28375)
@@ -44,4 +44,6 @@
     WARPTOOL_MODE_MASKED,
     WARPTOOL_MODE_UNBLOCK,
+    WARPTOOL_MODE_TOSUMMARY,
+    WARPTOOL_MODE_ADDSUMMARY,
     WARPTOOL_MODE_PENDINGCLEANUPRUN,
     WARPTOOL_MODE_PENDINGCLEANUPSKYFILE,
Index: trunk/ippTools/src/warptoolConfig.c
===================================================================
--- trunk/ippTools/src/warptoolConfig.c	(revision 28373)
+++ trunk/ippTools/src/warptoolConfig.c	(revision 28375)
@@ -321,4 +321,32 @@
     psMetadataAddStr(unblockArgs, PS_LIST_TAIL, "-label",  0,            "name of a label to unmask (required)", NULL);
 
+    // -tosummary
+    psMetadata *tosummaryArgs = psMetadataAlloc();
+    psMetadataAddS64(tosummaryArgs, PS_LIST_TAIL, "-warp_id", 0,         "search by warp ID", 0);
+    psMetadataAddStr(tosummaryArgs, PS_LIST_TAIL,  "-tess_id",  0,          "search by tessellation ID", NULL);
+    psMetadataAddStr(tosummaryArgs, PS_LIST_TAIL, "-state",  0,            "search by state", NULL);
+    psMetadataAddS64(tosummaryArgs, PS_LIST_TAIL, "-exp_id", 0,            "search by exposure tag", 0);
+    psMetadataAddStr(tosummaryArgs, PS_LIST_TAIL, "-exp_name", 0,          "search by exposure tag", 0);
+    psMetadataAddS64(tosummaryArgs, PS_LIST_TAIL, "-fake_id", 0,           "search by phase 3 version of exposure tag", 0);
+    psMetadataAddTime(tosummaryArgs, PS_LIST_TAIL, "-dateobs_begin", 0,    "search for exposures by time (>=)", NULL);
+    psMetadataAddTime(tosummaryArgs, PS_LIST_TAIL, "-dateobs_end", 0,      "search for exposures by time (<=)", NULL);
+    psMetadataAddStr(tosummaryArgs, PS_LIST_TAIL,  "-filter", 0,           "search for exposures by filter", NULL);
+    psMetadataAddS64(tosummaryArgs, PS_LIST_TAIL,  "-magicked", 0,         "search by magic id", 0);
+    psMetadataAddStr(tosummaryArgs, PS_LIST_TAIL,  "-label",  PS_META_DUPLICATE_OK, "search by warpRun label", NULL);
+    psMetadataAddStr(tosummaryArgs, PS_LIST_TAIL,  "-data_group",  PS_META_DUPLICATE_OK, "search by warpRun data_group", NULL);
+    psMetadataAddStr(tosummaryArgs, PS_LIST_TAIL,  "-dist_group",  PS_META_DUPLICATE_OK, "search by warpRun dist_group", NULL);
+    psMetadataAddBool(tosummaryArgs, PS_LIST_TAIL, "-destreaked", 0, "search for runs that have been destreaked", false);
+    psMetadataAddBool(tosummaryArgs, PS_LIST_TAIL, "-not_destreaked", 0, "search for runs that have not been destreaked", false);
+    
+    psMetadataAddBool(tosummaryArgs, PS_LIST_TAIL, "-all",  0,             "search without arguments", false);
+    psMetadataAddU64(tosummaryArgs, PS_LIST_TAIL,  "-limit",  0,            "limit result set to N items", 0);
+    psMetadataAddBool(tosummaryArgs, PS_LIST_TAIL, "-simple",  0,          "use the simple output format", false);
+
+    // -addsummary
+    psMetadata *addsummaryArgs = psMetadataAlloc();
+    psMetadataAddS64(addsummaryArgs, PS_LIST_TAIL, "-warp_id", 0,         "set warp ID", 0);
+    psMetadataAddStr(addsummaryArgs, PS_LIST_TAIL, "-projection_cell", 0,   "set projection cell", NULL);
+    psMetadataAddStr(addsummaryArgs, PS_LIST_TAIL, "-path_base", 0,       "set summary path base", NULL);
+    
     // -pendingcleanuprun
     psMetadata *pendingcleanuprunArgs = psMetadataAlloc();
@@ -430,4 +458,7 @@
     PXOPT_ADD_MODE("-updateskyfile", "update fault code for skyfile", WARPTOOL_MODE_UPDATESKYFILE, updateskyfileArgs);
     PXOPT_ADD_MODE("-setskyfiletoupdate", "set cleaned skyfile to be updated", WARPTOOL_MODE_SETSKYFILETOUPDATE, setskyfiletoupdateArgs);
+    PXOPT_ADD_MODE("-tosummary",            "show runs that can be summarized", WARPTOOL_MODE_TOSUMMARY, tosummaryArgs);
+    PXOPT_ADD_MODE("-addsummary",           "add entry to the summary table", WARPTOOL_MODE_ADDSUMMARY, addsummaryArgs);
+
     PXOPT_ADD_MODE("-exportrun",            "export run for import on other database", WARPTOOL_MODE_EXPORTRUN, exportrunArgs);
     PXOPT_ADD_MODE("-importrun",            "import run from metadata file",           WARPTOOL_MODE_IMPORTRUN, importrunArgs);
