Index: trunk/ippTools/share/Makefile.am
===================================================================
--- trunk/ippTools/share/Makefile.am	(revision 32960)
+++ trunk/ippTools/share/Makefile.am	(revision 32962)
@@ -387,4 +387,6 @@
 	staticskytool_defineskycalrun.sql \
 	staticskytool_pendingskycalrun.sql \
+	staticskytool_revertskycal.sql \
+	staticskytool_skycalresult.sql \
 	staticskytool_export_run.sql \
 	staticskytool_export_input.sql \
Index: trunk/ippTools/share/disttool_definebyquery_raw_no_magic.sql
===================================================================
--- trunk/ippTools/share/disttool_definebyquery_raw_no_magic.sql	(revision 32960)
+++ trunk/ippTools/share/disttool_definebyquery_raw_no_magic.sql	(revision 32962)
@@ -14,5 +14,4 @@
 JOIN rcInterest USING(target_id)
 LEFT JOIN distRun ON distRun.stage_id = exp_id AND distRun.target_id = distTarget.target_id
-WHERE distRun.dist_id IS NULL           -- no existing distRun for this exposure
-    AND distTarget.state = 'enabled'    -- target and intrest are enabled
+WHERE distTarget.state = 'enabled'    -- target and intrest are enabled
     AND rcInterest.state = 'enabled'
Index: trunk/ippTools/share/staticskytool_revertskycal.sql
===================================================================
--- trunk/ippTools/share/staticskytool_revertskycal.sql	(revision 32962)
+++ trunk/ippTools/share/staticskytool_revertskycal.sql	(revision 32962)
@@ -0,0 +1,6 @@
+DELETE FROM skycalResult
+USING skycalResult, skycalRun, stackRun
+WHERE skycalRun.skycal_id = skycalResult.skycal_id
+    AND stackRun.stack_id = skycalRun.stack_id
+    AND skycalRun.state = 'new'
+    AND skycalResult.fault != 0
Index: trunk/ippTools/share/staticskytool_skycalresult.sql
===================================================================
--- trunk/ippTools/share/staticskytool_skycalresult.sql	(revision 32962)
+++ trunk/ippTools/share/staticskytool_skycalresult.sql	(revision 32962)
@@ -0,0 +1,14 @@
+SELECT 
+    skycalResult.*,
+    skycalRun.stack_id,
+    stackRun.tess_id,
+    stackRun.skycell_id,
+    stackRun.filter,
+    skycalRun.state,
+    skycalRun.label,
+    skycalRun.data_group,
+    skycalRun.sky_id
+FROM skycalRun
+JOIN skycalResult USING(skycal_id)
+JOIN stackRun USING(stack_id)
+
Index: trunk/ippTools/src/staticskytool.c
===================================================================
--- trunk/ippTools/src/staticskytool.c	(revision 32960)
+++ trunk/ippTools/src/staticskytool.c	(revision 32962)
@@ -38,5 +38,5 @@
 static bool resultMode(pxConfig *config);
 static bool revertMode(pxConfig *config);
-static bool updateresult(pxConfig *config);
+static bool updateresultMode(pxConfig *config);
 static bool exportrunMode(pxConfig *config);
 static bool importrunMode(pxConfig *config);
@@ -45,4 +45,8 @@
 static bool updateskycalrunMode(pxConfig *config);
 static bool pendingskycalrunMode(pxConfig *config);
+static bool addskycalresultMode(pxConfig *config);
+static bool skycalresultMode(pxConfig *config);
+static bool revertskycalresultMode(pxConfig *config);
+static bool updateskycalresultMode(pxConfig *config);
 
 static bool setstaticskyRunState(pxConfig *config, psS64 sky_id, const char *state);
@@ -73,5 +77,5 @@
         MODECASE(STATICSKYTOOL_MODE_RESULT,            resultMode);
         MODECASE(STATICSKYTOOL_MODE_REVERT,            revertMode);
-        MODECASE(STATICSKYTOOL_MODE_UPDATERESULT,      updateresult);
+        MODECASE(STATICSKYTOOL_MODE_UPDATERESULT,      updateresultMode);
         MODECASE(STATICSKYTOOL_MODE_EXPORTRUN,         exportrunMode);
         MODECASE(STATICSKYTOOL_MODE_IMPORTRUN,         importrunMode);
