Index: trunk/ippdb/src/ippdb.c
===================================================================
--- trunk/ippdb/src/ippdb.c	(revision 9054)
+++ trunk/ippdb/src/ippdb.c	(revision 9107)
@@ -63,4 +63,6 @@
 #define DETPROCESSEDIMFILE_TABLE_NAME "detProcessedImfile"
 #define DETPROCESSEDIMFILE_INDEX_NAME IPPDB_DEFAULT_INDEX_NAME
+#define DETPROCESSEDEXP_TABLE_NAME "detProcessedExp"
+#define DETPROCESSEDEXP_INDEX_NAME IPPDB_DEFAULT_INDEX_NAME
 #define DETSTACKEDIMFILE_TABLE_NAME "detStackedImfile"
 #define DETSTACKEDIMFILE_INDEX_NAME IPPDB_DEFAULT_INDEX_NAME
@@ -14301,7 +14303,598 @@
     return true;
 }
+static void detProcessedExpRowFree(detProcessedExpRow *object);
+
+detProcessedExpRow *detProcessedExpRowAlloc(psS32 det_id, const char *exp_tag, const char *recipe, psF64 bg, psF64 bg_stdev, psF64 bg_mean_stdev, const char *b1_uri, const char *b2_uri)
+{
+    detProcessedExpRow *object;
+
+    object = psAlloc(sizeof(detProcessedExpRow));
+    psMemSetDeallocator(object, (psFreeFunc)detProcessedExpRowFree);
+
+    object->det_id = det_id;
+    object->exp_tag = psStringCopy(exp_tag);
+    object->recipe = psStringCopy(recipe);
+    object->bg = bg;
+    object->bg_stdev = bg_stdev;
+    object->bg_mean_stdev = bg_mean_stdev;
+    object->b1_uri = psStringCopy(b1_uri);
+    object->b2_uri = psStringCopy(b2_uri);
+
+    return object;
+}
+
+static void detProcessedExpRowFree(detProcessedExpRow *object)
+{
+    psFree(object->exp_tag);
+    psFree(object->recipe);
+    psFree(object->b1_uri);
+    psFree(object->b2_uri);
+}
+
+bool detProcessedExpCreateTable(psDB *dbh)
+{
+    psMetadata      *md;
+    bool            status;
+
+    md = psMetadataAlloc();
+    if (!psMetadataAdd(md, PS_LIST_TAIL, DETPROCESSEDEXP_INDEX_NAME, PS_DATA_S32, "AUTO_INCREMENT", 0.0)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item %s", DETPROCESSEDEXP_INDEX_NAME);
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAddS32(md, PS_LIST_TAIL, "det_id", 0, "Primary Key", 0)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item det_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAddStr(md, PS_LIST_TAIL, "exp_tag", 0, "Primary Key", "64")) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item exp_tag");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAddStr(md, PS_LIST_TAIL, "recipe", 0, NULL, "64")) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item recipe");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAddF64(md, PS_LIST_TAIL, "bg", 0, NULL, 0.0)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item bg");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAddF64(md, PS_LIST_TAIL, "bg_stdev", 0, NULL, 0.0)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item bg_stdev");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAddF64(md, PS_LIST_TAIL, "bg_mean_stdev", 0, NULL, 0.0)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item bg_mean_stdev");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAddStr(md, PS_LIST_TAIL, "b1_uri", 0, NULL, "64")) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item b1_uri");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAddStr(md, PS_LIST_TAIL, "b2_uri", 0, NULL, "64")) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item b2_uri");
+        psFree(md);
+        return false;
+    }
+
+    status = psDBCreateTable(dbh, DETPROCESSEDEXP_TABLE_NAME, md);
+
+    psFree(md);
+
+    return status;
+}
+
+bool detProcessedExpDropTable(psDB *dbh)
+{
+    return psDBDropTable(dbh, DETPROCESSEDEXP_TABLE_NAME);
+}
+
+bool detProcessedExpInsert(psDB * dbh, psS32 det_id, const char *exp_tag, const char *recipe, psF64 bg, psF64 bg_stdev, psF64 bg_mean_stdev, const char *b1_uri, const char *b2_uri)
+{
+    psMetadata      *md;
+    bool            status;
+
+    md = psMetadataAlloc();
+    if (!psMetadataAddS32(md, PS_LIST_TAIL, "det_id", 0, NULL, det_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item det_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAddStr(md, PS_LIST_TAIL, "exp_tag", 0, NULL, exp_tag)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item exp_tag");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAddStr(md, PS_LIST_TAIL, "recipe", 0, NULL, recipe)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item recipe");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAddF64(md, PS_LIST_TAIL, "bg", 0, NULL, bg)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item bg");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAddF64(md, PS_LIST_TAIL, "bg_stdev", 0, NULL, bg_stdev)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item bg_stdev");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAddF64(md, PS_LIST_TAIL, "bg_mean_stdev", 0, NULL, bg_mean_stdev)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item bg_mean_stdev");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAddStr(md, PS_LIST_TAIL, "b1_uri", 0, NULL, b1_uri)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item b1_uri");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAddStr(md, PS_LIST_TAIL, "b2_uri", 0, NULL, b2_uri)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item b2_uri");
+        psFree(md);
+        return false;
+    }
+
+    status = psDBInsertOneRow(dbh, DETPROCESSEDEXP_TABLE_NAME, md);
+    psFree(md);
+
+    return status;
+}
+
+long long detProcessedExpDelete(psDB *dbh, const psMetadata *where, unsigned long long limit)
+{
+    long long       deleted = 0;
+
+    long long count = psDBDeleteRows(dbh, DETPROCESSEDEXP_TABLE_NAME, where, limit);
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from detProcessedExp");
+        return count;
+
+        deleted += count;
+    }
+
+    return deleted;
+}
+bool detProcessedExpPop(psDB *dbh, psS32 *det_id, char **exp_tag, char **recipe, psF64 *bg, psF64 *bg_stdev, psF64 *bg_mean_stdev, char **b1_uri, char **b2_uri)
+{
+    psArray         *rowSet;
+    psMetadata      *row;
+    psMetadata      *popped;
+    long            deleted;
+    bool            status;
+    int             rowID;
+
+    rowSet = psDBSelectRows(dbh, DETPROCESSEDEXP_TABLE_NAME, NULL, 1);
+    if (!rowSet) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item %s", DETPROCESSEDEXP_INDEX_NAME);
+        psFree(rowSet);
+        return NULL;
+    }
+
+    row = psArrayGet(rowSet, 0);
+    psMemIncrRefCounter(row);
+    if (!row) {
+        psError(PS_ERR_UNKNOWN, true, "database error or table is empty");
+        return NULL;
+    }
+    psFree(rowSet);
+
+    rowID = psMetadataLookupS32(&status, row, DETPROCESSEDEXP_INDEX_NAME);
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item %s", DETPROCESSEDEXP_INDEX_NAME);
+        psFree(row);
+        return NULL;
+    }
+
+    popped = psMetadataAlloc();
+    psMetadataAddS32(popped, PS_LIST_TAIL, DETPROCESSEDEXP_INDEX_NAME, 0, NULL, rowID);
+
+    deleted = psDBDeleteRows(dbh, DETPROCESSEDEXP_TABLE_NAME, popped, 0);
+    if (deleted != 1) {
+        psError(PS_ERR_UNKNOWN, false, "database failed to delete row");
+        psFree(popped);
+        psFree(row);
+        return NULL;
+    }
+
+    psFree(popped);
+
+    *det_id = psMetadataLookupS32(&status, row, "det_id");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item det_id");
+        psFree(row);
+        return false;
+    }
+    *exp_tag = psMetadataLookupPtr(&status, row, "exp_tag");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item exp_tag");
+        psFree(row);
+        return false;
+    }
+    *recipe = psMetadataLookupPtr(&status, row, "recipe");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item recipe");
+        psFree(row);
+        return false;
+    }
+    *bg = psMetadataLookupF64(&status, row, "bg");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item bg");
+        psFree(row);
+        return false;
+    }
+    *bg_stdev = psMetadataLookupF64(&status, row, "bg_stdev");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item bg_stdev");
+        psFree(row);
+        return false;
+    }
+    *bg_mean_stdev = psMetadataLookupF64(&status, row, "bg_mean_stdev");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item bg_mean_stdev");
+        psFree(row);
+        return false;
+    }
+    *b1_uri = psMetadataLookupPtr(&status, row, "b1_uri");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item b1_uri");
+        psFree(row);
+        return false;
+    }
+    *b2_uri = psMetadataLookupPtr(&status, row, "b2_uri");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item b2_uri");
+        psFree(row);
+        return false;
+    }
+
+    psFree(row);
+
+    return true;
+}
+
+bool detProcessedExpInsertObject(psDB *dbh, detProcessedExpRow *object)
+{
+    return detProcessedExpInsert(dbh, object->det_id, object->exp_tag, object->recipe, object->bg, object->bg_stdev, object->bg_mean_stdev, object->b1_uri, object->b2_uri);
+}
+
+bool detProcessedExpInsertObjects(psDB *dbh, psArray *objects)
+{
+    for (long i = 0; i < psArrayLength(objects); i++) {
+        if (!detProcessedExpInsertObject(dbh, objects->data[i])) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+detProcessedExpRow *detProcessedExpPopObject(psDB *dbh)
+{
+    psS32           det_id;
+    char            exp_tag[256];
+    char            recipe[256];
+    psF64           bg;
+    psF64           bg_stdev;
+    psF64           bg_mean_stdev;
+    char            b1_uri[256];
+    char            b2_uri[256];
+
+    if (!detProcessedExpPop(dbh, &det_id, (char **)&exp_tag, (char **)&recipe, &bg, &bg_stdev, &bg_mean_stdev, (char **)&b1_uri, (char **)&b2_uri)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to pop a database row");
+        return NULL;
+    }
+
+    return detProcessedExpRowAlloc(det_id, exp_tag, recipe, bg, bg_stdev, bg_mean_stdev, b1_uri, b2_uri);
+}
+
+bool detProcessedExpInsertFits(psDB *dbh, const psFits *fits)
+{
+    psArray         *rowSet;
+
+    // move to (the first?) extension named  DETPROCESSEDEXP_TABLE_NAME
+    if (!psFitsMoveExtName(fits, DETPROCESSEDEXP_TABLE_NAME)) {
+        psError(PS_ERR_UNKNOWN, true, "failed to find FITS extension %s", DETPROCESSEDEXP_TABLE_NAME);
+        return false;
+    }
+
+    // check HDU type
+    if (psFitsGetExtType(fits) != PS_FITS_TYPE_BINARY_TABLE)  {
+        psError(PS_ERR_UNKNOWN, true, "FITS HDU type is not PS_FITS_TYPE_BINARY_TABLE");
+        return false;
+    }
+
+    // read fits table
+    rowSet = psFitsReadTable(fits);
+    if (!rowSet) {
+        psError(PS_ERR_UNKNOWN, true, "FITS read error or FITS table is empty");
+        psFree(rowSet);
+        return false;
+    }
+
+    if (!psDBInsertRows(dbh, DETPROCESSEDEXP_TABLE_NAME, rowSet)) {
+        psError(PS_ERR_UNKNOWN, false, "databse insert failed");
+        psFree(rowSet);
+        return false;
+    }
+
+    psFree(rowSet);
+
+    return true;
+}
+
+bool detProcessedExpPopFits(psDB *dbh, psFits *fits, unsigned long long limit)
+{
+    char            query[MAX_STRING_LENGTH];
+
+    if (!detProcessedExpSelectRowsFits(dbh, fits, NULL, limit)) {
+        psError(PS_ERR_UNKNOWN, true, "database error or table is empty");
+        return false;
+    }
+
+    // remove limit rows from the end of the database
+    if (snprintf(query, MAX_STRING_LENGTH,
+                "DELETE FROM %s ORDER BY %s DESC LIMIT %lld",
+                DETPROCESSEDEXP_TABLE_NAME, DETPROCESSEDEXP_INDEX_NAME, limit) < 0) {
+        psError(PS_ERR_UNKNOWN, true, "query value attempted to exceed %d bytes", MAX_STRING_LENGTH);
+        return false;
+    }
+            
+    if (!p_psDBRunQuery(dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database query failed");
+        return false;
+    }
+
+    return true;
+}
+
+bool detProcessedExpSelectRowsFits(psDB *dbh, psFits *fits, const psMetadata *where, unsigned long long limit)
+{
+    psArray         *rowSet;
+    psU64           i;
+
+    rowSet = psDBSelectRows(dbh, DETPROCESSEDEXP_TABLE_NAME, where, limit);
+    if (!rowSet) {
+        return false;
+    }
+
+    // strip index column
+    for (i = 0; i < rowSet->n; i++) {
+        if (!psMetadataRemove((psMetadata *)rowSet->data[i], 0, DETPROCESSEDEXP_INDEX_NAME)) {
+            psError(PS_ERR_UNKNOWN, true, "failed to remove item %s", DETPROCESSEDEXP_INDEX_NAME);
+            psFree(rowSet);
+            return false;
+        }
+    }
+
+    // output to fits
+    if (!psFitsWriteTable(fits, NULL, rowSet, DETPROCESSEDEXP_TABLE_NAME)) {
+        psError(PS_ERR_UNKNOWN, false, "FITS table write failed");
+        psFree(rowSet);
+        return false;
+    }
+
+    psFree(rowSet);
+
+    return true;
+}
+
+psMetadata *detProcessedExpMetadataFromObject(const detProcessedExpRow *object)
+{
+    psMetadata      *md;
+
+    md = psMetadataAlloc();
+    if (!psMetadataAddS32(md, PS_LIST_TAIL, "det_id", 0, NULL, object->det_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item det_id");
+        psFree(md);
+        return NULL;
+    }
+    if (!psMetadataAddStr(md, PS_LIST_TAIL, "exp_tag", 0, NULL, object->exp_tag)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item exp_tag");
+        psFree(md);
+        return NULL;
+    }
+    if (!psMetadataAddStr(md, PS_LIST_TAIL, "recipe", 0, NULL, object->recipe)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item recipe");
+        psFree(md);
+        return NULL;
+    }
+    if (!psMetadataAddF64(md, PS_LIST_TAIL, "bg", 0, NULL, object->bg)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item bg");
+        psFree(md);
+        return NULL;
+    }
+    if (!psMetadataAddF64(md, PS_LIST_TAIL, "bg_stdev", 0, NULL, object->bg_stdev)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item bg_stdev");
+        psFree(md);
+        return NULL;
+    }
+    if (!psMetadataAddF64(md, PS_LIST_TAIL, "bg_mean_stdev", 0, NULL, object->bg_mean_stdev)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item bg_mean_stdev");
+        psFree(md);
+        return NULL;
+    }
+    if (!psMetadataAddStr(md, PS_LIST_TAIL, "b1_uri", 0, NULL, object->b1_uri)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item b1_uri");
+        psFree(md);
+        return NULL;
+    }
+    if (!psMetadataAddStr(md, PS_LIST_TAIL, "b2_uri", 0, NULL, object->b2_uri)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item b2_uri");
+        psFree(md);
+        return NULL;
+    }
+
+    return md;
+}
+
+detProcessedExpRow *detProcessedExpObjectFromMetadata(psMetadata *md)
+{
+    bool            status;
+    psS32           det_id;
+    char            *exp_tag;
+    char            *recipe;
+    psF64           bg;
+    psF64           bg_stdev;
+    psF64           bg_mean_stdev;
+    char            *b1_uri;
+    char            *b2_uri;
+
+    det_id = psMetadataLookupS32(&status, md, "det_id");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item det_id");
+        return false;
+    }
+    exp_tag = psMetadataLookupPtr(&status, md, "exp_tag");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item exp_tag");
+        return false;
+    }
+    recipe = psMetadataLookupPtr(&status, md, "recipe");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item recipe");
+        return false;
+    }
+    bg = psMetadataLookupF64(&status, md, "bg");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item bg");
+        return false;
+    }
+    bg_stdev = psMetadataLookupF64(&status, md, "bg_stdev");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item bg_stdev");
+        return false;
+    }
+    bg_mean_stdev = psMetadataLookupF64(&status, md, "bg_mean_stdev");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item bg_mean_stdev");
+        return false;
+    }
+    b1_uri = psMetadataLookupPtr(&status, md, "b1_uri");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item b1_uri");
+        return false;
+    }
+    b2_uri = psMetadataLookupPtr(&status, md, "b2_uri");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item b2_uri");
+        return false;
+    }
+
+    return detProcessedExpRowAlloc(det_id, exp_tag, recipe, bg, bg_stdev, bg_mean_stdev, b1_uri, b2_uri);
+}
+psArray *detProcessedExpSelectRowObjects(psDB *dbh, const psMetadata *where, unsigned long long limit)
+{
+    psArray         *rowSet;
+    psArray         *returnSet;
+    psU64           i;
+
+    rowSet = psDBSelectRows(dbh, DETPROCESSEDEXP_TABLE_NAME, where, limit);
+    if (!rowSet) {
+        return NULL;
+    }
+
+    // strip index column
+    for (i = 0; i < rowSet->n; i++) {
+        if (!psMetadataRemove((psMetadata *)(rowSet->data[i]), 0, DETPROCESSEDEXP_INDEX_NAME)) {
+            psError(PS_ERR_UNKNOWN, true, "failed to remove item %s", DETPROCESSEDEXP_INDEX_NAME);
+            psFree(rowSet);
+            return false;
+        }
+    }
+
+    // convert psMetadata rows to row objects
+
+    returnSet = psArrayAlloc(rowSet->n);
+    returnSet->n = 0;
+
+    for (i = 0; i < rowSet->n; i++) {
+        detProcessedExpRow *object = detProcessedExpObjectFromMetadata(rowSet->data[i]);
+        psArrayAdd(returnSet, 0, object);
+        psFree(object);
+    }
+
+    psFree(rowSet);
+
+    return returnSet;
+}
+bool detProcessedExpDeleteObject(psDB *dbh, const detProcessedExpRow *object)
+{
+    psMetadata *where = detProcessedExpMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, DETPROCESSEDEXP_TABLE_NAME, where, 0);
+    psFree(where)
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from detProcessedExp");
+        return false;
+    }
+    if (count > 1) {
+        // XXX should this be a psAbort() instead?  It is possible that
+        // having an object match multiple rows was by design.
+        psError(PS_ERR_UNKNOWN, true, "detProcessedExpRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
+long long detProcessedExpDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
+{
+    long long       deleted = 0;
+
+    for (long long i = 0; i < objects->n; i++) {
+        detProcessedExpRow *object = objects->data[i];
+        psMetadata *where = detProcessedExpMetadataFromObject(object);
+        long long count = psDBDeleteRows(dbh, DETPROCESSEDEXP_TABLE_NAME, where, limit);
+        psFree(where)
+        if (count < 0) {
+            psError(PS_ERR_UNKNOWN, true, "failed to delete row from detProcessedExp");
+            return count;
+        }
+
+        deleted += count;
+    }
+
+    return deleted;
+}
+bool detProcessedExpPrintObjects(FILE *stream, psArray *objects, bool mdcf)
+{
+    PS_ASSERT_PTR_NON_NULL(objects, false);
+
+    psMetadata *output = psMetadataAlloc();
+    for (long i = 0; i < psArrayLength(objects); i++) {
+        psMetadata *md = detProcessedExpMetadataFromObject(objects->data[i]);
+        if (!psMetadataAddMetadata(
+            output,
+            PS_LIST_TAIL,
+            DETPROCESSEDEXP_TABLE_NAME,
+            PS_META_DUPLICATE_OK,
+            NULL,
+            md
+        )) {
+            psError(PS_ERR_UNKNOWN, false, "failed to add metadata");
+            psFree(md);
+            psFree(output);
+            return false;
+        }
+        psFree(md);
+    }
+
+    if (!ippdbPrintMetadataRaw(stream, output, mdcf)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print metadata");
+        psFree(output);
+    }
+    psFree(output);
+
+    return true;
+}
 static void detStackedImfileRowFree(detStackedImfileRow *object);
 
-detStackedImfileRow *detStackedImfileRowAlloc(psS32 det_id, psS32 iteration, const char *class_id, const char *uri, const char *recipe, psF64 bg, psF64 bg_stdev, psF64 bg_mean_stdev, bool normalize)
+detStackedImfileRow *detStackedImfileRowAlloc(psS32 det_id, psS32 iteration, const char *class_id, const char *uri, const char *recipe, psF64 bg, psF64 bg_stdev, psF64 bg_mean_stdev)
 {
     detStackedImfileRow *object;
@@ -14318,5 +14911,4 @@
     object->bg_stdev = bg_stdev;
     object->bg_mean_stdev = bg_mean_stdev;
-    object->normalize = normalize;
 
     return object;
@@ -14381,9 +14973,4 @@
         return false;
     }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "normalize", PS_DATA_BOOL, NULL, false)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item normalize");
-        psFree(md);
-        return false;
-    }
 
     status = psDBCreateTable(dbh, DETSTACKEDIMFILE_TABLE_NAME, md);
