Index: /trunk/ippTools/src/camtool.c
===================================================================
--- /trunk/ippTools/src/camtool.c	(revision 11074)
+++ /trunk/ippTools/src/camtool.c	(revision 11075)
@@ -30,5 +30,6 @@
 static bool pendingimfileMode(pxConfig *config);
 static bool addprocessedexpMode(pxConfig *config);
-static bool faultexpMode(pxConfig *config);
+static bool processedexpMode(pxConfig *config);
+static bool updateprocessedexpMode(pxConfig *config);
 static bool blockMode(pxConfig *config);
 static bool maskedMode(pxConfig *config);
@@ -52,5 +53,6 @@
         MODECASE(P3TOOL_MODE_PENDINGIMFILE,     pendingimfileMode);
         MODECASE(P3TOOL_MODE_ADDPROCESSEDEXP,   addprocessedexpMode);
-        MODECASE(P3TOOL_MODE_FAULTEXP,          faultexpMode);
+        MODECASE(P3TOOL_MODE_PROCESSEDEXP,      processedexpMode);
+        MODECASE(P3TOOL_MODE_UPDATEPROCESSEDEXP,updateprocessedexpMode);
         MODECASE(P3TOOL_MODE_BLOCK,             blockMode);
         MODECASE(P3TOOL_MODE_MASKED,            maskedMode);
@@ -86,16 +88,10 @@
     }
 
-    bool faulted = psMetadataLookupU64(&status, config->args, "-faulted");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -faulted");
-        return false;
-    }
-
     psString query = psStringCopy(
             "SELECT"
             "   p3PendingExp.*,"
-            "   rawScienceExp.camera"
+            "   rawExp.camera"
             " FROM p3PendingExp"
-            " JOIN rawScienceExp"
+            " JOIN rawExp"
             "   USING(exp_tag)"
             " LEFT JOIN p3ProcessedExp"
@@ -114,12 +110,4 @@
     }
 
-    if (faulted) {
-        // list only faulted rows
-        psStringAppend(&query, " %s", "AND p3PendingExp.fault != 0");
-    } else {
-        // don't list faulted rows
-        psStringAppend(&query, " %s", "AND p3PendingExp.fault = 0");
-    }
-
     // treat limit == 0 as "no limit"
     if (limit) {
@@ -177,7 +165,7 @@
             "SELECT"
             "   p2ProcessedImfile.*,"
-            "   rawScienceExp.camera"   
+            "   rawExp.camera"   
             " FROM p3PendingExp"
-            " JOIN rawScienceExp"
+            " JOIN rawExp"
             "   USING(exp_tag)"
             " JOIN p2ProcessedImfile"
@@ -345,4 +333,5 @@
         return false;
     }
+
     // optional
     psString b1_uri = psMetadataLookupStr(&status, config->args, "-b1_uri");
@@ -354,4 +343,11 @@
     if (!status) {
         psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -b2_uri");
+        return false;
+    }
+
+    // default
+    psS8 code = psMetadataLookupS8(&status, config->args, "-code");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -code");
         return false;
     }
@@ -380,7 +376,15 @@
     }
     if (!psArrayLength(output)) {
-        // XXX check psError here
         psError(PS_ERR_UNKNOWN, false, "no p3PendingExp rows found");
+        psFree(output);
         return true;
+    }
+
+    // start a transaction so we don't end up with an exp_tag is both
+    // p3PendingExp & p3ProcessedExp
+    if (!psDBTransaction(config->dbh)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(output);
+        return false;
     }
 
@@ -404,69 +408,91 @@
         pendingRow->p2_version,
         pendingRow->p3_version,
-        pendingRow->label
+        pendingRow->label,
+        code
     );
-    psFree(pendingRow);
 
     // insert the new row into the p3ProcessedImfile table
     if (!p3ProcessedExpInsertObject(config->dbh, row)) {
+        // rollback
+        if (!psDBRollback(config->dbh)) {
+            psError(PS_ERR_UNKNOWN, false, "database error");
+        }
         psError(PS_ERR_UNKNOWN, false, "database error");
         psFree(row);
-        return false;
-    }
-
+        psFree(pendingRow);
+        return false;
+    }
     psFree(row);
 
