Index: trunk/ippTools/src/stacktool.c
===================================================================
--- trunk/ippTools/src/stacktool.c	(revision 28043)
+++ 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)
 {
