Index: branches/eam_branches/ipp-20121219/ippTools/src/Makefile.am
===================================================================
--- branches/eam_branches/ipp-20121219/ippTools/src/Makefile.am	(revision 34903)
+++ branches/eam_branches/ipp-20121219/ippTools/src/Makefile.am	(revision 35096)
@@ -32,5 +32,6 @@
 	laptool \
 	vptool \
-	sctool
+	sctool \
+	releasetool
 
 pkginclude_HEADERS = \
@@ -85,5 +86,6 @@
 	laptool.h \
 	vptool.h \
-	sctool.h
+	sctool.h \
+	releasetool.h
 
 lib_LTLIBRARIES = libpxtools.la
@@ -324,4 +326,10 @@
     sctoolConfig.c
 
+releasetool_CFLAGS = $(PSLIB_CFLAGS) $(PSMODULES_CFLAGS) $(IPPDB_CFLAGS)
+releasetool_LDADD = $(PSLIB_LIBS) $(PSMODULES_LIBS) $(IPPDB_LIBS) libpxtools.la
+releasetool_SOURCES = \
+    releasetool.c \
+    releasetoolConfig.c
+
 clean-local:
 	-rm -f TAGS
Index: branches/eam_branches/ipp-20121219/ippTools/src/bgtool.c
===================================================================
--- branches/eam_branches/ipp-20121219/ippTools/src/bgtool.c	(revision 34903)
+++ branches/eam_branches/ipp-20121219/ippTools/src/bgtool.c	(revision 35096)
@@ -693,4 +693,5 @@
     psMetadata *where = psMetadataAlloc();
     PXOPT_COPY_S64(config->args, where, "-chip_bg_id",    "chipBackgroundRun.chip_bg_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-chip_id",    "chipBackgroundRun.chip_id", "==");
     PXOPT_COPY_STR(config->args, where, "-class_id", "chipBackgroundImfile.class_id", "==");
     pxAddLabelSearchArgs(config, where, "-label",   "chipBackgroundRun.label", "LIKE");
Index: branches/eam_branches/ipp-20121219/ippTools/src/bgtoolConfig.c
===================================================================
--- branches/eam_branches/ipp-20121219/ippTools/src/bgtoolConfig.c	(revision 34903)
+++ branches/eam_branches/ipp-20121219/ippTools/src/bgtoolConfig.c	(revision 35096)
@@ -162,4 +162,5 @@
     psMetadata *chipArgs = psMetadataAlloc();
     psMetadataAddS64(chipArgs, PS_LIST_TAIL, "-chip_bg_id", 0, "search by chip_bg_id", 0);
+    psMetadataAddS64(chipArgs, PS_LIST_TAIL, "-chip_id", 0, "search by chip_id", 0);
     psMetadataAddStr(chipArgs, PS_LIST_TAIL, "-class_id", 0, "search by class_id", NULL);
     psMetadataAddS16(chipArgs, PS_LIST_TAIL, "-fault",  0, "search by fault code", 0);
Index: branches/eam_branches/ipp-20121219/ippTools/src/pxspace.c
===================================================================
--- branches/eam_branches/ipp-20121219/ippTools/src/pxspace.c	(revision 34903)
+++ branches/eam_branches/ipp-20121219/ippTools/src/pxspace.c	(revision 35096)
@@ -67,4 +67,6 @@
     psMetadataAddF32(md,  PS_LIST_TAIL, "-glong_max",         0, "search by galactic longitude (degrees)", NAN);
     psMetadataAddF32(md,  PS_LIST_TAIL, "-glat_max",          0, "search by galactic latitude (degrees)", NAN);
+    psMetadataAddF32(md,  PS_LIST_TAIL, "-abs_glat_min",       0, "search by absolute value(galactic latitude) (degrees)", NAN);
+    psMetadataAddF32(md,  PS_LIST_TAIL, "-abs_glat_max",       0, "search by absolute value(galactic latitude) (degrees)", NAN);
 }
 
@@ -79,4 +81,6 @@
     PXOPT_COPY_F32(config->args, where, "-glong_max", "skycell.glong", "<");
     PXOPT_COPY_F32(config->args, where, "-glat_max", "skycell.glat", "<");
+    PXOPT_COPY_F32(config->args, where, "-abs_glat_min", "abs(skycell.glat)", ">=");
+    PXOPT_COPY_F32(config->args, where, "-abs_glat_max", "abs(skycell.glat)", "<");
     return true;
 }