-    return true;
-}
-
-
-static bool faultexpMode(pxConfig *config)
+    // delete the p3PendingExp row from the database
+    if (!p3PendingExpDeleteObject(config->dbh, pendingRow)) {
+        // rollback
+        if (!psDBRollback(config->dbh)) {
+            psError(PS_ERR_UNKNOWN, false, "database error");
+        }
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(pendingRow);
+        return false;
+    }
+
+    psFree(pendingRow);
+
+    // point of no return for p3PendingExp -> p3ProcessedExp
+    if (!psDBCommit(config->dbh)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+
+    return true;
+}
+
+static bool processedexpMode(pxConfig *config)
 {
     PS_ASSERT_PTR_NON_NULL(config, false);
 
     bool status = false;
-    psS8 code = psMetadataLookupS8(&status, config->args, "-code");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -code");
-        return false;
-    }
-
-    if (!pxSetFaultCode(config->dbh, "p3PendingExp", config->where, code)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to set set fault flag");
-        return false;
-    }
-
-    return true;
-}
-
-
-static bool blockMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    bool status = false;
-    psString label = psMetadataLookupStr(&status, config->args, "-label");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -label");
-        return false;
-    }
-    if (!label) {
-        psError(PS_ERR_UNKNOWN, true, "-label is required");
-        return false;
-    }
-
-    if (!p3MaskInsert(config->dbh, label)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-
-    return true;
-}
-
-static bool maskedMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psString query = psStringCopy("SELECT * FROM p3Mask");
+    psU64 limit = psMetadataLookupU64(&status, config->args, "-limit");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -limit");
+        return false;
+    }
+
+    bool faulted = psMetadataLookupU64(&status, config->args, "-faulted");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -faulted");
+        return false;
+    }
+
+    psString query = psStringCopy(
+            "SELECT"
+            "   p3ProcessedExp.*,"
+            "   rawExp.camera"
+            " FROM p3ProcessedExp"
+            " JOIN rawExp"
+            "   USING(exp_tag)"   
+            " WHERE"
+            "   p3ProcessedExp.exp_tag IS NOT NULL"
+    );
+
+    if (config->where) {
+        psString whereClause = psDBGenerateWhereConditionSQL(config->where, NULL);
+        psStringAppend(&query, " %s", whereClause);
+        psFree(whereClause);
+    }
+
+    if (faulted) {
+        // list only faulted rows
+        psStringAppend(&query, " %s", "AND p3ProcessedExp.fault != 0");
+    } else {
+        // don't list faulted rows
+        psStringAppend(&query, " %s", "AND p3ProcessedExp.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)) {
@@ -484,5 +510,5 @@
     if (!psArrayLength(output)) {
         // XXX check psError here
-        psError(PS_ERR_UNKNOWN, false, "no p3Mask rows found");
+        psError(PS_ERR_UNKNOWN, false, "no p3ProcessedExp rows found");
         psFree(output);
         return true;
@@ -499,4 +525,95 @@
     }
 
+    // negate simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "p3ProcessedExp", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+
+static bool updateprocessedexpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    bool status = false;
+    psS8 code = psMetadataLookupS8(&status, config->args, "-code");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -code");
+        return false;
+    }
+
+    if (!pxSetFaultCode(config->dbh, "p3ProcessedExp", config->where, code)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to set set fault flag");
+        return false;
+    }
+
+    return true;
+}
+
+
+static bool blockMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    bool status = false;
+    psString label = psMetadataLookupStr(&status, config->args, "-label");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -label");
+        return false;
+    }
+    if (!label) {
+        psError(PS_ERR_UNKNOWN, true, "-label is required");
+        return false;
+    }
+
+    if (!p3MaskInsert(config->dbh, label)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+
+    return true;
+}
+
+static bool maskedMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psString query = psStringCopy("SELECT * FROM p3Mask");
+
+    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 p3Mask rows found");
+        psFree(output);
+        return true;
+    }
+
+    bool simple = false;
+    {
+        bool status = false;
+        simple = psMetadataLookupBool(&status, config->args, "-simple");
+        if (!status) {
+            psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -simple");
+            return false;
+        }
+    }
+
     // negative simple so the default is true
     if (!ippdbPrintMetadatas(stdout, output, "p3Mask", !simple)) {
Index: /trunk/ippTools/src/camtool.h
===================================================================
--- /trunk/ippTools/src/camtool.h	(revision 11074)
+++ /trunk/ippTools/src/camtool.h	(revision 11075)
@@ -28,5 +28,6 @@
     P3TOOL_MODE_PENDINGIMFILE,
     P3TOOL_MODE_ADDPROCESSEDEXP,
-    P3TOOL_MODE_FAULTEXP,
+    P3TOOL_MODE_PROCESSEDEXP,
+    P3TOOL_MODE_UPDATEPROCESSEDEXP,
     P3TOOL_MODE_BLOCK,
     P3TOOL_MODE_MASKED,
Index: /trunk/ippTools/src/camtoolConfig.c
===================================================================
--- /trunk/ippTools/src/camtoolConfig.c	(revision 11074)
+++ /trunk/ippTools/src/camtoolConfig.c	(revision 11075)
@@ -51,6 +51,4 @@
     psMetadataAddU64(pendingexpArgs, PS_LIST_TAIL, "-limit",  0,
         "limit result set to N items", 0);
-    psMetadataAddBool(pendingexpArgs, PS_LIST_TAIL, "-faulted",  0,
-        "only return imfiles with a fault status set", false);
     psMetadataAddBool(pendingexpArgs, PS_LIST_TAIL, "-simple", 0,
             "use the simple output format", false);
@@ -97,14 +95,31 @@
     psMetadataAddStr(addprocessedexpArgs, PS_LIST_TAIL, "-b2_uri", 0,
             "define banana 2", NULL);
-
-    // -faultexp
-    psMetadata *faultexpArgs = psMetadataAlloc();
-    psMetadataAddStr(faultexpArgs, PS_LIST_TAIL, "-exp_tag",  0,
+    psMetadataAddS8(addprocessedexpArgs, PS_LIST_TAIL, "-code",  0,
+        "set fault code (required)", 0);
+    psMetadataAddBool(pendingexpArgs, PS_LIST_TAIL, "-faulted",  0,
+        "only return imfiles with a fault status set", false);
+
+    // -processedexp
+    psMetadata *processedexpArgs = psMetadataAlloc();
+    psMetadataAddStr(processedexpArgs, PS_LIST_TAIL, "-exp_tag", 0,
+            "search by exposure ID", NULL);
+    psMetadataAddS32(processedexpArgs, PS_LIST_TAIL, "-p2_version", 0,
+            "search for exposures with this p2 version", -1);
+    psMetadataAddS32(processedexpArgs, PS_LIST_TAIL, "-p3_version", 0,
+            "search for exposures with this p3 version", -1);
+    psMetadataAddU64(processedexpArgs, PS_LIST_TAIL, "-limit",  0,
+        "limit result set to N items", 0);
+    psMetadataAddBool(processedexpArgs, PS_LIST_TAIL, "-simple", 0,
+            "use the simple output format", false);
+
+    // -updateprocessedexp
+    psMetadata *updateprocessedexpArgs = psMetadataAlloc();
+    psMetadataAddStr(updateprocessedexpArgs, PS_LIST_TAIL, "-exp_tag",  0,
         "search by exposure ID", NULL);
-    psMetadataAddStr(faultexpArgs, PS_LIST_TAIL, "-class",  0,
+    psMetadataAddStr(updateprocessedexpArgs, PS_LIST_TAIL, "-class",  0,
         "search by class", NULL);
-    psMetadataAddStr(faultexpArgs, PS_LIST_TAIL, "-class_id",  0,
+    psMetadataAddStr(updateprocessedexpArgs, PS_LIST_TAIL, "-class_id",  0,
         "search by class ID", NULL);
-    psMetadataAddS8(faultexpArgs, PS_LIST_TAIL, "-code",  0,
+    psMetadataAddS8(updateprocessedexpArgs, PS_LIST_TAIL, "-code",  0,
         "set fault code (required)", 0);
 
@@ -146,6 +161,7 @@
     PXTOOL_MODE("-pendingexp",   P3TOOL_MODE_PENDINGEXP,    pendingexpArgs);
     PXTOOL_MODE("-pendingimfile",P3TOOL_MODE_PENDINGIMFILE, pendingimfileArgs);
-    PXTOOL_MODE("-faultexp",     P3TOOL_MODE_FAULTEXP,      faultexpArgs);
     PXTOOL_MODE("-addprocessedexp", P3TOOL_MODE_ADDPROCESSEDEXP, addprocessedexpArgs);
+    PXTOOL_MODE("-processedexp", P3TOOL_MODE_PROCESSEDEXP,  processedexpArgs);
+    PXTOOL_MODE("-updateprocessedexp", P3TOOL_MODE_UPDATEPROCESSEDEXP,updateprocessedexpArgs);
     PXTOOL_MODE("-block",        P3TOOL_MODE_BLOCK,         blockArgs);
     PXTOOL_MODE("-masked",       P3TOOL_MODE_MASKED,        maskedArgs);
Index: /trunk/ippTools/src/chiptool.c
===================================================================
--- /trunk/ippTools/src/chiptool.c	(revision 11074)
+++ /trunk/ippTools/src/chiptool.c	(revision 11075)
@@ -99,9 +99,9 @@
             "SELECT"
             "   p2PendingImfile.*,"
-            "   rawScienceExp.camera"
+            "   rawExp.camera"
             " FROM p2PendingImfile"
             " JOIN p2PendingExp"
             "   USING(exp_tag)"
-            " JOIN rawScienceExp"
+            " JOIN rawExp"
             "   USING(exp_tag)"
             " LEFT JOIN p2Mask"
@@ -353,7 +353,7 @@
             "SELECT"
             "   p2ProcessedImfile.*,"
-            "   rawScienceExp.camera"
+            "   rawExp.camera"
             " FROM p2ProcessedImfile"
-            " JOIN rawScienceExp"
+            " JOIN rawExp"
             "   USING(exp_tag)"
             " WHERE "
@@ -554,13 +554,13 @@
     // where exp_tag is not in p2PendingImfile
     // where the number of entries in p2ProccessedImfile matches the .imfiles
-    // entry in rawScienceExp
+    // entry in rawExp
     psString query = psStringCopy(
         "SELECT DISTINCT"
         "   p2PendingExp.*,"
-        "   rawScienceExp.imfiles,"
+        "   rawExp.imfiles,"
         "   p2ProcessedImfile.class_id"
         " FROM p2PendingExp"
-        " JOIN rawScienceExp"
-        "   ON p2PendingExp.exp_tag = rawScienceExp.exp_tag"
+        " JOIN rawExp"
+        "   ON p2PendingExp.exp_tag = rawExp.exp_tag"
         " LEFT JOIN p2ProcessedExp"
         "   ON p2PendingExp.exp_tag = p2ProcessedExp.exp_tag"
@@ -575,5 +575,5 @@
         " GROUP BY"
         "   p2PendingExp.exp_tag"
-        " HAVING rawScienceExp.imfiles = COUNT(p2ProcessedImfile.class_id)"
+        " HAVING rawExp.imfiles = COUNT(p2ProcessedImfile.class_id)"
         );
 
@@ -773,6 +773,5 @@
         pendingExp->p1_version,
         pendingExp->p2_version,
-        pendingExp->label,
-        0   // fault code
+        pendingExp->label
     );
 }
Index: /trunk/ippTools/src/detselect.c
===================================================================
--- /trunk/ippTools/src/detselect.c	(revision 11074)
+++ /trunk/ippTools/src/detselect.c	(revision 11075)
@@ -90,5 +90,5 @@
         // "   detRun.state,"
         // "   detRunSummary.accept,"
-        // "   rawDetrendExp.camera"
+        // "   rawExp.camera"
         " FROM detRun"
         " JOIN detRunSummary "
@@ -97,8 +97,8 @@
         "   ON detRunSummary.det_id = detInputExp.det_id"
         "   AND detRunSummary.iteration = detInputExp.iteration"
-        " JOIN rawDetrendExp"
-        "   ON detInputExp.exp_tag = rawDetrendExp.exp_tag"
+        " JOIN rawExp"
+        "   ON detInputExp.exp_tag = rawExp.exp_tag"
         " JOIN rawImfile"
-        "   ON rawDetrendExp.exp_tag = rawImfile.exp_tag"
+        "   ON rawExp.exp_tag = rawImfile.exp_tag"
         " WHERE"
         "   detRun.state = 'stop'"
@@ -106,5 +106,5 @@
         // XXX the following entry is needed to exclude db mismatched
         // XXX these are caused by an error upstream and should be fixed
-//        "   AND detRun.det_type = rawDetrendExp.object"
+//        "   AND detRun.det_type = rawExp.object"
     );
 # endif
