Index: trunk/ippTools/src/dettool.c
===================================================================
--- trunk/ippTools/src/dettool.c	(revision 18561)
+++ trunk/ippTools/src/dettool.c	(revision 19092)
@@ -28,51 +28,5 @@
 static bool inputMode(pxConfig *config);
 static bool rawMode(pxConfig *config);
-// processedimfile
-static bool toprocessedimfileMode(pxConfig *config);
-static bool addprocessedimfileMode(pxConfig *config);
-static bool processedimfileMode(pxConfig *config);
-static bool revertprocessedimfileMode(pxConfig *config);
-// processedexp
-static bool toprocessedexpMode(pxConfig *config);
-static bool addprocessedexpMode(pxConfig *config);
-static bool processedexpMode(pxConfig *config);
-static bool revertprocessedexpMode(pxConfig *config);
-// stackedimfile
-static bool tostackedMode(pxConfig *config);
-static bool addstackedMode(pxConfig *config);
-static bool stackedMode(pxConfig *config);
-static bool revertstackedMode(pxConfig *config);
-// normalizedstat
-static bool tonormalizedstatMode(pxConfig *config);
-static bool addnormalizedstatMode(pxConfig *config);
-static bool normalizedstatMode(pxConfig *config);
-static bool revertnormalizedstatMode(pxConfig *config);
-// normalizedimfile
-static bool tonormalizeMode(pxConfig *config);
-static bool addnormalizedimfileMode(pxConfig *config);
-static bool normalizedimfileMode(pxConfig *config);
-static bool revertnormalizedimfileMode(pxConfig *config);
-// normalizedexp
-static bool tonormalizedexpMode(pxConfig *config);
-static bool addnormalizedexpMode(pxConfig *config);
-static bool normalizedexpMode(pxConfig *config);
-static bool revertnormalizedexpMode(pxConfig *config);
-// residimfile
-static bool toresidimfileMode(pxConfig *config);
-static bool addresidimfileMode(pxConfig *config);
-static bool residimfileMode(pxConfig *config);
-static bool revertresidimfileMode(pxConfig *config);
-// residexp
-static bool toresidexpMode(pxConfig *config);
-static bool addresidexpMode(pxConfig *config);
-static bool residexpMode(pxConfig *config);
-static bool revertresidexpMode(pxConfig *config);
-static bool updateresidexpMode(pxConfig *config);
-// detrunsummary
-static bool todetrunsummaryMode(pxConfig *config);
-static bool adddetrunsummaryMode(pxConfig *config);
-static bool detrunsummaryMode(pxConfig *config);
-static bool revertdetrunsummaryMode(pxConfig *config);
-static bool updatedetrunsummaryMode(pxConfig *config);
+
 // run
 static bool updatedetrunMode(pxConfig *config);
@@ -81,13 +35,8 @@
 static bool register_detrendMode(pxConfig *config);
 
-static detRunSummaryRow *mdToDetRunSummary(pxConfig *config, psMetadata *row);
 //static psArray *validDetInputClassIds(pxConfig *config, const char *det_id);
 //static psArray *searchInputImfiles(pxConfig *config, const char *det_id);
 static detInputExpRow *rawDetrenTodetInputExpRow(rawExpRow *rawExp, psS64 det_id, psS32 iteration);
-static psArray *searchRawImfiles(pxConfig *config);
-static bool startNewIteration(pxConfig *config, psS64 det_id);
 static psS32 incrementIteration(pxConfig *config, psS64 det_id);
-static bool setDetRunState(pxConfig *config, psS64 det_id, const char *state);
-static bool isValidMode(pxConfig *config, const char *mode);
 
 # define MODECASE(caseName, func) \
@@ -127,4 +76,7 @@
         MODECASE(DETTOOL_MODE_PROCESSEDIMFILE,  processedimfileMode);
         MODECASE(DETTOOL_MODE_REVERTPROCESSEDIMFILE, revertprocessedimfileMode);
+        MODECASE(DETTOOL_MODE_UPDATEPROCESSEDIMFILE, updateprocessedimfileMode);
+        MODECASE(DETTOOL_MODE_PENDINGCLEANUP_PROCESSEDIMFILE, pendingcleanup_processedimfileMode);
+        MODECASE(DETTOOL_MODE_DONECLEANUP_PROCESSEDIMFILE, donecleanup_processedimfileMode);
         // exp
         MODECASE(DETTOOL_MODE_TOPROCESSEDEXP,   toprocessedexpMode);
@@ -132,4 +84,7 @@
         MODECASE(DETTOOL_MODE_PROCESSEDEXP,     processedexpMode);
         MODECASE(DETTOOL_MODE_REVERTPROCESSEDEXP, revertprocessedexpMode);
+        MODECASE(DETTOOL_MODE_UPDATEPROCESSEDEXP, updateprocessedexpMode);
+        MODECASE(DETTOOL_MODE_PENDINGCLEANUP_PROCESSEDEXP, pendingcleanup_processedexpMode);
+        MODECASE(DETTOOL_MODE_DONECLEANUP_PROCESSEDEXP, donecleanup_processedexpMode);
         // stacked
         MODECASE(DETTOOL_MODE_TOSTACKED,        tostackedMode);
@@ -137,4 +92,7 @@
         MODECASE(DETTOOL_MODE_STACKED,          stackedMode);
         MODECASE(DETTOOL_MODE_REVERTSTACKED,    revertstackedMode);
+        MODECASE(DETTOOL_MODE_UPDATESTACKED,    updatestackedMode);
+        MODECASE(DETTOOL_MODE_PENDINGCLEANUP_STACKED, pendingcleanup_stackedMode);
+        MODECASE(DETTOOL_MODE_DONECLEANUP_STACKED, donecleanup_stackedMode);
         // normalizedstat
         MODECASE(DETTOOL_MODE_TONORMALIZEDSTAT, tonormalizedstatMode);
@@ -142,4 +100,7 @@
         MODECASE(DETTOOL_MODE_NORMALIZEDSTAT,   normalizedstatMode);
         MODECASE(DETTOOL_MODE_REVERTNORMALIZEDSTAT, revertnormalizedstatMode);
+        MODECASE(DETTOOL_MODE_UPDATENORMALIZEDSTAT, updatenormalizedstatMode);
+        MODECASE(DETTOOL_MODE_PENDINGCLEANUP_NORMALIZEDSTAT, pendingcleanup_normalizedstatMode);
+        MODECASE(DETTOOL_MODE_DONECLEANUP_NORMALIZEDSTAT, donecleanup_normalizedstatMode);
         // normalizedimfile
         MODECASE(DETTOOL_MODE_TONORMALIZE,      tonormalizeMode);
@@ -147,4 +108,7 @@
         MODECASE(DETTOOL_MODE_NORMALIZEDIMFILE, normalizedimfileMode);
         MODECASE(DETTOOL_MODE_REVERTNORMALIZEDIMFILE, revertnormalizedimfileMode);
+        MODECASE(DETTOOL_MODE_UPDATENORMALIZEDIMFILE, updatenormalizedimfileMode);
+        MODECASE(DETTOOL_MODE_PENDINGCLEANUP_NORMALIZEDIMFILE, pendingcleanup_normalizedimfileMode);
+        MODECASE(DETTOOL_MODE_DONECLEANUP_NORMALIZEDIMFILE, donecleanup_normalizedimfileMode);
         // normalizedexp
         MODECASE(DETTOOL_MODE_TONORMALIZEDEXP,  tonormalizedexpMode);
@@ -152,4 +116,7 @@
         MODECASE(DETTOOL_MODE_NORMALIZEDEXP,    normalizedexpMode);
         MODECASE(DETTOOL_MODE_REVERTNORMALIZEDEXP, revertnormalizedexpMode);
+        MODECASE(DETTOOL_MODE_UPDATENORMALIZEDEXP, updatenormalizedexpMode);
+        MODECASE(DETTOOL_MODE_PENDINGCLEANUP_NORMALIZEDEXP, pendingcleanup_normalizedexpMode);
+        MODECASE(DETTOOL_MODE_DONECLEANUP_NORMALIZEDEXP, donecleanup_normalizedexpMode);
         // residimfile
         MODECASE(DETTOOL_MODE_TORESIDIMFILE,    toresidimfileMode);
@@ -157,4 +124,7 @@
         MODECASE(DETTOOL_MODE_RESIDIMFILE,      residimfileMode);
         MODECASE(DETTOOL_MODE_REVERTRESIDIMFILE,revertresidimfileMode);
+        MODECASE(DETTOOL_MODE_UPDATERESIDIMFILE, updateresidimfileMode);
+        MODECASE(DETTOOL_MODE_PENDINGCLEANUP_RESIDIMFILE, pendingcleanup_residimfileMode);
+        MODECASE(DETTOOL_MODE_DONECLEANUP_RESIDIMFILE, donecleanup_residimfileMode);
         // residexp
         MODECASE(DETTOOL_MODE_TORESIDEXP,       toresidexpMode);
@@ -163,4 +133,6 @@
         MODECASE(DETTOOL_MODE_REVERTRESIDEXP,   revertresidexpMode);
         MODECASE(DETTOOL_MODE_UPDATERESIDEXP,   updateresidexpMode);