@@ -14399,5 +14986,5 @@
 }
 
-bool detStackedImfileInsert(psDB * dbh, psS32 det_id, psS32 iteration, const char *class_id, const char *uri, const char *recipe, psF64 bg, psF64 bg_stdev, psF64 bg_mean_stdev, bool normalize)
+bool detStackedImfileInsert(psDB * dbh, psS32 det_id, psS32 iteration, const char *class_id, const char *uri, const char *recipe, psF64 bg, psF64 bg_stdev, psF64 bg_mean_stdev)
 {
     psMetadata      *md;
@@ -14442,9 +15029,4 @@
     if (!psMetadataAddF64(md, PS_LIST_TAIL, "bg_mean_stdev", 0, NULL, bg_mean_stdev)) {
         psError(PS_ERR_UNKNOWN, false, "failed to add item bg_mean_stdev");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "normalize", PS_DATA_BOOL, NULL, normalize)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item normalize");
         psFree(md);
         return false;
@@ -14471,5 +15053,5 @@
     return deleted;
 }
-bool detStackedImfilePop(psDB *dbh, psS32 *det_id, psS32 *iteration, char **class_id, char **uri, char **recipe, psF64 *bg, psF64 *bg_stdev, psF64 *bg_mean_stdev, bool *normalize)
+bool detStackedImfilePop(psDB *dbh, psS32 *det_id, psS32 *iteration, char **class_id, char **uri, char **recipe, psF64 *bg, psF64 *bg_stdev, psF64 *bg_mean_stdev)
 {
     psArray         *rowSet;
@@ -14563,10 +15145,4 @@
         return false;
     }