@@ -79,4 +83,8 @@
         MODECASE(STATICSKYTOOL_MODE_UPDATESKYCALRUN,   updateskycalrunMode);
         MODECASE(STATICSKYTOOL_MODE_PENDINGSKYCALRUN,  pendingskycalrunMode);
+        MODECASE(STATICSKYTOOL_MODE_ADDSKYCALRESULT,   addskycalresultMode);
+        MODECASE(STATICSKYTOOL_MODE_UPDATESKYCALRESULT,updateskycalresultMode);
+        MODECASE(STATICSKYTOOL_MODE_REVERTSKYCALRESULT,revertskycalresultMode);
+        MODECASE(STATICSKYTOOL_MODE_SKYCALRESULT,      skycalresultMode);
         default:
             psAbort("invalid option (this should not happen)");
@@ -741,5 +749,5 @@
 }
 
-static bool updateresult(pxConfig *config)
+static bool updateresultMode(pxConfig *config)
 {
     PS_ASSERT_PTR_NON_NULL(config, false);
@@ -1171,6 +1179,4 @@
     psFree(whereMD);
 
-//    psStringAppend(&query, "\n GROUP by skycal_id");
-
     // treat limit == 0 as "no limit"
     if (limit) {
@@ -1220,2 +1226,243 @@
     return true;
 }
+
+static bool addskycalresultMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    // required
+    PXOPT_LOOKUP_S64(skycal_id, config->args, "-skycal_id", true, false);
+
+    // optional
+    PXOPT_LOOKUP_F32(sigma_ra, config->args,  "-sigma_ra", false, false);
+    PXOPT_LOOKUP_F32(sigma_dec, config->args, "-sigma_dec", false, false);
+
+    PXOPT_LOOKUP_F32(zpt_obs, config->args,   "-zpt_obs", false, false);
+    PXOPT_LOOKUP_F32(zpt_stdev, config->args, "-zpt_stdev", false, false);
+
+
+    PXOPT_LOOKUP_F32(dtime_script, config->args,   "-dtime_script", false, false);
+    PXOPT_LOOKUP_F32(dtime_astrom, config->args,   "-dtime_astrom", false, false);
+
+    PXOPT_LOOKUP_STR(hostname, config->args,    "-hostname", false, false);
+//    PXOPT_LOOKUP_S32(n_stars, config->args,     "-n_stars", false, false);
+    PXOPT_LOOKUP_S32(n_astrom, config->args,    "-n_astrom", false, false);
+
+    PXOPT_LOOKUP_STR(path_base, config->args,   "-path_base", false, false);
+    PXOPT_LOOKUP_S16(fault, config->args,       "-fault", false, false);
+    PXOPT_LOOKUP_S16(quality, config->args,     "-quality", false, false);
+
+    PXOPT_LOOKUP_STR(ver_pslib, config->args,   "-ver_pslib", false, false);
+    PXOPT_LOOKUP_STR(ver_psmodules, config->args, "-ver_psmodules", false, false);
+    PXOPT_LOOKUP_STR(ver_psphot, config->args,  "-ver_psphot", false, false);
+    PXOPT_LOOKUP_STR(ver_psastro, config->args, "-ver_psastro", false, false);
+    PXOPT_LOOKUP_STR(ver_ppstats, config->args, "-ver_ppstats", false, false);
+
+    psString software_ver = NULL;
+    if ((ver_pslib)&&(ver_psmodules)) {
+      software_ver = pxMergeCodeVersions(ver_pslib,ver_psmodules);
+    }
+    if (ver_psphot) {
+      software_ver = pxMergeCodeVersions(software_ver,ver_psphot);
+    }
+    if (ver_psastro) {
+      software_ver = pxMergeCodeVersions(software_ver,ver_psastro);
+    }
+    if (ver_ppstats) {
+      software_ver = pxMergeCodeVersions(software_ver,ver_ppstats);
+    }
+
+    if (!psDBTransaction(config->dbh)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+
+    skycalResultRow *row = skycalResultRowAlloc(
+        skycal_id,
+        path_base,
+        dtime_script,
+        dtime_astrom,
+        sigma_ra,
+        sigma_dec,
+        n_astrom,
+        zpt_obs,
+        zpt_stdev,
+        quality,
+        software_ver,
+        hostname,
+        fault
+        );
+
+    if (!skycalResultInsertObject(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(row);
+
+    if (fault) {
+        if (!psDBCommit(config->dbh)) {
+            psError(PS_ERR_UNKNOWN, false, "database error");
+            return false;
+        }
+        return true;
+    }
+
+    psString query = "UPDATE skycalRun SET state = 'full' WHERE skycal_id = %" PRId64;
+    if (!p_psDBRunQueryF(config->dbh, query, skycal_id)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psDBCommit(config->dbh)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+
+    return true;
+}
+static bool updateskycalresultMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    PXOPT_LOOKUP_S16(fault, config->args, "-set_fault", true, false);
+    PXOPT_LOOKUP_S16(quality, config->args, "-set_quality", false, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-skycal_id",   "skycal_id",   "==");
+
+    if (!pxSetFaultCode(config->dbh, "skycalResult", where, fault, quality)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to set set fault flag");
+        psFree (where);
+        return false;
+    }
+    psFree (where);
+    return true;
+}
+static bool skycalresultMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-skycal_id",  "skycalRun.skycal_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-sky_id",     "skycalRun.sky_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-stack_id",   "skycalRun.stack_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-tess_id",    "stackRun.tess_id", "LIKE");
+    PXOPT_COPY_STR(config->args, where, "-skycell_id", "stackRun.skycell_id", "LIKE");
+    PXOPT_COPY_STR(config->args, where, "-filter",     "stackRun.filter", "LIKE");
+    PXOPT_COPY_STR(config->args, where, "-label",      "skycalRun.label", "==");
+    PXOPT_COPY_STR(config->args, where, "-data_group", "skycalRun.data_group", "LIKE");
+    PXOPT_COPY_S16(config->args, where, "-fault",      "skycalResult.fault", "==");
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psString query = pxDataGet("staticskytool_skycalresult.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (!psListLength(where->list)) {
+        psError(PXTOOLS_ERR_CONFIG, true, "search parameters are required");
+        return false;
+    }
+    psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+    psStringAppend(&query, " WHERE %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) {
+        psErrorCode err = psErrorCodeLast();
+        switch (err) {
+            case PS_ERR_DB_CLIENT:
+                psError(PXTOOLS_ERR_SYS, false, "database error");
+            case PS_ERR_DB_SERVER:
+                psError(PXTOOLS_ERR_PROG, false, "database error");
+            default:
+                psError(PXTOOLS_ERR_PROG, false, "unknown error");
+        }
+
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("staticskytool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    if (psArrayLength(output)) {
+        if (!ippdbPrintMetadatas(stdout, output, "staticskyResult", !simple)) {
+            psError(PS_ERR_UNKNOWN, false, "failed to print array");
+            psFree(output);
+            return false;
+        }
+    }
+
+    psFree(output);
+
+    return true;
+}
+static bool revertskycalresultMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-skycal_id", "staticskyResult.sky_id", "==");
+    pxAddLabelSearchArgs(config, where, "-label", "staticskyRun.label", "==");
+    pxAddLabelSearchArgs(config, where, "-data_group", "staticskyRun.data_group", "==");
+    pxAddLabelSearchArgs(config, where, "-filter", "stackRun.filter", "==");
+    PXOPT_COPY_S16(config->args, where, "-fault", "staticskyResult.fault", "==");
+
+    if (!psListLength(where->list) && !psMetadataLookupBool(NULL, config->args, "-all")) {
+        psFree(where);
+        psError(PXTOOLS_ERR_CONFIG, false, "search parameters are required");
+        return false;
+    }
+
+    // Delete product
+    psString delete = pxDataGet("staticskytool_revertskycal.sql");
+    if (!delete) {
+        psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&delete, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, delete)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(delete);
+        psFree(where);
+        return false;
+    }
+    psFree(delete);
+
+    int numRows = psDBAffectedRows(config->dbh); // Number of row affected
+    psLogMsg("staticskytool", PS_LOG_INFO, "Deleted %d rows", numRows);
+
+    psFree(where);
+    return true;
+}
Index: trunk/ippTools/src/staticskytoolConfig.c
===================================================================
--- trunk/ippTools/src/staticskytoolConfig.c	(revision 32960)
+++ trunk/ippTools/src/staticskytoolConfig.c	(revision 32962)
@@ -182,4 +182,60 @@
     psMetadataAddBool(pendingskycalrunArgs, PS_LIST_TAIL, "-simple", 0, "use the simple output format", false);
 
+
+    // -addskycalresult
+    psMetadata *addskycalresultArgs = psMetadataAlloc();
+    psMetadataAddS64(addskycalresultArgs, PS_LIST_TAIL, "-skycal_id", 0,            "define camtool ID (required)", 0);
+    psMetadataAddF32(addskycalresultArgs, PS_LIST_TAIL, "-sigma_ra", 0,            "define exposure E ra", NAN);
+    psMetadataAddF32(addskycalresultArgs, PS_LIST_TAIL, "-sigma_dec", 0,            "define exposure E dec", NAN);
+    psMetadataAddF32(addskycalresultArgs, PS_LIST_TAIL, "-zpt_obs", 0,   "define observed zero point", 0);
+    psMetadataAddF32(addskycalresultArgs, PS_LIST_TAIL, "-zpt_stdev", 0,   "define observed zero point stdandard deviation", 0);
+
+    psMetadataAddF32(addskycalresultArgs, PS_LIST_TAIL, "-dtime_script", 0, "define elapsed time in script (seconds)", NAN);
+    psMetadataAddF32(addskycalresultArgs, PS_LIST_TAIL, "-dtime_astrom", 0, "define elapsed time for astrometry (seconds)", NAN);
+
+    psMetadataAddStr(addskycalresultArgs, PS_LIST_TAIL, "-hostname", 0,            "define hostname", NULL);
+    // psMetadataAddS32(addskycalresultArgs, PS_LIST_TAIL, "-n_stars", 0,            "define number of stars", 0);
+    psMetadataAddS32(addskycalresultArgs, PS_LIST_TAIL, "-n_astrom", 0,            "define number of astrometry reference objects", 0);
+
+    psMetadataAddStr(addskycalresultArgs, PS_LIST_TAIL, "-path_base", 0,            "define base output location", NULL);
+    psMetadataAddS16(addskycalresultArgs, PS_LIST_TAIL, "-fault",  0,            "set fault code", 0);
+    psMetadataAddS16(addskycalresultArgs, PS_LIST_TAIL, "-quality",  0,            "set quality", 0);
+
+    psMetadataAddStr(addskycalresultArgs, PS_LIST_TAIL, "-ver_pslib", 0, "define psLib version", NULL);
+    psMetadataAddStr(addskycalresultArgs, PS_LIST_TAIL, "-ver_psmodules", 0, "define psModules version", NULL);
+    psMetadataAddStr(addskycalresultArgs, PS_LIST_TAIL, "-ver_psphot", 0, "define psphot version", NULL);
+    psMetadataAddStr(addskycalresultArgs, PS_LIST_TAIL, "-ver_psastro", 0, "define psastro version", NULL);
+    psMetadataAddStr(addskycalresultArgs, PS_LIST_TAIL, "-ver_ppstats", 0, "define ppStats version", NULL);
+    psMetadataAddStr(addskycalresultArgs, PS_LIST_TAIL, "-ver_streaks", 0, "define streaksremove version", NULL);
+
+    // -revertskycal
+    psMetadata *revertskycalArgs= psMetadataAlloc();
+    psMetadataAddS64(revertskycalArgs, PS_LIST_TAIL, "-skycal_id", 0, "search by staticsky ID", 0);
+    psMetadataAddStr(revertskycalArgs, PS_LIST_TAIL, "-label", PS_META_DUPLICATE_OK, "search by label", 0);
+    psMetadataAddStr(revertskycalArgs, PS_LIST_TAIL, "-data_group", PS_META_DUPLICATE_OK, "search by data_group", 0);
+    psMetadataAddStr(revertskycalArgs, PS_LIST_TAIL, "-filter", PS_META_DUPLICATE_OK, "search by filter", 0);
+    psMetadataAddS16(revertskycalArgs, PS_LIST_TAIL, "-fault", 0, "search by fault code", 0);
+    psMetadataAddBool(revertskycalArgs, PS_LIST_TAIL, "-all", 0, "allow no search terms", false);
+
+    // -updateskycalresult
+    psMetadata *updateskycalresultArgs = psMetadataAlloc();
+    psMetadataAddS64(updateskycalresultArgs, PS_LIST_TAIL, "-skycal_id", 0, "define staticksky ID (required)", 0);
+    psMetadataAddS16(updateskycalresultArgs, PS_LIST_TAIL, "-set_fault", 0, "set fault code (required)", 0);
+    psMetadataAddS16(updateskycalresultArgs, PS_LIST_TAIL, "-set_quality", 0, "set quality code", 0);
+
+    // -skycalresult
+    psMetadata *skycalresultArgs= psMetadataAlloc();
+    psMetadataAddS64(skycalresultArgs, PS_LIST_TAIL, "-skycal_id", 0, "search by skycal ID", 0);
+    psMetadataAddS64(skycalresultArgs, PS_LIST_TAIL, "-sky_id", 0, "search by staticsky ID", 0);
+    psMetadataAddS64(skycalresultArgs, PS_LIST_TAIL, "-stack_id", 0, "search by stack ID", 0);
+    psMetadataAddStr(skycalresultArgs, PS_LIST_TAIL, "-tess_id", 0, "search by tess ID (LIKE comparison)", 0);
+    psMetadataAddStr(skycalresultArgs, PS_LIST_TAIL, "-skycell_id", 0, "search by skycell ID (LIKE comparison)", 0);
+    psMetadataAddStr(skycalresultArgs, PS_LIST_TAIL, "-filter", 0, "search by filter (LIKE comparison)", 0);
+    psMetadataAddStr(skycalresultArgs, PS_LIST_TAIL, "-label", 0, "search by label (LIKE comparison)", NULL);
+    psMetadataAddStr(skycalresultArgs, PS_LIST_TAIL, "-data_group", 0, "search by data_group (LIKE comparison)", NULL);
+    psMetadataAddS16(skycalresultArgs, PS_LIST_TAIL, "-fault", 0, "search by fault code", 0);
+    psMetadataAddU64(skycalresultArgs, PS_LIST_TAIL, "-limit", 0, "limit skycalresult set to N items", 0);
+    psMetadataAddBool(skycalresultArgs, PS_LIST_TAIL, "-simple", 0, "use the simple output format", false);
+
     psFree(now);
 
@@ -200,4 +256,8 @@
     PXOPT_ADD_MODE("-updateskycalrun", "Update a skycalrun", STATICSKYTOOL_MODE_UPDATESKYCALRUN,     updateskycalrunArgs);
     PXOPT_ADD_MODE("-pendingskycalrun", "Get skcal runs to do",       STATICSKYTOOL_MODE_PENDINGSKYCALRUN,          pendingskycalrunArgs);
+    PXOPT_ADD_MODE("-addskycalresult", "add skycal result",       STATICSKYTOOL_MODE_ADDSKYCALRESULT, addskycalresultArgs);
+    PXOPT_ADD_MODE("-revertskycal",  "revert faulted skycal run", STATICSKYTOOL_MODE_REVERTSKYCALRESULT, revertskycalArgs);
+    PXOPT_ADD_MODE("-updateskycal",  "revert faulted skycal run", STATICSKYTOOL_MODE_UPDATESKYCALRESULT, updateskycalresultArgs);
+    PXOPT_ADD_MODE("-skycalresult",  "Get result of skycal run",  STATICSKYTOOL_MODE_SKYCALRESULT, skycalresultArgs);
 
     if (!pxGetOptions(stderr, argc, argv, config, modes, argSets)) {