+        MODECASE(DETTOOL_MODE_PENDINGCLEANUP_RESIDEXP, pendingcleanup_residexpMode);
+        MODECASE(DETTOOL_MODE_DONECLEANUP_RESIDEXP, donecleanup_residexpMode);
         // detrunsummary
         MODECASE(DETTOOL_MODE_TODETRUNSUMMARY,  todetrunsummaryMode);
@@ -208,5 +180,5 @@
     
     psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-exp_id", "exp_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-exp_id", "exp_id", "==");
     PXOPT_COPY_STR(config->args, where, "-exp_type", "exp_type", "==");
     PXOPT_COPY_STR(config->args, where, "-inst", "camera", "==");
@@ -722,5 +694,5 @@
 
     
-    PXOPT_LOOKUP_STR(det_id, config->args, "-det_id", true, false); // required
+    PXOPT_LOOKUP_S64(det_id, config->args, "-det_id", true, false); // required
     PXOPT_LOOKUP_STR(det_type, config->args, "-set_det_type", false, false); // optional
     PXOPT_LOOKUP_STR(mode, config->args, "-set_mode", false, false); // optional
@@ -758,5 +730,5 @@
     {
         psMetadata *where = psMetadataAlloc();
-        psMetadataAddS64(where, PS_LIST_TAIL, "det_id", 0, "==", (psS64)atoll(det_id));
+        psMetadataAddS64(where, PS_LIST_TAIL, "det_id", 0, "==", det_id);
         detRuns = detRunSelectRowObjects(config->dbh, where, 0);
         psFree(where);
@@ -768,5 +740,5 @@
     // sanity check the result... we should have only found one det_id
     if (psArrayLength(detRuns) != 1) {
-        psAbort("found more then one detRun matching det_id %" PRId64 " (this should not happen)", (psS64)atoll(det_id));
+        psAbort("found more then one detRun matching det_id %" PRId64 " (this should not happen)", det_id);
         return false;                   // unreachable
     }
@@ -939,5 +911,5 @@
     psFree(time_filter);
 
-    if (!p_psDBRunQuery(config->dbh, query, (psS64)newDet_id, (psS64)atoll(det_id))) {
+    if (!p_psDBRunQuery(config->dbh, query, (long long) newDet_id, (long long) det_id)) {
         psError(PS_ERR_UNKNOWN, false, "database error");
         psFree(query);
@@ -987,5 +959,5 @@
     psMetadata *where = psMetadataAlloc();
     PXOPT_COPY_STR(config->args, where, "-det_type", "det_type", "==");
-    PXOPT_COPY_STR(config->args, where, "-det_id",   "det_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-det_id",   "det_id", "==");
 
     PXOPT_COPY_STR(config->args, where, "-inst", "camera", "==");
@@ -1152,5 +1124,5 @@
 
     psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id",    "det_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-det_id",    "det_id", "==");
     PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
     PXOPT_COPY_S64(config->args, where, "-exp_id",    "exp_id", "==");
@@ -1251,2351 +1223,9 @@
 }
 
-static bool toprocessedimfileMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id",   "det_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-exp_id",   "exp_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-class_id", "class_id", "==");
-
-    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
-    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-
-    psString query = pxDataGet("dettool_toprocessedimfile.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(where, "rawImfile");
-        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("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "detPendingProcessedImfile", !simple)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print array");
-        psFree(output);
-        return false;
-    }
-
-    psFree(output);
-
-    return true;
-}
-
-static bool addprocessedimfileMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    // det_id, exp_id, class_id, uri, recipe, -bg, -bg_stdev are required
-    PXOPT_LOOKUP_STR(det_id, config->args, "-det_id", true, false);
-    PXOPT_LOOKUP_STR(exp_id, config->args, "-exp_id", true, false);
-    PXOPT_LOOKUP_STR(class_id, config->args, "-class_id", true, false);
-
-    // default values
-    PXOPT_LOOKUP_S16(code, config->args, "-code", false, false);
-
-    // Required if code == 0
-    PXOPT_LOOKUP_STR(uri, config->args, "-uri", (code == 0), false);
-    PXOPT_LOOKUP_STR(recipe, config->args, "-recip", (code == 0), false);
-
-    // optional
-    PXOPT_LOOKUP_F64(bg, config->args, "-bg", false, false);
-    PXOPT_LOOKUP_F64(bg_stdev, config->args, "-bg_stdev", false, false);
-    PXOPT_LOOKUP_F64(bg_mean_stdev, config->args, "-bg_mean_stdev", false, false);
-    PXOPT_LOOKUP_F64(fringe_0, config->args, "-fringe_0", false, false);
-    PXOPT_LOOKUP_F64(fringe_1, config->args, "-fringe_1", false, false);
-    PXOPT_LOOKUP_F64(fringe_2, config->args, "-fringe_2", false, false);
-    PXOPT_LOOKUP_F64(user_1, config->args, "-user_1", false, false);
-    PXOPT_LOOKUP_F64(user_2, config->args, "-user_2", false, false);
-    PXOPT_LOOKUP_F64(user_3, config->args, "-user_3", false, false);
-    PXOPT_LOOKUP_F64(user_4, config->args, "-user_4", false, false);
-    PXOPT_LOOKUP_F64(user_5, config->args, "-user_5", false, false);
-    PXOPT_LOOKUP_STR(path_base, config->args, "-path_base", false, false);
-
-    // find the matching rawImfile by exp_id/class_id
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-exp_id",   "exp_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-class_id", "class_id", "==");
-
-    psArray *rawImfiles = rawImfileSelectRowObjects(config->dbh, where, 0);
-    psFree(where);
-
-    if (!rawImfiles) {
-        psError(PS_ERR_UNKNOWN, false, "no rawImfile rows found ");
-        return false;
-    }
-
-    // create a new detProcessedImfile object
-    detProcessedImfileRow *detRow = detProcessedImfileRowAlloc(
-        (psS64)atoll(det_id),
-        (psS64)atoll(exp_id),
-        class_id,
-        uri,
-        recipe,
-        bg,
-        bg_stdev,
-        bg_mean_stdev,
-        fringe_0,
-        fringe_1,
-        fringe_2,
-        user_1,
-        user_2,
-        user_3,
-        user_4,
-        user_5,
-        path_base,
-        code
-    );
-    psFree(rawImfiles);
-
-    // insert the new row into the detProcessedImfile table
-    if (!detProcessedImfileInsertObject(config->dbh, detRow)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(detRow);
-        return false;
-    }
-
-    psFree(detRow);
-
-    return true;
-}
-
-static bool processedimfileMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    char *value = NULL;
-
-    PXOPT_LOOKUP_BOOL(included, config->args, "-included", false);
-    PXOPT_LOOKUP_BOOL(faulted, config->args, "-faulted", 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, "-det_id", "det_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-exp_id", "exp_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-class_id", "class_id", "==");
-
-    psString query = pxDataGet("dettool_processedimfile.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        psFree(where);
-        return false;
-    }
-
-    // add the two required restrictions: detRun.state and detRun.mode
-    // NOTE the above query requires one of the following two WHERE statements
-    {
-        bool status;
-        if ((value = psMetadataLookupStr(&status, config->args, "-select_state"))) {
-            psStringAppend(&query, " WHERE detRun.state = '%s'", value);
-        } else {
-            psStringAppend(&query, " WHERE detRun.state = 'run'");
-        }
-        if ((value = psMetadataLookupStr(&status, config->args, "-select_mode"))) {
-            psStringAppend(&query, " AND detRun.mode = '%s'", value);
-        } else {
-            psStringAppend(&query, " AND detRun.mode = 'master'");
-        }
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(where, "detProcessedImfile");
-        psStringAppend(&query, " AND %s", whereClause);
-        psFree(whereClause);
-    }
-    psFree (where);
-
-    // restrict search to included imfiles
-    if (included) {
-	psStringAppend(&query, " AND detInputExp.include = 1");
-    }
-
-    if (faulted) {
-        // list only faulted rows
-        psStringAppend(&query, " %s", "AND detProcessedImfile.fault != 0");
-    } else {
-        // don't list faulted rows
-        psStringAppend(&query, " %s", "AND detProcessedImfile.fault = 0");
-    }
-
-    // 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("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "rawImfile", !simple)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print array");
-        psFree(output);
-        return false;
-    }
-
-    psFree(output);
-
-    return true;
-}
-
-static bool revertprocessedimfileMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id", "det_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-exp_id", "exp_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-class_id", "class_id", "==");
-    PXOPT_COPY_S16(config->args, where, "-code", "fault", "==");
-
-    psString query = pxDataGet("dettool_revertprocessedimfile.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(where, "detProcessedImfile");
-        psStringAppend(&query, " AND %s", whereClause);
-        psFree(whereClause);
-    }
-    psFree(where);
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    if (psDBAffectedRows(config->dbh) < 1) {
-        psError(PS_ERR_UNKNOWN, false, "should have affected atleast 1 row");
-        return false;
-    }
-
-    return true;
-}
-
-static bool toprocessedexpMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
-    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-
-    psString query = pxDataGet("dettool_toprocessedexp.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    // 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("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "detPendingProcessedExp", !simple)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print array");
-        psFree(output);
-        return false;
-    }
-
-    psFree(output);
-
-    return true;
-}
-
-static bool addprocessedexpMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    // det_id, exp_id, recip, -bg, -bg_stdev
-    // are required
-    PXOPT_LOOKUP_STR(det_id, config->args, "-det_id", true, false);
-    PXOPT_LOOKUP_STR(exp_id, config->args, "-exp_id", true, false);
-
-    // default values
-    PXOPT_LOOKUP_S16(code, config->args, "-code", false, false);
-
-    // Required if code == 0
-    PXOPT_LOOKUP_STR(recipe, config->args, "-recip", (code == 0), false);
-
-    // optional
-    PXOPT_LOOKUP_F64(bg, config->args, "-bg", false, false);
-    PXOPT_LOOKUP_F64(bg_stdev, config->args, "-bg_stdev", false, false);
-    PXOPT_LOOKUP_F64(bg_mean_stdev, config->args, "-bg_mean_stdev", false, false);
-    PXOPT_LOOKUP_F64(fringe_0, config->args, "-fringe_0", false, false);
-    PXOPT_LOOKUP_F64(fringe_1, config->args, "-fringe_1", false, false);
-    PXOPT_LOOKUP_F64(fringe_2, config->args, "-fringe_2", false, false);
-    PXOPT_LOOKUP_F64(user_1, config->args, "-user_1", false, false);
-    PXOPT_LOOKUP_F64(user_2, config->args, "-user_2", false, false);
-    PXOPT_LOOKUP_F64(user_3, config->args, "-user_3", false, false);
-    PXOPT_LOOKUP_F64(user_4, config->args, "-user_4", false, false);
-    PXOPT_LOOKUP_F64(user_5, config->args, "-user_5", false, false);
-    PXOPT_LOOKUP_STR(path_base, config->args, "-path_base", true, false);
-
-    psString query = pxDataGet("dettool_addprocessedexp.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    if (!p_psDBRunQuery(config->dbh, query, det_id, exp_id)) {
-        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("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-    psFree(output);
-
-    // create a new detProcessedImfile object
-    detProcessedExpRow *detRow = detProcessedExpRowAlloc(
-        (psS64)atoll(det_id),
-        (psS64)atoll(exp_id),
-        recipe,
-        bg,
-        bg_stdev,
-        bg_mean_stdev,
-        fringe_0,
-        fringe_1,
-        fringe_2,
-        user_1,
-        user_2,
-        user_3,
-        user_4,
-        user_5,
-        path_base,
-        code
-    );
-
-    // insert the new row into the detProcessedImfile table
-    if (!detProcessedExpInsertObject(config->dbh, detRow)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(detRow);
-        return false;
-    }
-
-    psFree(detRow);
-
-    return true;
-}
-
-static bool processedexpMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id", "det_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-exp_id", "exp_id", "==");
-
-    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
-    PXOPT_LOOKUP_BOOL(faulted, config->args, "-faulted", false);
-    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-
-    psString query = psStringCopy("SELECT * FROM detProcessedExp");
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereSQL(where, NULL);
-        psStringAppend(&query, " %s", whereClause);
-        psFree(whereClause);
-    }
-    psFree(where);
-
-    if (faulted) {
-        // list only faulted rows
-        psStringAppend(&query, " %s", "AND detProcessedExp.fault != 0");
-    } else {
-        // don't list faulted rows
-        psStringAppend(&query, " %s", "AND detProcessedExp.fault = 0");
-    }
-
-    // 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("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "detProcessedExp", !simple)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print array");
-        psFree(output);
-        return false;
-    }
-
-    psFree(output);
-
-    return true;
-}
-
-
-static bool revertprocessedexpMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id", "det_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-exp_id", "exp_id", "==");
-    PXOPT_COPY_S16(config->args, where, "-code",   "fault", "==");
-
-    psString query = pxDataGet("dettool_revertprocessedexp.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(where, "detProcessedExp");
-        psStringAppend(&query, " AND %s", whereClause);
-        psFree(whereClause);
-    }
-    psFree(where);
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    if (psDBAffectedRows(config->dbh) < 1) {
-        psError(PS_ERR_UNKNOWN, false, "should have affected atleast 1 row");
-        return false;
-    }
-
-    return true;
-}
-
-
-static bool tostackedMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
-    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-
-    psString query = pxDataGet("dettool_tostacked.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    // 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("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "detPendingStackedImfile", !simple)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print array");
-        psFree(output);
-        return false;
-    }
-
-    psFree(output);
-
-    return true;
-}
-
-// this is NOT a command-line mode : it is used by 'addstackedMode'
-static psArray *searchRawImfiles(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, NULL);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id",    "det_id", "==");
-    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
-
-    // select exp_ids from detInputExp matching det_id & iteration
-    // where query should be pre-generated
-    psArray *detInputExp = detInputExpSelectRowObjects(config->dbh, where, 0);
-    psFree (where);
-
-    if (!detInputExp) {
-        psError(PS_ERR_UNKNOWN, false, "no rawExp rows found");
-        return NULL;
-    }
-
-    // generate where query with just the exp_ids
-    psMetadata *where_exp_ids = psMetadataAlloc();
-    for (long i = 0; i < psArrayLength(detInputExp); i++) {
-        detInputExpRow *row = detInputExp->data[i];
-        if (!psMetadataAddS64(where_exp_ids, PS_LIST_TAIL, "exp_id",
-                PS_META_DUPLICATE_OK, "==", row->exp_id)
-        ) {
-            psError(PS_ERR_UNKNOWN, false, "failed to add item exp_id");
-            psFree(detInputExp);
-            psFree(where_exp_ids);
-            return NULL;
-        }
-    }
-    psFree(detInputExp);
-
-    // select rawImfiles with matching exp_ids
-    psArray *rawImfiles =
-        rawImfileSelectRowObjects(config->dbh, where_exp_ids, 0);
-    psFree(where_exp_ids);
-    if (!rawImfiles) {
-        psError(PS_ERR_UNKNOWN, false, "no rawImfile rows found");
-        return NULL;
-    }
-
-    return rawImfiles;
-}
-
-static bool addstackedMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    // det_id, iteration, class_id, uri, & recipe are required
-    PXOPT_LOOKUP_STR(det_id, config->args, "-det_id", true, false);
-    PXOPT_LOOKUP_S32(iteration, config->args, "-iteration", true, false);
-    PXOPT_LOOKUP_STR(class_id, config->args, "-class_id", true, false);
-
-    PXOPT_LOOKUP_S16(code, config->args, "-code", false, false);
-
-    // Required if code == 0
-    PXOPT_LOOKUP_STR(uri, config->args, "-uri", (code == 0), false);
-    PXOPT_LOOKUP_STR(recipe, config->args, "-recip", (code == 0), false);
-
-    // optional
-    PXOPT_LOOKUP_F64(bg, config->args, "-bg", false, false);
-    PXOPT_LOOKUP_F64(bg_stdev, config->args, "-bg_stdev", false, false);
-    PXOPT_LOOKUP_F64(bg_mean_stdev, config->args, "-bg_mean_stdev", false, false);
-    PXOPT_LOOKUP_F64(user_1, config->args, "-user_1", false, false);
-    PXOPT_LOOKUP_F64(user_2, config->args, "-user_2", false, false);
-    PXOPT_LOOKUP_F64(user_3, config->args, "-user_3", false, false);
-    PXOPT_LOOKUP_F64(user_4, config->args, "-user_4", false, false);
-    PXOPT_LOOKUP_F64(user_5, config->args, "-user_5", false, false);
-
-    // correlate the class_id against the input exposure(s)
-    // searchRawImfiles defines a where clause to search by det_id and iteration
-    psArray *rawImfiles = searchRawImfiles(config);
-
-    if (!rawImfiles) {
-        psError(PS_ERR_UNKNOWN, false, "failed to get rawImfiles from db");
-        return false;
-    }
-
-    bool valid_class_id = false;
-    if (rawImfiles) {
-        for (long i = 0; i < psArrayLength(rawImfiles); i++) {
-            if (!rawImfiles->data[i]) {
-                fprintf (stderr, "*");
-                continue;
-            }
-            if (strcmp(class_id, ((rawImfileRow *)rawImfiles->data[i])->class_id) == 0) {
-                valid_class_id = true;
-                break;
-            }
-        }
-        psFree(rawImfiles);
-    }
-
-    if (!valid_class_id) {
-        psError(PS_ERR_UNKNOWN, true,
-            "class_id can not be correlated with the input exposures");
-        return false;
-    }
-
-    // create a new detStackedImfile object
-    detStackedImfileRow *stackedImfile = detStackedImfileRowAlloc(
-            (psS64)atoll(det_id),
-            iteration,
-            class_id,
-            uri,
-            recipe,
-            bg,
-            bg_stdev,
-            bg_mean_stdev,
-            user_1,
-            user_2,
-            user_3,
-            user_4,
-            user_5,
-            code
-        );
-
-    // insert the new row into the detProcessedImfile table
-    if (!detStackedImfileInsertObject(config->dbh, stackedImfile)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(stackedImfile);
-        return false;
-    }
-
-    psFree(stackedImfile);
-
-    return true;
-}
-
-static bool stackedMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id",    "det_id", "==");
-    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
-    PXOPT_COPY_STR(config->args, where, "-class_id",  "class_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-recip",     "recipe", "==");
-
-    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
-    PXOPT_LOOKUP_BOOL(faulted, config->args, "-faulted", false);
-    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-
-    psString query = pxDataGet("dettool_stacked.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        psFree(where);
-        return false;
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(where, "detStackedImfile");
-        psStringAppend(&query, " AND %s", whereClause);
-        psFree(whereClause);
-    }
-    psFree(where);
-
-    if (faulted) {
-        // list only faulted rows
-        psStringAppend(&query, " %s", "AND detStackedImfile.fault != 0");
-    } else {
-        // don't list faulted rows
-        psStringAppend(&query, " %s", "AND detStackedImfile.fault = 0");
-    }
-
-    // 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("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "rawImfile", !simple)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print array");
-        psFree(output);
-        return false;
-    }
-
-    psFree(output);
-
-    return true;
-}
-
-
-static bool revertstackedMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id",    "det_id", "==");
-    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
-    PXOPT_COPY_STR(config->args, where, "-class_id",  "class_id", "==");
-    PXOPT_COPY_S16(config->args, where, "-code",      "fault", "==");
-
-    psString query = pxDataGet("dettool_revertstacked.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(where, "detStackedImfile");
-        psStringAppend(&query, " AND %s", whereClause);
-        psFree(whereClause);
-    }
-    psFree(where);
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    if (psDBAffectedRows(config->dbh) < 1) {
-        psError(PS_ERR_UNKNOWN, false, "should have affected atleast 1 row");
-        return false;
-    }
-
-    return true;
-}
-
-static bool tonormalizedstatMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
-    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-
-    psString query = pxDataGet("dettool_tonormalizedstat.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    // 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("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "detPendingNormStatImfile", !simple)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print array");
-        psFree(output);
-        return false;
-    }
-
-    psFree(output);
-
-    return true;
-}
-
-static bool addnormalizedstatMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, NULL);
-
-    // required
-    PXOPT_LOOKUP_STR(det_id, config->args, "-det_id", true, false);
-    PXOPT_LOOKUP_STR(class_id, config->args, "-class_id", true, false);
-
-    // optional
-    PXOPT_LOOKUP_F32(norm, config->args, "-norm", false, false);
-
-    // default
-    PXOPT_LOOKUP_S32(iteration, config->args, "-iteration", false, false);
-    PXOPT_LOOKUP_S16(code, config->args, "-code", false, false);
-
-    if (!detNormalizedStatImfileInsert(config->dbh,
-        (psS64)atoll(det_id),
-        iteration,
-        class_id,
-        norm,
-        code
-    )) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-
-    return true;
-}
-
-
-static bool normalizedstatMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id",    "det_id", "==");
-    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
-    PXOPT_COPY_STR(config->args, where, "-class_id",  "class_id", "==");
-
-    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
-    PXOPT_LOOKUP_BOOL(faulted, config->args, "-faulted", false);
-    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-
-    psString query = pxDataGet("dettool_normalizedstat.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    if (faulted) {
-        // list only faulted rows
-        psStringAppend(&query, " %s", "WHERE fault != 0");
-    } else {
-        // don't list faulted rows
-        psStringAppend(&query, " %s", "WHERE fault = 0");
-    }
-
-    if (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("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "detNormalizedStatImfile", !simple)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print array");
-        psFree(output);
-        return false;
-    }
-
-    psFree(output);
-
-    return true;
-}
-
-static bool revertnormalizedstatMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id",    "det_id", "==");
-    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
-    PXOPT_COPY_STR(config->args, where, "-class_id",  "class_id", "==");
-    PXOPT_COPY_S16(config->args, where, "-code",      "fault", "==");
-
-    psString query = pxDataGet("dettool_revertnormalizedstat.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(where, "detNormalizedStatImfile");
-        psStringAppend(&query, " AND %s", whereClause);
-        psFree(whereClause);
-    }
-    psFree(where);
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    if (psDBAffectedRows(config->dbh) < 1) {
-        psError(PS_ERR_UNKNOWN, false, "should have affected atleast 1 row");
-        return false;
-    }
-
-    return true;
-}
-
-static bool tonormalizeMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
-    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-
-    psString query = pxDataGet("dettool_tonormalize.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    // 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("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "detPendingNormImfile", !simple)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print array");
-        psFree(output);
-        return false;
-    }
-
-    psFree(output);
-
-    return true;
-}
-
-static bool addnormalizedimfileMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    // required
-    PXOPT_LOOKUP_STR(det_id, config->args, "-det_id", true, false);
-    PXOPT_LOOKUP_S32(iteration, config->args, "-iteration", false, false);
-    PXOPT_LOOKUP_STR(class_id, config->args, "-class_id", true, false);
-
-    PXOPT_LOOKUP_S16(code, config->args, "-code", false, false);
-
-    // Required if code == 0
-    PXOPT_LOOKUP_STR(uri, config->args, "-uri", (code == 0), false);
-
-    // optional
-    PXOPT_LOOKUP_F64(bg, config->args, "-bg", false, false);
-    PXOPT_LOOKUP_F64(bg_stdev, config->args, "-bg_stdev", false, false);
-    PXOPT_LOOKUP_F64(bg_mean_stdev, config->args, "-bg_mean_stdev", false, false);
-    PXOPT_LOOKUP_F64(user_1, config->args, "-user_1", false, false);
-    PXOPT_LOOKUP_F64(user_2, config->args, "-user_2", false, false);
-    PXOPT_LOOKUP_F64(user_3, config->args, "-user_3", false, false);
-    PXOPT_LOOKUP_F64(user_4, config->args, "-user_4", false, false);
-    PXOPT_LOOKUP_F64(user_5, config->args, "-user_5", false, false);
-    PXOPT_LOOKUP_STR(path_base, config->args, "-path_base", false, false);
-
-    if (!detNormalizedImfileInsert(config->dbh,
-        (psS64)atoll(det_id),
-        iteration,
-        class_id,
-        uri,
-        bg,
-        bg_stdev,
-        bg_mean_stdev,
-        user_1,
-        user_2,
-        user_3,
-        user_4,
-        user_5,
-        path_base,
-        code
-    )) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-
-    return true;
-}
-
-static bool normalizedimfileMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id",    "det_id", "==");
-    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
-    PXOPT_COPY_STR(config->args, where, "-class_id",  "class_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-recip",     "recipe", "==");
-
-    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
-    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-    PXOPT_LOOKUP_BOOL(faulted, config->args, "-faulted", false);
-
-    psString query = pxDataGet("dettool_normalizedimfile.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(where, "detNormalizedImfile");
-        psStringAppend(&query, " AND %s", whereClause);
-        psFree(whereClause);
-    }
-    psFree(where);
-
-    if (faulted) {
-        // list only faulted rows
-        psStringAppend(&query, " %s", "AND detNormalizedImfile.fault != 0");
-    } else {
-        // don't list faulted rows
-        psStringAppend(&query, " %s", "AND detNormalizedImfile.fault = 0");
-    }
-
-    // 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("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "detNormalizedImfile", !simple)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print array");
-        psFree(output);
-        return false;
-    }
-
-    psFree(output);
-
-    return true;
-}
-
-
-static bool revertnormalizedimfileMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id",    "det_id", "==");
-    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
-    PXOPT_COPY_STR(config->args, where, "-class_id",  "class_id", "==");
-    PXOPT_COPY_S16(config->args, where, "-code",      "fault", "==");
-
-    psString query = pxDataGet("dettool_revertnormalizedimfile.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(where, "detNormalizedImfile");
-        psStringAppend(&query, " AND %s", whereClause);
-        psFree(whereClause);
-    }
-    psFree(where);
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    if (psDBAffectedRows(config->dbh) < 1) {
-        psError(PS_ERR_UNKNOWN, false, "should have affected atleast 1 row");
-        return false;
-    }
-
-    return true;
-}
-
-static bool tonormalizedexpMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
-    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-
-    psString query = pxDataGet("dettool_tonormalizedexp.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    // 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("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "detPendingNormExp", !simple)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print array");
-        psFree(output);
-        return false;
-    }
-
-    psFree(output);
-
-    return true;
-}
-
-static bool addnormalizedexpMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-    
-    PXOPT_LOOKUP_STR(det_id, config->args, "-det_id", true, false); // required
-    PXOPT_LOOKUP_S32(iteration, config->args, "-iteration", false, false);
-    PXOPT_LOOKUP_S16(code, config->args, "-code", false, false);
-    PXOPT_LOOKUP_STR(recipe, config->args, "-recip", (code == 0), false); // Required if code == 0
-    PXOPT_LOOKUP_F64(bg, config->args, "-bg", false, false);
-    PXOPT_LOOKUP_F64(bg_stdev, config->args, "-bg_stdev", false, false);
-    PXOPT_LOOKUP_F64(bg_mean_stdev, config->args, "-bg_mean_stdev", false, false);
-    PXOPT_LOOKUP_F64(user_1, config->args, "-user_1", false, false);
-    PXOPT_LOOKUP_F64(user_2, config->args, "-user_2", false, false);
-    PXOPT_LOOKUP_F64(user_3, config->args, "-user_3", false, false);
-    PXOPT_LOOKUP_F64(user_4, config->args, "-user_4", false, false);
-    PXOPT_LOOKUP_F64(user_5, config->args, "-user_5", false, false);
-    PXOPT_LOOKUP_STR(path_base, config->args, "-path_base", false, false);
-
-    psString query = pxDataGet("dettool_tonormalizedexp.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    // XXX in some other places, we put the arguments in the .sql and supply them to RunQuery
-    psStringAppend(&query, " WHERE det_id = %s AND iteration = %d", det_id, iteration);
-
-    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("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-    psFree(output);
-
-    // insert the new row into the detProcessedImfile table
-    if (!detNormalizedExpInsert(config->dbh,
-        (psS64)atoll(det_id),
-        iteration,
-        recipe,
-        bg,
-        bg_stdev,
-        bg_mean_stdev,
-        user_1,
-        user_2,
-        user_3,
-        user_4,
-        user_5,
-        path_base,
-        code
-    )) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-
-    return true;
-}
-
-
-static bool normalizedexpMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id",    "det_id", "==");
-    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
-    PXOPT_COPY_STR(config->args, where, "-recip",  "recipe", "==");
-
-    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
-    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-    PXOPT_LOOKUP_BOOL(faulted, config->args, "-faulted", false);
-
-    psString query = pxDataGet("dettool_normalizedexp.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereSQL(where, NULL);
-        psStringAppend(&query, " %s", whereClause);
-        psFree(whereClause);
-    }
-    psFree(where);
-
-    if (faulted) {
-        // list only faulted rows
-        psStringAppend(&query, " %s", "AND detNormalizedExp.fault != 0");
-    } else {
-        // don't list faulted rows
-        psStringAppend(&query, " %s", "AND detNormalizedExp.fault = 0");
-    }
-
-    // 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("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "detNormalizedExp", !simple)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print array");
-        psFree(output);
-        return false;
-    }
-
-    psFree(output);
-
-    return true;
-}
-
-
-
-static bool revertnormalizedexpMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id",    "det_id", "==");
-    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
-    PXOPT_COPY_S16(config->args, where, "-code",      "fault", "==");
-
-    psString query = pxDataGet("dettool_revertnormalizedexp.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(where, "detNormalizedExp");
-        psStringAppend(&query, " AND %s", whereClause);
-        psFree(whereClause);
-    }
-    psFree(where);
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    if (psDBAffectedRows(config->dbh) < 1) {
-        psError(PS_ERR_UNKNOWN, false, "should have affected atleast 1 row");
-        return false;
-    }
-
-    return true;
-}
-
-
-static bool toresidimfileMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
-    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-
-    psString query = pxDataGet("dettool_toresidimfile.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    // 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("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "detPendingResidImfile", !simple)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print array");
-        psFree(output);
-        return false;
-    }
-
-    psFree(output);
-
-    return true;
-}
-
-
-static bool addresidimfileMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    
-    PXOPT_LOOKUP_STR(det_id, config->args, "-det_id", true, false); // required
-    PXOPT_LOOKUP_S32(iteration, config->args, "-iteration", false, false);
-    PXOPT_LOOKUP_STR(exp_id, config->args, "-exp_id", true, false); // required
-    PXOPT_LOOKUP_STR(class_id, config->args, "-class_id", true, false); // required
-    PXOPT_LOOKUP_S16(code, config->args, "-code", false, false);
-    PXOPT_LOOKUP_STR(uri, config->args, "-uri", (code == 0), false); // Required if code == 0
-    PXOPT_LOOKUP_STR(recipe, config->args, "-recip", (code == 0), false); // Required if code == 0
-    PXOPT_LOOKUP_F64(bg, config->args, "-bg", false, false);
-    PXOPT_LOOKUP_F64(bg_stdev, config->args, "-bg_stdev", false, false);
-    PXOPT_LOOKUP_F64(bg_mean_stdev, config->args, "-bg_mean_stdev", false, false);
-    PXOPT_LOOKUP_F64(bg_skewness, config->args, "-bg_skewness", false, false);
-    PXOPT_LOOKUP_F64(bg_kurtosis, config->args, "-bg_kurtosis", false, false);
-    PXOPT_LOOKUP_F64(bin_stdev, config->args, "-bin_stdev", false, false);
-    PXOPT_LOOKUP_F64(fringe_0, config->args, "-fringe_0", false, false);
-    PXOPT_LOOKUP_F64(fringe_1, config->args, "-fringe_1", false, false);
-    PXOPT_LOOKUP_F64(fringe_2, config->args, "-fringe_2", false, false);
-    PXOPT_LOOKUP_F64(fringe_resid_0, config->args, "-fringe_resid_0", false, false);
-    PXOPT_LOOKUP_F64(fringe_resid_1, config->args, "-fringe_resid_1", false, false);
-    PXOPT_LOOKUP_F64(fringe_resid_2, config->args, "-fringe_resid_2", false, false);
-    PXOPT_LOOKUP_F64(user_1, config->args, "-user_1", false, false);
-    PXOPT_LOOKUP_F64(user_2, config->args, "-user_2", false, false);
-    PXOPT_LOOKUP_F64(user_3, config->args, "-user_3", false, false);
-    PXOPT_LOOKUP_F64(user_4, config->args, "-user_4", false, false);
-    PXOPT_LOOKUP_F64(user_5, config->args, "-user_5", false, false);
-    PXOPT_LOOKUP_STR(path_base, config->args, "-path_base", false, false);
-
-    if (!detResidImfileInsert(config->dbh,
-            (psS64)atoll(det_id),
-            iteration,
-            (psS64)atoll(exp_id),
-            class_id,
-            uri,
-            recipe,
-            bg,
-            bg_stdev,
-            bg_mean_stdev,
-            bg_skewness,
-            bg_kurtosis,
-            bin_stdev,
-            fringe_0,
-            fringe_1,
-            fringe_2,
-            fringe_resid_0,
-            fringe_resid_1,
-            fringe_resid_2,
-            user_1,
-            user_2,
-            user_3,
-            user_4,
-            user_5,
-            path_base,
-            code
-    )) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-
-    return true;
-}
-
-
-static bool residimfileMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id",     "det_id", "==");
-    PXOPT_COPY_S32(config->args, where, "-iteration",  "iteration", "==");
-    PXOPT_COPY_STR(config->args, where, "-exp_id",     "exp_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-class_id",   "class_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-recip",      "recipe", "==");
-
-    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
-    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-    PXOPT_LOOKUP_BOOL(faulted, config->args, "-faulted", false);
-
-    psString query = pxDataGet("dettool_residimfile.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    // NOTE: the query ends in a WHERE, add the required restriction on detRun.state
-    char *value = NULL;
-    bool status;
-    if ((value = psMetadataLookupStr(&status, config->args, "-select_state"))) {
-        psStringAppend(&query, " detRun.state = '%s'", value);
-    } else {
-        psStringAppend(&query, " detRun.state = 'run'");
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(where, "detResidImfile");
-        psStringAppend(&query, " AND %s", whereClause);
-        psFree(whereClause);
-    }
-    psFree(where);
-
-    if (faulted) {
-        // list only faulted rows
-        psStringAppend(&query, " %s", "AND detResidImfile.fault != 0");
-    } else {
-        // don't list faulted rows
-        psStringAppend(&query, " %s", "AND detResidImfile.fault = 0");
-    }
-
-    // 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("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "rawResidImfile", !simple)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print array");
-        psFree(output);
-        return false;
-    }
-
-    psFree(output);
-
-    return true;
-}
-
-
-static bool revertresidimfileMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id",    "det_id", "==");
-    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
-    PXOPT_COPY_STR(config->args, where, "-exp_id",  "exp_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-class_id",  "class_id", "==");
-    PXOPT_COPY_S16(config->args, where, "-code",      "fault", "==");
-
-    psString query = pxDataGet("dettool_revertresidimfile.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(where, "detResidImfile");
-        psStringAppend(&query, " AND %s", whereClause);
-        psFree(whereClause);
-    }
-    psFree(where);
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    if (psDBAffectedRows(config->dbh) < 1) {
-        psError(PS_ERR_UNKNOWN, false, "should have affected atleast 1 row");
-        return false;
-    }
-
-    return true;
-}
-
-
-/*
-  The SQL returns a list of exposures for which all component class ids have had residuals
-  created.  This list includes the detrend id, iteration, exposure id, detrend type, and
-  whether the exposure was included in the stack for this iteration.
-*/
-
-static bool toresidexpMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
-    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-
-    psString query = pxDataGet("dettool_toresidexp.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    // 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("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "detPendingResidExp", !simple)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print array");
-        psFree(output);
-        return false;
-    }
-
-    psFree(output);
-
-    return true;
-}
-
-/*
-  The SQL returns a list of exposures for which all component class ids have had residuals
-  created.  This list includes the detrend id, iteration, exposure id, detrend type, and
-  whether the exposure was included in the stack for this iteration.
-*/
-
-static bool addresidexpMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    // limit search by det_id, iteration, exp_id
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id", "det_id", "==");
-    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
-    PXOPT_COPY_STR(config->args, where, "-exp_id", "exp_id", "==");
-
-    PXOPT_LOOKUP_STR(det_id, config->args, "-det_id", true, false); // required
-    PXOPT_LOOKUP_S32(iteration, config->args, "-iteration", false, false);
-    PXOPT_LOOKUP_STR(exp_id, config->args, "-exp_id", true, false); // required
-    PXOPT_LOOKUP_S16(code, config->args, "-code", false, false);
-    PXOPT_LOOKUP_STR(recipe, config->args, "-recip", (code == 0), false); // Required if code == 0
-    PXOPT_LOOKUP_F64(bg, config->args, "-bg", false, false);
-    PXOPT_LOOKUP_F64(bg_stdev, config->args, "-bg_stdev", false, false);
-    PXOPT_LOOKUP_F64(bg_mean_stdev, config->args, "-bg_mean_stdev", false, false);
-    PXOPT_LOOKUP_F64(bg_skewness, config->args, "-bg_skewness", false, false);
-    PXOPT_LOOKUP_F64(bg_kurtosis, config->args, "-bg_kurtosis", false, false);
-    PXOPT_LOOKUP_F64(bin_stdev, config->args, "-bin_stdev", false, false);
-    PXOPT_LOOKUP_F64(fringe_0, config->args, "-fringe_0", false, false);
-    PXOPT_LOOKUP_F64(fringe_1, config->args, "-fringe_1", false, false);
-    PXOPT_LOOKUP_F64(fringe_2, config->args, "-fringe_2", false, false);
-    PXOPT_LOOKUP_F64(fringe_resid_0, config->args, "-fringe_resid_0", false, false);
-    PXOPT_LOOKUP_F64(fringe_resid_1, config->args, "-fringe_resid_1", false, false);
-    PXOPT_LOOKUP_F64(fringe_resid_2, config->args, "-fringe_resid_2", false, false);
-    PXOPT_LOOKUP_F64(user_1, config->args, "-user_1", false, false);
-    PXOPT_LOOKUP_F64(user_2, config->args, "-user_2", false, false);
-    PXOPT_LOOKUP_F64(user_3, config->args, "-user_3", false, false);
-    PXOPT_LOOKUP_F64(user_4, config->args, "-user_4", false, false);
-    PXOPT_LOOKUP_F64(user_5, config->args, "-user_5", false, false);
-    PXOPT_LOOKUP_STR(path_base, config->args, "-path_base", false, false);
-    PXOPT_LOOKUP_BOOL(reject, config->args, "-reject", false);
-
-    psString query = pxDataGet("dettool_toresidexp.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    if (psListLength(where->list)) {
-	psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
-	psStringAppend(&query, " WHERE %s", whereClause);
-	psFree(whereClause);
-    }
-    psFree(where);
-
-    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)) {
-        // XXX check psError here
-        psError(PS_ERR_UNKNOWN, false, "no detResidImfile rows found");
-        psFree(output);
-        return false;
-    }
-    psFree(output);
-
-    if (!detResidExpInsert(config->dbh,
-            (psS64)atoll(det_id),
-            iteration,
-            (psS64)atoll(exp_id),
-            recipe,
-            bg,
-            bg_stdev,
-            bg_mean_stdev,
-            bg_skewness,
-            bg_kurtosis,
-            bin_stdev,
-            fringe_0,
-            fringe_1,
-            fringe_2,
-            fringe_resid_0,
-            fringe_resid_1,
-            fringe_resid_2,
-            user_1,
-            user_2,
-            user_3,
-            user_4,
-            user_5,
-            path_base,
-            !reject,
-            code
-        )) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-
-    return true;
-}
-
-static bool residexpMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id",    "det_id", "==");
-    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
-    PXOPT_COPY_STR(config->args, where, "-exp_id",    "exp_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-recip",     "recipe", "==");
-
-    PXOPT_LOOKUP_U64(limit,    config->args, "-limit", false, false);
-    PXOPT_LOOKUP_BOOL(simple,  config->args, "-simple", false);
-    PXOPT_LOOKUP_BOOL(faulted, config->args, "-faulted", false);
-    PXOPT_LOOKUP_BOOL(reject,  config->args, "-reject", false);
-
-    psString query = pxDataGet("dettool_residexp.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(where, "detResidExp");
-        psStringAppend(&query, " AND %s", whereClause);
-        psFree(whereClause);
-    }
-    psFree(where);
-
-    if (faulted) {
-        // list only faulted rows
-        psStringAppend(&query, " %s", "AND detResidExp.fault != 0");
-    } else {
-        // don't list faulted rows
-        psStringAppend(&query, " %s", "AND detResidExp.fault = 0");
-    }
-
-    // list only accepted rows
-    // XXX the usage of this flag is unclear : -reject means "accepted"?
-    if (reject) {
-        psStringAppend(&query, " %s", "AND detResidExp.accept != 0");
-    } 
-
-    // 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("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "detResidExp", !simple)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print array");
-        psFree(output);
-        return false;
-    }
-
-    psFree(output);
-
-    return true;
-}
-
-
-static bool revertresidexpMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id",    "det_id", "==");
-    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
-    PXOPT_COPY_STR(config->args, where, "-exp_id",    "exp_id", "==");
-    PXOPT_COPY_S16(config->args, where, "-code",      "fault", "==");
-
-    psString query = pxDataGet("dettool_revertresidexp.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(where, "detResidExp");
-        psStringAppend(&query, " AND %s", whereClause);
-        psFree(whereClause);
-    }
-    psFree(where);
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    if (psDBAffectedRows(config->dbh) < 1) {
-        psError(PS_ERR_UNKNOWN, false, "should have affected atleast 1 row");
-        return false;
-    }
-
-    return true;
-}
-
-
-static bool updateresidexpMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    PXOPT_LOOKUP_BOOL(reject, config->args, "-reject", false);
-
-    // build a query to search by det_id, iteration, exp_id
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id", "det_id", "==");
-    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
-    PXOPT_COPY_STR(config->args, where, "-exp_id", "exp_id", "==");
-
-    // find the values we're going to set
-    // copy everything but det_id, iteration, & exp_id from the args and
-    // remove the '-' prefix
-    psMetadata *set = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, set, "-recip", "recipe", "==");
-    PXOPT_COPY_F64(config->args, set, "-bg", "bg", "==");
-    PXOPT_COPY_F64(config->args, set, "-bg_stdev", "bg_stdev", "==");
-    PXOPT_COPY_F64(config->args, set, "-bg_mean_stdev", "bg_mean_stdev", "==");
-    PXOPT_COPY_STR(config->args, set, "-path_base", "path_base", "==");
-
-    // this can't be PXOPT_ macro-ized as reject is !'d
-    if (!psMetadataAddBool(set, PS_LIST_TAIL, "accept", 0, "==", !reject)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item accept");
-        psFree(set);
-        psFree(where);
-        return false;
-    }
-
-    long changed = psDBUpdateRows(config->dbh, "detResidExp", where, set);
-    psFree(set);
-    psFree(where);
-
-    if (changed < 0) {
-        psError(PS_ERR_UNKNOWN, false, "no rows were updated");
-        return false;
-    }
-
-    return true;
-}
-
-/* The SQL returns a list of detrend runs (with detrend id, iteration and detrend type) which
- * have completed all residexps.
- */
-
-static bool todetrunsummaryMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
-    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-
-    psString query = pxDataGet("dettool_todetrunsummary.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    // 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("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "detRejectExp", !simple)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print array");
-        psFree(output);
-        return false;
-    }
-
-    psFree(output);
-
-    return true;
-}
-
-// this function is used to generate the detrunSummary entries used below
-// XXX why is this a separate function?  roll it back into adddetrunsummary?
-static detRunSummaryRow *mdToDetRunSummary(pxConfig *config, psMetadata *row)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    bool status = false;
-    // from row
-    psS64 det_id = psMetadataLookupS64(&status, row, "det_id");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for det_id");
-        return false;
-    }
-    psS32 iteration = psMetadataLookupS32(&status, row, "iteration");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for iteration");
-        return false;
-    }
-
-    // optional
-    PXOPT_LOOKUP_F64(bg, config->args, "-bg", false, false);
-    PXOPT_LOOKUP_F64(bg_stdev, config->args, "-bg_stdev", false, false);
-    PXOPT_LOOKUP_F64(bg_mean_stdev, config->args, "-bg_mean_stdev", false, false);
-
-    // default values
-    PXOPT_LOOKUP_S16(code, config->args, "-code", false, false);
-    PXOPT_LOOKUP_BOOL(accept, config->args, "-accept", false);
-
-    return detRunSummaryRowAlloc(
-            det_id,
-            iteration,
-            bg,
-            bg_stdev,
-            bg_mean_stdev,
-            accept,
-            code
-        );
-}
-
-static bool adddetrunsummaryMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-    
-    // build a query to search by det_id, iteration, exp_id
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id", "det_id", "==");
-    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
-
-    PXOPT_LOOKUP_STR(det_id, config->args, "-det_id", true, false); // required
-    PXOPT_LOOKUP_BOOL(again, config->args, "-again", false);
-
-    // The values supplied as arguments on the command (eg, -bg) are parsed 
-    // by mdToDetRunSummary below. 
-    // XXX why is there ever more than one?
-
-    psString query = pxDataGet("dettool_find_completed_runs.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
-	psStringAppend(&query, " WHERE %s", whereClause);
-	psFree(whereClause);
-    }
-    psFree(where);
-
-    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("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // start a transaction so it's all rows or nothing
-    if (!psDBTransaction(config->dbh)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(output);
-        return false;
-    }
-
-    // XXX why is there ever more than one result here?
-    for (long i = 0; i < psArrayLength(output); i++) {
-        psMetadata *row = output->data[i];
-        // convert metadata into a detResidExp object
-        detRunSummaryRow *runSummary = mdToDetRunSummary(config, row);
-        if (!runSummary) {
-            if (!psDBRollback(config->dbh)) {
-                psError(PS_ERR_UNKNOWN, false, "database error");
-            }
-            psError(PS_ERR_UNKNOWN, false, "failed to convert metadata to detResidExp");
-            psFree(output);
-            return false;
-        }
-        // insert detResidExp object into the database
-        if (!detRunSummaryInsertObject(config->dbh, runSummary)) {
-            if (!psDBRollback(config->dbh)) {
-                psError(PS_ERR_UNKNOWN, false, "database error");
-            }
-            psError(PS_ERR_UNKNOWN, false, "database error");
-            psFree(runSummary);
-            psFree(output);
-            return false;
-        }
-        psFree(runSummary);
-    }
-
-    psFree(output);
-
-    // XXX this logic does not deal with the case of -code being set
-    // XXX it should be an error for -again and -code to both be set
-    if (again) {
-        if (!startNewIteration(config, (psS64)atoll(det_id))) {
-            if (!psDBRollback(config->dbh)) {
-                psError(PS_ERR_UNKNOWN, false, "database error");
-            }
-            psError(PS_ERR_UNKNOWN, false, "failed to start new iteration");
-            return false;
-        }
-    } else {
-        // set detRun.state to stop
-        if (!setDetRunState(config, (psS64)atoll(det_id), "stop")) {
-            if (!psDBRollback(config->dbh)) {
-                psError(PS_ERR_UNKNOWN, false, "database error");
-            }
-            psError(PS_ERR_UNKNOWN, false, "failed to set detRun.state");
-            return false;
-        }
-    }
-
-    if (!psDBCommit(config->dbh)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-    return true;
-}
-
-static bool detrunsummaryMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id",    "det_id", "==");
-    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
-
-    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
-    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-    PXOPT_LOOKUP_BOOL(faulted, config->args, "-faulted", false);
-
-    psString query = pxDataGet("dettool_detrunsummary.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        psFree(where);
-        return false;
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(where, "NULL");
-        psStringAppend(&query, " AND %s", whereClause);
-        psFree(whereClause);
-    }
-    psFree(where);
-
-    if (faulted) {
-        // list only faulted rows
-        psStringAppend(&query, " %s", "AND detRunSummary.fault != 0");
-    } else {
-        // don't list faulted rows
-        psStringAppend(&query, " %s", "AND detRunSummary.fault = 0");
-    }
-
-    // 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("dettool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "rawDetrendImfile", !simple)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print array");
-        psFree(output);
-        return false;
-    }
-
-    psFree(output);
-
-    return true;
-}
-
-
-static bool revertdetrunsummaryMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-det_id",    "det_id", "==");
-    PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
-    PXOPT_COPY_STR(config->args, where, "-code",      "fault", "==");
-
-    psString query = pxDataGet("dettool_revertdetrunsummary.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(where, "detRunSummary");
-        psStringAppend(&query, " AND %s", whereClause);
-        psFree(whereClause);
-    }
-    psFree(where);
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    if (psDBAffectedRows(config->dbh) < 1) {
-        psError(PS_ERR_UNKNOWN, false, "should have affected atleast 1 row");
-        return false;
-    }
-
-    return true;
-}
-
-
-static bool updatedetrunsummaryMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-    
-    PXOPT_LOOKUP_STR(det_id, config->args, "-det_id", true, false); // required
-    PXOPT_LOOKUP_BOOL(accept, config->args, "-accept", false);
-    PXOPT_LOOKUP_BOOL(reject, config->args, "-reject", false);
-
-    if (accept && reject) {
-        psError(PS_ERR_UNKNOWN, true, "-accept and -reject are exclusive");
-        return false;
-    }
-
-    if (!(accept || reject)) {
-        psError(PS_ERR_UNKNOWN, true, "either -accept or -reject is required");
-        return false;
-    }
-
-    char *query = "UPDATE detRunSummary SET accept = %d WHERE det_id = %"PRId64; 
-    if (!p_psDBRunQuery(config->dbh, query, accept, (psS64)atoll(det_id))) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-
-    return true;
-}
-
-
 static bool updatedetrunMode(pxConfig *config)
 {
     PS_ASSERT_PTR_NON_NULL(config, false);
 
-    PXOPT_LOOKUP_STR(det_id, config->args, "-det_id", true, false); // required
+    PXOPT_LOOKUP_S64(det_id, config->args, "-det_id", true, false); // required
     PXOPT_LOOKUP_BOOL(again, config->args, "-again", false);
     PXOPT_LOOKUP_STR(state, config->args, "-state", false, false);
@@ -3613,10 +1243,10 @@
     if (state) {
         // set detRun.state to state
-        return setDetRunState(config, (psS64)atoll(det_id), state);
+        return setDetRunState(config, det_id, state);
     }
 
     // else
     // -again
-    if (!startNewIteration(config, (psS64)atoll(det_id))) {
+    if (!startNewIteration(config, det_id)) {
         psError(PS_ERR_UNKNOWN, false, "failed to start new iteration");
         return false;
@@ -3627,5 +1257,5 @@
 
 // used by updatedetrunMode 
-static bool startNewIteration(pxConfig *config, psS64 det_id)
+bool startNewIteration(pxConfig *config, psS64 det_id)
 {
     PS_ASSERT_PTR_NON_NULL(config, false);
@@ -3739,5 +1369,5 @@
 
     // det_id is required
-    PXOPT_LOOKUP_STR(det_id, config->args, "-det_id", true, false);
+    PXOPT_LOOKUP_S64(det_id, config->args, "-det_id", true, false);
 
     // we have to support multipe exp_ids
@@ -3784,6 +1414,5 @@
 
     // add the det_id & iteration == 0 to the where clause
-    if (!psMetadataAddS64(where, PS_LIST_TAIL, "det_id", 0, "==",
-                (psS64)atoll(det_id))) {
+    if (!psMetadataAddS64(where, PS_LIST_TAIL, "det_id", 0, "==", det_id)) {
         psError(PS_ERR_UNKNOWN, false, "failed to add item det_id");
         psFree(where);
@@ -3822,5 +1451,5 @@
 
     // up the detRuns iteration count
-    psS32 newIteration = incrementIteration(config, (psS64)atoll(det_id));
+    psS32 newIteration = incrementIteration(config, det_id);
     if (!newIteration) {
         // rollback
@@ -3846,5 +1475,5 @@
             }
             // invalid exp_id
-            psError(PS_ERR_UNKNOWN, false, "exp_id %s is invalid for det_id %s",
+            psError(PS_ERR_UNKNOWN, false, "exp_id %s is invalid for det_id %" PRId64,
                     (char *)mItem->data.V, det_id);
             psFree(iter);
@@ -3853,5 +1482,5 @@
         }
         detInputExpRow *newInputExp = detInputExpRowAlloc(
-            (psS64)atoll(det_id),
+	    det_id,
             newIteration,
             inputExp->exp_id,
@@ -3912,5 +1541,5 @@
     PXOPT_LOOKUP_TIME(use_begin, config->args, "-use_begin", false, false);
     PXOPT_LOOKUP_TIME(use_end, config->args, "-use_end", false, false);
-    PXOPT_LOOKUP_STR(parent, config->args, "-parent", false, false);
+    PXOPT_LOOKUP_S64(parent, config->args, "-parent", false, false);
     PXOPT_LOOKUP_STR(label, config->args, "-label", false, false);
     PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
@@ -3950,5 +1579,5 @@
                       solang_max,
                       label,      // label
-                      parent ? (psS64)atoll(parent) : 0
+                      parent
             )) {
         psError(PS_ERR_UNKNOWN, false, "database error");
@@ -4001,5 +1630,5 @@
     PS_ASSERT_PTR_NON_NULL(config, false);
     
-    PXOPT_LOOKUP_STR(det_id, config->args, "-det_id", true, false); // required
+    PXOPT_LOOKUP_S64(det_id, config->args, "-det_id", true, false); // required
     PXOPT_LOOKUP_STR(class_id, config->args, "-class_id", true, false); // required
     PXOPT_LOOKUP_STR(uri, config->args, "-uri", true, false); // required
@@ -4015,19 +1644,20 @@
 
     if (!detRegisteredImfileInsert(config->dbh,
-        (psS64)atoll(det_id),
-        0,  // the iteration is fixed at 0
-        class_id,
-        uri,
-        bg,
-        bg_stdev,
-        bg_mean_stdev,
-        user_1,
-        user_2,
-        user_3,
-        user_4,
-        user_5,
-        path_base,
-        0       // fault code
-    )) {
+				   det_id,
+				   0,  // the iteration is fixed at 0
+				   class_id,
+				   uri,
+				   bg,
+				   bg_stdev,
+				   bg_mean_stdev,
+				   user_1,
+				   user_2,
+				   user_3,
+				   user_4,
+				   user_5,
+				   path_base,
+				   "full",				   
+				   0       // fault code
+	    )) {
         psError(PS_ERR_UNKNOWN, false, "database error");
         return false;
@@ -4075,5 +1705,5 @@
 }
 
-static bool setDetRunState(pxConfig *config, psS64 det_id, const char *state)
+bool setDetRunState(pxConfig *config, psS64 det_id, const char *state)
 {
     PS_ASSERT_PTR_NON_NULL(config, false);
@@ -4103,5 +1733,17 @@
 }
 
-static bool isValidMode(pxConfig *config, const char *mode)
+bool isValidDataState (const char *data_state) {
+
+    // check that state is a valid string value
+    if (!strncmp(data_state, "run", 4)) return true;
+    if (!strncmp(data_state, "stop", 5)) return true;
+    if (!strncmp(data_state, "drop", 5)) return true;
+    if (!strncmp(data_state, "register", 4)) return true;
+
+    psError(PS_ERR_UNKNOWN, true, "invalid data state: %s", data_state);
+    return false;
+}
+
+bool isValidMode(pxConfig *config, const char *mode)
 {
     PS_ASSERT_PTR_NON_NULL(config, false);
@@ -4122,4 +1764,177 @@
 }
 
+
+bool setProcessedImfileDataState(pxConfig *config, psS64 det_id, psS64 exp_id, const char *class_id, const char *data_state)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+    PS_ASSERT_PTR_NON_NULL(data_state, false);
+    PS_ASSERT_PTR_NON_NULL(class_id, false);
+
+    if (!isValidDataState (data_state)) return false;
+
+    char *query = "UPDATE detProcessedImfile SET data_state = '%s'"
+	" WHERE det_id = %" PRId64
+	" AND exp_id = %" PRId64 
+	" AND class_id = '%s'";
+    if (!p_psDBRunQuery(config->dbh, query, data_state, det_id, exp_id, class_id)) {
+        psError(PS_ERR_UNKNOWN, false,
+                "failed to change state for det_id %" PRId64 ", exp_id %" PRId64 ", class_id %s", 
+		det_id, exp_id, class_id);
+        return false;
+    }
+
+    return true;
+}
+
+bool setProcessedExpDataState(pxConfig *config, psS64 det_id, psS64 exp_id, const char *data_state)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+    PS_ASSERT_PTR_NON_NULL(data_state, false);
+
+    if (!isValidDataState (data_state)) return false;
+
+    char *query = "UPDATE detProcessedExp SET data_state = '%s'"
+	" WHERE det_id = %" PRId64
+	" AND exp_id = %" PRId64;
+    if (!p_psDBRunQuery(config->dbh, query, data_state, det_id, exp_id)) {
+        psError(PS_ERR_UNKNOWN, false,
+                "failed to change state for det_id %" PRId64 ", exp_id %" PRId64, 
+		det_id, exp_id);
+        return false;
+    }
+
+    return true;
+}
+
+
+bool setStackedImfileDataState(pxConfig *config, psS64 det_id, psS32 iteration, const char *class_id, const char *data_state)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+    PS_ASSERT_PTR_NON_NULL(class_id, false);
+    PS_ASSERT_PTR_NON_NULL(data_state, false);
+
+    if (!isValidDataState (data_state)) return false;
+
+    char *query = "UPDATE detStackedImfile SET data_state = '%s'"
+	" WHERE det_id = %" PRId64
+	" AND iteration = %" PRId32
+	" AND class_id = %s";
+    if (!p_psDBRunQuery(config->dbh, query, data_state, det_id, iteration, class_id)) {
+        psError(PS_ERR_UNKNOWN, false,
+                "failed to change state for det_id %" PRId64 ", iteration %" PRId32 "class_id %s", 
+		det_id, iteration, class_id);
+        return false;
+    }
+
+    return true;
+}
+
+bool setNormStatImfileDataState(pxConfig *config, psS64 det_id, psS32 iteration, const char *class_id, const char *data_state)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+    PS_ASSERT_PTR_NON_NULL(class_id, false);
+    PS_ASSERT_PTR_NON_NULL(data_state, false);
+
+    if (!isValidDataState (data_state)) return false;
+
+    char *query = "UPDATE detNormalizedStatImfile SET data_state = '%s'"
+	" WHERE det_id = %" PRId64
+	" AND iteration = %" PRId32
+	" AND class_id = %s";
+    if (!p_psDBRunQuery(config->dbh, query, data_state, det_id, iteration)) {
+        psError(PS_ERR_UNKNOWN, false,
+                "failed to change state for det_id %" PRId64 ", iteration %" PRId32, 
+		det_id, iteration);
+        return false;
+    }
+
+    return true;
+}
+
+bool setNormImfileDataState(pxConfig *config, psS64 det_id, psS32 iteration, const char *class_id, const char *data_state)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+    PS_ASSERT_PTR_NON_NULL(class_id, false);
+    PS_ASSERT_PTR_NON_NULL(data_state, false);
+
+    if (!isValidDataState (data_state)) return false;
+
+    char *query = "UPDATE detNormalizedImfile SET data_state = '%s'"
+	" WHERE det_id = %" PRId64
+	" AND iteration = %" PRId32
+	" AND class_id = %s";
+    if (!p_psDBRunQuery(config->dbh, query, data_state, det_id, iteration, class_id)) {
+        psError(PS_ERR_UNKNOWN, false,
+                "failed to change state for det_id %" PRId64 ", iteration %" PRId32 " class %s", 
+		det_id, iteration, class_id);
+        return false;
+    }
+
+    return true;
+}
+
+bool setNormExpDataState(pxConfig *config, psS64 det_id, psS32 iteration, const char *data_state)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+    PS_ASSERT_PTR_NON_NULL(data_state, false);
+
+    if (!isValidDataState (data_state)) return false;
+
+    char *query = "UPDATE detNormalizedExp SET data_state = '%s'"
+	" WHERE det_id = %" PRId64
+	" AND iteration = %" PRId32;
+    if (!p_psDBRunQuery(config->dbh, query, data_state, det_id, iteration)) {
+        psError(PS_ERR_UNKNOWN, false,
+                "failed to change state for det_id %" PRId64 ", iteration %" PRId32, 
+		det_id, iteration);
+        return false;
+    }
+
+    return true;
+}
+
+bool setResidImfileDataState(pxConfig *config, psS64 det_id, psS32 iteration, psS64 exp_id, const char *class_id, const char *data_state)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+    PS_ASSERT_PTR_NON_NULL(data_state, false);
+    PS_ASSERT_PTR_NON_NULL(class_id, false);
+
+    if (!isValidDataState (data_state)) return false;
+
+    char *query = "UPDATE detResidImfile SET data_state = '%s'"
+	" WHERE det_id = %" PRId64
+	" AND iteration = %" PRId32 
+	" AND exp_id = %" PRId64 
+	" AND class_id = '%s'";
+    if (!p_psDBRunQuery(config->dbh, query, data_state, det_id, iteration, exp_id, class_id)) {
+        psError(PS_ERR_UNKNOWN, false,
+                "failed to change state for det_id %" PRId64 ", iteration %" PRId32 ", exp_id %" PRId64 ", class_id %s", 
+		det_id, iteration, exp_id, class_id);
+        return false;
+    }
+
+    return true;
+}
+
+bool setResidExpDataState(pxConfig *config, psS64 det_id, psS32 iteration, psS64 exp_id, const char *data_state)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+    PS_ASSERT_PTR_NON_NULL(data_state, false);
+
+    if (!isValidDataState (data_state)) return false;
+
+    char *query = "UPDATE detResidExp SET data_state = '%s'"
+	" WHERE det_id = %" PRId64
+	" AND iteration = %" PRId32 
+	" AND exp_id = %" PRId64;
+    if (!p_psDBRunQuery(config->dbh, query, data_state, det_id, iteration, exp_id)) {
+        psError(PS_ERR_UNKNOWN, false,
+                "failed to change state for det_id %" PRId64 ", iteration %" PRId32 ", exp_id %" PRId64, 
+		det_id, iteration, exp_id);
+        return false;
+    }
+
+    return true;
+}
 
 #if 0