-    *normalize = psMetadataLookupBool(&status, row, "normalize");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item normalize");
-        psFree(row);
-        return false;
-    }
 
     psFree(row);
@@ -14577,5 +15153,5 @@
 bool detStackedImfileInsertObject(psDB *dbh, detStackedImfileRow *object)
 {
-    return detStackedImfileInsert(dbh, object->det_id, object->iteration, object->class_id, object->uri, object->recipe, object->bg, object->bg_stdev, object->bg_mean_stdev, object->normalize);
+    return detStackedImfileInsert(dbh, object->det_id, object->iteration, object->class_id, object->uri, object->recipe, object->bg, object->bg_stdev, object->bg_mean_stdev);
 }
 
@@ -14601,12 +15177,11 @@
     psF64           bg_stdev;
     psF64           bg_mean_stdev;
-    bool            normalize;
-
-    if (!detStackedImfilePop(dbh, &det_id, &iteration, (char **)&class_id, (char **)&uri, (char **)&recipe, &bg, &bg_stdev, &bg_mean_stdev, &normalize)) {
+
+    if (!detStackedImfilePop(dbh, &det_id, &iteration, (char **)&class_id, (char **)&uri, (char **)&recipe, &bg, &bg_stdev, &bg_mean_stdev)) {
         psError(PS_ERR_UNKNOWN, false, "failed to pop a database row");
         return NULL;
     }
 
-    return detStackedImfileRowAlloc(det_id, iteration, class_id, uri, recipe, bg, bg_stdev, bg_mean_stdev, normalize);
+    return detStackedImfileRowAlloc(det_id, iteration, class_id, uri, recipe, bg, bg_stdev, bg_mean_stdev);
 }
 