Index: branches/eam_branches/ipp-20121219/ippTools/src/releasetool.c
===================================================================
--- branches/eam_branches/ipp-20121219/ippTools/src/releasetool.c	(revision 35096)
+++ branches/eam_branches/ipp-20121219/ippTools/src/releasetool.c	(revision 35096)
@@ -0,0 +1,535 @@
+/*
+ * releasetool.c
+ *
+ * Copyright (C) 2013 IfA University of Hawaii
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "pxtools.h"
+#include "pxdata.h"
+#include "pxchip.h"
+#include "pxspace.h"
+
+#include "releasetool.h"
+
+static bool definesurveyMode(pxConfig *config);
+static bool listsurveyMode(pxConfig *config);
+static bool definereleaseMode(pxConfig *config);
+static bool updatereleaseMode(pxConfig *config);
+static bool listreleaseMode(pxConfig *config);
+static bool definerelexpMode(pxConfig *config);
+static bool updaterelexpMode(pxConfig *config);
+static bool listrelexpMode(pxConfig *config);
+
+# define MODECASE(caseName, func) \
+    case caseName: \
+    if (!func(config)) { \
+        goto FAIL; \
+    } \
+    break;
+
+int main(int argc, char **argv) {
+    psLibInit(NULL);
+
+    pxConfig *config = releasetoolConfig(NULL, argc, argv);
+    if (!config) {
+        psError(PXTOOLS_ERR_CONFIG, false, "failed to configure");
+        goto FAIL;
+    }
+
+    switch (config->mode) {
+        MODECASE(RELEASETOOL_MODE_DEFINESURVEY,     definesurveyMode);
+        MODECASE(RELEASETOOL_MODE_LISTSURVEY,       listsurveyMode);
+
+        MODECASE(RELEASETOOL_MODE_DEFINERELEASE,    definereleaseMode);
+        MODECASE(RELEASETOOL_MODE_UPDATERELEASE,    updatereleaseMode);
+        MODECASE(RELEASETOOL_MODE_LISTRELEASE,      listreleaseMode);
+
+        MODECASE(RELEASETOOL_MODE_DEFINERELEXP,     definerelexpMode);
+        MODECASE(RELEASETOOL_MODE_UPDATERELEXP,     updaterelexpMode);
+        MODECASE(RELEASETOOL_MODE_LISTRELEXP,       listrelexpMode);
+        default:
+            psAbort("invalid option (this should not happen)");
+    }
+
+    psFree(config);
+    pmConfigDone();
+    psLibFinalize();
+
+    exit(EXIT_SUCCESS);
+
+FAIL:
+    psErrorStackPrint(stderr, "\n");
+    int exit_status = pxerrorGetExitStatus();
+
+    psFree(config);
+    pmConfigDone();
+    psLibFinalize();
+
+    exit(exit_status);
+}
+
+static bool definesurveyMode(pxConfig *config)
+{
+    psError(PS_ERR_UNKNOWN, true, "not yet implemented");
+    return false;
+}
+
+static bool listsurveyMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+    psMetadata *where = psMetadataAlloc();
+
+    PXOPT_COPY_STR(config->args, where, "-surveyName", "surveyName", "LIKE");
+
+    psString query = pxDataGet("releasetool_listsurvey.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " WHERE %s", whereClause);
+        psFree(whereClause);
+    } else {
+        // carry on The list of surveys is short there is no need to require parameters
+    }
+
+    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("releasetool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    if (!ippdbPrintMetadatas(stdout, output, "survey", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+static bool definereleaseMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    PXOPT_LOOKUP_S32(surveyID,    config->args, "-set_surveyID", true, false);
+    PXOPT_LOOKUP_STR(releaseName, config->args, "-set_releaseName", true, false);
+    PXOPT_LOOKUP_STR(release_state, config->args, "-set_release_state",  true, false);
+    PXOPT_LOOKUP_S32(dataRelease, config->args, "-set_dataRelease", false, false);
+    PXOPT_LOOKUP_S32(priority,    config->args, "-set_priority", false, false);
+
+    if (!ippReleaseInsert(config->dbh,
+        0,      // rel_id (auto_increment)
+        surveyID,
+        releaseName,
+        release_state,
+        dataRelease,
+        priority
+    )) {
+        psError(PS_ERR_UNKNOWN, false, "failed to insert ippRelease");
+        return false;
+    }
+
+    return true;
+}
+
+static bool updatereleaseMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    PXOPT_LOOKUP_STR(releaseName, config->args, "-releaseName", false, false);
+    PXOPT_LOOKUP_S32(rel_id, config->args,      "-rel_id", false, false);
+
+    if (!releaseName && !rel_id) {
+        psError(PXTOOLS_ERR_CONFIG, true, "either -releaseName or -rel_id is required\n");
+        return false;
+    }
+    PXOPT_LOOKUP_STR(release_state,       config->args, "-set_release_state",  true, false);
+
+    psMetadata *where = psMetadataAlloc();
+
+    PXOPT_COPY_S32(config->args, where, "-rel_id",  "rel_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-releaseName", "releaseName", "==");
+
+    psString query = NULL;
+    psStringAppend(&query, "UPDATE ippRelease SET release_state = '%s'", release_state);
+
+    psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+    psStringAppend(&query, " WHERE %s", whereClause);
+    psFree(whereClause);
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+
+    psU64 affected = psDBAffectedRows(config->dbh);
+    psLogMsg("releasetool", PS_LOG_INFO, "Updated %" PRIu64 " ippReleases", affected);
+
+
+    psFree(query);
+
+    return true;
+}
+
+static bool listreleaseMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+    psMetadata *where = psMetadataAlloc();
+
+    PXOPT_COPY_STR(config->args, where, "-surveyName",  "surveyName", "LIKE");
+    PXOPT_COPY_STR(config->args, where, "-releaseName", "releaseName", "LIKE");
+    PXOPT_COPY_STR(config->args, where, "-release_state", "release_state", "==");
+    PXOPT_COPY_S32(config->args, where, "-rel_id",  "rel_id", "==");
+
+        psString query = pxDataGet("releasetool_listrelease.sql");
+        if (!query) {
+            psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
+            return false;
+        }
+
+        if (psListLength(where->list)) {
+            psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+            psStringAppend(&query, " WHERE %s", whereClause);
+            psFree(whereClause);
+        } else {
+            // The list of releases is short there is no need to require parameters
+        #ifdef notyet
+            psError(PXTOOLS_ERR_CONFIG, false, "search parameters are required\n");
+            psFree(where);
+            return false;
+        #endif
+        }
+
+        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("releasetool", PS_LOG_INFO, "no rows found");
+            psFree(output);
+            return true;
+        }
+
+        if (!ippdbPrintMetadatas(stdout, output, "ippRelease", !simple)) {
+            psError(PS_ERR_UNKNOWN, false, "failed to print array");
+            psFree(output);
+            return false;
+        }
+
+        psFree(output);
+
+        return true;
+    }
+
+static bool definerelexpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    psMetadata *where = psMetadataAlloc();
+
+    PXOPT_COPY_STR(config->args, where, "-label",      "camRun.label", "==");
+    PXOPT_COPY_STR(config->args, where, "-data_group", "camRun.data_group", "==");
+    PXOPT_COPY_S64(config->args, where, "-cam_id",     "camRun.cam_id", "==");
+
+    // Insure that at least one of the camRun selectors is supplied
+    if (!psListLength(where->list)) {
+        psFree(where);
+        psError(PXTOOLS_ERR_CONFIG, false, "at least one of -label, -data_group, or -cam_id is required");
+        return false;
+    }
+
+    PXOPT_COPY_S64(config->args, where, "-exp_id",     "rawExp.exp_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-exp_name",   "rawExp.exp_name", "==");
+
+    // insure that at least one of these is supplied to select the release
+    PXOPT_LOOKUP_S64(rel_id, config->args,      "-rel_id", false, false);
+    PXOPT_LOOKUP_STR(releaseName, config->args, "-releaseName", false, false);
+    if (!rel_id && !releaseName) {
+        psError(PXTOOLS_ERR_CONFIG, true, "either -rel_id or -releaseName is required");
+        return false;
+    }
+
+    // limit query to the target release. (Note: this will select nothing of releaseName and rel_id don't match)
+    // note: we add these after above to insure that search args are supplied
+    PXOPT_COPY_STR(config->args, where, "-releaseName", "ippRelease.releaseName", "==");
+    PXOPT_COPY_S32(config->args, where, "-rel_id", "ippRelease.rel_id", "==");
+
+
+    PXOPT_LOOKUP_STR(state, config->args,     "-set_state", true, false);
+    PXOPT_LOOKUP_U32(flags, config->args,     "-set_flags", false, false);
+    PXOPT_LOOKUP_STR(path_base, config->args, "-set_path_base", false, false);
+
+    PXOPT_LOOKUP_BOOL(pretend, config->args, "-pretend", false);
+    PXOPT_LOOKUP_BOOL(simple, config->args,  "-simple", false);
+
+    // find the parameters of all the exposures that we want to add to the release
+    psString query = pxDataGet("releasetool_definerelexp.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
+        psFree(where);
+        return false;
+    }
+
+    psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+    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);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("releasetool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    if (pretend) {
+        // negative simple so the default is true
+        if (!ippdbPrintMetadatas(stdout, output, "chipRun", !simple)) {
+            psError(PS_ERR_UNKNOWN, false, "failed to print array");
+            psFree(output);
+            return false;
+        }
+        psFree(output);
+        return true;
+    }
+
+    if (!psDBTransaction(config->dbh)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(output);
+        return false;
+    }
+
+    psTime *now = psTimeGetNow(PS_TIME_TAI);
+    // loop over our list of  exposures
+    for (long i = 0; i < psArrayLength(output); i++) {
+        psMetadata *md = output->data[i];
+
+        bool status = true;
+        psS32 rel_id = psMetadataLookupS32(&status, md, "rel_id");
+        psS64 exp_id = psMetadataLookupS64(&status, md, "exp_id");
+        psS64 chip_id = psMetadataLookupS64(&status, md, "chip_id");
+        psS64 cam_id = psMetadataLookupS64(&status, md, "cam_id");
+        psF32 zpt_obs = psMetadataLookupF32(&status, md, "zpt_obs");
+        psF32 zpt_stdev = psMetadataLookupF32(&status, md, "zpt_stdev");
+
+        if (!relExpInsert(config->dbh,
+            0,          // relexp_id (auto increment)
+            rel_id,
+            exp_id,
+            chip_id,
+            cam_id,
+            state,
+            flags,
+            zpt_obs,
+            zpt_stdev,
+            path_base,
+            now,       // registered
+            now        // time_stamp
+        )) {
+            if (!psDBRollback(config->dbh)) {
+                psError(PS_ERR_UNKNOWN, false, "database error");
+            }
+            psError(PS_ERR_UNKNOWN, false,
+                    "failed to trying to insert relExp for cam_id %" PRId64, cam_id);
+            psFree(output);
+            psFree(now);
+            return false;
+        }
+    }
+    psFree(output);
+
+    if (!psDBCommit(config->dbh)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+
+    return true;
+}
+
+static bool updaterelexpMode(pxConfig *config)
+{
+    psError(PS_ERR_UNKNOWN, true, "not yet implemented");
+    return false;
+}
+
+static bool listrelexpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    psMetadata *where = psMetadataAlloc();
+
+    PXOPT_COPY_STR(config->args, where, "-releaseName", "ippRelease.releaseName", "LIKE");
+    pxAddLabelSearchArgs(config, where, "-release_state","ippRelease.state", "==");
+    PXOPT_COPY_STR(config->args, where, "-state",       "relExp.state", "==");
+    PXOPT_COPY_STR(config->args, where, "-filter",      "rawExp.filter", "LIKE");
+    PXOPT_COPY_TIME(config->args, where, "-dateobs_begin","rawExp.dateobs", ">=");
+    PXOPT_COPY_TIME(config->args, where, "-dateobs_end", "rawExp.dateobs", "<=");
+    PXOPT_COPY_F32(config->args, where, "-fwhm_min",    "camProcessedExp.fwhm_major", ">=");
+    PXOPT_COPY_F32(config->args, where, "-fwhm_max",    "camProcessedExp.fwhm_major", "<=");
+    PXOPT_COPY_STR(config->args, where, "-exp_name",    "rawExp.exp_name", "==");
+    PXOPT_COPY_S64(config->args, where, "-exp_id",      "relExp.exp_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-chip_id",     "relExp.chip_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-cam_id",      "relExp.cam_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-warp_id",     "warpRun.warp_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-chip_data_group", "chipRun.data_group", "LIKE");
+    PXOPT_COPY_STR(config->args, where, "-cam_data_group",  "camRun.data_group", "LIKE");
+    PXOPT_COPY_STR(config->args, where, "-warp_data_group", "warpRun.data_group", "LIKE");
+
+    PXOPT_COPY_STR(config->args, where, "-surveyName",  "survey.surveyName", "LIKE");
+    PXOPT_COPY_S32(config->args, where, "-rel_id",      "relExp.rel_id", "==");
+
+    PXOPT_LOOKUP_BOOL(priority_order, config->args, "-priority_order", false);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psString query = pxDataGet("releasetool_listrelexp.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    psString where2 = NULL;
+    if (!pxspaceAddWhere(config, &where2, "rawExp")) {
+        psError(psErrorCodeLast(), false, "pxspaceAddWhere failed");
+        return false;
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, "\nWHERE %s", whereClause);
+        psFree(whereClause);
+    } else if (where2) {
+        psStringAppend(&query, "\nWHERE ");
+    } else {
+        psError(PXTOOLS_ERR_CONFIG, false, "search parameters are required\n");
+        psFree(where);
+        return false;
+    }
+
+    if (where2) {
+        psStringAppend(&query, "\n%s", where2);
+        psFree(where2);
+    }
+
+    if (priority_order) {
+        psStringAppend(&query, "\nAND priority > 0 order by exp_id, priority");
+    }
+
+    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("releasetool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    if (!ippdbPrintMetadatas(stdout, output, "relExp", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
Index: branches/eam_branches/ipp-20121219/ippTools/src/releasetool.h
===================================================================
--- branches/eam_branches/ipp-20121219/ippTools/src/releasetool.h	(revision 35096)
+++ branches/eam_branches/ipp-20121219/ippTools/src/releasetool.h	(revision 35096)
@@ -0,0 +1,39 @@
+/*
+ * releasetool.h
+ *
+ * Copyright (C) 2013 University of Hawaii IFA 
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef RELEASETOOL_H
+#define RELEASETOOL_H 1
+
+#include "pxtools.h"
+
+typedef enum {
+    RELEASETOOL_MODE_NONE      = 0x0,
+    RELEASETOOL_MODE_DEFINESURVEY,
+    RELEASETOOL_MODE_LISTSURVEY,
+    RELEASETOOL_MODE_DEFINERELEASE,
+    RELEASETOOL_MODE_UPDATERELEASE,
+    RELEASETOOL_MODE_LISTRELEASE,
+    RELEASETOOL_MODE_DEFINERELEXP,
+    RELEASETOOL_MODE_UPDATERELEXP,
+    RELEASETOOL_MODE_LISTRELEXP,
+} releasetoolMode;
+
+pxConfig *releasetoolConfig(pxConfig *config, int argc, char **argv);
+
+#endif // RELEASETOOL_H
Index: branches/eam_branches/ipp-20121219/ippTools/src/releasetoolConfig.c
===================================================================
--- branches/eam_branches/ipp-20121219/ippTools/src/releasetoolConfig.c	(revision 35096)
+++ branches/eam_branches/ipp-20121219/ippTools/src/releasetoolConfig.c	(revision 35096)
@@ -0,0 +1,189 @@
+/*
+ * releasetoolConfig.c
+ *
+ * Copyright (C) 2013 IfA University of Hawaii
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdint.h>
+
+#include <psmodules.h>
+
+#include "pxtools.h"
+#include "pxspace.h"
+#include "releasetool.h"
+
+pxConfig *releasetoolConfig(pxConfig *config, int argc, char **argv)
+{
+    if (!config) {
+        config = pxConfigAlloc();
+    }
+
+    pmConfigReadParamsSet(false);
+
+    config->modules = pmConfigRead(&argc, argv, NULL);
+    if (! config->modules) {
+        psError(psErrorCodeLast(), false, "Can't find site configuration");
+        psFree(config);
+        return NULL;
+    }
+
+    // -definesurvey
+    psMetadata *definesurveyArgs = psMetadataAlloc();
+    psMetadataAddS32(definesurveyArgs, PS_LIST_TAIL, "-set_surveyID",   0, "define survey ID (required)", 0);
+    psMetadataAddStr(definesurveyArgs, PS_LIST_TAIL, "-set_surveyName", 0, "define survey name (required)", NULL);
+    psMetadataAddStr(definesurveyArgs, PS_LIST_TAIL, "-set_description", 0, "define survey description", NULL);
+
+    // -listsurvey
+    psMetadata *listsurveyArgs = psMetadataAlloc();
+    psMetadataAddStr(listsurveyArgs,  PS_LIST_TAIL, "-surveyName", 0, "select by survey name (LIKE comparision)", NULL);
+    psMetadataAddU64(listsurveyArgs,  PS_LIST_TAIL, "-limit",       0, "limit result set to N items", 0);
+    psMetadataAddBool(listsurveyArgs, PS_LIST_TAIL, "-simple",      0, "use the simple output format", false);
+
+    // -definerelease
+    psMetadata *definereleaseArgs = psMetadataAlloc();
+    psMetadataAddS32(definereleaseArgs, PS_LIST_TAIL, "-set_surveyID", 0,      "define survey ID (required)", 0);
+    psMetadataAddStr(definereleaseArgs, PS_LIST_TAIL, "-set_releaseName", 0,   "define release name (required)", NULL);
+    psMetadataAddS32(definereleaseArgs, PS_LIST_TAIL, "-set_dataRelease", 0,   "define dataRelease", -1);
+    psMetadataAddStr(definereleaseArgs, PS_LIST_TAIL, "-set_release_state", 0, "define release state", NULL);
+    psMetadataAddS32(definereleaseArgs, PS_LIST_TAIL, "-set_priority", 0,      "define release priority", -1);
+
+    // -uptdaterelease
+    psMetadata *updatereleaseArgs = psMetadataAlloc();
+
+    // releaseName and/or rel_id is required. This is handled in updatereleaseMode
+    psMetadataAddStr(updatereleaseArgs, PS_LIST_TAIL, "-releaseName", 0,        "select by release name", NULL);
+    psMetadataAddS32(updatereleaseArgs, PS_LIST_TAIL, "-rel_id", 0,             "select by release ID", 0);
+
+    // Only support changing state and priority for now
+    psMetadataAddStr(updatereleaseArgs, PS_LIST_TAIL, "-set_release_state", 0,  "define new release state(required)", NULL);
+    psMetadataAddS32(updatereleaseArgs, PS_LIST_TAIL, "-set_priority", 0,       "define new release priority", 0);
+
+//    psMetadataAddS32(updatereleaseArgs, PS_LIST_TAIL, "-set_surveyID", 0,       "define surveyID (required)", 0);
+//    psMetadataAddStr(updatereleaseArgs, PS_LIST_TAIL, "-set_releaseName", 0,    "define release name (required)", NULL);
+//    psMetadataAddS32(updatereleaseArgs, PS_LIST_TAIL, "-set_dataRelease", 0,    "define dataRelease", -1);
+
+
+    // -listrelease
+    psMetadata *listreleaseArgs = psMetadataAlloc();
+    psMetadataAddStr(listreleaseArgs,  PS_LIST_TAIL, "-surveyName", 0,  "select by survey name (LIKE comparision)", NULL);
+    psMetadataAddStr(listreleaseArgs,  PS_LIST_TAIL, "-releaseName", 0, "select by release name (LIKE comparision)", NULL);
+    psMetadataAddStr(listreleaseArgs,  PS_LIST_TAIL, "-release_state",  0, "select by release state", NULL);
+    psMetadataAddS32(listreleaseArgs, PS_LIST_TAIL,  "-rel_id", 0,      "select by release ID", 0);
+
+    psMetadataAddU64(listreleaseArgs,  PS_LIST_TAIL, "-limit",       0, "limit result set to N items", 0);
+    psMetadataAddBool(listreleaseArgs, PS_LIST_TAIL, "-simple",      0, "use the simple output format", false);
+
+    // -definerelexp
+    psMetadata *definerelexpArgs = psMetadataAlloc();
+
+        // set the target release
+    psMetadataAddStr(definerelexpArgs,  PS_LIST_TAIL, "-releaseName", 0, "define release name", NULL);
+    psMetadataAddS32(definerelexpArgs, PS_LIST_TAIL,  "-rel_id", 0,      "define release ID", 0);
+
+        // select the processing
+    psMetadataAddS64(definerelexpArgs, PS_LIST_TAIL,  "-cam_id", 0,      "select by cam ID", 0);
+    psMetadataAddStr(definerelexpArgs,  PS_LIST_TAIL, "-label",  0,      "select by camRun.label", NULL);
+    psMetadataAddStr(definerelexpArgs,  PS_LIST_TAIL, "-data_group", 0,  "select by camRun.data_group", NULL);
+
+        // select a specific exposure from the "processing"
+    psMetadataAddS64(definerelexpArgs, PS_LIST_TAIL,  "-exp_id", 0,      "select by exposure ID", 0);
+    psMetadataAddStr(definerelexpArgs,  PS_LIST_TAIL, "-exp_name", 0,    "select by exposure name", NULL);
+
+        // parameters of the relExp
+    psMetadataAddStr(definerelexpArgs,  PS_LIST_TAIL, "-set_state", 0,      "define state (required)", NULL);
+    psMetadataAddStr(definerelexpArgs,  PS_LIST_TAIL, "-set_path_base", 0,  "define state", NULL);
+    psMetadataAddU32(definerelexpArgs,  PS_LIST_TAIL, "-set_flags", 0,      "define flags", 0);
+
+    psMetadataAddBool(definerelexpArgs, PS_LIST_TAIL, "-pretend",  0, "do not actual modify the database", false);
+    psMetadataAddBool(definerelexpArgs, PS_LIST_TAIL, "-simple",  0, "use the simpel output format", false);
+
+
+
+    // -updaterelexp
+    psMetadata *updaterelexpArgs = psMetadataAlloc();
+    psMetadataAddStr(updaterelexpArgs,  PS_LIST_TAIL, "-releaseName", 0, "select by release name (LIKE comparision)", NULL);
+
+    // -listrelexp
+    psMetadata *listrelexpArgs = psMetadataAlloc();
+    psMetadataAddStr(listrelexpArgs,  PS_LIST_TAIL, "-releaseName", 0,  "select by release name (LIKE comparision)", NULL);
+    psMetadataAddStr(listrelexpArgs,  PS_LIST_TAIL, "-release_state", PS_META_DUPLICATE_OK, "select by release state", NULL);
+    psMetadataAddStr(listrelexpArgs,  PS_LIST_TAIL, "-state", 0,        "select by released exposure state", NULL);
+
+    psMetadataAddStr(listrelexpArgs,  PS_LIST_TAIL, "-filter", 0,       "select by exposure name (LIKE comparison)", NULL);
+    psMetadataAddTime(listrelexpArgs, PS_LIST_TAIL, "-dateobs_begin", 0,"search for exposures by time (>=)", NULL);
+    psMetadataAddTime(listrelexpArgs, PS_LIST_TAIL, "-dateobs_end", 0,  "search for exposures by time (<=)", NULL);
+
+    pxspaceAddArguments(listrelexpArgs);
+
+    psMetadataAddF32(listrelexpArgs,  PS_LIST_TAIL, "-fwhm_min", 0, "search by measured seeing (>=)", NAN);
+    psMetadataAddF32(listrelexpArgs,  PS_LIST_TAIL, "-fwhm_max", 0, "search by seeing (<=)", NAN);
+
+    psMetadataAddStr(listrelexpArgs,  PS_LIST_TAIL, "-exp_name", 0, "select by exposure name", NULL);
+
+    psMetadataAddS64(listrelexpArgs,  PS_LIST_TAIL, "-exp_id", 0, "select by exposure ID", 0);
+    psMetadataAddS64(listrelexpArgs,  PS_LIST_TAIL, "-chip_id", 0, "select by chip ID", 0);
+    psMetadataAddS64(listrelexpArgs,  PS_LIST_TAIL, "-cam_id", 0, "select by cam ID", 0);
+    psMetadataAddS64(listrelexpArgs,  PS_LIST_TAIL, "-warp_id", 0, "select by warp ID", 0);
+
+    psMetadataAddStr(listrelexpArgs,  PS_LIST_TAIL, "-chip_data_group", 0, "chipRun.data_group (LIKE comparison)", NULL);
+    psMetadataAddStr(listrelexpArgs,  PS_LIST_TAIL, "-cam_data_group", 0, "camRun.data_group (LIKE comparison)", NULL);
+    psMetadataAddStr(listrelexpArgs,  PS_LIST_TAIL, "-warp_data_group", 0, "warpRun.data_group (LIKE comparison)", NULL);
+
+    psMetadataAddStr(listrelexpArgs,  PS_LIST_TAIL, "-surveyName", 0, "select by survey name (LIKE comparision)", NULL);
+    psMetadataAddS64(listrelexpArgs,  PS_LIST_TAIL, "-rel_id", 0, "select by release ID", 0);
+
+    psMetadataAddBool(listrelexpArgs, PS_LIST_TAIL, "-priority_order",   0, "order by release priority", false);
+
+    psMetadataAddU64(listrelexpArgs,  PS_LIST_TAIL, "-limit",       0, "limit result set to N items", 0);
+    psMetadataAddBool(listrelexpArgs, PS_LIST_TAIL, "-simple",      0, "use the simple output format", false);
+
+    psMetadata *argSets = psMetadataAlloc();
+    psMetadata *modes = psMetadataAlloc();
+
+    PXOPT_ADD_MODE("-definesurvey",     "define a survey",              RELEASETOOL_MODE_DEFINESURVEY,  definesurveyArgs);
+    PXOPT_ADD_MODE("-listsurvey",       "list skycell parameters",      RELEASETOOL_MODE_LISTSURVEY,    listsurveyArgs);
+    PXOPT_ADD_MODE("-definerelease",    "define a release",             RELEASETOOL_MODE_DEFINERELEASE, definereleaseArgs);
+    PXOPT_ADD_MODE("-updaterelease",    "update a release",             RELEASETOOL_MODE_UPDATERELEASE, updatereleaseArgs);
+    PXOPT_ADD_MODE("-listrelease",      "list releases",                RELEASETOOL_MODE_LISTRELEASE,   listreleaseArgs);
+    PXOPT_ADD_MODE("-definerelexp",     "define a released exposure",   RELEASETOOL_MODE_DEFINERELEXP,  definerelexpArgs);
+    PXOPT_ADD_MODE("-updaterelexp",     "update a released exposure",   RELEASETOOL_MODE_UPDATERELEXP,  updaterelexpArgs);
+    PXOPT_ADD_MODE("-listrelexp",       "list released exposures",      RELEASETOOL_MODE_LISTRELEXP,    listrelexpArgs);
+
+    if (!pxGetOptions(stderr, argc, argv, config, modes, argSets)) {
+        psError(PS_ERR_UNKNOWN, false, "option parsing failed");
+        psFree(argSets);
+        psFree(modes);
+        psFree(config);
+        return NULL;
+    }
+
+    psFree(argSets);
+    psFree(modes);
+
+    // define Database handle, if used
+    config->dbh = psMemIncrRefCounter(pmConfigDB(config->modules));
+    if (!config->dbh) {
+        psError(PS_ERR_UNKNOWN, false, "Can't configure database");
+        psFree(config);
+        return NULL;
+    }
+
+    return config;
+}
Index: branches/eam_branches/ipp-20121219/ippTools/src/staticskytool.c
===================================================================
--- branches/eam_branches/ipp-20121219/ippTools/src/staticskytool.c	(revision 34903)
+++ branches/eam_branches/ipp-20121219/ippTools/src/staticskytool.c	(revision 35096)
@@ -503,4 +503,5 @@
     PXOPT_COPY_S64(config->args, whereMD, "-sky_id", "sky_id", "==");
     pxAddLabelSearchArgs (config, whereMD, "-label", "staticskyRun.label", "==");
+    pxskycellAddWhere(config, whereMD);
 
     PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
@@ -736,4 +737,9 @@
     PXOPT_COPY_S16(config->args, where, "-fault", "staticskyResult.fault", "==");
 
+    if (!pxskycellAddWhere(config, where)) {
+        psError(PXTOOLS_ERR_CONFIG, false, "failed to add skycell search arguments");
+        return false;
+    }
+
     if (!psListLength(where->list) && !psMetadataLookupBool(NULL, config->args, "-all")) {
         psFree(where);
@@ -1066,16 +1072,20 @@
     psFree(whereMD);
 
+    psString labelHook = psStringCopy("");
     if (!rerun) {
         if (label)  {
-            psStringAppend(&query, "\nAND (skycalRun.label IS NULL OR skycalRun.label = '%s')", label);
+            psStringAppend(&labelHook, "\nAND skycalRun.label = '%s'", label);
         }
         psStringAppend(&query, "\nAND skycal_id IS NULL");
     }
 
-    if (!p_psDBRunQuery(config->dbh, query)) {
+
+    if (!p_psDBRunQueryF(config->dbh, query, labelHook)) {
         psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(labelHook);
         psFree(query);
         return false;
     }
+    psFree(labelHook);
     psFree(query);
 
@@ -1392,5 +1402,11 @@
     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, "-quality",     "skycalResult.quality", "==");
     PXOPT_COPY_S16(config->args, where, "-fault",      "skycalResult.fault", "==");
+
+    if (!pxskycellAddWhere(config, where)) {
+        psError(PXTOOLS_ERR_CONFIG, false, "failed to add skycell search arguments");
+        return false;
+    }
 
     PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
@@ -1468,4 +1484,8 @@
     pxAddLabelSearchArgs(config, where, "-filter", "stackRun.filter", "==");
     PXOPT_COPY_S16(config->args, where, "-fault", "skycalResult.fault", "==");
+    if (!pxskycellAddWhere(config, where)) {
+        psError(PXTOOLS_ERR_CONFIG, false, "failed to add skycell search arguments");
+        return false;
+    }
 
     if (!psListLength(where->list) && !psMetadataLookupBool(NULL, config->args, "-all")) {
Index: branches/eam_branches/ipp-20121219/ippTools/src/staticskytoolConfig.c
===================================================================
--- branches/eam_branches/ipp-20121219/ippTools/src/staticskytoolConfig.c	(revision 34903)
+++ branches/eam_branches/ipp-20121219/ippTools/src/staticskytoolConfig.c	(revision 35096)
@@ -51,5 +51,5 @@
     psMetadataAddStr(definebyqueryArgs,  PS_LIST_TAIL, "-select_skycell_id", 0, "search for skycell_id", NULL);
     psMetadataAddStr(definebyqueryArgs,  PS_LIST_TAIL, "-select_tess_id", 0, "search for tess_id", NULL);
-    psMetadataAddF32(definebyqueryArgs,  PS_LIST_TAIL, "-select_good_frac_min", 0, "define min good_frac", 0.0);
+    psMetadataAddF32(definebyqueryArgs,  PS_LIST_TAIL, "-select_good_frac_min", 0, "define min good_frac", NAN);
     psMetadataAddStr(definebyqueryArgs,  PS_LIST_TAIL, "-select_label", PS_META_DUPLICATE_OK, "search by stackRun label (LIKE comparison, multiple OK)", NULL);
     psMetadataAddStr(definebyqueryArgs,  PS_LIST_TAIL, "-select_data_group", PS_META_DUPLICATE_OK, "search by stackRun data_group (LIKE comparison, multiple OK)", NULL);
@@ -103,4 +103,5 @@
     psMetadataAddS64(todoArgs, PS_LIST_TAIL, "-sky_id", 0, "search by staticsky ID", 0);
     psMetadataAddStr(todoArgs, PS_LIST_TAIL, "-label", PS_META_DUPLICATE_OK, "search by label", NULL);
+    pxskycellAddArguments(todoArgs);
     psMetadataAddU64(todoArgs, PS_LIST_TAIL, "-limit", 0, "limit result set to N items", 0);
     psMetadataAddBool(todoArgs, PS_LIST_TAIL, "-simple", 0, "use the simple output format", false);
@@ -138,4 +139,5 @@
     psMetadataAddStr(revertArgs, PS_LIST_TAIL, "-label", PS_META_DUPLICATE_OK, "search by label", 0);
     psMetadataAddS16(revertArgs, PS_LIST_TAIL, "-fault", 0, "search by fault code", 0);
+    pxskycellAddArguments(revertArgs);
     psMetadataAddBool(revertArgs, PS_LIST_TAIL, "-all", 0, "allow no search terms", false);
 
@@ -162,5 +164,5 @@
     psMetadataAddStr(defineskycalrunArgs,  PS_LIST_TAIL, "-select_skycell_id", 0, "search for skycell_id", NULL);
     psMetadataAddStr(defineskycalrunArgs,  PS_LIST_TAIL, "-select_tess_id", 0, "search for tess_id", NULL);
-    psMetadataAddF32(defineskycalrunArgs,  PS_LIST_TAIL, "-select_good_frac_min", 0, "define min good_frac", 0.0);
+    psMetadataAddF32(defineskycalrunArgs,  PS_LIST_TAIL, "-select_good_frac_min", 0, "define min good_frac", NAN);
     psMetadataAddStr(defineskycalrunArgs,  PS_LIST_TAIL, "-select_label", PS_META_DUPLICATE_OK, "search by stackRun label (LIKE comparison, multiple OK)", NULL);
     psMetadataAddStr(defineskycalrunArgs,  PS_LIST_TAIL, "-select_data_group", PS_META_DUPLICATE_OK, "search by stackRun data_group (LIKE comparison, multiple OK)", NULL);
@@ -238,4 +240,5 @@
     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);
+    pxskycellAddArguments(revertskycalArgs);
     psMetadataAddS16(revertskycalArgs, PS_LIST_TAIL, "-fault", 0, "search by fault code", 0);
     psMetadataAddBool(revertskycalArgs, PS_LIST_TAIL, "-all", 0, "allow no search terms", false);
@@ -257,5 +260,7 @@
     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, "-quality",  0, "search by quality", 0);
     psMetadataAddS16(skycalresultArgs, PS_LIST_TAIL, "-fault", 0, "search by fault code", 0);
+    pxskycellAddArguments(skycalresultArgs);
     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);
