Index: /trunk/ippdb/Makefile.am
===================================================================
--- /trunk/ippdb/Makefile.am	(revision 9300)
+++ /trunk/ippdb/Makefile.am	(revision 9301)
@@ -32,4 +32,5 @@
     $(top_builddir)/docs/man/man3/p2ProcessedImfileRow.3 \
     $(top_builddir)/docs/man/man3/p3PendingExpRow.3 \
+    $(top_builddir)/docs/man/man3/p3ProcessedExpRow.3 \
     $(top_builddir)/docs/man/man3/detRunRow.3 \
     $(top_builddir)/docs/man/man3/detInputExpRow.3 \
@@ -47,5 +48,5 @@
 
 
-docs/man/man3/ippdb.3 docs/man/man3/weatherRow.3 docs/man/man3/skyp_transparencyRow.3 docs/man/man3/skyp_absorptionRow.3 docs/man/man3/skyp_emissionRow.3 docs/man/man3/dimmRow.3 docs/man/man3/skyp_irRow.3 docs/man/man3/domeRow.3 docs/man/man3/telescopeRow.3 docs/man/man3/summitExpRow.3 docs/man/man3/pzPendingExpRow.3 docs/man/man3/pzPendingImfileRow.3 docs/man/man3/newExpRow.3 docs/man/man3/newImfileRow.3 docs/man/man3/rawDetrendExpRow.3 docs/man/man3/rawScienceExpRow.3 docs/man/man3/rawImfileRow.3 docs/man/man3/p1PendingExpRow.3 docs/man/man3/p2PendingExpRow.3 docs/man/man3/p2PendingImfileRow.3 docs/man/man3/p2ProcessedExpRow.3 docs/man/man3/p2ProcessedImfileRow.3 docs/man/man3/p3PendingExpRow.3 docs/man/man3/detRunRow.3 docs/man/man3/detInputExpRow.3 docs/man/man3/detProcessedImfileRow.3 docs/man/man3/detProcessedExpRow.3 docs/man/man3/detStackedImfileRow.3 docs/man/man3/detNormalizedStatImfileRow.3 docs/man/man3/detNormalizedImfileRow.3 docs/man/man3/detNormalizedExpRow.3 docs/man/man3/detMasterFrameRow.3 docs/man/man3/detMasterImfileRow.3 docs/man/man3/detResidImfileRow.3 docs/man/man3/detResidExpRow.3 docs/man/man3/detRunSummaryRow.3:
+docs/man/man3/ippdb.3 docs/man/man3/weatherRow.3 docs/man/man3/skyp_transparencyRow.3 docs/man/man3/skyp_absorptionRow.3 docs/man/man3/skyp_emissionRow.3 docs/man/man3/dimmRow.3 docs/man/man3/skyp_irRow.3 docs/man/man3/domeRow.3 docs/man/man3/telescopeRow.3 docs/man/man3/summitExpRow.3 docs/man/man3/pzPendingExpRow.3 docs/man/man3/pzPendingImfileRow.3 docs/man/man3/newExpRow.3 docs/man/man3/newImfileRow.3 docs/man/man3/rawDetrendExpRow.3 docs/man/man3/rawScienceExpRow.3 docs/man/man3/rawImfileRow.3 docs/man/man3/p1PendingExpRow.3 docs/man/man3/p2PendingExpRow.3 docs/man/man3/p2PendingImfileRow.3 docs/man/man3/p2ProcessedExpRow.3 docs/man/man3/p2ProcessedImfileRow.3 docs/man/man3/p3PendingExpRow.3 docs/man/man3/p3ProcessedExpRow.3 docs/man/man3/detRunRow.3 docs/man/man3/detInputExpRow.3 docs/man/man3/detProcessedImfileRow.3 docs/man/man3/detProcessedExpRow.3 docs/man/man3/detStackedImfileRow.3 docs/man/man3/detNormalizedStatImfileRow.3 docs/man/man3/detNormalizedImfileRow.3 docs/man/man3/detNormalizedExpRow.3 docs/man/man3/detMasterFrameRow.3 docs/man/man3/detMasterImfileRow.3 docs/man/man3/detResidImfileRow.3 docs/man/man3/detResidExpRow.3 docs/man/man3/detRunSummaryRow.3:
 	$(DOXYGEN)
 
Index: /trunk/ippdb/configure.ac
===================================================================
--- /trunk/ippdb/configure.ac	(revision 9300)
+++ /trunk/ippdb/configure.ac	(revision 9301)
@@ -7,5 +7,5 @@
 AC_PREREQ(2.59)
 
-AC_INIT([ippdb], [0.0.46], [pan-starrs.ifa.hawaii.edu])
+AC_INIT([ippdb], [0.0.47], [pan-starrs.ifa.hawaii.edu])
 AC_CONFIG_SRCDIR([ippdb.pc.in])
 
Index: /trunk/ippdb/src/ippdb.c
===================================================================
--- /trunk/ippdb/src/ippdb.c	(revision 9300)
+++ /trunk/ippdb/src/ippdb.c	(revision 9301)
@@ -57,4 +57,6 @@
 #define P3PENDINGEXP_TABLE_NAME "p3PendingExp"
 #define P3PENDINGEXP_INDEX_NAME IPPDB_DEFAULT_INDEX_NAME
+#define P3PROCESSEDEXP_TABLE_NAME "p3ProcessedExp"
+#define P3PROCESSEDEXP_INDEX_NAME IPPDB_DEFAULT_INDEX_NAME
 #define DETRUN_TABLE_NAME "detRun"
 #define DETRUN_INDEX_NAME IPPDB_DEFAULT_INDEX_NAME
@@ -12858,4 +12860,741 @@
     return true;
 }