@@ -14744,9 +15319,4 @@
     if (!psMetadataAddF64(md, PS_LIST_TAIL, "bg_mean_stdev", 0, NULL, object->bg_mean_stdev)) {
         psError(PS_ERR_UNKNOWN, false, "failed to add item bg_mean_stdev");
-        psFree(md);
-        return NULL;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "normalize", PS_DATA_BOOL, NULL, object->normalize)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item normalize");
         psFree(md);
         return NULL;
@@ -14767,5 +15337,4 @@
     psF64           bg_stdev;
     psF64           bg_mean_stdev;
-    bool            normalize;
 
     det_id = psMetadataLookupS32(&status, md, "det_id");
@@ -14809,11 +15378,6 @@
         return false;
     }
-    normalize = psMetadataLookupBool(&status, md, "normalize");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item normalize");
-        return false;
-    }
-
-    return detStackedImfileRowAlloc(det_id, iteration, class_id, uri, recipe, bg, bg_stdev, bg_mean_stdev, normalize);
+
+    return detStackedImfileRowAlloc(det_id, iteration, class_id, uri, recipe, bg, bg_stdev, bg_mean_stdev);
 }
 psArray *detStackedImfileSelectRowObjects(psDB *dbh, const psMetadata *where, unsigned long long limit)