+static void p3ProcessedExpRowFree(p3ProcessedExpRow *object);
+
+p3ProcessedExpRow *p3ProcessedExpRowAlloc(const char *exp_tag, const char *uri, const char *recipe, psF64 bg, psF64 bg_stdev, psF64 bg_mean_stdev, psF32 sigma_ra, psF32 sigma_dec, psS32 nastro, const char *b1_uri, const char *b2_uri, psS32 p2_version, psS32 p3_version)
+{
+    p3ProcessedExpRow *_object;
+
+    _object = psAlloc(sizeof(p3ProcessedExpRow));
+    psMemSetDeallocator(_object, (psFreeFunc)p3ProcessedExpRowFree);
+
+    _object->exp_tag = psStringCopy(exp_tag);
+    _object->uri = psStringCopy(uri);
+    _object->recipe = psStringCopy(recipe);
+    _object->bg = bg;
+    _object->bg_stdev = bg_stdev;
+    _object->bg_mean_stdev = bg_mean_stdev;
+    _object->sigma_ra = sigma_ra;
+    _object->sigma_dec = sigma_dec;
+    _object->nastro = nastro;
+    _object->b1_uri = psStringCopy(b1_uri);
+    _object->b2_uri = psStringCopy(b2_uri);
+    _object->p2_version = p2_version;
+    _object->p3_version = p3_version;
+
+    return _object;
+}
+
+static void p3ProcessedExpRowFree(p3ProcessedExpRow *object)
+{
+    psFree(object->exp_tag);
+    psFree(object->uri);
+    psFree(object->recipe);
+    psFree(object->b1_uri);
+    psFree(object->b2_uri);
+}
+
+bool p3ProcessedExpCreateTable(psDB *dbh)
+{
+    psMetadata      *md;
+    bool            status;
+
+    md = psMetadataAlloc();
+    if (!psMetadataAdd(md, PS_LIST_TAIL, P3PROCESSEDEXP_INDEX_NAME, PS_DATA_S32, "AUTO_INCREMENT", 0.0)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item %s", P3PROCESSEDEXP_INDEX_NAME);
+        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, "uri", 0, NULL, "255")) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item uri");
+        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 (!psMetadataAddF32(md, PS_LIST_TAIL, "sigma_ra", 0, NULL, 0.0)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item sigma_ra");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAddF32(md, PS_LIST_TAIL, "sigma_dec", 0, NULL, 0.0)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item sigma_dec");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAddS32(md, PS_LIST_TAIL, "nastro", 0, NULL, 0)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item nastro");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAddStr(md, PS_LIST_TAIL, "b1_uri", 0, NULL, "255")) {
+        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, "255")) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item b2_uri");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAddS32(md, PS_LIST_TAIL, "p2_version", 0, NULL, 0)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p2_version");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAddS32(md, PS_LIST_TAIL, "p3_version", 0, NULL, 0)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p3_version");
+        psFree(md);
+        return false;
+    }
+
+    status = psDBCreateTable(dbh, P3PROCESSEDEXP_TABLE_NAME, md);
+
+    psFree(md);
+
+    return status;
+}
+
+bool p3ProcessedExpDropTable(psDB *dbh)
+{
+    return psDBDropTable(dbh, P3PROCESSEDEXP_TABLE_NAME);
+}
+
+bool p3ProcessedExpInsert(psDB * dbh, const char *exp_tag, const char *uri, const char *recipe, psF64 bg, psF64 bg_stdev, psF64 bg_mean_stdev, psF32 sigma_ra, psF32 sigma_dec, psS32 nastro, const char *b1_uri, const char *b2_uri, psS32 p2_version, psS32 p3_version)
+{
+    psMetadata      *md;
+    bool            status;
+
+    md = psMetadataAlloc();
+    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, "uri", 0, NULL, uri)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item uri");
+        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 (!psMetadataAddF32(md, PS_LIST_TAIL, "sigma_ra", 0, NULL, sigma_ra)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item sigma_ra");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAddF32(md, PS_LIST_TAIL, "sigma_dec", 0, NULL, sigma_dec)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item sigma_dec");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAddS32(md, PS_LIST_TAIL, "nastro", 0, NULL, nastro)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item nastro");
+        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;
+    }
+    if (!psMetadataAddS32(md, PS_LIST_TAIL, "p2_version", 0, NULL, p2_version)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p2_version");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAddS32(md, PS_LIST_TAIL, "p3_version", 0, NULL, p3_version)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p3_version");
+        psFree(md);
+        return false;
+    }
+
+    status = psDBInsertOneRow(dbh, P3PROCESSEDEXP_TABLE_NAME, md);
+    psFree(md);
+
+    return status;
+}
+
+long long p3ProcessedExpDelete(psDB *dbh, const psMetadata *where, unsigned long long limit)
+{
+    long long       deleted = 0;
+
+    long long count = psDBDeleteRows(dbh, P3PROCESSEDEXP_TABLE_NAME, where, limit);
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from p3ProcessedExp");
+        return count;
+
+        deleted += count;
+    }
+
+    return deleted;
+}
+bool p3ProcessedExpPop(psDB *dbh, char **exp_tag, char **uri, char **recipe, psF64 *bg, psF64 *bg_stdev, psF64 *bg_mean_stdev, psF32 *sigma_ra, psF32 *sigma_dec, psS32 *nastro, char **b1_uri, char **b2_uri, psS32 *p2_version, psS32 *p3_version)
+{
+    psArray         *rowSet;
+    psMetadata      *row;
+    psMetadata      *popped;
+    long            deleted;
+    bool            status;
+    int             rowID;
+
+    rowSet = psDBSelectRows(dbh, P3PROCESSEDEXP_TABLE_NAME, NULL, 1);
+    if (!rowSet) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item %s", P3PROCESSEDEXP_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, P3PROCESSEDEXP_INDEX_NAME);
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item %s", P3PROCESSEDEXP_INDEX_NAME);
+        psFree(row);
+        return NULL;
+    }
+
+    popped = psMetadataAlloc();
+    psMetadataAddS32(popped, PS_LIST_TAIL, P3PROCESSEDEXP_INDEX_NAME, 0, NULL, rowID);
+
+    deleted = psDBDeleteRows(dbh, P3PROCESSEDEXP_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);
+
+    *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;
+    }
+    *uri = psMetadataLookupPtr(&status, row, "uri");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item uri");
+        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;
+    }
+    *sigma_ra = psMetadataLookupF32(&status, row, "sigma_ra");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item sigma_ra");
+        psFree(row);
+        return false;
+    }
+    *sigma_dec = psMetadataLookupF32(&status, row, "sigma_dec");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item sigma_dec");
+        psFree(row);
+        return false;
+    }
+    *nastro = psMetadataLookupS32(&status, row, "nastro");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item nastro");
+        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;
+    }
+    *p2_version = psMetadataLookupS32(&status, row, "p2_version");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item p2_version");
+        psFree(row);
+        return false;
+    }
+    *p3_version = psMetadataLookupS32(&status, row, "p3_version");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item p3_version");
+        psFree(row);
+        return false;
+    }
+
+    psFree(row);
+
+    return true;
+}
+
+bool p3ProcessedExpInsertObject(psDB *dbh, p3ProcessedExpRow *object)
+{
+    return p3ProcessedExpInsert(dbh, object->exp_tag, object->uri, object->recipe, object->bg, object->bg_stdev, object->bg_mean_stdev, object->sigma_ra, object->sigma_dec, object->nastro, object->b1_uri, object->b2_uri, object->p2_version, object->p3_version);
+}
+
+bool p3ProcessedExpInsertObjects(psDB *dbh, psArray *objects)
+{
+    for (long i = 0; i < psArrayLength(objects); i++) {
+        if (!p3ProcessedExpInsertObject(dbh, objects->data[i])) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+p3ProcessedExpRow *p3ProcessedExpPopObject(psDB *dbh)
+{
+    char            exp_tag[256];
+    char            uri[256];
+    char            recipe[256];
+    psF64           bg;
+    psF64           bg_stdev;
+    psF64           bg_mean_stdev;
+    psF32           sigma_ra;
+    psF32           sigma_dec;
+    psS32           nastro;
+    char            b1_uri[256];
+    char            b2_uri[256];
+    psS32           p2_version;
+    psS32           p3_version;
+
+    if (!p3ProcessedExpPop(dbh, (char **)&exp_tag, (char **)&uri, (char **)&recipe, &bg, &bg_stdev, &bg_mean_stdev, &sigma_ra, &sigma_dec, &nastro, (char **)&b1_uri, (char **)&b2_uri, &p2_version, &p3_version)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to pop a database row");
+        return NULL;
+    }
+
+    return p3ProcessedExpRowAlloc(exp_tag, uri, recipe, bg, bg_stdev, bg_mean_stdev, sigma_ra, sigma_dec, nastro, b1_uri, b2_uri, p2_version, p3_version);
+}
+
+bool p3ProcessedExpInsertFits(psDB *dbh, const psFits *fits)
+{
+    psArray         *rowSet;
+
+    // move to (the first?) extension named  P3PROCESSEDEXP_TABLE_NAME
+    if (!psFitsMoveExtName(fits, P3PROCESSEDEXP_TABLE_NAME)) {
+        psError(PS_ERR_UNKNOWN, true, "failed to find FITS extension %s", P3PROCESSEDEXP_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, P3PROCESSEDEXP_TABLE_NAME, rowSet)) {
+        psError(PS_ERR_UNKNOWN, false, "databse insert failed");
+        psFree(rowSet);
+        return false;
+    }
+
+    psFree(rowSet);
+
+    return true;
+}
+
+bool p3ProcessedExpPopFits(psDB *dbh, psFits *fits, unsigned long long limit)
+{
+    char            query[MAX_STRING_LENGTH];
+
+    if (!p3ProcessedExpSelectRowsFits(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",
+                P3PROCESSEDEXP_TABLE_NAME, P3PROCESSEDEXP_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 p3ProcessedExpSelectRowsFits(psDB *dbh, psFits *fits, const psMetadata *where, unsigned long long limit)
+{
+    psArray         *rowSet;
+    psU64           i;
+
+    rowSet = psDBSelectRows(dbh, P3PROCESSEDEXP_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, P3PROCESSEDEXP_INDEX_NAME)) {
+            psError(PS_ERR_UNKNOWN, true, "failed to remove item %s", P3PROCESSEDEXP_INDEX_NAME);
+            psFree(rowSet);
+            return false;
+        }
+    }
+
+    // output to fits
+    if (!psFitsWriteTable(fits, NULL, rowSet, P3PROCESSEDEXP_TABLE_NAME)) {
+        psError(PS_ERR_UNKNOWN, false, "FITS table write failed");
+        psFree(rowSet);
+        return false;
+    }
+
+    psFree(rowSet);
+
+    return true;
+}
+
+psMetadata *p3ProcessedExpMetadataFromObject(const p3ProcessedExpRow *object)
+{
+    psMetadata      *md;
+
+    md = psMetadataAlloc();
+    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, "uri", 0, NULL, object->uri)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item uri");
+        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 (!psMetadataAddF32(md, PS_LIST_TAIL, "sigma_ra", 0, NULL, object->sigma_ra)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item sigma_ra");
+        psFree(md);
+        return NULL;
+    }
+    if (!psMetadataAddF32(md, PS_LIST_TAIL, "sigma_dec", 0, NULL, object->sigma_dec)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item sigma_dec");
+        psFree(md);
+        return NULL;
+    }
+    if (!psMetadataAddS32(md, PS_LIST_TAIL, "nastro", 0, NULL, object->nastro)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item nastro");
+        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;
+    }
+    if (!psMetadataAddS32(md, PS_LIST_TAIL, "p2_version", 0, NULL, object->p2_version)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p2_version");
+        psFree(md);
+        return NULL;
+    }
+    if (!psMetadataAddS32(md, PS_LIST_TAIL, "p3_version", 0, NULL, object->p3_version)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p3_version");
+        psFree(md);
+        return NULL;
+    }
+
+    return md;
+}
+
+p3ProcessedExpRow *p3ProcessedExpObjectFromMetadata(psMetadata *md)
+{
+    bool            status;
+    char            *exp_tag;
+    char            *uri;
+    char            *recipe;
+    psF64           bg;
+    psF64           bg_stdev;
+    psF64           bg_mean_stdev;
+    psF32           sigma_ra;
+    psF32           sigma_dec;
+    psS32           nastro;
+    char            *b1_uri;
+    char            *b2_uri;
+    psS32           p2_version;
+    psS32           p3_version;
+
+    exp_tag = psMetadataLookupPtr(&status, md, "exp_tag");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item exp_tag");
+        return false;
+    }
+    uri = psMetadataLookupPtr(&status, md, "uri");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item uri");
+        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;
+    }
+    sigma_ra = psMetadataLookupF32(&status, md, "sigma_ra");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item sigma_ra");
+        return false;
+    }
+    sigma_dec = psMetadataLookupF32(&status, md, "sigma_dec");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item sigma_dec");
+        return false;
+    }
+    nastro = psMetadataLookupS32(&status, md, "nastro");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item nastro");
+        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;
+    }
+    p2_version = psMetadataLookupS32(&status, md, "p2_version");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item p2_version");
+        return false;
+    }
+    p3_version = psMetadataLookupS32(&status, md, "p3_version");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item p3_version");
+        return false;
+    }
+
+    return p3ProcessedExpRowAlloc(exp_tag, uri, recipe, bg, bg_stdev, bg_mean_stdev, sigma_ra, sigma_dec, nastro, b1_uri, b2_uri, p2_version, p3_version);
+}
+psArray *p3ProcessedExpSelectRowObjects(psDB *dbh, const psMetadata *where, unsigned long long limit)
+{
+    psArray         *rowSet;
+    psArray         *returnSet;
+    psU64           i;
+
+    rowSet = psDBSelectRows(dbh, P3PROCESSEDEXP_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, P3PROCESSEDEXP_INDEX_NAME)) {
+            psError(PS_ERR_UNKNOWN, true, "failed to remove item %s", P3PROCESSEDEXP_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++) {
+        p3ProcessedExpRow *object = p3ProcessedExpObjectFromMetadata(rowSet->data[i]);
+        psArrayAdd(returnSet, 0, object);
+        psFree(object);
+    }
+
+    psFree(rowSet);
+
+    return returnSet;
+}
+bool p3ProcessedExpDeleteObject(psDB *dbh, const p3ProcessedExpRow *object)
+{
+    psMetadata *where = p3ProcessedExpMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, P3PROCESSEDEXP_TABLE_NAME, where, 0);
+    psFree(where)
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from p3ProcessedExp");
+        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, "p3ProcessedExpRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
+long long p3ProcessedExpDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
+{
+    long long       deleted = 0;
+
+    for (long long i = 0; i < objects->n; i++) {
+        p3ProcessedExpRow *object = objects->data[i];
+        psMetadata *where = p3ProcessedExpMetadataFromObject(object);
+        long long count = psDBDeleteRows(dbh, P3PROCESSEDEXP_TABLE_NAME, where, limit);
+        psFree(where)
+        if (count < 0) {
+            psError(PS_ERR_UNKNOWN, true, "failed to delete row from p3ProcessedExp");
+            return count;
+        }
+
+        deleted += count;
+    }
+
+    return deleted;
+}
+bool p3ProcessedExpPrintObjects(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 = p3ProcessedExpMetadataFromObject(objects->data[i]);
+        if (!psMetadataAddMetadata(
+            output,
+            PS_LIST_TAIL,
+            P3PROCESSEDEXP_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 detRunRowFree(detRunRow *object);
 
Index: /trunk/ippdb/src/ippdb.h
===================================================================
--- /trunk/ippdb/src/ippdb.h	(revision 9300)
+++ /trunk/ippdb/src/ippdb.h	(revision 9301)
@@ -5399,4 +5399,267 @@
     bool            mdcf                ///< format as mdconfig or simple
 );
+/** p3ProcessedExpRow data structure
+ *
+ * Structure for representing a single row of p3ProcessedExp table data.
+ */
+
+typedef struct {
+    char            *exp_tag;
+    char            *uri;
+    char            *recipe;
+    psF64           bg;
+    psF64           bg_stdev;
+    psF64           bg_mean_stdev;
+    psF32           sigma_ra;
+    psF32           sigma_dec;
+    psS32           nastro;
+    char            *b1_uri;
+    char            *b2_uri;
+    psS32           p2_version;
+    psS32           p3_version;
+} p3ProcessedExpRow;
+
+/** Creates a new p3ProcessedExpRow object
+ *
+ *  @return A new p3ProcessedExpRow object or NULL on failure.
+ */
+
+p3ProcessedExpRow *p3ProcessedExpRowAlloc(
+    const char      *exp_tag,
+    const char      *uri,
+    const char      *recipe,
+    psF64           bg,
+    psF64           bg_stdev,
+    psF64           bg_mean_stdev,
+    psF32           sigma_ra,
+    psF32           sigma_dec,
+    psS32           nastro,
+    const char      *b1_uri,
+    const char      *b2_uri,
+    psS32           p2_version,
+    psS32           p3_version
+);
+
+/** Creates a new p3ProcessedExp table
+ *
+ * @return true on success
+ */
+
+bool p3ProcessedExpCreateTable(
+    psDB            *dbh                ///< Database handle
+);
+
+/** Deletes a p3ProcessedExp table
+ *
+ * @return true on success
+ */
+
+bool p3ProcessedExpDropTable(
+    psDB            *dbh                ///< Database handle
+);
+
+/** Insert a single row into a table
+ *
+ * This function constructs and inserts a single row based on it's parameters.
+ *
+ * @return true on success
+ */
+
+bool p3ProcessedExpInsert(
+    psDB            *dbh,               ///< Database handle
+    const char      *exp_tag,
+    const char      *uri,
+    const char      *recipe,
+    psF64           bg,
+    psF64           bg_stdev,
+    psF64           bg_mean_stdev,
+    psF32           sigma_ra,
+    psF32           sigma_dec,
+    psS32           nastro,
+    const char      *b1_uri,
+    const char      *b2_uri,
+    psS32           p2_version,
+    psS32           p3_version
+);
+
+/** Deletes up to limit rows from the database and returns the number of rows actually deleted. 
+ *
+ * @return A The number of rows removed or a negative value on error
+ */
+
+long long p3ProcessedExpDelete(
+    psDB            *dbh,               ///< Database handle
+    const psMetadata *where,            ///< Row match criteria
+    unsigned long long limit            ///< Maximum number of elements to delete 
+);
+
+/** Removes the last row from the database and returns it
+ *
+ * @return true on success
+ */
+
+bool p3ProcessedExpPop(
+    psDB            *dbh,               ///< Database handle
+    char            **exp_tag,
+    char            **uri,
+    char            **recipe,
+    psF64           *bg,
+    psF64           *bg_stdev,
+    psF64           *bg_mean_stdev,
+    psF32           *sigma_ra,
+    psF32           *sigma_dec,
+    psS32           *nastro,
+    char            **b1_uri,
+    char            **b2_uri,
+    psS32           *p2_version,
+    psS32           *p3_version
+);
+
+/** Insert a single p3ProcessedExpRow object into a table
+ *
+ * This function constructs and inserts a single row based on it's parameters.
+ *
+ * @return true on success
+ */
+
+bool p3ProcessedExpInsertObject(
+    psDB            *dbh,               ///< Database handle
+    p3ProcessedExpRow *object             ///< p3ProcessedExpRow object
+);
+
+/** Insert an array of p3ProcessedExpRow object into a table
+ *
+ * This function constructs and inserts multiple rows based on it's parameters.
+ *
+ * @return true on success
+ */
+
+bool p3ProcessedExpInsertObjects(
+    psDB            *dbh,               ///< Database handle
+    psArray         *objects            ///< array of p3ProcessedExpRow objects
+);
+
+/** Removes the last row from the database and returns it
+ *
+ * @return A new p3ProcessedExpRow on success or NULL on failure.
+ */
+
+p3ProcessedExpRow *p3ProcessedExpPopObject(
+    psDB            *dbh                ///< Database handle
+);
+
+/** Insert data from a binary FITS table p3ProcessedExpRow into the database
+ *
+ * This function expects a psFits object with a FITS table as the first
+ * extension.  The table must have at least one row of data in it, that is of
+ * the appropriate format (number of columns and their type).  All other
+ * extensions are ignored.
+ *
+ * @return true on success
+ */
+
+bool p3ProcessedExpInsertFits(
+    psDB            *dbh,               ///< Database handle
+    const psFits    *fits               ///< psFits object
+);
+
+/** Removes the last limit row from the database and returns them in a binary FITS table.
+ *
+ * This function assumes an empty psFits object and will create a FITS table as
+ * the first extension. 
+ *
+ * @return true on success
+ */
+
+bool p3ProcessedExpPopFits(
+    psDB            *dbh,               ///< Database handle
+    psFits          *fits,              ///< psFits object
+    unsigned long long limit            ///< Maximum number of elements to return
+);
+
+/** Selects up to limit from the database and returns them in a binary FITS table
+ *
+ * This function assumes an empty psFits object and will create a FITS table
+ * as the first extension.
+ *
+ *  See psDBSelectRows() for documentation on the format of where.
+ *
+ * @return true on success
+ */
+
+bool p3ProcessedExpSelectRowsFits(
+    psDB            *dbh,               ///< Database handle
+    psFits          *fits,              ///< psFits object
+    const psMetadata *where,            ///< Row match criteria
+    unsigned long long limit            ///< Maximum number of elements to return
+);
+
+/** Convert a p3ProcessedExpRow into an equivalent psMetadata
+ *
+ * @return A psMetadata pointer or NULL on error
+ */
+
+psMetadata *p3ProcessedExpMetadataFromObject(
+    const p3ProcessedExpRow *object             ///< fooRow to convert into a psMetadata
+);
+
+/** Convert a psMetadata into an equivalent fooRow
+ *
+ * @return A p3ProcessedExpRow pointer or NULL on error
+ */
+
+p3ProcessedExpRow *p3ProcessedExpObjectFromMetadata(
+    psMetadata      *md                 ///< psMetadata to convert into a fooRow
+);
+/** Selects up to limit rows from the database and returns as p3ProcessedExpRow objects in a psArray
+ *
+ *  See psDBSelectRows() for documentation on the format of where.
+ *
+ * @return A psArray pointer or NULL on error
+ */
+
+psArray *p3ProcessedExpSelectRowObjects(
+    psDB            *dbh,               ///< Database handle
+    const psMetadata *where,            ///< Row match criteria
+    unsigned long long limit            ///< Maximum number of elements to return
+);
+/** Deletes a row from the database coresponding to an p3ProcessedExp
+ *
+ *  Note that a 'where' search psMetadata is constructed from each object and
+ *  used to find rows to delete.
+ *
+ * @return A The number of rows removed or a negative value on error
+ */
+
+bool p3ProcessedExpDeleteObject(
+    psDB            *dbh,               ///< Database handle
+    const p3ProcessedExpRow *object    ///< Object to delete
+);
+/** Deletes up to limit rows from the database and returns the number of rows actually deleted. 
+ *
+ *  Note that a 'where' search psMetadata is constructed from each object and
+ *  used to find rows to delete.
+ *
+ * @return A The number of rows removed or a negative value on error
+ */
+
+long long p3ProcessedExpDeleteRowObjects(
+    psDB            *dbh,               ///< Database handle
+    const psArray   *objects,           ///< Array of objects to delete
+    unsigned long long limit            ///< Maximum number of elements to delete 
+);
+/** Formats and prints an array of p3ProcessedExpRow objects
+ *
+ * When mdcf is set the formated output is in psMetadataConfig
+ * format, otherwise it is in a simple tabular format.
+ *
+ * @return true on success
+ */
+
+bool p3ProcessedExpPrintObjects(
+    FILE            *stream,            ///< a stream
+    psArray         *objects,           ///< An array of p3ProcessedExpRow objects
+    bool            mdcf                ///< format as mdconfig or simple
+);
 /** detRunRow data structure
  *
Index: /trunk/ippdb/tests/alloc.c
===================================================================
--- /trunk/ippdb/tests/alloc.c	(revision 9300)
+++ /trunk/ippdb/tests/alloc.c	(revision 9301)
@@ -947,4 +947,69 @@
 
     {
+        p3ProcessedExpRow *object;
+
+        object = p3ProcessedExpRowAlloc("a string", "a string", "a string", 64.64, 64.64, 64.64, 32.32, 32.32, -32, "a string", "a string", -32, -32    );
+
+        if (!object) {
+            exit(EXIT_FAILURE);
+        }
+
+        if (strncmp(object->exp_tag, "a string", MAX_STRING_LENGTH)) {
+            psFree(object);
+            exit(EXIT_FAILURE);
+        }
+        if (strncmp(object->uri, "a string", MAX_STRING_LENGTH)) {
+            psFree(object);
+            exit(EXIT_FAILURE);
+        }
+        if (strncmp(object->recipe, "a string", MAX_STRING_LENGTH)) {
+            psFree(object);
+            exit(EXIT_FAILURE);
+        }
+        if (!object->bg == 64.64) {
+            psFree(object);
+            exit(EXIT_FAILURE);
+        }
+        if (!object->bg_stdev == 64.64) {
+            psFree(object);
+            exit(EXIT_FAILURE);
+        }
+        if (!object->bg_mean_stdev == 64.64) {
+            psFree(object);
+            exit(EXIT_FAILURE);
+        }
+        if (!object->sigma_ra == 32.32) {
+            psFree(object);
+            exit(EXIT_FAILURE);
+        }
+        if (!object->sigma_dec == 32.32) {
+            psFree(object);
+            exit(EXIT_FAILURE);
+        }
+        if (!object->nastro == -32) {
+            psFree(object);
+            exit(EXIT_FAILURE);
+        }
+        if (strncmp(object->b1_uri, "a string", MAX_STRING_LENGTH)) {
+            psFree(object);
+            exit(EXIT_FAILURE);
+        }
+        if (strncmp(object->b2_uri, "a string", MAX_STRING_LENGTH)) {
+            psFree(object);
+            exit(EXIT_FAILURE);
+        }
+        if (!object->p2_version == -32) {
+            psFree(object);
+            exit(EXIT_FAILURE);
+        }
+        if (!object->p3_version == -32) {
+            psFree(object);
+            exit(EXIT_FAILURE);
+        }
+
+        psFree(object);
+    }
+
+    {
         detRunRow       *object;
 
Index: /trunk/ippdb/tests/createtable.c
===================================================================
--- /trunk/ippdb/tests/createtable.c	(revision 9300)
+++ /trunk/ippdb/tests/createtable.c	(revision 9301)
@@ -343,4 +343,19 @@
         }
 
+        if(!p3ProcessedExpCreateTable(dbh)) {
+            exit(EXIT_FAILURE);
+        }
+
+        psDBCleanup(dbh);
+    }
+
+    {
+        psDB            *dbh;
+
+        dbh = psDBInit("localhost", "test", NULL, "test");
+        if (!dbh) {
+            exit(EXIT_FAILURE);
+        }
+
         if(!detRunCreateTable(dbh)) {
             exit(EXIT_FAILURE);
Index: /trunk/ippdb/tests/dbcleanup.c
===================================================================
--- /trunk/ippdb/tests/dbcleanup.c	(revision 9300)
+++ /trunk/ippdb/tests/dbcleanup.c	(revision 9301)
@@ -33,4 +33,5 @@
     p_psDBRunQuery(dbh, "DROP TABLE IF EXISTS p2ProcessedImfile");
     p_psDBRunQuery(dbh, "DROP TABLE IF EXISTS p3PendingExp");
+    p_psDBRunQuery(dbh, "DROP TABLE IF EXISTS p3ProcessedExp");
     p_psDBRunQuery(dbh, "DROP TABLE IF EXISTS detRun");
     p_psDBRunQuery(dbh, "DROP TABLE IF EXISTS detInputExp");
Index: /trunk/ippdb/tests/dbsetup.c
===================================================================
--- /trunk/ippdb/tests/dbsetup.c	(revision 9300)
+++ /trunk/ippdb/tests/dbsetup.c	(revision 9301)
@@ -79,4 +79,7 @@
     p3PendingExpCreateTable(dbh);
 
+    p_psDBRunQuery(dbh, "DROP TABLE IF EXISTS p3ProcessedExp");
+    p3ProcessedExpCreateTable(dbh);
+
     p_psDBRunQuery(dbh, "DROP TABLE IF EXISTS detRun");
     detRunCreateTable(dbh);
Index: /trunk/ippdb/tests/droptable.c
===================================================================
--- /trunk/ippdb/tests/droptable.c	(revision 9300)
+++ /trunk/ippdb/tests/droptable.c	(revision 9301)
@@ -343,4 +343,19 @@
         }
 
+        if (!p3ProcessedExpDropTable(dbh)) {
+            exit(EXIT_FAILURE);
+        }
+
+        psDBCleanup(dbh);
+    }
+
+    {
+        psDB            *dbh;
+
+        dbh = psDBInit("localhost", "test", NULL, "test");
+        if (!dbh) {
+            exit(EXIT_FAILURE);
+        }
+
         if (!detRunDropTable(dbh)) {
             exit(EXIT_FAILURE);
Index: /trunk/ippdb/tests/insert.c
===================================================================
--- /trunk/ippdb/tests/insert.c	(revision 9300)
+++ /trunk/ippdb/tests/insert.c	(revision 9301)
@@ -343,4 +343,19 @@
         }
 
+        if (!p3ProcessedExpInsert(dbh, "a string", "a string", "a string", 64.64, 64.64, 64.64, 32.32, 32.32, -32, "a string", "a string", -32, -32)) {
+            exit(EXIT_FAILURE);
+        }
+
+        psDBCleanup(dbh);
+    }
+
+    {
+        psDB            *dbh;
+
+        dbh = psDBInit("localhost", "test", NULL, "test");
+        if (!dbh) {
+            exit(EXIT_FAILURE);
+        }
+
         if (!detRunInsert(dbh, -32, "a string", "a string")) {
             exit(EXIT_FAILURE);
Index: /trunk/ippdb/tests/insertfits.c
===================================================================
--- /trunk/ippdb/tests/insertfits.c	(revision 9300)
+++ /trunk/ippdb/tests/insertfits.c	(revision 9301)
@@ -596,4 +596,30 @@
         }
 
+        if (!p3ProcessedExpInsertFits(dbh, fits)) {
+            exit(EXIT_FAILURE);
+        }
+
+        if (!psFitsClose(fits)) {
+            exit(EXIT_FAILURE);
+        }
+
+        psDBCleanup(dbh);
+    }
+
+    {
+        psDB            *dbh;
+        psFits          *fits;
+
+        dbh = psDBInit("localhost", "test", NULL, "test");
+        if (!dbh) {
+            exit(EXIT_FAILURE);
+        }
+
+        // open a temp
+        fits = psFitsOpen(TMP_FILENAME, "r");
+        if (!fits) {
+            exit(EXIT_FAILURE);
+        }
+
         if (!detRunInsertFits(dbh, fits)) {
             exit(EXIT_FAILURE);
Index: /trunk/ippdb/tests/insertobject.c
===================================================================
--- /trunk/ippdb/tests/insertobject.c	(revision 9300)
+++ /trunk/ippdb/tests/insertobject.c	(revision 9301)
@@ -491,4 +491,26 @@
     {
         psDB            *dbh;
+        p3ProcessedExpRow *object;
+
+        dbh = psDBInit("localhost", "test", NULL, "test");
+        if (!dbh) {
+            exit(EXIT_FAILURE);
+        }
+
+        object = p3ProcessedExpRowAlloc("a string", "a string", "a string", 64.64, 64.64, 64.64, 32.32, 32.32, -32, "a string", "a string", -32, -32);
+        if (!object) {
+            exit(EXIT_FAILURE);
+        }
+
+        if (!p3ProcessedExpInsertObject(dbh, object)) {
+            exit(EXIT_FAILURE);
+        }
+
+        psFree(object);
+        psDBCleanup(dbh);
+    }
+
+    {
+        psDB            *dbh;
         detRunRow       *object;
 
Index: /trunk/ippdb/tests/metadatafromobject.c
===================================================================
--- /trunk/ippdb/tests/metadatafromobject.c	(revision 9300)
+++ /trunk/ippdb/tests/metadatafromobject.c	(revision 9301)
@@ -1124,4 +1124,77 @@
     {
         psMetadata      *md;
+        p3ProcessedExpRow *object;
+        bool            status;
+
+        object = p3ProcessedExpRowAlloc("a string", "a string", "a string", 64.64, 64.64, 64.64, 32.32, 32.32, -32, "a string", "a string", -32, -32);
+        if (!object) {
+            exit(EXIT_FAILURE);
+        }
+
+        md = p3ProcessedExpMetadataFromObject(object);
+        if (!md) {
+            exit(EXIT_FAILURE);
+        }
+
+        psFree(object);
+
+        if (strncmp(psMetadataLookupPtr(&status, md, "exp_tag"), "a string", MAX_STRING_LENGTH)) {
+            psFree(md);
+            exit(EXIT_FAILURE);
+        }
+        if (strncmp(psMetadataLookupPtr(&status, md, "uri"), "a string", MAX_STRING_LENGTH)) {
+            psFree(md);
+            exit(EXIT_FAILURE);
+        }
+        if (strncmp(psMetadataLookupPtr(&status, md, "recipe"), "a string", MAX_STRING_LENGTH)) {
+            psFree(md);
+            exit(EXIT_FAILURE);
+        }
+        if (!psMetadataLookupF64(&status, md, "bg") == 64.64) {
+            psFree(md);
+            exit(EXIT_FAILURE);
+        }
+        if (!psMetadataLookupF64(&status, md, "bg_stdev") == 64.64) {
+            psFree(md);
+            exit(EXIT_FAILURE);
+        }
+        if (!psMetadataLookupF64(&status, md, "bg_mean_stdev") == 64.64) {
+            psFree(md);
+            exit(EXIT_FAILURE);
+        }
+        if (!psMetadataLookupF32(&status, md, "sigma_ra") == 32.32) {
+            psFree(md);
+            exit(EXIT_FAILURE);
+        }
+        if (!psMetadataLookupF32(&status, md, "sigma_dec") == 32.32) {
+            psFree(md);
+            exit(EXIT_FAILURE);
+        }
+        if (!psMetadataLookupS32(&status, md, "nastro") == -32) {
+            psFree(md);
+            exit(EXIT_FAILURE);
+        }
+        if (strncmp(psMetadataLookupPtr(&status, md, "b1_uri"), "a string", MAX_STRING_LENGTH)) {
+            psFree(md);
+            exit(EXIT_FAILURE);
+        }
+        if (strncmp(psMetadataLookupPtr(&status, md, "b2_uri"), "a string", MAX_STRING_LENGTH)) {
+            psFree(md);
+            exit(EXIT_FAILURE);
+        }
+        if (!psMetadataLookupS32(&status, md, "p2_version") == -32) {
+            psFree(md);
+            exit(EXIT_FAILURE);
+        }
+        if (!psMetadataLookupS32(&status, md, "p3_version") == -32) {
+            psFree(md);
+            exit(EXIT_FAILURE);
+        }
+
+        psFree(md);
+    }
+
+    {
+        psMetadata      *md;
         detRunRow       *object;
         bool            status;
Index: /trunk/ippdb/tests/objectfrommetadata.c
===================================================================
--- /trunk/ippdb/tests/objectfrommetadata.c	(revision 9300)
+++ /trunk/ippdb/tests/objectfrommetadata.c	(revision 9301)
@@ -1710,4 +1710,126 @@
     {
         psMetadata      *md;
+        p3ProcessedExpRow *object;
+
+        md = psMetadataAlloc();
+        if (!psMetadataAddStr(md, PS_LIST_TAIL, "exp_tag", 0, NULL, "a string")) {
+            psFree(md);
+            exit(EXIT_FAILURE);
+        }
+        if (!psMetadataAddStr(md, PS_LIST_TAIL, "uri", 0, NULL, "a string")) {
+            psFree(md);
+            exit(EXIT_FAILURE);
+        }
+        if (!psMetadataAddStr(md, PS_LIST_TAIL, "recipe", 0, NULL, "a string")) {
+            psFree(md);
+            exit(EXIT_FAILURE);
+        }
+        if (!psMetadataAddF64(md, PS_LIST_TAIL, "bg", 0, NULL, 64.64)) {
+            psFree(md);
+            exit(EXIT_FAILURE);
+        }
+        if (!psMetadataAddF64(md, PS_LIST_TAIL, "bg_stdev", 0, NULL, 64.64)) {
+            psFree(md);
+            exit(EXIT_FAILURE);
+        }
+        if (!psMetadataAddF64(md, PS_LIST_TAIL, "bg_mean_stdev", 0, NULL, 64.64)) {
+            psFree(md);
+            exit(EXIT_FAILURE);
+        }
+        if (!psMetadataAddF32(md, PS_LIST_TAIL, "sigma_ra", 0, NULL, 32.32)) {
+            psFree(md);
+            exit(EXIT_FAILURE);
+        }
+        if (!psMetadataAddF32(md, PS_LIST_TAIL, "sigma_dec", 0, NULL, 32.32)) {
+            psFree(md);
+            exit(EXIT_FAILURE);
+        }
+        if (!psMetadataAddS32(md, PS_LIST_TAIL, "nastro", 0, NULL, -32)) {
+            psFree(md);
+            exit(EXIT_FAILURE);
+        }
+        if (!psMetadataAddStr(md, PS_LIST_TAIL, "b1_uri", 0, NULL, "a string")) {
+            psFree(md);
+            exit(EXIT_FAILURE);
+        }
+        if (!psMetadataAddStr(md, PS_LIST_TAIL, "b2_uri", 0, NULL, "a string")) {
+            psFree(md);
+            exit(EXIT_FAILURE);
+        }
+        if (!psMetadataAddS32(md, PS_LIST_TAIL, "p2_version", 0, NULL, -32)) {
+            psFree(md);
+            exit(EXIT_FAILURE);
+        }
+        if (!psMetadataAddS32(md, PS_LIST_TAIL, "p3_version", 0, NULL, -32)) {
+            psFree(md);
+            exit(EXIT_FAILURE);
+        }
+
+        object = p3ProcessedExpObjectFromMetadata(md);
+        if (!object) {
+            psFree(md);
+            exit(EXIT_FAILURE);
+        }
+
+        psFree(md);
+
+        if (strncmp(object->exp_tag, "a string", MAX_STRING_LENGTH)) {
+            psFree(object);
+            exit(EXIT_FAILURE);
+        }
+        if (strncmp(object->uri, "a string", MAX_STRING_LENGTH)) {
+            psFree(object);
+            exit(EXIT_FAILURE);
+        }
+        if (strncmp(object->recipe, "a string", MAX_STRING_LENGTH)) {
+            psFree(object);
+            exit(EXIT_FAILURE);
+        }
+        if (!object->bg == 64.64) {
+            psFree(object);
+            exit(EXIT_FAILURE);
+        }
+        if (!object->bg_stdev == 64.64) {
+            psFree(object);
+            exit(EXIT_FAILURE);
+        }
+        if (!object->bg_mean_stdev == 64.64) {
+            psFree(object);
+            exit(EXIT_FAILURE);
+        }
+        if (!object->sigma_ra == 32.32) {
+            psFree(object);
+            exit(EXIT_FAILURE);
+        }
+        if (!object->sigma_dec == 32.32) {
+            psFree(object);
+            exit(EXIT_FAILURE);
+        }
+        if (!object->nastro == -32) {
+            psFree(object);
+            exit(EXIT_FAILURE);
+        }
+        if (strncmp(object->b1_uri, "a string", MAX_STRING_LENGTH)) {
+            psFree(object);
+            exit(EXIT_FAILURE);
+        }
+        if (strncmp(object->b2_uri, "a string", MAX_STRING_LENGTH)) {
+            psFree(object);
+            exit(EXIT_FAILURE);
+        }
+        if (!object->p2_version == -32) {
+            psFree(object);
+            exit(EXIT_FAILURE);
+        }
+        if (!object->p3_version == -32) {
+            psFree(object);
+            exit(EXIT_FAILURE);
+        }
+
+        psFree(object);
+    }
+
+    {
+        psMetadata      *md;
         detRunRow       *object;
 
Index: /trunk/ippdb/tests/pop.c
===================================================================
--- /trunk/ippdb/tests/pop.c	(revision 9300)
+++ /trunk/ippdb/tests/pop.c	(revision 9301)
@@ -500,4 +500,32 @@
     {
         psDB            *dbh;
+        char            exp_tag[256];
+        char            uri[256];
+        char            recipe[256];
+        psF64           bg;
+        psF64           bg_stdev;
+        psF64           bg_mean_stdev;
+        psF32           sigma_ra;
+        psF32           sigma_dec;
+        psS32           nastro;
+        char            b1_uri[256];
+        char            b2_uri[256];
+        psS32           p2_version;
+        psS32           p3_version;
+
+        dbh = psDBInit("localhost", "test", NULL, "test");
+        if (!dbh) {
+            exit(EXIT_FAILURE);
+        }
+
+        if (!p3ProcessedExpPop(dbh, (char **)&exp_tag, (char **)&uri, (char **)&recipe, &bg, &bg_stdev, &bg_mean_stdev, &sigma_ra, &sigma_dec, &nastro, (char **)&b1_uri, (char **)&b2_uri, &p2_version, &p3_version)) { 
+            exit(EXIT_FAILURE);
+        }
+
+        psDBCleanup(dbh);
+    }
+
+    {
+        psDB            *dbh;
         psS32           iteration;
         char            det_type[256];
Index: /trunk/ippdb/tests/popfits.c
===================================================================
--- /trunk/ippdb/tests/popfits.c	(revision 9300)
+++ /trunk/ippdb/tests/popfits.c	(revision 9301)
@@ -596,4 +596,30 @@
         }
 
+        if (!p3ProcessedExpPopFits(dbh, fits, 1)) {
+            exit(EXIT_FAILURE);
+        }
+
+        if (!psFitsClose(fits)) {
+            exit(EXIT_FAILURE);
+        }
+
+        psDBCleanup(dbh);
+    }
+
+    {
+        psDB            *dbh;
+        psFits          *fits;
+
+        dbh = psDBInit("localhost", "test", NULL, "test");
+        if (!dbh) {
+            exit(EXIT_FAILURE);
+        }
+
+        // allocate a temp
+        fits = psFitsOpen(TMP_FILENAME, "w");
+        if (!fits) {
+            exit(EXIT_FAILURE);
+        }
+
         if (!detRunPopFits(dbh, fits, 1)) {
             exit(EXIT_FAILURE);
Index: /trunk/ippdb/tests/popobject.c
===================================================================
--- /trunk/ippdb/tests/popobject.c	(revision 9300)
+++ /trunk/ippdb/tests/popobject.c	(revision 9301)
@@ -403,4 +403,22 @@
     {
         psDB            *dbh;
+        p3ProcessedExpRow *object;
+
+        dbh = psDBInit("localhost", "test", NULL, "test");
+        if (!dbh) {
+            exit(EXIT_FAILURE);
+        }
+
+        object = p3ProcessedExpPopObject(dbh);
+        if (!object) {
+            exit(EXIT_FAILURE);
+        }
+
+        psFree(object);
+        psDBCleanup(dbh);
+    }
+
+    {
+        psDB            *dbh;
         detRunRow       *object;
 
Index: /trunk/ippdb/tests/selectrowsfits.c
===================================================================
--- /trunk/ippdb/tests/selectrowsfits.c	(revision 9300)
+++ /trunk/ippdb/tests/selectrowsfits.c	(revision 9301)
@@ -505,4 +505,26 @@
         }
 
+        if (!p3ProcessedExpSelectRowsFits(dbh, fits, NULL, 1)) {
+            exit(EXIT_FAILURE);
+        }
+
+        psFree(fits);
+        psDBCleanup(dbh);
+    }
+
+    {
+        psDB            *dbh;
+        psFits          *fits;
+
+        dbh = psDBInit("localhost", "test", NULL, "test");
+        if (!dbh) {
+            exit(EXIT_FAILURE);
+        }
+
+        fits = psFitsOpen(TMP_FILENAME, "w");
+        if (!fits) {
+            exit(EXIT_FAILURE);
+        }
+
         if (!detRunSelectRowsFits(dbh, fits, NULL, 1)) {
             exit(EXIT_FAILURE);
