Index: trunk/ippdb/src/ippdb.c
===================================================================
--- trunk/ippdb/src/ippdb.c	(revision 11635)
+++ trunk/ippdb/src/ippdb.c	(revision 11679)
@@ -20,5 +20,5 @@
 /*
  *
- * This file was generated by glueforge 1.00
+ * This file was generated by glueforge 0.36
  *
  * Do NOT directly edit this file.
@@ -62,10 +62,15 @@
 #define DETRESIDEXP_TABLE_NAME "detResidExp"
 #define DETRUNSUMMARY_TABLE_NAME "detRunSummary"
-#define P4RUN_TABLE_NAME "p4Run"
-#define P4INPUTIMFILE_TABLE_NAME "p4InputImfile"
-#define P4WARPEDIMFILE_TABLE_NAME "p4WarpedImfile"
-#define P4STACKEDIMFILE_TABLE_NAME "p4StackedImfile"
-#define P4DIFFIMFILE_TABLE_NAME "p4DiffImfile"
+#define P4ARUN_TABLE_NAME "p4aRun"
+#define P4AINPUTEXP_TABLE_NAME "p4aInputExp"
+#define P4ASCFILE_TABLE_NAME "p4aScfile"
+#define P4BRUN_TABLE_NAME "p4bRun"
+#define P4BINPUTSCFILE_TABLE_NAME "p4bInputScfile"
+#define P4BDIFFSCFILE_TABLE_NAME "p4bDiffScfile"
+#define P4CRUN_TABLE_NAME "p4cRun"
+#define P4CINPUTEXP_TABLE_NAME "p4cInputExp"
 #define P4MAGICMASKIMFILE_TABLE_NAME "p4MagicMaskImfile"
+#define SKYCELL_TABLE_NAME "skyCell"
+#define SKYCELLMAP_TABLE_NAME "skyCellMap"
 #define MAX_STRING_LENGTH 1024
 
@@ -438,5 +443,5 @@
     psMetadata *where = expTagCounterMetadataFromObject(object);
     long long count = psDBDeleteRows(dbh, EXPTAGCOUNTER_TABLE_NAME, where, 0);
-    psFree(where)
+    psFree(where);
     if (count < 0) {
         psError(PS_ERR_UNKNOWN, true, "failed to delete row from expTagCounter");
@@ -460,5 +465,5 @@
         psMetadata *where = expTagCounterMetadataFromObject(object);
         long long count = psDBDeleteRows(dbh, EXPTAGCOUNTER_TABLE_NAME, where, limit);
-        psFree(where)
+        psFree(where);
         if (count < 0) {
             psError(PS_ERR_UNKNOWN, true, "failed to delete row from expTagCounter");
@@ -843,5 +848,5 @@
     psMetadata *where = summitExpMetadataFromObject(object);
     long long count = psDBDeleteRows(dbh, SUMMITEXP_TABLE_NAME, where, 0);
-    psFree(where)
+    psFree(where);
     if (count < 0) {
         psError(PS_ERR_UNKNOWN, true, "failed to delete row from summitExp");
@@ -865,5 +870,5 @@
         psMetadata *where = summitExpMetadataFromObject(object);
         long long count = psDBDeleteRows(dbh, SUMMITEXP_TABLE_NAME, where, limit);
-        psFree(where)
+        psFree(where);
         if (count < 0) {
             psError(PS_ERR_UNKNOWN, true, "failed to delete row from summitExp");
@@ -1292,5 +1297,5 @@
     psMetadata *where = summitImfileMetadataFromObject(object);
     long long count = psDBDeleteRows(dbh, SUMMITIMFILE_TABLE_NAME, where, 0);
-    psFree(where)
+    psFree(where);
     if (count < 0) {
         psError(PS_ERR_UNKNOWN, true, "failed to delete row from summitImfile");
@@ -1314,5 +1319,5 @@
         psMetadata *where = summitImfileMetadataFromObject(object);
         long long count = psDBDeleteRows(dbh, SUMMITIMFILE_TABLE_NAME, where, limit);
-        psFree(where)
+        psFree(where);
         if (count < 0) {
             psError(PS_ERR_UNKNOWN, true, "failed to delete row from summitImfile");
@@ -1610,5 +1615,5 @@
     psMetadata *where = pzPendingExpMetadataFromObject(object);
     long long count = psDBDeleteRows(dbh, PZPENDINGEXP_TABLE_NAME, where, 0);
-    psFree(where)
+    psFree(where);
     if (count < 0) {
         psError(PS_ERR_UNKNOWN, true, "failed to delete row from pzPendingExp");
@@ -1632,5 +1637,5 @@
         psMetadata *where = pzPendingExpMetadataFromObject(object);
         long long count = psDBDeleteRows(dbh, PZPENDINGEXP_TABLE_NAME, where, limit);
-        psFree(where)
+        psFree(where);
         if (count < 0) {
             psError(PS_ERR_UNKNOWN, true, "failed to delete row from pzPendingExp");
@@ -1994,5 +1999,5 @@
     psMetadata *where = pzPendingImfileMetadataFromObject(object);
     long long count = psDBDeleteRows(dbh, PZPENDINGIMFILE_TABLE_NAME, where, 0);
-    psFree(where)
+    psFree(where);
     if (count < 0) {
         psError(PS_ERR_UNKNOWN, true, "failed to delete row from pzPendingImfile");
@@ -2016,5 +2021,5 @@
         psMetadata *where = pzPendingImfileMetadataFromObject(object);
         long long count = psDBDeleteRows(dbh, PZPENDINGIMFILE_TABLE_NAME, where, limit);
-        psFree(where)
+        psFree(where);
         if (count < 0) {
             psError(PS_ERR_UNKNOWN, true, "failed to delete row from pzPendingImfile");
@@ -2312,5 +2317,5 @@
     psMetadata *where = pzDoneExpMetadataFromObject(object);
     long long count = psDBDeleteRows(dbh, PZDONEEXP_TABLE_NAME, where, 0);
-    psFree(where)
+    psFree(where);
     if (count < 0) {
         psError(PS_ERR_UNKNOWN, true, "failed to delete row from pzDoneExp");
@@ -2334,5 +2339,5 @@
         psMetadata *where = pzDoneExpMetadataFromObject(object);
         long long count = psDBDeleteRows(dbh, PZDONEEXP_TABLE_NAME, where, limit);
-        psFree(where)
+        psFree(where);
         if (count < 0) {
             psError(PS_ERR_UNKNOWN, true, "failed to delete row from pzDoneExp");
@@ -2718,5 +2723,5 @@
     psMetadata *where = pzDoneImfileMetadataFromObject(object);
     long long count = psDBDeleteRows(dbh, PZDONEIMFILE_TABLE_NAME, where, 0);
-    psFree(where)
+    psFree(where);
     if (count < 0) {
         psError(PS_ERR_UNKNOWN, true, "failed to delete row from pzDoneImfile");
@@ -2740,5 +2745,5 @@
         psMetadata *where = pzDoneImfileMetadataFromObject(object);
         long long count = psDBDeleteRows(dbh, PZDONEIMFILE_TABLE_NAME, where, limit);
-        psFree(where)
+        psFree(where);
         if (count < 0) {
             psError(PS_ERR_UNKNOWN, true, "failed to delete row from pzDoneImfile");
@@ -3101,5 +3106,5 @@
     psMetadata *where = newExpMetadataFromObject(object);
     long long count = psDBDeleteRows(dbh, NEWEXP_TABLE_NAME, where, 0);
-    psFree(where)
+    psFree(where);
     if (count < 0) {
         psError(PS_ERR_UNKNOWN, true, "failed to delete row from newExp");
@@ -3123,5 +3128,5 @@
         psMetadata *where = newExpMetadataFromObject(object);
         long long count = psDBDeleteRows(dbh, NEWEXP_TABLE_NAME, where, limit);
-        psFree(where)
+        psFree(where);
         if (count < 0) {
             psError(PS_ERR_UNKNOWN, true, "failed to delete row from newExp");
@@ -3441,5 +3446,5 @@
     psMetadata *where = newImfileMetadataFromObject(object);
     long long count = psDBDeleteRows(dbh, NEWIMFILE_TABLE_NAME, where, 0);
-    psFree(where)
+    psFree(where);
     if (count < 0) {
         psError(PS_ERR_UNKNOWN, true, "failed to delete row from newImfile");
@@ -3463,5 +3468,5 @@
         psMetadata *where = newImfileMetadataFromObject(object);
         long long count = psDBDeleteRows(dbh, NEWIMFILE_TABLE_NAME, where, limit);
-        psFree(where)
+        psFree(where);
         if (count < 0) {
             psError(PS_ERR_UNKNOWN, true, "failed to delete row from newImfile");
@@ -4164,5 +4169,5 @@
     psMetadata *where = rawExpMetadataFromObject(object);
     long long count = psDBDeleteRows(dbh, RAWEXP_TABLE_NAME, where, 0);
-    psFree(where)
+    psFree(where);
     if (count < 0) {
         psError(PS_ERR_UNKNOWN, true, "failed to delete row from rawExp");
@@ -4186,5 +4191,5 @@
         psMetadata *where = rawExpMetadataFromObject(object);
         long long count = psDBDeleteRows(dbh, RAWEXP_TABLE_NAME, where, limit);
-        psFree(where)
+        psFree(where);
         if (count < 0) {
             psError(PS_ERR_UNKNOWN, true, "failed to delete row from rawExp");
@@ -4844,5 +4849,5 @@
     psMetadata *where = rawImfileMetadataFromObject(object);
     long long count = psDBDeleteRows(dbh, RAWIMFILE_TABLE_NAME, where, 0);
-    psFree(where)
+    psFree(where);
     if (count < 0) {
         psError(PS_ERR_UNKNOWN, true, "failed to delete row from rawImfile");
@@ -4866,5 +4871,5 @@
         psMetadata *where = rawImfileMetadataFromObject(object);
         long long count = psDBDeleteRows(dbh, RAWIMFILE_TABLE_NAME, where, limit);
-        psFree(where)
+        psFree(where);
         if (count < 0) {
             psError(PS_ERR_UNKNOWN, true, "failed to delete row from rawImfile");
@@ -5161,5 +5166,5 @@
     psMetadata *where = p1PendingExpMetadataFromObject(object);
     long long count = psDBDeleteRows(dbh, P1PENDINGEXP_TABLE_NAME, where, 0);
-    psFree(where)
+    psFree(where);
     if (count < 0) {
         psError(PS_ERR_UNKNOWN, true, "failed to delete row from p1PendingExp");
@@ -5183,5 +5188,5 @@
         psMetadata *where = p1PendingExpMetadataFromObject(object);
         long long count = psDBDeleteRows(dbh, P1PENDINGEXP_TABLE_NAME, where, limit);
-        psFree(where)
+        psFree(where);
         if (count < 0) {
             psError(PS_ERR_UNKNOWN, true, "failed to delete row from p1PendingExp");
@@ -5521,5 +5526,5 @@
     psMetadata *where = p2PendingExpMetadataFromObject(object);
     long long count = psDBDeleteRows(dbh, P2PENDINGEXP_TABLE_NAME, where, 0);
-    psFree(where)
+    psFree(where);
     if (count < 0) {
         psError(PS_ERR_UNKNOWN, true, "failed to delete row from p2PendingExp");
@@ -5543,5 +5548,5 @@
         psMetadata *where = p2PendingExpMetadataFromObject(object);
         long long count = psDBDeleteRows(dbh, P2PENDINGEXP_TABLE_NAME, where, limit);
-        psFree(where)
+        psFree(where);
         if (count < 0) {
             psError(PS_ERR_UNKNOWN, true, "failed to delete row from p2PendingExp");
@@ -5903,5 +5908,5 @@
     psMetadata *where = p2PendingImfileMetadataFromObject(object);
     long long count = psDBDeleteRows(dbh, P2PENDINGIMFILE_TABLE_NAME, where, 0);
-    psFree(where)
+    psFree(where);
     if (count < 0) {
         psError(PS_ERR_UNKNOWN, true, "failed to delete row from p2PendingImfile");
@@ -5925,5 +5930,5 @@
         psMetadata *where = p2PendingImfileMetadataFromObject(object);
         long long count = psDBDeleteRows(dbh, P2PENDINGIMFILE_TABLE_NAME, where, limit);
-        psFree(where)
+        psFree(where);
         if (count < 0) {
             psError(PS_ERR_UNKNOWN, true, "failed to delete row from p2PendingImfile");
@@ -6241,5 +6246,5 @@
     psMetadata *where = p2ProcessedExpMetadataFromObject(object);
     long long count = psDBDeleteRows(dbh, P2PROCESSEDEXP_TABLE_NAME, where, 0);
-    psFree(where)
+    psFree(where);
     if (count < 0) {
         psError(PS_ERR_UNKNOWN, true, "failed to delete row from p2ProcessedExp");
@@ -6263,5 +6268,5 @@
         psMetadata *where = p2ProcessedExpMetadataFromObject(object);
         long long count = psDBDeleteRows(dbh, P2PROCESSEDEXP_TABLE_NAME, where, limit);
-        psFree(where)
+        psFree(where);
         if (count < 0) {
             psError(PS_ERR_UNKNOWN, true, "failed to delete row from p2ProcessedExp");
@@ -6515,5 +6520,5 @@
     psMetadata *where = p2MaskMetadataFromObject(object);
     long long count = psDBDeleteRows(dbh, P2MASK_TABLE_NAME, where, 0);
-    psFree(where)
+    psFree(where);
     if (count < 0) {
         psError(PS_ERR_UNKNOWN, true, "failed to delete row from p2Mask");
@@ -6537,5 +6542,5 @@
         psMetadata *where = p2MaskMetadataFromObject(object);
         long long count = psDBDeleteRows(dbh, P2MASK_TABLE_NAME, where, limit);
-        psFree(where)
+        psFree(where);
         if (count < 0) {
             psError(PS_ERR_UNKNOWN, true, "failed to delete row from p2Mask");
@@ -7025,5 +7030,5 @@
     psMetadata *where = p2ProcessedImfileMetadataFromObject(object);
     long long count = psDBDeleteRows(dbh, P2PROCESSEDIMFILE_TABLE_NAME, where, 0);
-    psFree(where)
+    psFree(where);
     if (count < 0) {
         psError(PS_ERR_UNKNOWN, true, "failed to delete row from p2ProcessedImfile");
@@ -7047,5 +7052,5 @@
         psMetadata *where = p2ProcessedImfileMetadataFromObject(object);
         long long count = psDBDeleteRows(dbh, P2PROCESSEDIMFILE_TABLE_NAME, where, limit);
-        psFree(where)
+        psFree(where);
         if (count < 0) {
             psError(PS_ERR_UNKNOWN, true, "failed to delete row from p2ProcessedImfile");
@@ -7363,5 +7368,5 @@
     psMetadata *where = p3PendingExpMetadataFromObject(object);
     long long count = psDBDeleteRows(dbh, P3PENDINGEXP_TABLE_NAME, where, 0);
-    psFree(where)
+    psFree(where);
     if (count < 0) {
         psError(PS_ERR_UNKNOWN, true, "failed to delete row from p3PendingExp");
@@ -7385,5 +7390,5 @@
         psMetadata *where = p3PendingExpMetadataFromObject(object);
         long long count = psDBDeleteRows(dbh, P3PENDINGEXP_TABLE_NAME, where, limit);
-        psFree(where)
+        psFree(where);
         if (count < 0) {
             psError(PS_ERR_UNKNOWN, true, "failed to delete row from p3PendingExp");
@@ -7978,5 +7983,5 @@
     psMetadata *where = p3ProcessedExpMetadataFromObject(object);
     long long count = psDBDeleteRows(dbh, P3PROCESSEDEXP_TABLE_NAME, where, 0);
-    psFree(where)
+    psFree(where);
     if (count < 0) {
         psError(PS_ERR_UNKNOWN, true, "failed to delete row from p3ProcessedExp");
@@ -8000,5 +8005,5 @@
         psMetadata *where = p3ProcessedExpMetadataFromObject(object);
         long long count = psDBDeleteRows(dbh, P3PROCESSEDEXP_TABLE_NAME, where, limit);
-        psFree(where)
+        psFree(where);
         if (count < 0) {
             psError(PS_ERR_UNKNOWN, true, "failed to delete row from p3ProcessedExp");
@@ -8252,5 +8257,5 @@
     psMetadata *where = p3MaskMetadataFromObject(object);
     long long count = psDBDeleteRows(dbh, P3MASK_TABLE_NAME, where, 0);
-    psFree(where)
+    psFree(where);
     if (count < 0) {
         psError(PS_ERR_UNKNOWN, true, "failed to delete row from p3Mask");
@@ -8274,5 +8279,5 @@
         psMetadata *where = p3MaskMetadataFromObject(object);
         long long count = psDBDeleteRows(dbh, P3MASK_TABLE_NAME, where, limit);
-        psFree(where)
+        psFree(where);
         if (count < 0) {
             psError(PS_ERR_UNKNOWN, true, "failed to delete row from p3Mask");
@@ -9000,5 +9005,5 @@
     psMetadata *where = detRunMetadataFromObject(object);
     long long count = psDBDeleteRows(dbh, DETRUN_TABLE_NAME, where, 0);
-    psFree(where)
+    psFree(where);
     if (count < 0) {
         psError(PS_ERR_UNKNOWN, true, "failed to delete row from detRun");
@@ -9022,5 +9027,5 @@
         psMetadata *where = detRunMetadataFromObject(object);
         long long count = psDBDeleteRows(dbh, DETRUN_TABLE_NAME, where, limit);
-        psFree(where)
+        psFree(where);
         if (count < 0) {
             psError(PS_ERR_UNKNOWN, true, "failed to delete row from detRun");
@@ -9337,5 +9342,5 @@
     psMetadata *where = detInputExpMetadataFromObject(object);
     long long count = psDBDeleteRows(dbh, DETINPUTEXP_TABLE_NAME, where, 0);
-    psFree(where)
+    psFree(where);
     if (count < 0) {
         psError(PS_ERR_UNKNOWN, true, "failed to delete row from detInputExp");
@@ -9359,5 +9364,5 @@
         psMetadata *where = detInputExpMetadataFromObject(object);
         long long count = psDBDeleteRows(dbh, DETINPUTEXP_TABLE_NAME, where, limit);
-        psFree(where)
+        psFree(where);
         if (count < 0) {
             psError(PS_ERR_UNKNOWN, true, "failed to delete row from detInputExp");
@@ -9826,5 +9831,5 @@
     psMetadata *where = detProcessedImfileMetadataFromObject(object);
     long long count = psDBDeleteRows(dbh, DETPROCESSEDIMFILE_TABLE_NAME, where, 0);
-    psFree(where)
+    psFree(where);
     if (count < 0) {
         psError(PS_ERR_UNKNOWN, true, "failed to delete row from detProcessedImfile");
@@ -9848,5 +9853,5 @@
         psMetadata *where = detProcessedImfileMetadataFromObject(object);
         long long count = psDBDeleteRows(dbh, DETPROCESSEDIMFILE_TABLE_NAME, where, limit);
-        psFree(where)
+        psFree(where);
         if (count < 0) {
             psError(PS_ERR_UNKNOWN, true, "failed to delete row from detProcessedImfile");
@@ -10271,5 +10276,5 @@
     psMetadata *where = detProcessedExpMetadataFromObject(object);
     long long count = psDBDeleteRows(dbh, DETPROCESSEDEXP_TABLE_NAME, where, 0);
-    psFree(where)
+    psFree(where);
     if (count < 0) {
         psError(PS_ERR_UNKNOWN, true, "failed to delete row from detProcessedExp");
@@ -10293,5 +10298,5 @@
         psMetadata *where = detProcessedExpMetadataFromObject(object);
         long long count = psDBDeleteRows(dbh, DETPROCESSEDEXP_TABLE_NAME, where, limit);
-        psFree(where)
+        psFree(where);
         if (count < 0) {
             psError(PS_ERR_UNKNOWN, true, "failed to delete row from detProcessedExp");
@@ -10715,5 +10720,5 @@
     psMetadata *where = detStackedImfileMetadataFromObject(object);
     long long count = psDBDeleteRows(dbh, DETSTACKEDIMFILE_TABLE_NAME, where, 0);
-    psFree(where)
+    psFree(where);
     if (count < 0) {
         psError(PS_ERR_UNKNOWN, true, "failed to delete row from detStackedImfile");
@@ -10737,5 +10742,5 @@
         psMetadata *where = detStackedImfileMetadataFromObject(object);
         long long count = psDBDeleteRows(dbh, DETSTACKEDIMFILE_TABLE_NAME, where, limit);
-        psFree(where)
+        psFree(where);
         if (count < 0) {
             psError(PS_ERR_UNKNOWN, true, "failed to delete row from detStackedImfile");
@@ -11073,5 +11078,5 @@
     psMetadata *where = detNormalizedStatImfileMetadataFromObject(object);
     long long count = psDBDeleteRows(dbh, DETNORMALIZEDSTATIMFILE_TABLE_NAME, where, 0);
-    psFree(where)
+    psFree(where);
     if (count < 0) {
         psError(PS_ERR_UNKNOWN, true, "failed to delete row from detNormalizedStatImfile");
@@ -11095,5 +11100,5 @@
         psMetadata *where = detNormalizedStatImfileMetadataFromObject(object);
         long long count = psDBDeleteRows(dbh, DETNORMALIZEDSTATIMFILE_TABLE_NAME, where, limit);
-        psFree(where)
+        psFree(where);
         if (count < 0) {
             psError(PS_ERR_UNKNOWN, true, "failed to delete row from detNormalizedStatImfile");
@@ -11539,5 +11544,5 @@
     psMetadata *where = detNormalizedImfileMetadataFromObject(object);
     long long count = psDBDeleteRows(dbh, DETNORMALIZEDIMFILE_TABLE_NAME, where, 0);
-    psFree(where)
+    psFree(where);
     if (count < 0) {
         psError(PS_ERR_UNKNOWN, true, "failed to delete row from detNormalizedImfile");
@@ -11561,5 +11566,5 @@
         psMetadata *where = detNormalizedImfileMetadataFromObject(object);
         long long count = psDBDeleteRows(dbh, DETNORMALIZEDIMFILE_TABLE_NAME, where, limit);
-        psFree(where)
+        psFree(where);
         if (count < 0) {
             psError(PS_ERR_UNKNOWN, true, "failed to delete row from detNormalizedImfile");
@@ -11983,5 +11988,5 @@
     psMetadata *where = detNormalizedExpMetadataFromObject(object);
     long long count = psDBDeleteRows(dbh, DETNORMALIZEDEXP_TABLE_NAME, where, 0);
-    psFree(where)
+    psFree(where);
     if (count < 0) {
         psError(PS_ERR_UNKNOWN, true, "failed to delete row from detNormalizedExp");
@@ -12005,5 +12010,5 @@
         psMetadata *where = detNormalizedExpMetadataFromObject(object);
         long long count = psDBDeleteRows(dbh, DETNORMALIZEDEXP_TABLE_NAME, where, limit);
-        psFree(where)
+        psFree(where);
         if (count < 0) {
             psError(PS_ERR_UNKNOWN, true, "failed to delete row from detNormalizedExp");
@@ -12493,5 +12498,5 @@
     psMetadata *where = detResidImfileMetadataFromObject(object);
     long long count = psDBDeleteRows(dbh, DETRESIDIMFILE_TABLE_NAME, where, 0);
-    psFree(where)
+    psFree(where);
     if (count < 0) {
         psError(PS_ERR_UNKNOWN, true, "failed to delete row from detResidImfile");
@@ -12515,5 +12520,5 @@
         psMetadata *where = detResidImfileMetadataFromObject(object);
         long long count = psDBDeleteRows(dbh, DETRESIDIMFILE_TABLE_NAME, where, limit);
-        psFree(where)
+        psFree(where);
         if (count < 0) {
             psError(PS_ERR_UNKNOWN, true, "failed to delete row from detResidImfile");
@@ -12980,5 +12985,5 @@
     psMetadata *where = detResidExpMetadataFromObject(object);
     long long count = psDBDeleteRows(dbh, DETRESIDEXP_TABLE_NAME, where, 0);
-    psFree(where)
+    psFree(where);
     if (count < 0) {
         psError(PS_ERR_UNKNOWN, true, "failed to delete row from detResidExp");
@@ -13002,5 +13007,5 @@
         psMetadata *where = detResidExpMetadataFromObject(object);
         long long count = psDBDeleteRows(dbh, DETRESIDEXP_TABLE_NAME, where, limit);
-        psFree(where)
+        psFree(where);
         if (count < 0) {
             psError(PS_ERR_UNKNOWN, true, "failed to delete row from detResidExp");
@@ -13379,5 +13384,5 @@
     psMetadata *where = detRunSummaryMetadataFromObject(object);
     long long count = psDBDeleteRows(dbh, DETRUNSUMMARY_TABLE_NAME, where, 0);
-    psFree(where)
+    psFree(where);
     if (count < 0) {
         psError(PS_ERR_UNKNOWN, true, "failed to delete row from detRunSummary");
@@ -13401,5 +13406,5 @@
         psMetadata *where = detRunSummaryMetadataFromObject(object);
         long long count = psDBDeleteRows(dbh, DETRUNSUMMARY_TABLE_NAME, where, limit);
-        psFree(where)
+        psFree(where);
         if (count < 0) {
             psError(PS_ERR_UNKNOWN, true, "failed to delete row from detRunSummary");
@@ -13458,50 +13463,32 @@
     return true;
 }
-static void p4RunRowFree(p4RunRow *object);
-
-p4RunRow *p4RunRowAlloc(psS32 p4_id, const char *survey_mode, const char *state, const char *workdir, const char *filter, const char *skycell_id, const char *tess_id, psF64 ra, psF64 decl, const char *input_ss, const char *output_ss)
-{
-    p4RunRow        *_object;
-
-    _object = psAlloc(sizeof(p4RunRow));
-    psMemSetDeallocator(_object, (psFreeFunc)p4RunRowFree);
-
-    _object->p4_id = p4_id;
-    _object->survey_mode = psStringCopy(survey_mode);
+static void p4aRunRowFree(p4aRunRow *object);
+
+p4aRunRow *p4aRunRowAlloc(psS32 p4a_id, const char *state, const char *workdir, bool magic)
+{
+    p4aRunRow       *_object;
+
+    _object = psAlloc(sizeof(p4aRunRow));
+    psMemSetDeallocator(_object, (psFreeFunc)p4aRunRowFree);
+
+    _object->p4a_id = p4a_id;
     _object->state = psStringCopy(state);
     _object->workdir = psStringCopy(workdir);
-    _object->filter = psStringCopy(filter);
-    _object->skycell_id = psStringCopy(skycell_id);
-    _object->tess_id = psStringCopy(tess_id);
-    _object->ra = ra;
-    _object->decl = decl;
-    _object->input_ss = psStringCopy(input_ss);
-    _object->output_ss = psStringCopy(output_ss);
+    _object->magic = magic;
 
     return _object;
 }
 
-static void p4RunRowFree(p4RunRow *object)
-{
-    psFree(object->survey_mode);
+static void p4aRunRowFree(p4aRunRow *object)
+{
     psFree(object->state);
     psFree(object->workdir);
-    psFree(object->filter);
-    psFree(object->skycell_id);
-    psFree(object->tess_id);
-    psFree(object->input_ss);
-    psFree(object->output_ss);
-}
-
-bool p4RunCreateTable(psDB *dbh)
+}
+
+bool p4aRunCreateTable(psDB *dbh)
 {
     psMetadata *md = psMetadataAlloc();
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4_id", PS_DATA_S32, "Primary Key AUTO_INCREMENT", 0)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item p4_id");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "survey_mode", PS_DATA_STRING, "Key", "64")) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item survey_mode");
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4a_id", PS_DATA_S32, "Primary Key AUTO_INCREMENT", 0)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p4a_id");
         psFree(md);
         return false;
@@ -13517,41 +13504,11 @@
         return false;
     }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "filter", PS_DATA_STRING, NULL, "64")) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item filter");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "skycell_id", PS_DATA_STRING, NULL, "64")) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item skycell_id");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "tess_id", PS_DATA_STRING, NULL, "64")) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item tess_id");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "ra", PS_DATA_F64, NULL, 0.0)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item ra");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "decl", PS_DATA_F64, NULL, 0.0)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item decl");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "input_ss", PS_DATA_STRING, NULL, "64")) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item input_ss");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "output_ss", PS_DATA_STRING, NULL, "64")) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item output_ss");
-        psFree(md);
-        return false;
-    }
-
-    bool status = psDBCreateTable(dbh, P4RUN_TABLE_NAME, md);
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "magic", PS_DATA_BOOL, "Primary Key", 0)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item magic");
+        psFree(md);
+        return false;
+    }
+
+    bool status = psDBCreateTable(dbh, P4ARUN_TABLE_NAME, md);
 
     psFree(md);
@@ -13560,19 +13517,14 @@
 }
 
-bool p4RunDropTable(psDB *dbh)
-{
-    return psDBDropTable(dbh, P4RUN_TABLE_NAME);
-}
-
-bool p4RunInsert(psDB * dbh, psS32 p4_id, const char *survey_mode, const char *state, const char *workdir, const char *filter, const char *skycell_id, const char *tess_id, psF64 ra, psF64 decl, const char *input_ss, const char *output_ss)
+bool p4aRunDropTable(psDB *dbh)
+{
+    return psDBDropTable(dbh, P4ARUN_TABLE_NAME);
+}
+
+bool p4aRunInsert(psDB * dbh, psS32 p4a_id, const char *state, const char *workdir, bool magic)
 {
     psMetadata *md = psMetadataAlloc();
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4_id", PS_DATA_S32, NULL, p4_id)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item p4_id");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "survey_mode", PS_DATA_STRING, NULL, survey_mode)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item survey_mode");
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4a_id", PS_DATA_S32, NULL, p4a_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p4a_id");
         psFree(md);
         return false;
@@ -13588,41 +13540,11 @@
         return false;
     }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "filter", PS_DATA_STRING, NULL, filter)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item filter");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "skycell_id", PS_DATA_STRING, NULL, skycell_id)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item skycell_id");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "tess_id", PS_DATA_STRING, NULL, tess_id)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item tess_id");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "ra", PS_DATA_F64, NULL, ra)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item ra");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "decl", PS_DATA_F64, NULL, decl)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item decl");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "input_ss", PS_DATA_STRING, NULL, input_ss)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item input_ss");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "output_ss", PS_DATA_STRING, NULL, output_ss)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item output_ss");
-        psFree(md);
-        return false;
-    }
-
-    bool status = psDBInsertOneRow(dbh, P4RUN_TABLE_NAME, md);
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "magic", PS_DATA_BOOL, NULL, magic)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item magic");
+        psFree(md);
+        return false;
+    }
+
+    bool status = psDBInsertOneRow(dbh, P4ARUN_TABLE_NAME, md);
     psFree(md);
 
@@ -13630,11 +13552,11 @@
 }
 
-long long p4RunDelete(psDB *dbh, const psMetadata *where, unsigned long long limit)
+long long p4aRunDelete(psDB *dbh, const psMetadata *where, unsigned long long limit)
 {
     long long       deleted = 0;
 
-    long long count = psDBDeleteRows(dbh, P4RUN_TABLE_NAME, where, limit);
+    long long count = psDBDeleteRows(dbh, P4ARUN_TABLE_NAME, where, limit);
     if (count < 0) {
-        psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4Run");
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4aRun");
         return count;
 
@@ -13644,13 +13566,13 @@
     return deleted;
 }
-bool p4RunInsertObject(psDB *dbh, p4RunRow *object)
-{
-    return p4RunInsert(dbh, object->p4_id, object->survey_mode, object->state, object->workdir, object->filter, object->skycell_id, object->tess_id, object->ra, object->decl, object->input_ss, object->output_ss);
-}
-
-bool p4RunInsertObjects(psDB *dbh, psArray *objects)
+bool p4aRunInsertObject(psDB *dbh, p4aRunRow *object)
+{
+    return p4aRunInsert(dbh, object->p4a_id, object->state, object->workdir, object->magic);
+}
+
+bool p4aRunInsertObjects(psDB *dbh, psArray *objects)
 {
     for (long i = 0; i < psArrayLength(objects); i++) {
-        if (!p4RunInsertObject(dbh, objects->data[i])) {
+        if (!p4aRunInsertObject(dbh, objects->data[i])) {
             return false;
         }
@@ -13660,11 +13582,11 @@
 }
 
-bool p4RunInsertFits(psDB *dbh, const psFits *fits)
+bool p4aRunInsertFits(psDB *dbh, const psFits *fits)
 {
     psArray         *rowSet;
 
-    // move to (the first?) extension named  P4RUN_TABLE_NAME
-    if (!psFitsMoveExtName(fits, P4RUN_TABLE_NAME)) {
-        psError(PS_ERR_UNKNOWN, true, "failed to find FITS extension %s", P4RUN_TABLE_NAME);
+    // move to (the first?) extension named  P4ARUN_TABLE_NAME
+    if (!psFitsMoveExtName(fits, P4ARUN_TABLE_NAME)) {
+        psError(PS_ERR_UNKNOWN, true, "failed to find FITS extension %s", P4ARUN_TABLE_NAME);
         return false;
     }
@@ -13684,5 +13606,5 @@
     }
 
-    if (!psDBInsertRows(dbh, P4RUN_TABLE_NAME, rowSet)) {
+    if (!psDBInsertRows(dbh, P4ARUN_TABLE_NAME, rowSet)) {
         psError(PS_ERR_UNKNOWN, false, "databse insert failed");
         psFree(rowSet);
@@ -13695,9 +13617,9 @@
 }
 
-bool p4RunSelectRowsFits(psDB *dbh, psFits *fits, const psMetadata *where, unsigned long long limit)
+bool p4aRunSelectRowsFits(psDB *dbh, psFits *fits, const psMetadata *where, unsigned long long limit)
 {
     psArray         *rowSet;
 
-    rowSet = psDBSelectRows(dbh, P4RUN_TABLE_NAME, where, limit);
+    rowSet = psDBSelectRows(dbh, P4ARUN_TABLE_NAME, where, limit);
     if (!rowSet) {
         return false;
@@ -13705,5 +13627,5 @@
 
     // output to fits
-    if (!psFitsWriteTable(fits, NULL, rowSet, P4RUN_TABLE_NAME)) {
+    if (!psFitsWriteTable(fits, NULL, rowSet, P4ARUN_TABLE_NAME)) {
         psError(PS_ERR_UNKNOWN, false, "FITS table write failed");
         psFree(rowSet);
@@ -13716,14 +13638,9 @@
 }
 
-psMetadata *p4RunMetadataFromObject(const p4RunRow *object)
+psMetadata *p4aRunMetadataFromObject(const p4aRunRow *object)
 {
     psMetadata *md = psMetadataAlloc();
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4_id", PS_DATA_S32, NULL, object->p4_id)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item p4_id");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "survey_mode", PS_DATA_STRING, NULL, object->survey_mode)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item survey_mode");
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4a_id", PS_DATA_S32, NULL, object->p4a_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p4a_id");
         psFree(md);
         return false;
@@ -13739,36 +13656,6 @@
         return false;
     }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "filter", PS_DATA_STRING, NULL, object->filter)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item filter");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "skycell_id", PS_DATA_STRING, NULL, object->skycell_id)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item skycell_id");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "tess_id", PS_DATA_STRING, NULL, object->tess_id)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item tess_id");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "ra", PS_DATA_F64, NULL, object->ra)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item ra");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "decl", PS_DATA_F64, NULL, object->decl)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item decl");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "input_ss", PS_DATA_STRING, NULL, object->input_ss)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item input_ss");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "output_ss", PS_DATA_STRING, NULL, object->output_ss)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item output_ss");
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "magic", PS_DATA_BOOL, NULL, object->magic)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item magic");
         psFree(md);
         return false;
@@ -13779,16 +13666,11 @@
 }
 
-p4RunRow *p4RunObjectFromMetadata(psMetadata *md)
+p4aRunRow *p4aRunObjectFromMetadata(psMetadata *md)
 {
 
 bool status = false;
-    psS32 p4_id = psMetadataLookupS32(&status, md, "p4_id");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item p4_id");
-        return false;
-    }
-    char* survey_mode = psMetadataLookupPtr(&status, md, "survey_mode");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item survey_mode");
+    psS32 p4a_id = psMetadataLookupS32(&status, md, "p4a_id");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item p4a_id");
         return false;
     }
@@ -13803,43 +13685,13 @@
         return false;
     }
-    char* filter = psMetadataLookupPtr(&status, md, "filter");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item filter");
-        return false;
-    }
-    char* skycell_id = psMetadataLookupPtr(&status, md, "skycell_id");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item skycell_id");
-        return false;
-    }
-    char* tess_id = psMetadataLookupPtr(&status, md, "tess_id");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item tess_id");
-        return false;
-    }
-    psF64 ra = psMetadataLookupF64(&status, md, "ra");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item ra");
-        return false;
-    }
-    psF64 decl = psMetadataLookupF64(&status, md, "decl");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item decl");
-        return false;
-    }
-    char* input_ss = psMetadataLookupPtr(&status, md, "input_ss");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item input_ss");
-        return false;
-    }
-    char* output_ss = psMetadataLookupPtr(&status, md, "output_ss");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item output_ss");
-        return false;
-    }
-
-    return p4RunRowAlloc(p4_id, survey_mode, state, workdir, filter, skycell_id, tess_id, ra, decl, input_ss, output_ss);
-}
-psArray *p4RunSelectRowObjects(psDB *dbh, const psMetadata *where, unsigned long long limit)
+    bool magic = psMetadataLookupBool(&status, md, "magic");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item magic");
+        return false;
+    }
+
+    return p4aRunRowAlloc(p4a_id, state, workdir, magic);
+}
+psArray *p4aRunSelectRowObjects(psDB *dbh, const psMetadata *where, unsigned long long limit)
 {
     psArray         *rowSet;
@@ -13847,5 +13699,5 @@
     psU64           i;
 
-    rowSet = psDBSelectRows(dbh, P4RUN_TABLE_NAME, where, limit);
+    rowSet = psDBSelectRows(dbh, P4ARUN_TABLE_NAME, where, limit);
     if (!rowSet) {
         return NULL;
@@ -13857,5 +13709,5 @@
 
     for (i = 0; i < rowSet->n; i++) {
-        p4RunRow *object = p4RunObjectFromMetadata(rowSet->data[i]);
+        p4aRunRow *object = p4aRunObjectFromMetadata(rowSet->data[i]);
         psArrayAdd(returnSet, 0, object);
         psFree(object);
@@ -13866,11 +13718,11 @@
     return returnSet;
 }
-bool p4RunDeleteObject(psDB *dbh, const p4RunRow *object)
-{
-    psMetadata *where = p4RunMetadataFromObject(object);
-    long long count = psDBDeleteRows(dbh, P4RUN_TABLE_NAME, where, 0);
-    psFree(where)
+bool p4aRunDeleteObject(psDB *dbh, const p4aRunRow *object)
+{
+    psMetadata *where = p4aRunMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, P4ARUN_TABLE_NAME, where, 0);
+    psFree(where);
     if (count < 0) {
-        psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4Run");
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4aRun");
         return false;
     }
@@ -13878,21 +13730,21 @@
         // 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, "p4RunRow object matched more then one row.  Check your database schema");
-        return false;
-    }
-
-    return true;
-}
-long long p4RunDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
+        psError(PS_ERR_UNKNOWN, true, "p4aRunRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
+long long p4aRunDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
 {
     long long       deleted = 0;
 
     for (long long i = 0; i < objects->n; i++) {
-        p4RunRow *object = objects->data[i];
-        psMetadata *where = p4RunMetadataFromObject(object);
-        long long count = psDBDeleteRows(dbh, P4RUN_TABLE_NAME, where, limit);
-        psFree(where)
+        p4aRunRow *object = objects->data[i];
+        psMetadata *where = p4aRunMetadataFromObject(object);
+        long long count = psDBDeleteRows(dbh, P4ARUN_TABLE_NAME, where, limit);
+        psFree(where);
         if (count < 0) {
-            psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4Run");
+            psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4aRun");
             return count;
         }
@@ -13903,5 +13755,5 @@
     return deleted;
 }
-bool p4RunPrintObjects(FILE *stream, psArray *objects, bool mdcf)
+bool p4aRunPrintObjects(FILE *stream, psArray *objects, bool mdcf)
 {
     PS_ASSERT_PTR_NON_NULL(objects, false);
@@ -13909,9 +13761,9 @@
     psMetadata *output = psMetadataAlloc();
     for (long i = 0; i < psArrayLength(objects); i++) {
-        psMetadata *md = p4RunMetadataFromObject(objects->data[i]);
+        psMetadata *md = p4aRunMetadataFromObject(objects->data[i]);
         if (!psMetadataAddMetadata(
             output,
             PS_LIST_TAIL,
-            P4RUN_TABLE_NAME,
+            P4ARUN_TABLE_NAME,
             PS_META_DUPLICATE_OK,
             NULL,
@@ -13934,9 +13786,9 @@
     return true;
 }
-bool p4RunPrintObject(FILE *stream, p4RunRow *object, bool mdcf)
+bool p4aRunPrintObject(FILE *stream, p4aRunRow *object, bool mdcf)
 {
     PS_ASSERT_PTR_NON_NULL(object, false);
 
-    psMetadata *md = p4RunMetadataFromObject(object);
+    psMetadata *md = p4aRunMetadataFromObject(object);
 
     if (!ippdbPrintMetadataRaw(stream, md, mdcf)) {
@@ -13949,32 +13801,30 @@
     return true;
 }
-static void p4InputImfileRowFree(p4InputImfileRow *object);
-
-p4InputImfileRow *p4InputImfileRowAlloc(psS32 p4_id, const char *exp_tag, psS32 p3_version, const char *class_id)
-{
-    p4InputImfileRow *_object;
-
-    _object = psAlloc(sizeof(p4InputImfileRow));
-    psMemSetDeallocator(_object, (psFreeFunc)p4InputImfileRowFree);
-
-    _object->p4_id = p4_id;
+static void p4aInputExpRowFree(p4aInputExpRow *object);
+
+p4aInputExpRow *p4aInputExpRowAlloc(psS32 p4a_id, const char *exp_tag, psS32 p3_version)
+{
+    p4aInputExpRow  *_object;
+
+    _object = psAlloc(sizeof(p4aInputExpRow));
+    psMemSetDeallocator(_object, (psFreeFunc)p4aInputExpRowFree);
+
+    _object->p4a_id = p4a_id;
     _object->exp_tag = psStringCopy(exp_tag);
     _object->p3_version = p3_version;
-    _object->class_id = psStringCopy(class_id);
 
     return _object;
 }
 
-static void p4InputImfileRowFree(p4InputImfileRow *object)
+static void p4aInputExpRowFree(p4aInputExpRow *object)
 {
     psFree(object->exp_tag);
-    psFree(object->class_id);
-}
-
-bool p4InputImfileCreateTable(psDB *dbh)
+}
+
+bool p4aInputExpCreateTable(psDB *dbh)
 {
     psMetadata *md = psMetadataAlloc();
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4_id", PS_DATA_S32, "Primary Key", 0)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item p4_id");
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4a_id", PS_DATA_S32, "Primary Key", 0)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p4a_id");
         psFree(md);
         return false;
@@ -13990,11 +13840,6 @@
         return false;
     }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "class_id", PS_DATA_STRING, "Primary Key", "64")) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item class_id");
-        psFree(md);
-        return false;
-    }
-
-    bool status = psDBCreateTable(dbh, P4INPUTIMFILE_TABLE_NAME, md);
+
+    bool status = psDBCreateTable(dbh, P4AINPUTEXP_TABLE_NAME, md);
 
     psFree(md);
@@ -14003,14 +13848,14 @@
 }
 
-bool p4InputImfileDropTable(psDB *dbh)
-{
-    return psDBDropTable(dbh, P4INPUTIMFILE_TABLE_NAME);
-}
-
-bool p4InputImfileInsert(psDB * dbh, psS32 p4_id, const char *exp_tag, psS32 p3_version, const char *class_id)
+bool p4aInputExpDropTable(psDB *dbh)
+{
+    return psDBDropTable(dbh, P4AINPUTEXP_TABLE_NAME);
+}
+
+bool p4aInputExpInsert(psDB * dbh, psS32 p4a_id, const char *exp_tag, psS32 p3_version)
 {
     psMetadata *md = psMetadataAlloc();
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4_id", PS_DATA_S32, NULL, p4_id)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item p4_id");
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4a_id", PS_DATA_S32, NULL, p4a_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p4a_id");
         psFree(md);
         return false;
@@ -14026,11 +13871,6 @@
         return false;
     }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "class_id", PS_DATA_STRING, NULL, class_id)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item class_id");
-        psFree(md);
-        return false;
-    }
-
-    bool status = psDBInsertOneRow(dbh, P4INPUTIMFILE_TABLE_NAME, md);
+
+    bool status = psDBInsertOneRow(dbh, P4AINPUTEXP_TABLE_NAME, md);
     psFree(md);
 
@@ -14038,11 +13878,11 @@
 }
 
-long long p4InputImfileDelete(psDB *dbh, const psMetadata *where, unsigned long long limit)
+long long p4aInputExpDelete(psDB *dbh, const psMetadata *where, unsigned long long limit)
 {
     long long       deleted = 0;
 
-    long long count = psDBDeleteRows(dbh, P4INPUTIMFILE_TABLE_NAME, where, limit);
+    long long count = psDBDeleteRows(dbh, P4AINPUTEXP_TABLE_NAME, where, limit);
     if (count < 0) {
-        psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4InputImfile");
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4aInputExp");
         return count;
 
@@ -14052,13 +13892,13 @@
     return deleted;
 }
-bool p4InputImfileInsertObject(psDB *dbh, p4InputImfileRow *object)
-{
-    return p4InputImfileInsert(dbh, object->p4_id, object->exp_tag, object->p3_version, object->class_id);
-}
-
-bool p4InputImfileInsertObjects(psDB *dbh, psArray *objects)
+bool p4aInputExpInsertObject(psDB *dbh, p4aInputExpRow *object)
+{
+    return p4aInputExpInsert(dbh, object->p4a_id, object->exp_tag, object->p3_version);
+}
+
+bool p4aInputExpInsertObjects(psDB *dbh, psArray *objects)
 {
     for (long i = 0; i < psArrayLength(objects); i++) {
-        if (!p4InputImfileInsertObject(dbh, objects->data[i])) {
+        if (!p4aInputExpInsertObject(dbh, objects->data[i])) {
             return false;
         }
@@ -14068,11 +13908,11 @@
 }
 
-bool p4InputImfileInsertFits(psDB *dbh, const psFits *fits)
+bool p4aInputExpInsertFits(psDB *dbh, const psFits *fits)
 {
     psArray         *rowSet;
 
-    // move to (the first?) extension named  P4INPUTIMFILE_TABLE_NAME
-    if (!psFitsMoveExtName(fits, P4INPUTIMFILE_TABLE_NAME)) {
-        psError(PS_ERR_UNKNOWN, true, "failed to find FITS extension %s", P4INPUTIMFILE_TABLE_NAME);
+    // move to (the first?) extension named  P4AINPUTEXP_TABLE_NAME
+    if (!psFitsMoveExtName(fits, P4AINPUTEXP_TABLE_NAME)) {
+        psError(PS_ERR_UNKNOWN, true, "failed to find FITS extension %s", P4AINPUTEXP_TABLE_NAME);
         return false;
     }
@@ -14092,5 +13932,5 @@
     }
 
-    if (!psDBInsertRows(dbh, P4INPUTIMFILE_TABLE_NAME, rowSet)) {
+    if (!psDBInsertRows(dbh, P4AINPUTEXP_TABLE_NAME, rowSet)) {
         psError(PS_ERR_UNKNOWN, false, "databse insert failed");
         psFree(rowSet);
@@ -14103,9 +13943,9 @@
 }
 
-bool p4InputImfileSelectRowsFits(psDB *dbh, psFits *fits, const psMetadata *where, unsigned long long limit)
+bool p4aInputExpSelectRowsFits(psDB *dbh, psFits *fits, const psMetadata *where, unsigned long long limit)
 {
     psArray         *rowSet;
 
-    rowSet = psDBSelectRows(dbh, P4INPUTIMFILE_TABLE_NAME, where, limit);
+    rowSet = psDBSelectRows(dbh, P4AINPUTEXP_TABLE_NAME, where, limit);
     if (!rowSet) {
         return false;
@@ -14113,5 +13953,5 @@
 
     // output to fits
-    if (!psFitsWriteTable(fits, NULL, rowSet, P4INPUTIMFILE_TABLE_NAME)) {
+    if (!psFitsWriteTable(fits, NULL, rowSet, P4AINPUTEXP_TABLE_NAME)) {
         psError(PS_ERR_UNKNOWN, false, "FITS table write failed");
         psFree(rowSet);
@@ -14124,9 +13964,9 @@
 }
 
-psMetadata *p4InputImfileMetadataFromObject(const p4InputImfileRow *object)
+psMetadata *p4aInputExpMetadataFromObject(const p4aInputExpRow *object)
 {
     psMetadata *md = psMetadataAlloc();
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4_id", PS_DATA_S32, NULL, object->p4_id)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item p4_id");
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4a_id", PS_DATA_S32, NULL, object->p4a_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p4a_id");
         psFree(md);
         return false;
@@ -14142,9 +13982,4 @@
         return false;
     }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "class_id", PS_DATA_STRING, NULL, object->class_id)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item class_id");
-        psFree(md);
-        return false;
-    }
 
 
@@ -14152,11 +13987,11 @@
 }
 
-p4InputImfileRow *p4InputImfileObjectFromMetadata(psMetadata *md)
+p4aInputExpRow *p4aInputExpObjectFromMetadata(psMetadata *md)
 {
 
 bool status = false;
-    psS32 p4_id = psMetadataLookupS32(&status, md, "p4_id");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item p4_id");
+    psS32 p4a_id = psMetadataLookupS32(&status, md, "p4a_id");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item p4a_id");
         return false;
     }
@@ -14171,13 +14006,8 @@
         return false;
     }
-    char* class_id = psMetadataLookupPtr(&status, md, "class_id");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item class_id");
-        return false;
-    }
-
-    return p4InputImfileRowAlloc(p4_id, exp_tag, p3_version, class_id);
-}
-psArray *p4InputImfileSelectRowObjects(psDB *dbh, const psMetadata *where, unsigned long long limit)
+
+    return p4aInputExpRowAlloc(p4a_id, exp_tag, p3_version);
+}
+psArray *p4aInputExpSelectRowObjects(psDB *dbh, const psMetadata *where, unsigned long long limit)
 {
     psArray         *rowSet;
@@ -14185,5 +14015,5 @@
     psU64           i;
 
-    rowSet = psDBSelectRows(dbh, P4INPUTIMFILE_TABLE_NAME, where, limit);
+    rowSet = psDBSelectRows(dbh, P4AINPUTEXP_TABLE_NAME, where, limit);
     if (!rowSet) {
         return NULL;
@@ -14195,5 +14025,5 @@
 
     for (i = 0; i < rowSet->n; i++) {
-        p4InputImfileRow *object = p4InputImfileObjectFromMetadata(rowSet->data[i]);
+        p4aInputExpRow *object = p4aInputExpObjectFromMetadata(rowSet->data[i]);
         psArrayAdd(returnSet, 0, object);
         psFree(object);
@@ -14204,11 +14034,11 @@
     return returnSet;
 }
-bool p4InputImfileDeleteObject(psDB *dbh, const p4InputImfileRow *object)
-{
-    psMetadata *where = p4InputImfileMetadataFromObject(object);
-    long long count = psDBDeleteRows(dbh, P4INPUTIMFILE_TABLE_NAME, where, 0);
-    psFree(where)
+bool p4aInputExpDeleteObject(psDB *dbh, const p4aInputExpRow *object)
+{
+    psMetadata *where = p4aInputExpMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, P4AINPUTEXP_TABLE_NAME, where, 0);
+    psFree(where);
     if (count < 0) {
-        psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4InputImfile");
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4aInputExp");
         return false;
     }
@@ -14216,21 +14046,21 @@
         // 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, "p4InputImfileRow object matched more then one row.  Check your database schema");
-        return false;
-    }
-
-    return true;
-}
-long long p4InputImfileDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
+        psError(PS_ERR_UNKNOWN, true, "p4aInputExpRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
+long long p4aInputExpDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
 {
     long long       deleted = 0;
 
     for (long long i = 0; i < objects->n; i++) {
-        p4InputImfileRow *object = objects->data[i];
-        psMetadata *where = p4InputImfileMetadataFromObject(object);
-        long long count = psDBDeleteRows(dbh, P4INPUTIMFILE_TABLE_NAME, where, limit);
-        psFree(where)
+        p4aInputExpRow *object = objects->data[i];
+        psMetadata *where = p4aInputExpMetadataFromObject(object);
+        long long count = psDBDeleteRows(dbh, P4AINPUTEXP_TABLE_NAME, where, limit);
+        psFree(where);
         if (count < 0) {
-            psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4InputImfile");
+            psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4aInputExp");
             return count;
         }
@@ -14241,5 +14071,5 @@
     return deleted;
 }
-bool p4InputImfilePrintObjects(FILE *stream, psArray *objects, bool mdcf)
+bool p4aInputExpPrintObjects(FILE *stream, psArray *objects, bool mdcf)
 {
     PS_ASSERT_PTR_NON_NULL(objects, false);
@@ -14247,9 +14077,9 @@
     psMetadata *output = psMetadataAlloc();
     for (long i = 0; i < psArrayLength(objects); i++) {
-        psMetadata *md = p4InputImfileMetadataFromObject(objects->data[i]);
+        psMetadata *md = p4aInputExpMetadataFromObject(objects->data[i]);
         if (!psMetadataAddMetadata(
             output,
             PS_LIST_TAIL,
-            P4INPUTIMFILE_TABLE_NAME,
+            P4AINPUTEXP_TABLE_NAME,
             PS_META_DUPLICATE_OK,
             NULL,
@@ -14272,9 +14102,9 @@
     return true;
 }
-bool p4InputImfilePrintObject(FILE *stream, p4InputImfileRow *object, bool mdcf)
+bool p4aInputExpPrintObject(FILE *stream, p4aInputExpRow *object, bool mdcf)
 {
     PS_ASSERT_PTR_NON_NULL(object, false);
 
-    psMetadata *md = p4InputImfileMetadataFromObject(object);
+    psMetadata *md = p4aInputExpMetadataFromObject(object);
 
     if (!ippdbPrintMetadataRaw(stream, md, mdcf)) {
@@ -14287,38 +14117,48 @@
     return true;
 }
-static void p4WarpedImfileRowFree(p4WarpedImfileRow *object);
-
-p4WarpedImfileRow *p4WarpedImfileRowAlloc(psS32 p4_id, const char *exp_tag, psS32 p3_version, const char *class_id, const char *uri, const char *b1_uri, const char *b2_uri)
-{
-    p4WarpedImfileRow *_object;
-
-    _object = psAlloc(sizeof(p4WarpedImfileRow));
-    psMemSetDeallocator(_object, (psFreeFunc)p4WarpedImfileRowFree);
-
-    _object->p4_id = p4_id;
+static void p4aScfileRowFree(p4aScfileRow *object);
+
+p4aScfileRow *p4aScfileRowAlloc(psS32 p4a_id, const char *skycell_id, const char *tess_id, const char *exp_tag, psS32 p3_version, const char *uri, psF64 bg, psF64 bg_mean_stdev)
+{
+    p4aScfileRow    *_object;
+
+    _object = psAlloc(sizeof(p4aScfileRow));
+    psMemSetDeallocator(_object, (psFreeFunc)p4aScfileRowFree);
+
+    _object->p4a_id = p4a_id;
+    _object->skycell_id = psStringCopy(skycell_id);
+    _object->tess_id = psStringCopy(tess_id);
     _object->exp_tag = psStringCopy(exp_tag);
     _object->p3_version = p3_version;
-    _object->class_id = psStringCopy(class_id);
     _object->uri = psStringCopy(uri);
-    _object->b1_uri = psStringCopy(b1_uri);
-    _object->b2_uri = psStringCopy(b2_uri);
+    _object->bg = bg;
+    _object->bg_mean_stdev = bg_mean_stdev;
 
     return _object;
 }
 
-static void p4WarpedImfileRowFree(p4WarpedImfileRow *object)
-{
+static void p4aScfileRowFree(p4aScfileRow *object)
+{
+    psFree(object->skycell_id);
+    psFree(object->tess_id);
     psFree(object->exp_tag);
-    psFree(object->class_id);
     psFree(object->uri);
-    psFree(object->b1_uri);
-    psFree(object->b2_uri);
-}
-
-bool p4WarpedImfileCreateTable(psDB *dbh)
+}
+
+bool p4aScfileCreateTable(psDB *dbh)
 {
     psMetadata *md = psMetadataAlloc();
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4_id", PS_DATA_S32, "Primary Key", 0)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item p4_id");
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4a_id", PS_DATA_S32, "Primary Key", 0)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p4a_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "skycell_id", PS_DATA_STRING, "Primary Key", "64")) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item skycell_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "tess_id", PS_DATA_STRING, "Primary Key", "64")) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item tess_id");
         psFree(md);
         return false;
@@ -14334,9 +14174,4 @@
         return false;
     }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "class_id", PS_DATA_STRING, "Primary Key", "64")) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item class_id");
-        psFree(md);
-        return false;
-    }
     if (!psMetadataAdd(md, PS_LIST_TAIL, "uri", PS_DATA_STRING, NULL, "255")) {
         psError(PS_ERR_UNKNOWN, false, "failed to add item uri");
@@ -14344,16 +14179,16 @@
         return false;
     }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "b1_uri", PS_DATA_STRING, NULL, "255")) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item b1_uri");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "b2_uri", PS_DATA_STRING, NULL, "255")) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item b2_uri");
-        psFree(md);
-        return false;
-    }
-
-    bool status = psDBCreateTable(dbh, P4WARPEDIMFILE_TABLE_NAME, md);
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "bg", PS_DATA_F64, NULL, 0.0)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item bg");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "bg_mean_stdev", PS_DATA_F64, NULL, 0.0)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item bg_mean_stdev");
+        psFree(md);
+        return false;
+    }
+
+    bool status = psDBCreateTable(dbh, P4ASCFILE_TABLE_NAME, md);
 
     psFree(md);
@@ -14362,14 +14197,24 @@
 }
 
-bool p4WarpedImfileDropTable(psDB *dbh)
-{
-    return psDBDropTable(dbh, P4WARPEDIMFILE_TABLE_NAME);
-}
-
-bool p4WarpedImfileInsert(psDB * dbh, psS32 p4_id, const char *exp_tag, psS32 p3_version, const char *class_id, const char *uri, const char *b1_uri, const char *b2_uri)
+bool p4aScfileDropTable(psDB *dbh)
+{
+    return psDBDropTable(dbh, P4ASCFILE_TABLE_NAME);
+}
+
+bool p4aScfileInsert(psDB * dbh, psS32 p4a_id, const char *skycell_id, const char *tess_id, const char *exp_tag, psS32 p3_version, const char *uri, psF64 bg, psF64 bg_mean_stdev)
 {
     psMetadata *md = psMetadataAlloc();
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4_id", PS_DATA_S32, NULL, p4_id)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item p4_id");
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4a_id", PS_DATA_S32, NULL, p4a_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p4a_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "skycell_id", PS_DATA_STRING, NULL, skycell_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item skycell_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "tess_id", PS_DATA_STRING, NULL, tess_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item tess_id");
         psFree(md);
         return false;
@@ -14385,9 +14230,4 @@
         return false;
     }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "class_id", PS_DATA_STRING, NULL, class_id)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item class_id");
-        psFree(md);
-        return false;
-    }
     if (!psMetadataAdd(md, PS_LIST_TAIL, "uri", PS_DATA_STRING, NULL, uri)) {
         psError(PS_ERR_UNKNOWN, false, "failed to add item uri");
@@ -14395,16 +14235,16 @@
         return false;
     }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "b1_uri", PS_DATA_STRING, NULL, b1_uri)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item b1_uri");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "b2_uri", PS_DATA_STRING, NULL, b2_uri)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item b2_uri");
-        psFree(md);
-        return false;
-    }
-
-    bool status = psDBInsertOneRow(dbh, P4WARPEDIMFILE_TABLE_NAME, md);
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "bg", PS_DATA_F64, NULL, bg)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item bg");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "bg_mean_stdev", PS_DATA_F64, NULL, bg_mean_stdev)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item bg_mean_stdev");
+        psFree(md);
+        return false;
+    }
+
+    bool status = psDBInsertOneRow(dbh, P4ASCFILE_TABLE_NAME, md);
     psFree(md);
 
@@ -14412,11 +14252,11 @@
 }
 
-long long p4WarpedImfileDelete(psDB *dbh, const psMetadata *where, unsigned long long limit)
+long long p4aScfileDelete(psDB *dbh, const psMetadata *where, unsigned long long limit)
 {
     long long       deleted = 0;
 
-    long long count = psDBDeleteRows(dbh, P4WARPEDIMFILE_TABLE_NAME, where, limit);
+    long long count = psDBDeleteRows(dbh, P4ASCFILE_TABLE_NAME, where, limit);
     if (count < 0) {
-        psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4WarpedImfile");
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4aScfile");
         return count;
 
@@ -14426,13 +14266,13 @@
     return deleted;
 }
-bool p4WarpedImfileInsertObject(psDB *dbh, p4WarpedImfileRow *object)
-{
-    return p4WarpedImfileInsert(dbh, object->p4_id, object->exp_tag, object->p3_version, object->class_id, object->uri, object->b1_uri, object->b2_uri);
-}
-
-bool p4WarpedImfileInsertObjects(psDB *dbh, psArray *objects)
+bool p4aScfileInsertObject(psDB *dbh, p4aScfileRow *object)
+{
+    return p4aScfileInsert(dbh, object->p4a_id, object->skycell_id, object->tess_id, object->exp_tag, object->p3_version, object->uri, object->bg, object->bg_mean_stdev);
+}
+
+bool p4aScfileInsertObjects(psDB *dbh, psArray *objects)
 {
     for (long i = 0; i < psArrayLength(objects); i++) {
-        if (!p4WarpedImfileInsertObject(dbh, objects->data[i])) {
+        if (!p4aScfileInsertObject(dbh, objects->data[i])) {
             return false;
         }
@@ -14442,11 +14282,11 @@
 }
 
-bool p4WarpedImfileInsertFits(psDB *dbh, const psFits *fits)
+bool p4aScfileInsertFits(psDB *dbh, const psFits *fits)
 {
     psArray         *rowSet;
 
-    // move to (the first?) extension named  P4WARPEDIMFILE_TABLE_NAME
-    if (!psFitsMoveExtName(fits, P4WARPEDIMFILE_TABLE_NAME)) {
-        psError(PS_ERR_UNKNOWN, true, "failed to find FITS extension %s", P4WARPEDIMFILE_TABLE_NAME);
+    // move to (the first?) extension named  P4ASCFILE_TABLE_NAME
+    if (!psFitsMoveExtName(fits, P4ASCFILE_TABLE_NAME)) {
+        psError(PS_ERR_UNKNOWN, true, "failed to find FITS extension %s", P4ASCFILE_TABLE_NAME);
         return false;
     }
@@ -14466,5 +14306,5 @@
     }
 
-    if (!psDBInsertRows(dbh, P4WARPEDIMFILE_TABLE_NAME, rowSet)) {
+    if (!psDBInsertRows(dbh, P4ASCFILE_TABLE_NAME, rowSet)) {
         psError(PS_ERR_UNKNOWN, false, "databse insert failed");
         psFree(rowSet);
@@ -14477,9 +14317,9 @@
 }
 
-bool p4WarpedImfileSelectRowsFits(psDB *dbh, psFits *fits, const psMetadata *where, unsigned long long limit)
+bool p4aScfileSelectRowsFits(psDB *dbh, psFits *fits, const psMetadata *where, unsigned long long limit)
 {
     psArray         *rowSet;
 
-    rowSet = psDBSelectRows(dbh, P4WARPEDIMFILE_TABLE_NAME, where, limit);
+    rowSet = psDBSelectRows(dbh, P4ASCFILE_TABLE_NAME, where, limit);
     if (!rowSet) {
         return false;
@@ -14487,5 +14327,5 @@
 
     // output to fits
-    if (!psFitsWriteTable(fits, NULL, rowSet, P4WARPEDIMFILE_TABLE_NAME)) {
+    if (!psFitsWriteTable(fits, NULL, rowSet, P4ASCFILE_TABLE_NAME)) {
         psError(PS_ERR_UNKNOWN, false, "FITS table write failed");
         psFree(rowSet);
@@ -14498,9 +14338,19 @@
 }
 
-psMetadata *p4WarpedImfileMetadataFromObject(const p4WarpedImfileRow *object)
+psMetadata *p4aScfileMetadataFromObject(const p4aScfileRow *object)
 {
     psMetadata *md = psMetadataAlloc();
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4_id", PS_DATA_S32, NULL, object->p4_id)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item p4_id");
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4a_id", PS_DATA_S32, NULL, object->p4a_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p4a_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "skycell_id", PS_DATA_STRING, NULL, object->skycell_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item skycell_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "tess_id", PS_DATA_STRING, NULL, object->tess_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item tess_id");
         psFree(md);
         return false;
@@ -14516,9 +14366,4 @@
         return false;
     }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "class_id", PS_DATA_STRING, NULL, object->class_id)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item class_id");
-        psFree(md);
-        return false;
-    }
     if (!psMetadataAdd(md, PS_LIST_TAIL, "uri", PS_DATA_STRING, NULL, object->uri)) {
         psError(PS_ERR_UNKNOWN, false, "failed to add item uri");
@@ -14526,11 +14371,11 @@
         return false;
     }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "b1_uri", PS_DATA_STRING, NULL, object->b1_uri)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item b1_uri");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "b2_uri", PS_DATA_STRING, NULL, object->b2_uri)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item b2_uri");
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "bg", PS_DATA_F64, NULL, object->bg)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item bg");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "bg_mean_stdev", PS_DATA_F64, NULL, object->bg_mean_stdev)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item bg_mean_stdev");
         psFree(md);
         return false;
@@ -14541,11 +14386,21 @@
 }
 
-p4WarpedImfileRow *p4WarpedImfileObjectFromMetadata(psMetadata *md)
+p4aScfileRow *p4aScfileObjectFromMetadata(psMetadata *md)
 {
 
 bool status = false;
-    psS32 p4_id = psMetadataLookupS32(&status, md, "p4_id");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item p4_id");
+    psS32 p4a_id = psMetadataLookupS32(&status, md, "p4a_id");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item p4a_id");
+        return false;
+    }
+    char* skycell_id = psMetadataLookupPtr(&status, md, "skycell_id");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item skycell_id");
+        return false;
+    }
+    char* tess_id = psMetadataLookupPtr(&status, md, "tess_id");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item tess_id");
         return false;
     }
@@ -14560,9 +14415,4 @@
         return false;
     }
-    char* class_id = psMetadataLookupPtr(&status, md, "class_id");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item class_id");
-        return false;
-    }
     char* uri = psMetadataLookupPtr(&status, md, "uri");
     if (!status) {
@@ -14570,18 +14420,18 @@
         return false;
     }
-    char* b1_uri = psMetadataLookupPtr(&status, md, "b1_uri");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item b1_uri");
-        return false;
-    }
-    char* 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 p4WarpedImfileRowAlloc(p4_id, exp_tag, p3_version, class_id, uri, b1_uri, b2_uri);
-}
-psArray *p4WarpedImfileSelectRowObjects(psDB *dbh, const psMetadata *where, unsigned long long limit)
+    psF64 bg = psMetadataLookupF64(&status, md, "bg");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item bg");
+        return false;
+    }
+    psF64 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;
+    }
+
+    return p4aScfileRowAlloc(p4a_id, skycell_id, tess_id, exp_tag, p3_version, uri, bg, bg_mean_stdev);
+}
+psArray *p4aScfileSelectRowObjects(psDB *dbh, const psMetadata *where, unsigned long long limit)
 {
     psArray         *rowSet;
@@ -14589,5 +14439,5 @@
     psU64           i;
 
-    rowSet = psDBSelectRows(dbh, P4WARPEDIMFILE_TABLE_NAME, where, limit);
+    rowSet = psDBSelectRows(dbh, P4ASCFILE_TABLE_NAME, where, limit);
     if (!rowSet) {
         return NULL;
@@ -14599,5 +14449,5 @@
 
     for (i = 0; i < rowSet->n; i++) {
-        p4WarpedImfileRow *object = p4WarpedImfileObjectFromMetadata(rowSet->data[i]);
+        p4aScfileRow *object = p4aScfileObjectFromMetadata(rowSet->data[i]);
         psArrayAdd(returnSet, 0, object);
         psFree(object);
@@ -14608,11 +14458,11 @@
     return returnSet;
 }
-bool p4WarpedImfileDeleteObject(psDB *dbh, const p4WarpedImfileRow *object)
-{
-    psMetadata *where = p4WarpedImfileMetadataFromObject(object);
-    long long count = psDBDeleteRows(dbh, P4WARPEDIMFILE_TABLE_NAME, where, 0);
-    psFree(where)
+bool p4aScfileDeleteObject(psDB *dbh, const p4aScfileRow *object)
+{
+    psMetadata *where = p4aScfileMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, P4ASCFILE_TABLE_NAME, where, 0);
+    psFree(where);
     if (count < 0) {
-        psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4WarpedImfile");
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4aScfile");
         return false;
     }
@@ -14620,21 +14470,21 @@
         // 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, "p4WarpedImfileRow object matched more then one row.  Check your database schema");
-        return false;
-    }
-
-    return true;
-}
-long long p4WarpedImfileDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
+        psError(PS_ERR_UNKNOWN, true, "p4aScfileRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
+long long p4aScfileDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
 {
     long long       deleted = 0;
 
     for (long long i = 0; i < objects->n; i++) {
-        p4WarpedImfileRow *object = objects->data[i];
-        psMetadata *where = p4WarpedImfileMetadataFromObject(object);
-        long long count = psDBDeleteRows(dbh, P4WARPEDIMFILE_TABLE_NAME, where, limit);
-        psFree(where)
+        p4aScfileRow *object = objects->data[i];
+        psMetadata *where = p4aScfileMetadataFromObject(object);
+        long long count = psDBDeleteRows(dbh, P4ASCFILE_TABLE_NAME, where, limit);
+        psFree(where);
         if (count < 0) {
-            psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4WarpedImfile");
+            psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4aScfile");
             return count;
         }
@@ -14645,5 +14495,5 @@
     return deleted;
 }
-bool p4WarpedImfilePrintObjects(FILE *stream, psArray *objects, bool mdcf)
+bool p4aScfilePrintObjects(FILE *stream, psArray *objects, bool mdcf)
 {
     PS_ASSERT_PTR_NON_NULL(objects, false);
@@ -14651,9 +14501,9 @@
     psMetadata *output = psMetadataAlloc();
     for (long i = 0; i < psArrayLength(objects); i++) {
-        psMetadata *md = p4WarpedImfileMetadataFromObject(objects->data[i]);
+        psMetadata *md = p4aScfileMetadataFromObject(objects->data[i]);
         if (!psMetadataAddMetadata(
             output,
             PS_LIST_TAIL,
-            P4WARPEDIMFILE_TABLE_NAME,
+            P4ASCFILE_TABLE_NAME,
             PS_META_DUPLICATE_OK,
             NULL,
@@ -14676,9 +14526,9 @@
     return true;
 }
-bool p4WarpedImfilePrintObject(FILE *stream, p4WarpedImfileRow *object, bool mdcf)
+bool p4aScfilePrintObject(FILE *stream, p4aScfileRow *object, bool mdcf)
 {
     PS_ASSERT_PTR_NON_NULL(object, false);
 
-    psMetadata *md = p4WarpedImfileMetadataFromObject(object);
+    psMetadata *md = p4aScfileMetadataFromObject(object);
 
     if (!ippdbPrintMetadataRaw(stream, md, mdcf)) {
@@ -14691,60 +14541,52 @@
     return true;
 }
-static void p4StackedImfileRowFree(p4StackedImfileRow *object);
-
-p4StackedImfileRow *p4StackedImfileRowAlloc(psS32 p4_id, const char *class_id, const char *uri, const char *b1_uri, const char *b2_uri)
-{
-    p4StackedImfileRow *_object;
-
-    _object = psAlloc(sizeof(p4StackedImfileRow));
-    psMemSetDeallocator(_object, (psFreeFunc)p4StackedImfileRowFree);
-
-    _object->p4_id = p4_id;
-    _object->class_id = psStringCopy(class_id);
-    _object->uri = psStringCopy(uri);
-    _object->b1_uri = psStringCopy(b1_uri);
-    _object->b2_uri = psStringCopy(b2_uri);
+static void p4bRunRowFree(p4bRunRow *object);
+
+p4bRunRow *p4bRunRowAlloc(psS32 p4b_id, const char *state, const char *workdir, bool magic)
+{
+    p4bRunRow       *_object;
+
+    _object = psAlloc(sizeof(p4bRunRow));
+    psMemSetDeallocator(_object, (psFreeFunc)p4bRunRowFree);
+
+    _object->p4b_id = p4b_id;
+    _object->state = psStringCopy(state);
+    _object->workdir = psStringCopy(workdir);
+    _object->magic = magic;
 
     return _object;
 }
 
-static void p4StackedImfileRowFree(p4StackedImfileRow *object)
-{
-    psFree(object->class_id);
-    psFree(object->uri);
-    psFree(object->b1_uri);
-    psFree(object->b2_uri);
-}
-
-bool p4StackedImfileCreateTable(psDB *dbh)
+static void p4bRunRowFree(p4bRunRow *object)
+{
+    psFree(object->state);
+    psFree(object->workdir);
+}
+
+bool p4bRunCreateTable(psDB *dbh)
 {
     psMetadata *md = psMetadataAlloc();
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4_id", PS_DATA_S32, "Primary Key", 0)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item p4_id");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "class_id", PS_DATA_STRING, "Primary Key", "64")) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item class_id");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "uri", PS_DATA_STRING, NULL, "255")) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item uri");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "b1_uri", PS_DATA_STRING, NULL, "255")) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item b1_uri");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "b2_uri", PS_DATA_STRING, NULL, "255")) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item b2_uri");
-        psFree(md);
-        return false;
-    }
-
-    bool status = psDBCreateTable(dbh, P4STACKEDIMFILE_TABLE_NAME, md);
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4b_id", PS_DATA_S32, "Primary Key AUTO_INCREMENT", 0)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p4b_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "state", PS_DATA_STRING, "Key", "64")) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item state");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "workdir", PS_DATA_STRING, NULL, "255")) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item workdir");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "magic", PS_DATA_BOOL, "Primary Key", 0)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item magic");
+        psFree(md);
+        return false;
+    }
+
+    bool status = psDBCreateTable(dbh, P4BRUN_TABLE_NAME, md);
 
     psFree(md);
@@ -14753,39 +14595,34 @@
 }
 
-bool p4StackedImfileDropTable(psDB *dbh)
-{
-    return psDBDropTable(dbh, P4STACKEDIMFILE_TABLE_NAME);
-}
-
-bool p4StackedImfileInsert(psDB * dbh, psS32 p4_id, const char *class_id, const char *uri, const char *b1_uri, const char *b2_uri)
+bool p4bRunDropTable(psDB *dbh)
+{
+    return psDBDropTable(dbh, P4BRUN_TABLE_NAME);
+}
+
+bool p4bRunInsert(psDB * dbh, psS32 p4b_id, const char *state, const char *workdir, bool magic)
 {
     psMetadata *md = psMetadataAlloc();
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4_id", PS_DATA_S32, NULL, p4_id)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item p4_id");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "class_id", PS_DATA_STRING, NULL, class_id)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item class_id");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "uri", PS_DATA_STRING, NULL, uri)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item uri");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "b1_uri", PS_DATA_STRING, NULL, b1_uri)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item b1_uri");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "b2_uri", PS_DATA_STRING, NULL, b2_uri)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item b2_uri");
-        psFree(md);
-        return false;
-    }
-
-    bool status = psDBInsertOneRow(dbh, P4STACKEDIMFILE_TABLE_NAME, md);
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4b_id", PS_DATA_S32, NULL, p4b_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p4b_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "state", PS_DATA_STRING, NULL, state)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item state");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "workdir", PS_DATA_STRING, NULL, workdir)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item workdir");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "magic", PS_DATA_BOOL, NULL, magic)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item magic");
+        psFree(md);
+        return false;
+    }
+
+    bool status = psDBInsertOneRow(dbh, P4BRUN_TABLE_NAME, md);
     psFree(md);
 
@@ -14793,11 +14630,11 @@
 }
 
-long long p4StackedImfileDelete(psDB *dbh, const psMetadata *where, unsigned long long limit)
+long long p4bRunDelete(psDB *dbh, const psMetadata *where, unsigned long long limit)
 {
     long long       deleted = 0;
 
-    long long count = psDBDeleteRows(dbh, P4STACKEDIMFILE_TABLE_NAME, where, limit);
+    long long count = psDBDeleteRows(dbh, P4BRUN_TABLE_NAME, where, limit);
     if (count < 0) {
-        psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4StackedImfile");
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4bRun");
         return count;
 
@@ -14807,13 +14644,13 @@
     return deleted;
 }
-bool p4StackedImfileInsertObject(psDB *dbh, p4StackedImfileRow *object)
-{
-    return p4StackedImfileInsert(dbh, object->p4_id, object->class_id, object->uri, object->b1_uri, object->b2_uri);
-}
-
-bool p4StackedImfileInsertObjects(psDB *dbh, psArray *objects)
+bool p4bRunInsertObject(psDB *dbh, p4bRunRow *object)
+{
+    return p4bRunInsert(dbh, object->p4b_id, object->state, object->workdir, object->magic);
+}
+
+bool p4bRunInsertObjects(psDB *dbh, psArray *objects)
 {
     for (long i = 0; i < psArrayLength(objects); i++) {
-        if (!p4StackedImfileInsertObject(dbh, objects->data[i])) {
+        if (!p4bRunInsertObject(dbh, objects->data[i])) {
             return false;
         }
@@ -14823,11 +14660,11 @@
 }
 
-bool p4StackedImfileInsertFits(psDB *dbh, const psFits *fits)
+bool p4bRunInsertFits(psDB *dbh, const psFits *fits)
 {
     psArray         *rowSet;
 
-    // move to (the first?) extension named  P4STACKEDIMFILE_TABLE_NAME
-    if (!psFitsMoveExtName(fits, P4STACKEDIMFILE_TABLE_NAME)) {
-        psError(PS_ERR_UNKNOWN, true, "failed to find FITS extension %s", P4STACKEDIMFILE_TABLE_NAME);
+    // move to (the first?) extension named  P4BRUN_TABLE_NAME
+    if (!psFitsMoveExtName(fits, P4BRUN_TABLE_NAME)) {
+        psError(PS_ERR_UNKNOWN, true, "failed to find FITS extension %s", P4BRUN_TABLE_NAME);
         return false;
     }
@@ -14847,5 +14684,5 @@
     }
 
-    if (!psDBInsertRows(dbh, P4STACKEDIMFILE_TABLE_NAME, rowSet)) {
+    if (!psDBInsertRows(dbh, P4BRUN_TABLE_NAME, rowSet)) {
         psError(PS_ERR_UNKNOWN, false, "databse insert failed");
         psFree(rowSet);
@@ -14858,9 +14695,9 @@
 }
 
-bool p4StackedImfileSelectRowsFits(psDB *dbh, psFits *fits, const psMetadata *where, unsigned long long limit)
+bool p4bRunSelectRowsFits(psDB *dbh, psFits *fits, const psMetadata *where, unsigned long long limit)
 {
     psArray         *rowSet;
 
-    rowSet = psDBSelectRows(dbh, P4STACKEDIMFILE_TABLE_NAME, where, limit);
+    rowSet = psDBSelectRows(dbh, P4BRUN_TABLE_NAME, where, limit);
     if (!rowSet) {
         return false;
@@ -14868,5 +14705,5 @@
 
     // output to fits
-    if (!psFitsWriteTable(fits, NULL, rowSet, P4STACKEDIMFILE_TABLE_NAME)) {
+    if (!psFitsWriteTable(fits, NULL, rowSet, P4BRUN_TABLE_NAME)) {
         psError(PS_ERR_UNKNOWN, false, "FITS table write failed");
         psFree(rowSet);
@@ -14879,29 +14716,24 @@
 }
 
-psMetadata *p4StackedImfileMetadataFromObject(const p4StackedImfileRow *object)
+psMetadata *p4bRunMetadataFromObject(const p4bRunRow *object)
 {
     psMetadata *md = psMetadataAlloc();
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4_id", PS_DATA_S32, NULL, object->p4_id)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item p4_id");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "class_id", PS_DATA_STRING, NULL, object->class_id)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item class_id");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "uri", PS_DATA_STRING, NULL, object->uri)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item uri");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "b1_uri", PS_DATA_STRING, NULL, object->b1_uri)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item b1_uri");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "b2_uri", PS_DATA_STRING, NULL, object->b2_uri)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item b2_uri");
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4b_id", PS_DATA_S32, NULL, object->p4b_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p4b_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "state", PS_DATA_STRING, NULL, object->state)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item state");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "workdir", PS_DATA_STRING, NULL, object->workdir)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item workdir");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "magic", PS_DATA_BOOL, NULL, object->magic)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item magic");
         psFree(md);
         return false;
@@ -14912,37 +14744,32 @@
 }
 
-p4StackedImfileRow *p4StackedImfileObjectFromMetadata(psMetadata *md)
+p4bRunRow *p4bRunObjectFromMetadata(psMetadata *md)
 {
 
 bool status = false;
-    psS32 p4_id = psMetadataLookupS32(&status, md, "p4_id");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item p4_id");
-        return false;
-    }
-    char* class_id = psMetadataLookupPtr(&status, md, "class_id");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item class_id");
-        return false;
-    }
-    char* uri = psMetadataLookupPtr(&status, md, "uri");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item uri");
-        return false;
-    }
-    char* b1_uri = psMetadataLookupPtr(&status, md, "b1_uri");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item b1_uri");
-        return false;
-    }
-    char* 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 p4StackedImfileRowAlloc(p4_id, class_id, uri, b1_uri, b2_uri);
-}
-psArray *p4StackedImfileSelectRowObjects(psDB *dbh, const psMetadata *where, unsigned long long limit)
+    psS32 p4b_id = psMetadataLookupS32(&status, md, "p4b_id");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item p4b_id");
+        return false;
+    }
+    char* state = psMetadataLookupPtr(&status, md, "state");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item state");
+        return false;
+    }
+    char* workdir = psMetadataLookupPtr(&status, md, "workdir");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item workdir");
+        return false;
+    }
+    bool magic = psMetadataLookupBool(&status, md, "magic");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item magic");
+        return false;
+    }
+
+    return p4bRunRowAlloc(p4b_id, state, workdir, magic);
+}
+psArray *p4bRunSelectRowObjects(psDB *dbh, const psMetadata *where, unsigned long long limit)
 {
     psArray         *rowSet;
@@ -14950,5 +14777,5 @@
     psU64           i;
 
-    rowSet = psDBSelectRows(dbh, P4STACKEDIMFILE_TABLE_NAME, where, limit);
+    rowSet = psDBSelectRows(dbh, P4BRUN_TABLE_NAME, where, limit);
     if (!rowSet) {
         return NULL;
@@ -14960,5 +14787,5 @@
 
     for (i = 0; i < rowSet->n; i++) {
-        p4StackedImfileRow *object = p4StackedImfileObjectFromMetadata(rowSet->data[i]);
+        p4bRunRow *object = p4bRunObjectFromMetadata(rowSet->data[i]);
         psArrayAdd(returnSet, 0, object);
         psFree(object);
@@ -14969,11 +14796,11 @@
     return returnSet;
 }
-bool p4StackedImfileDeleteObject(psDB *dbh, const p4StackedImfileRow *object)
-{
-    psMetadata *where = p4StackedImfileMetadataFromObject(object);
-    long long count = psDBDeleteRows(dbh, P4STACKEDIMFILE_TABLE_NAME, where, 0);
-    psFree(where)
+bool p4bRunDeleteObject(psDB *dbh, const p4bRunRow *object)
+{
+    psMetadata *where = p4bRunMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, P4BRUN_TABLE_NAME, where, 0);
+    psFree(where);
     if (count < 0) {
-        psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4StackedImfile");
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4bRun");
         return false;
     }
@@ -14981,21 +14808,21 @@
         // 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, "p4StackedImfileRow object matched more then one row.  Check your database schema");
-        return false;
-    }
-
-    return true;
-}
-long long p4StackedImfileDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
+        psError(PS_ERR_UNKNOWN, true, "p4bRunRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
+long long p4bRunDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
 {
     long long       deleted = 0;
 
     for (long long i = 0; i < objects->n; i++) {
-        p4StackedImfileRow *object = objects->data[i];
-        psMetadata *where = p4StackedImfileMetadataFromObject(object);
-        long long count = psDBDeleteRows(dbh, P4STACKEDIMFILE_TABLE_NAME, where, limit);
-        psFree(where)
+        p4bRunRow *object = objects->data[i];
+        psMetadata *where = p4bRunMetadataFromObject(object);
+        long long count = psDBDeleteRows(dbh, P4BRUN_TABLE_NAME, where, limit);
+        psFree(where);
         if (count < 0) {
-            psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4StackedImfile");
+            psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4bRun");
             return count;
         }
@@ -15006,5 +14833,5 @@
     return deleted;
 }
-bool p4StackedImfilePrintObjects(FILE *stream, psArray *objects, bool mdcf)
+bool p4bRunPrintObjects(FILE *stream, psArray *objects, bool mdcf)
 {
     PS_ASSERT_PTR_NON_NULL(objects, false);
@@ -15012,9 +14839,9 @@
     psMetadata *output = psMetadataAlloc();
     for (long i = 0; i < psArrayLength(objects); i++) {
-        psMetadata *md = p4StackedImfileMetadataFromObject(objects->data[i]);
+        psMetadata *md = p4bRunMetadataFromObject(objects->data[i]);
         if (!psMetadataAddMetadata(
             output,
             PS_LIST_TAIL,
-            P4STACKEDIMFILE_TABLE_NAME,
+            P4BRUN_TABLE_NAME,
             PS_META_DUPLICATE_OK,
             NULL,
@@ -15037,9 +14864,9 @@
     return true;
 }
-bool p4StackedImfilePrintObject(FILE *stream, p4StackedImfileRow *object, bool mdcf)
+bool p4bRunPrintObject(FILE *stream, p4bRunRow *object, bool mdcf)
 {
     PS_ASSERT_PTR_NON_NULL(object, false);
 
-    psMetadata *md = p4StackedImfileMetadataFromObject(object);
+    psMetadata *md = p4bRunMetadataFromObject(object);
 
     if (!ippdbPrintMetadataRaw(stream, md, mdcf)) {
@@ -15052,38 +14879,46 @@
     return true;
 }
-static void p4DiffImfileRowFree(p4DiffImfileRow *object);
-
-p4DiffImfileRow *p4DiffImfileRowAlloc(psS32 p4_id, const char *exp_tag, psS32 p3_version, const char *class_id, const char *uri, const char *b1_uri, const char *b2_uri)
-{
-    p4DiffImfileRow *_object;
-
-    _object = psAlloc(sizeof(p4DiffImfileRow));
-    psMemSetDeallocator(_object, (psFreeFunc)p4DiffImfileRowFree);
-
-    _object->p4_id = p4_id;
+static void p4bInputScfileRowFree(p4bInputScfileRow *object);
+
+p4bInputScfileRow *p4bInputScfileRowAlloc(psS32 p4b_id, const char *skycell_id, const char *tess_id, const char *exp_tag, psS32 p3_version, const char *kind)
+{
+    p4bInputScfileRow *_object;
+
+    _object = psAlloc(sizeof(p4bInputScfileRow));
+    psMemSetDeallocator(_object, (psFreeFunc)p4bInputScfileRowFree);
+
+    _object->p4b_id = p4b_id;
+    _object->skycell_id = psStringCopy(skycell_id);
+    _object->tess_id = psStringCopy(tess_id);
     _object->exp_tag = psStringCopy(exp_tag);
     _object->p3_version = p3_version;
-    _object->class_id = psStringCopy(class_id);
-    _object->uri = psStringCopy(uri);
-    _object->b1_uri = psStringCopy(b1_uri);
-    _object->b2_uri = psStringCopy(b2_uri);
+    _object->kind = psStringCopy(kind);
 
     return _object;
 }
 
-static void p4DiffImfileRowFree(p4DiffImfileRow *object)
-{
+static void p4bInputScfileRowFree(p4bInputScfileRow *object)
+{
+    psFree(object->skycell_id);
+    psFree(object->tess_id);
     psFree(object->exp_tag);
-    psFree(object->class_id);
-    psFree(object->uri);
-    psFree(object->b1_uri);
-    psFree(object->b2_uri);
-}
-
-bool p4DiffImfileCreateTable(psDB *dbh)
+    psFree(object->kind);
+}
+
+bool p4bInputScfileCreateTable(psDB *dbh)
 {
     psMetadata *md = psMetadataAlloc();
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4_id", PS_DATA_S32, "Primary Key", 0)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item p4_id");
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4b_id", PS_DATA_S32, "Primary Key", 0)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p4b_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "skycell_id", PS_DATA_STRING, "Primary Key", "64")) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item skycell_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "tess_id", PS_DATA_STRING, "Primary Key", "64")) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item tess_id");
         psFree(md);
         return false;
@@ -15099,26 +14934,11 @@
         return false;
     }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "class_id", PS_DATA_STRING, "Primary Key", "64")) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item class_id");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "uri", PS_DATA_STRING, NULL, "255")) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item uri");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "b1_uri", PS_DATA_STRING, NULL, "255")) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item b1_uri");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "b2_uri", PS_DATA_STRING, NULL, "255")) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item b2_uri");
-        psFree(md);
-        return false;
-    }
-
-    bool status = psDBCreateTable(dbh, P4DIFFIMFILE_TABLE_NAME, md);
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "kind", PS_DATA_STRING, "Key", "64")) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item kind");
+        psFree(md);
+        return false;
+    }
+
+    bool status = psDBCreateTable(dbh, P4BINPUTSCFILE_TABLE_NAME, md);
 
     psFree(md);
@@ -15127,14 +14947,24 @@
 }
 
-bool p4DiffImfileDropTable(psDB *dbh)
-{
-    return psDBDropTable(dbh, P4DIFFIMFILE_TABLE_NAME);
-}
-
-bool p4DiffImfileInsert(psDB * dbh, psS32 p4_id, const char *exp_tag, psS32 p3_version, const char *class_id, const char *uri, const char *b1_uri, const char *b2_uri)
+bool p4bInputScfileDropTable(psDB *dbh)
+{
+    return psDBDropTable(dbh, P4BINPUTSCFILE_TABLE_NAME);
+}
+
+bool p4bInputScfileInsert(psDB * dbh, psS32 p4b_id, const char *skycell_id, const char *tess_id, const char *exp_tag, psS32 p3_version, const char *kind)
 {
     psMetadata *md = psMetadataAlloc();
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4_id", PS_DATA_S32, NULL, p4_id)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item p4_id");
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4b_id", PS_DATA_S32, NULL, p4b_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p4b_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "skycell_id", PS_DATA_STRING, NULL, skycell_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item skycell_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "tess_id", PS_DATA_STRING, NULL, tess_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item tess_id");
         psFree(md);
         return false;
@@ -15150,26 +14980,11 @@
         return false;
     }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "class_id", PS_DATA_STRING, NULL, class_id)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item class_id");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "uri", PS_DATA_STRING, NULL, uri)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item uri");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "b1_uri", PS_DATA_STRING, NULL, b1_uri)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item b1_uri");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "b2_uri", PS_DATA_STRING, NULL, b2_uri)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item b2_uri");
-        psFree(md);
-        return false;
-    }
-
-    bool status = psDBInsertOneRow(dbh, P4DIFFIMFILE_TABLE_NAME, md);
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "kind", PS_DATA_STRING, NULL, kind)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item kind");
+        psFree(md);
+        return false;
+    }
+
+    bool status = psDBInsertOneRow(dbh, P4BINPUTSCFILE_TABLE_NAME, md);
     psFree(md);
 
@@ -15177,11 +14992,11 @@
 }
 
-long long p4DiffImfileDelete(psDB *dbh, const psMetadata *where, unsigned long long limit)
+long long p4bInputScfileDelete(psDB *dbh, const psMetadata *where, unsigned long long limit)
 {
     long long       deleted = 0;
 
-    long long count = psDBDeleteRows(dbh, P4DIFFIMFILE_TABLE_NAME, where, limit);
+    long long count = psDBDeleteRows(dbh, P4BINPUTSCFILE_TABLE_NAME, where, limit);
     if (count < 0) {
-        psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4DiffImfile");
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4bInputScfile");
         return count;
 
@@ -15191,13 +15006,13 @@
     return deleted;
 }
-bool p4DiffImfileInsertObject(psDB *dbh, p4DiffImfileRow *object)
-{
-    return p4DiffImfileInsert(dbh, object->p4_id, object->exp_tag, object->p3_version, object->class_id, object->uri, object->b1_uri, object->b2_uri);
-}
-
-bool p4DiffImfileInsertObjects(psDB *dbh, psArray *objects)
+bool p4bInputScfileInsertObject(psDB *dbh, p4bInputScfileRow *object)
+{
+    return p4bInputScfileInsert(dbh, object->p4b_id, object->skycell_id, object->tess_id, object->exp_tag, object->p3_version, object->kind);
+}
+
+bool p4bInputScfileInsertObjects(psDB *dbh, psArray *objects)
 {
     for (long i = 0; i < psArrayLength(objects); i++) {
-        if (!p4DiffImfileInsertObject(dbh, objects->data[i])) {
+        if (!p4bInputScfileInsertObject(dbh, objects->data[i])) {
             return false;
         }
@@ -15207,11 +15022,11 @@
 }
 
-bool p4DiffImfileInsertFits(psDB *dbh, const psFits *fits)
+bool p4bInputScfileInsertFits(psDB *dbh, const psFits *fits)
 {
     psArray         *rowSet;
 
-    // move to (the first?) extension named  P4DIFFIMFILE_TABLE_NAME
-    if (!psFitsMoveExtName(fits, P4DIFFIMFILE_TABLE_NAME)) {
-        psError(PS_ERR_UNKNOWN, true, "failed to find FITS extension %s", P4DIFFIMFILE_TABLE_NAME);
+    // move to (the first?) extension named  P4BINPUTSCFILE_TABLE_NAME
+    if (!psFitsMoveExtName(fits, P4BINPUTSCFILE_TABLE_NAME)) {
+        psError(PS_ERR_UNKNOWN, true, "failed to find FITS extension %s", P4BINPUTSCFILE_TABLE_NAME);
         return false;
     }
@@ -15231,5 +15046,5 @@
     }
 
-    if (!psDBInsertRows(dbh, P4DIFFIMFILE_TABLE_NAME, rowSet)) {
+    if (!psDBInsertRows(dbh, P4BINPUTSCFILE_TABLE_NAME, rowSet)) {
         psError(PS_ERR_UNKNOWN, false, "databse insert failed");
         psFree(rowSet);
@@ -15242,9 +15057,9 @@
 }
 
-bool p4DiffImfileSelectRowsFits(psDB *dbh, psFits *fits, const psMetadata *where, unsigned long long limit)
+bool p4bInputScfileSelectRowsFits(psDB *dbh, psFits *fits, const psMetadata *where, unsigned long long limit)
 {
     psArray         *rowSet;
 
-    rowSet = psDBSelectRows(dbh, P4DIFFIMFILE_TABLE_NAME, where, limit);
+    rowSet = psDBSelectRows(dbh, P4BINPUTSCFILE_TABLE_NAME, where, limit);
     if (!rowSet) {
         return false;
@@ -15252,5 +15067,5 @@
 
     // output to fits
-    if (!psFitsWriteTable(fits, NULL, rowSet, P4DIFFIMFILE_TABLE_NAME)) {
+    if (!psFitsWriteTable(fits, NULL, rowSet, P4BINPUTSCFILE_TABLE_NAME)) {
         psError(PS_ERR_UNKNOWN, false, "FITS table write failed");
         psFree(rowSet);
@@ -15263,9 +15078,19 @@
 }
 
-psMetadata *p4DiffImfileMetadataFromObject(const p4DiffImfileRow *object)
+psMetadata *p4bInputScfileMetadataFromObject(const p4bInputScfileRow *object)
 {
     psMetadata *md = psMetadataAlloc();
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4_id", PS_DATA_S32, NULL, object->p4_id)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item p4_id");
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4b_id", PS_DATA_S32, NULL, object->p4b_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p4b_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "skycell_id", PS_DATA_STRING, NULL, object->skycell_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item skycell_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "tess_id", PS_DATA_STRING, NULL, object->tess_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item tess_id");
         psFree(md);
         return false;
@@ -15281,21 +15106,6 @@
         return false;
     }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "class_id", PS_DATA_STRING, NULL, object->class_id)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item class_id");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "uri", PS_DATA_STRING, NULL, object->uri)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item uri");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "b1_uri", PS_DATA_STRING, NULL, object->b1_uri)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item b1_uri");
-        psFree(md);
-        return false;
-    }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "b2_uri", PS_DATA_STRING, NULL, object->b2_uri)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item b2_uri");
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "kind", PS_DATA_STRING, NULL, object->kind)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item kind");
         psFree(md);
         return false;
@@ -15306,11 +15116,21 @@
 }
 
-p4DiffImfileRow *p4DiffImfileObjectFromMetadata(psMetadata *md)
+p4bInputScfileRow *p4bInputScfileObjectFromMetadata(psMetadata *md)
 {
 
 bool status = false;
-    psS32 p4_id = psMetadataLookupS32(&status, md, "p4_id");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item p4_id");
+    psS32 p4b_id = psMetadataLookupS32(&status, md, "p4b_id");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item p4b_id");
+        return false;
+    }
+    char* skycell_id = psMetadataLookupPtr(&status, md, "skycell_id");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item skycell_id");
+        return false;
+    }
+    char* tess_id = psMetadataLookupPtr(&status, md, "tess_id");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item tess_id");
         return false;
     }
@@ -15325,28 +15145,13 @@
         return false;
     }
-    char* class_id = psMetadataLookupPtr(&status, md, "class_id");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item class_id");
-        return false;
-    }
-    char* uri = psMetadataLookupPtr(&status, md, "uri");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item uri");
-        return false;
-    }
-    char* b1_uri = psMetadataLookupPtr(&status, md, "b1_uri");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item b1_uri");
-        return false;
-    }
-    char* 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 p4DiffImfileRowAlloc(p4_id, exp_tag, p3_version, class_id, uri, b1_uri, b2_uri);
-}
-psArray *p4DiffImfileSelectRowObjects(psDB *dbh, const psMetadata *where, unsigned long long limit)
+    char* kind = psMetadataLookupPtr(&status, md, "kind");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item kind");
+        return false;
+    }
+
+    return p4bInputScfileRowAlloc(p4b_id, skycell_id, tess_id, exp_tag, p3_version, kind);
+}
+psArray *p4bInputScfileSelectRowObjects(psDB *dbh, const psMetadata *where, unsigned long long limit)
 {
     psArray         *rowSet;
@@ -15354,5 +15159,5 @@
     psU64           i;
 
-    rowSet = psDBSelectRows(dbh, P4DIFFIMFILE_TABLE_NAME, where, limit);
+    rowSet = psDBSelectRows(dbh, P4BINPUTSCFILE_TABLE_NAME, where, limit);
     if (!rowSet) {
         return NULL;
@@ -15364,5 +15169,5 @@
 
     for (i = 0; i < rowSet->n; i++) {
-        p4DiffImfileRow *object = p4DiffImfileObjectFromMetadata(rowSet->data[i]);
+        p4bInputScfileRow *object = p4bInputScfileObjectFromMetadata(rowSet->data[i]);
         psArrayAdd(returnSet, 0, object);
         psFree(object);
@@ -15373,11 +15178,11 @@
     return returnSet;
 }
-bool p4DiffImfileDeleteObject(psDB *dbh, const p4DiffImfileRow *object)
-{
-    psMetadata *where = p4DiffImfileMetadataFromObject(object);
-    long long count = psDBDeleteRows(dbh, P4DIFFIMFILE_TABLE_NAME, where, 0);
-    psFree(where)
+bool p4bInputScfileDeleteObject(psDB *dbh, const p4bInputScfileRow *object)
+{
+    psMetadata *where = p4bInputScfileMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, P4BINPUTSCFILE_TABLE_NAME, where, 0);
+    psFree(where);
     if (count < 0) {
-        psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4DiffImfile");
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4bInputScfile");
         return false;
     }
@@ -15385,21 +15190,21 @@
         // 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, "p4DiffImfileRow object matched more then one row.  Check your database schema");
-        return false;
-    }
-
-    return true;
-}
-long long p4DiffImfileDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
+        psError(PS_ERR_UNKNOWN, true, "p4bInputScfileRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
+long long p4bInputScfileDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
 {
     long long       deleted = 0;
 
     for (long long i = 0; i < objects->n; i++) {
-        p4DiffImfileRow *object = objects->data[i];
-        psMetadata *where = p4DiffImfileMetadataFromObject(object);
-        long long count = psDBDeleteRows(dbh, P4DIFFIMFILE_TABLE_NAME, where, limit);
-        psFree(where)
+        p4bInputScfileRow *object = objects->data[i];
+        psMetadata *where = p4bInputScfileMetadataFromObject(object);
+        long long count = psDBDeleteRows(dbh, P4BINPUTSCFILE_TABLE_NAME, where, limit);
+        psFree(where);
         if (count < 0) {
-            psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4DiffImfile");
+            psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4bInputScfile");
             return count;
         }
@@ -15410,5 +15215,5 @@
     return deleted;
 }
-bool p4DiffImfilePrintObjects(FILE *stream, psArray *objects, bool mdcf)
+bool p4bInputScfilePrintObjects(FILE *stream, psArray *objects, bool mdcf)
 {
     PS_ASSERT_PTR_NON_NULL(objects, false);
@@ -15416,9 +15221,9 @@
     psMetadata *output = psMetadataAlloc();
     for (long i = 0; i < psArrayLength(objects); i++) {
-        psMetadata *md = p4DiffImfileMetadataFromObject(objects->data[i]);
+        psMetadata *md = p4bInputScfileMetadataFromObject(objects->data[i]);
         if (!psMetadataAddMetadata(
             output,
             PS_LIST_TAIL,
-            P4DIFFIMFILE_TABLE_NAME,
+            P4BINPUTSCFILE_TABLE_NAME,
             PS_META_DUPLICATE_OK,
             NULL,
@@ -15441,9 +15246,9 @@
     return true;
 }
-bool p4DiffImfilePrintObject(FILE *stream, p4DiffImfileRow *object, bool mdcf)
+bool p4bInputScfilePrintObject(FILE *stream, p4bInputScfileRow *object, bool mdcf)
 {
     PS_ASSERT_PTR_NON_NULL(object, false);
 
-    psMetadata *md = p4DiffImfileMetadataFromObject(object);
+    psMetadata *md = p4bInputScfileMetadataFromObject(object);
 
     if (!ippdbPrintMetadataRaw(stream, md, mdcf)) {
@@ -15456,34 +15261,48 @@
     return true;
 }
-static void p4MagicMaskImfileRowFree(p4MagicMaskImfileRow *object);
-
-p4MagicMaskImfileRow *p4MagicMaskImfileRowAlloc(psS32 p4_id, const char *exp_tag, psS32 p3_version, const char *class_id, const char *uri)
-{
-    p4MagicMaskImfileRow *_object;
-
-    _object = psAlloc(sizeof(p4MagicMaskImfileRow));
-    psMemSetDeallocator(_object, (psFreeFunc)p4MagicMaskImfileRowFree);
-
-    _object->p4_id = p4_id;
+static void p4bDiffScfileRowFree(p4bDiffScfileRow *object);
+
+p4bDiffScfileRow *p4bDiffScfileRowAlloc(psS32 p4b_id, const char *skycell_id, const char *tess_id, const char *exp_tag, psS32 p3_version, const char *uri, psF64 bg, psF64 bg_mean_stdev)
+{
+    p4bDiffScfileRow *_object;
+
+    _object = psAlloc(sizeof(p4bDiffScfileRow));
+    psMemSetDeallocator(_object, (psFreeFunc)p4bDiffScfileRowFree);
+
+    _object->p4b_id = p4b_id;
+    _object->skycell_id = psStringCopy(skycell_id);
+    _object->tess_id = psStringCopy(tess_id);
     _object->exp_tag = psStringCopy(exp_tag);
     _object->p3_version = p3_version;
-    _object->class_id = psStringCopy(class_id);
     _object->uri = psStringCopy(uri);
+    _object->bg = bg;
+    _object->bg_mean_stdev = bg_mean_stdev;
 
     return _object;
 }
 
-static void p4MagicMaskImfileRowFree(p4MagicMaskImfileRow *object)
-{
+static void p4bDiffScfileRowFree(p4bDiffScfileRow *object)
+{
+    psFree(object->skycell_id);
+    psFree(object->tess_id);
     psFree(object->exp_tag);
-    psFree(object->class_id);
     psFree(object->uri);
 }
 
-bool p4MagicMaskImfileCreateTable(psDB *dbh)
+bool p4bDiffScfileCreateTable(psDB *dbh)
 {
     psMetadata *md = psMetadataAlloc();
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4_id", PS_DATA_S32, "Primary Key", 0)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item p4_id");
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4b_id", PS_DATA_S32, "Primary Key", 0)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p4b_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "skycell_id", PS_DATA_STRING, "Primary Key", "64")) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item skycell_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "tess_id", PS_DATA_STRING, "Primary Key", "64")) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item tess_id");
         psFree(md);
         return false;
@@ -15499,9 +15318,4 @@
         return false;
     }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "class_id", PS_DATA_STRING, "Primary Key", "64")) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item class_id");
-        psFree(md);
-        return false;
-    }
     if (!psMetadataAdd(md, PS_LIST_TAIL, "uri", PS_DATA_STRING, NULL, "255")) {
         psError(PS_ERR_UNKNOWN, false, "failed to add item uri");
@@ -15509,6 +15323,16 @@
         return false;
     }
-
-    bool status = psDBCreateTable(dbh, P4MAGICMASKIMFILE_TABLE_NAME, md);
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "bg", PS_DATA_F64, NULL, 0.0)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item bg");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "bg_mean_stdev", PS_DATA_F64, NULL, 0.0)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item bg_mean_stdev");
+        psFree(md);
+        return false;
+    }
+
+    bool status = psDBCreateTable(dbh, P4BDIFFSCFILE_TABLE_NAME, md);
 
     psFree(md);
@@ -15517,14 +15341,24 @@
 }
 
-bool p4MagicMaskImfileDropTable(psDB *dbh)
-{
-    return psDBDropTable(dbh, P4MAGICMASKIMFILE_TABLE_NAME);
-}
-
-bool p4MagicMaskImfileInsert(psDB * dbh, psS32 p4_id, const char *exp_tag, psS32 p3_version, const char *class_id, const char *uri)
+bool p4bDiffScfileDropTable(psDB *dbh)
+{
+    return psDBDropTable(dbh, P4BDIFFSCFILE_TABLE_NAME);
+}
+
+bool p4bDiffScfileInsert(psDB * dbh, psS32 p4b_id, const char *skycell_id, const char *tess_id, const char *exp_tag, psS32 p3_version, const char *uri, psF64 bg, psF64 bg_mean_stdev)
 {
     psMetadata *md = psMetadataAlloc();
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4_id", PS_DATA_S32, NULL, p4_id)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item p4_id");
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4b_id", PS_DATA_S32, NULL, p4b_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p4b_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "skycell_id", PS_DATA_STRING, NULL, skycell_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item skycell_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "tess_id", PS_DATA_STRING, NULL, tess_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item tess_id");
         psFree(md);
         return false;
@@ -15540,9 +15374,4 @@
         return false;
     }
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "class_id", PS_DATA_STRING, NULL, class_id)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item class_id");
-        psFree(md);
-        return false;
-    }
     if (!psMetadataAdd(md, PS_LIST_TAIL, "uri", PS_DATA_STRING, NULL, uri)) {
         psError(PS_ERR_UNKNOWN, false, "failed to add item uri");
@@ -15550,6 +15379,16 @@
         return false;
     }
-
-    bool status = psDBInsertOneRow(dbh, P4MAGICMASKIMFILE_TABLE_NAME, md);
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "bg", PS_DATA_F64, NULL, bg)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item bg");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "bg_mean_stdev", PS_DATA_F64, NULL, bg_mean_stdev)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item bg_mean_stdev");
+        psFree(md);
+        return false;
+    }
+
+    bool status = psDBInsertOneRow(dbh, P4BDIFFSCFILE_TABLE_NAME, md);
     psFree(md);
 
@@ -15557,11 +15396,11 @@
 }
 
-long long p4MagicMaskImfileDelete(psDB *dbh, const psMetadata *where, unsigned long long limit)
+long long p4bDiffScfileDelete(psDB *dbh, const psMetadata *where, unsigned long long limit)
 {
     long long       deleted = 0;
 
-    long long count = psDBDeleteRows(dbh, P4MAGICMASKIMFILE_TABLE_NAME, where, limit);
+    long long count = psDBDeleteRows(dbh, P4BDIFFSCFILE_TABLE_NAME, where, limit);
     if (count < 0) {
-        psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4MagicMaskImfile");
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4bDiffScfile");
         return count;
 
@@ -15571,13 +15410,13 @@
     return deleted;
 }
-bool p4MagicMaskImfileInsertObject(psDB *dbh, p4MagicMaskImfileRow *object)
-{
-    return p4MagicMaskImfileInsert(dbh, object->p4_id, object->exp_tag, object->p3_version, object->class_id, object->uri);
-}
-
-bool p4MagicMaskImfileInsertObjects(psDB *dbh, psArray *objects)
+bool p4bDiffScfileInsertObject(psDB *dbh, p4bDiffScfileRow *object)
+{
+    return p4bDiffScfileInsert(dbh, object->p4b_id, object->skycell_id, object->tess_id, object->exp_tag, object->p3_version, object->uri, object->bg, object->bg_mean_stdev);
+}
+
+bool p4bDiffScfileInsertObjects(psDB *dbh, psArray *objects)
 {
     for (long i = 0; i < psArrayLength(objects); i++) {
-        if (!p4MagicMaskImfileInsertObject(dbh, objects->data[i])) {
+        if (!p4bDiffScfileInsertObject(dbh, objects->data[i])) {
             return false;
         }
@@ -15587,11 +15426,11 @@
 }
 
-bool p4MagicMaskImfileInsertFits(psDB *dbh, const psFits *fits)
+bool p4bDiffScfileInsertFits(psDB *dbh, const psFits *fits)
 {
     psArray         *rowSet;
 
-    // move to (the first?) extension named  P4MAGICMASKIMFILE_TABLE_NAME
-    if (!psFitsMoveExtName(fits, P4MAGICMASKIMFILE_TABLE_NAME)) {
-        psError(PS_ERR_UNKNOWN, true, "failed to find FITS extension %s", P4MAGICMASKIMFILE_TABLE_NAME);
+    // move to (the first?) extension named  P4BDIFFSCFILE_TABLE_NAME
+    if (!psFitsMoveExtName(fits, P4BDIFFSCFILE_TABLE_NAME)) {
+        psError(PS_ERR_UNKNOWN, true, "failed to find FITS extension %s", P4BDIFFSCFILE_TABLE_NAME);
         return false;
     }
@@ -15611,4 +15450,1048 @@
     }
 
+    if (!psDBInsertRows(dbh, P4BDIFFSCFILE_TABLE_NAME, rowSet)) {
+        psError(PS_ERR_UNKNOWN, false, "databse insert failed");
+        psFree(rowSet);
+        return false;
+    }
+
+    psFree(rowSet);
+
+    return true;
+}
+
+bool p4bDiffScfileSelectRowsFits(psDB *dbh, psFits *fits, const psMetadata *where, unsigned long long limit)
+{
+    psArray         *rowSet;
+
+    rowSet = psDBSelectRows(dbh, P4BDIFFSCFILE_TABLE_NAME, where, limit);
+    if (!rowSet) {
+        return false;
+    }
+
+    // output to fits
+    if (!psFitsWriteTable(fits, NULL, rowSet, P4BDIFFSCFILE_TABLE_NAME)) {
+        psError(PS_ERR_UNKNOWN, false, "FITS table write failed");
+        psFree(rowSet);
+        return false;
+    }
+
+    psFree(rowSet);
+
+    return true;
+}
+
+psMetadata *p4bDiffScfileMetadataFromObject(const p4bDiffScfileRow *object)
+{
+    psMetadata *md = psMetadataAlloc();
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4b_id", PS_DATA_S32, NULL, object->p4b_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p4b_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "skycell_id", PS_DATA_STRING, NULL, object->skycell_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item skycell_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "tess_id", PS_DATA_STRING, NULL, object->tess_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item tess_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "exp_tag", PS_DATA_STRING, NULL, object->exp_tag)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item exp_tag");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "p3_version", PS_DATA_S32, NULL, object->p3_version)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p3_version");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "uri", PS_DATA_STRING, NULL, object->uri)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item uri");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "bg", PS_DATA_F64, NULL, object->bg)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item bg");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "bg_mean_stdev", PS_DATA_F64, NULL, object->bg_mean_stdev)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item bg_mean_stdev");
+        psFree(md);
+        return false;
+    }
+
+
+    return md;
+}
+
+p4bDiffScfileRow *p4bDiffScfileObjectFromMetadata(psMetadata *md)
+{
+
+bool status = false;
+    psS32 p4b_id = psMetadataLookupS32(&status, md, "p4b_id");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item p4b_id");
+        return false;
+    }
+    char* skycell_id = psMetadataLookupPtr(&status, md, "skycell_id");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item skycell_id");
+        return false;
+    }
+    char* tess_id = psMetadataLookupPtr(&status, md, "tess_id");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item tess_id");
+        return false;
+    }
+    char* exp_tag = psMetadataLookupPtr(&status, md, "exp_tag");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item exp_tag");
+        return false;
+    }
+    psS32 p3_version = psMetadataLookupS32(&status, md, "p3_version");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item p3_version");
+        return false;
+    }
+    char* uri = psMetadataLookupPtr(&status, md, "uri");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item uri");
+        return false;
+    }
+    psF64 bg = psMetadataLookupF64(&status, md, "bg");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item bg");
+        return false;
+    }
+    psF64 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;
+    }
+
+    return p4bDiffScfileRowAlloc(p4b_id, skycell_id, tess_id, exp_tag, p3_version, uri, bg, bg_mean_stdev);
+}
+psArray *p4bDiffScfileSelectRowObjects(psDB *dbh, const psMetadata *where, unsigned long long limit)
+{
+    psArray         *rowSet;
+    psArray         *returnSet;
+    psU64           i;
+
+    rowSet = psDBSelectRows(dbh, P4BDIFFSCFILE_TABLE_NAME, where, limit);
+    if (!rowSet) {
+        return NULL;
+    }
+
+    // convert psMetadata rows to row objects
+
+    returnSet = psArrayAllocEmpty(rowSet->n);
+
+    for (i = 0; i < rowSet->n; i++) {
+        p4bDiffScfileRow *object = p4bDiffScfileObjectFromMetadata(rowSet->data[i]);
+        psArrayAdd(returnSet, 0, object);
+        psFree(object);
+    }
+
+    psFree(rowSet);
+
+    return returnSet;
+}
+bool p4bDiffScfileDeleteObject(psDB *dbh, const p4bDiffScfileRow *object)
+{
+    psMetadata *where = p4bDiffScfileMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, P4BDIFFSCFILE_TABLE_NAME, where, 0);
+    psFree(where);
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4bDiffScfile");
+        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, "p4bDiffScfileRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
+long long p4bDiffScfileDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
+{
+    long long       deleted = 0;
+
+    for (long long i = 0; i < objects->n; i++) {
+        p4bDiffScfileRow *object = objects->data[i];
+        psMetadata *where = p4bDiffScfileMetadataFromObject(object);
+        long long count = psDBDeleteRows(dbh, P4BDIFFSCFILE_TABLE_NAME, where, limit);
+        psFree(where);
+        if (count < 0) {
+            psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4bDiffScfile");
+            return count;
+        }
+
+        deleted += count;
+    }
+
+    return deleted;
+}
+bool p4bDiffScfilePrintObjects(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 = p4bDiffScfileMetadataFromObject(objects->data[i]);
+        if (!psMetadataAddMetadata(
+            output,
+            PS_LIST_TAIL,
+            P4BDIFFSCFILE_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;
+}
+bool p4bDiffScfilePrintObject(FILE *stream, p4bDiffScfileRow *object, bool mdcf)
+{
+    PS_ASSERT_PTR_NON_NULL(object, false);
+
+    psMetadata *md = p4bDiffScfileMetadataFromObject(object);
+
+    if (!ippdbPrintMetadataRaw(stream, md, mdcf)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print metadata");
+        psFree(md);
+    }
+
+    psFree(md);
+
+    return true;
+}
+static void p4cRunRowFree(p4cRunRow *object);
+
+p4cRunRow *p4cRunRowAlloc(psS32 p4c_id, const char *state, const char *workdir, bool magic)
+{
+    p4cRunRow       *_object;
+
+    _object = psAlloc(sizeof(p4cRunRow));
+    psMemSetDeallocator(_object, (psFreeFunc)p4cRunRowFree);
+
+    _object->p4c_id = p4c_id;
+    _object->state = psStringCopy(state);
+    _object->workdir = psStringCopy(workdir);
+    _object->magic = magic;
+
+    return _object;
+}
+
+static void p4cRunRowFree(p4cRunRow *object)
+{
+    psFree(object->state);
+    psFree(object->workdir);
+}
+
+bool p4cRunCreateTable(psDB *dbh)
+{
+    psMetadata *md = psMetadataAlloc();
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4c_id", PS_DATA_S32, "Primary Key AUTO_INCREMENT", 0)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p4c_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "state", PS_DATA_STRING, "Key", "64")) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item state");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "workdir", PS_DATA_STRING, NULL, "255")) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item workdir");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "magic", PS_DATA_BOOL, "Primary Key", 0)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item magic");
+        psFree(md);
+        return false;
+    }
+
+    bool status = psDBCreateTable(dbh, P4CRUN_TABLE_NAME, md);
+
+    psFree(md);
+
+    return status;
+}
+
+bool p4cRunDropTable(psDB *dbh)
+{
+    return psDBDropTable(dbh, P4CRUN_TABLE_NAME);
+}
+
+bool p4cRunInsert(psDB * dbh, psS32 p4c_id, const char *state, const char *workdir, bool magic)
+{
+    psMetadata *md = psMetadataAlloc();
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4c_id", PS_DATA_S32, NULL, p4c_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p4c_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "state", PS_DATA_STRING, NULL, state)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item state");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "workdir", PS_DATA_STRING, NULL, workdir)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item workdir");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "magic", PS_DATA_BOOL, NULL, magic)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item magic");
+        psFree(md);
+        return false;
+    }
+
+    bool status = psDBInsertOneRow(dbh, P4CRUN_TABLE_NAME, md);
+    psFree(md);
+
+    return status;
+}
+
+long long p4cRunDelete(psDB *dbh, const psMetadata *where, unsigned long long limit)
+{
+    long long       deleted = 0;
+
+    long long count = psDBDeleteRows(dbh, P4CRUN_TABLE_NAME, where, limit);
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4cRun");
+        return count;
+
+        deleted += count;
+    }
+
+    return deleted;
+}
+bool p4cRunInsertObject(psDB *dbh, p4cRunRow *object)
+{
+    return p4cRunInsert(dbh, object->p4c_id, object->state, object->workdir, object->magic);
+}
+
+bool p4cRunInsertObjects(psDB *dbh, psArray *objects)
+{
+    for (long i = 0; i < psArrayLength(objects); i++) {
+        if (!p4cRunInsertObject(dbh, objects->data[i])) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool p4cRunInsertFits(psDB *dbh, const psFits *fits)
+{
+    psArray         *rowSet;
+
+    // move to (the first?) extension named  P4CRUN_TABLE_NAME
+    if (!psFitsMoveExtName(fits, P4CRUN_TABLE_NAME)) {
+        psError(PS_ERR_UNKNOWN, true, "failed to find FITS extension %s", P4CRUN_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, P4CRUN_TABLE_NAME, rowSet)) {
+        psError(PS_ERR_UNKNOWN, false, "databse insert failed");
+        psFree(rowSet);
+        return false;
+    }
+
+    psFree(rowSet);
+
+    return true;
+}
+
+bool p4cRunSelectRowsFits(psDB *dbh, psFits *fits, const psMetadata *where, unsigned long long limit)
+{
+    psArray         *rowSet;
+
+    rowSet = psDBSelectRows(dbh, P4CRUN_TABLE_NAME, where, limit);
+    if (!rowSet) {
+        return false;
+    }
+
+    // output to fits
+    if (!psFitsWriteTable(fits, NULL, rowSet, P4CRUN_TABLE_NAME)) {
+        psError(PS_ERR_UNKNOWN, false, "FITS table write failed");
+        psFree(rowSet);
+        return false;
+    }
+
+    psFree(rowSet);
+
+    return true;
+}
+
+psMetadata *p4cRunMetadataFromObject(const p4cRunRow *object)
+{
+    psMetadata *md = psMetadataAlloc();
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4c_id", PS_DATA_S32, NULL, object->p4c_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p4c_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "state", PS_DATA_STRING, NULL, object->state)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item state");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "workdir", PS_DATA_STRING, NULL, object->workdir)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item workdir");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "magic", PS_DATA_BOOL, NULL, object->magic)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item magic");
+        psFree(md);
+        return false;
+    }
+
+
+    return md;
+}
+
+p4cRunRow *p4cRunObjectFromMetadata(psMetadata *md)
+{
+
+bool status = false;
+    psS32 p4c_id = psMetadataLookupS32(&status, md, "p4c_id");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item p4c_id");
+        return false;
+    }
+    char* state = psMetadataLookupPtr(&status, md, "state");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item state");
+        return false;
+    }
+    char* workdir = psMetadataLookupPtr(&status, md, "workdir");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item workdir");
+        return false;
+    }
+    bool magic = psMetadataLookupBool(&status, md, "magic");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item magic");
+        return false;
+    }
+
+    return p4cRunRowAlloc(p4c_id, state, workdir, magic);
+}
+psArray *p4cRunSelectRowObjects(psDB *dbh, const psMetadata *where, unsigned long long limit)
+{
+    psArray         *rowSet;
+    psArray         *returnSet;
+    psU64           i;
+
+    rowSet = psDBSelectRows(dbh, P4CRUN_TABLE_NAME, where, limit);
+    if (!rowSet) {
+        return NULL;
+    }
+
+    // convert psMetadata rows to row objects
+
+    returnSet = psArrayAllocEmpty(rowSet->n);
+
+    for (i = 0; i < rowSet->n; i++) {
+        p4cRunRow *object = p4cRunObjectFromMetadata(rowSet->data[i]);
+        psArrayAdd(returnSet, 0, object);
+        psFree(object);
+    }
+
+    psFree(rowSet);
+
+    return returnSet;
+}
+bool p4cRunDeleteObject(psDB *dbh, const p4cRunRow *object)
+{
+    psMetadata *where = p4cRunMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, P4CRUN_TABLE_NAME, where, 0);
+    psFree(where);
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4cRun");
+        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, "p4cRunRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
+long long p4cRunDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
+{
+    long long       deleted = 0;
+
+    for (long long i = 0; i < objects->n; i++) {
+        p4cRunRow *object = objects->data[i];
+        psMetadata *where = p4cRunMetadataFromObject(object);
+        long long count = psDBDeleteRows(dbh, P4CRUN_TABLE_NAME, where, limit);
+        psFree(where);
+        if (count < 0) {
+            psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4cRun");
+            return count;
+        }
+
+        deleted += count;
+    }
+
+    return deleted;
+}
+bool p4cRunPrintObjects(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 = p4cRunMetadataFromObject(objects->data[i]);
+        if (!psMetadataAddMetadata(
+            output,
+            PS_LIST_TAIL,
+            P4CRUN_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;
+}
+bool p4cRunPrintObject(FILE *stream, p4cRunRow *object, bool mdcf)
+{
+    PS_ASSERT_PTR_NON_NULL(object, false);
+
+    psMetadata *md = p4cRunMetadataFromObject(object);
+
+    if (!ippdbPrintMetadataRaw(stream, md, mdcf)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print metadata");
+        psFree(md);
+    }
+
+    psFree(md);
+
+    return true;
+}
+static void p4cInputExpRowFree(p4cInputExpRow *object);
+
+p4cInputExpRow *p4cInputExpRowAlloc(psS32 p4c_id, const char *exp_tag, psS32 p3_version)
+{
+    p4cInputExpRow  *_object;
+
+    _object = psAlloc(sizeof(p4cInputExpRow));
+    psMemSetDeallocator(_object, (psFreeFunc)p4cInputExpRowFree);
+
+    _object->p4c_id = p4c_id;
+    _object->exp_tag = psStringCopy(exp_tag);
+    _object->p3_version = p3_version;
+
+    return _object;
+}
+
+static void p4cInputExpRowFree(p4cInputExpRow *object)
+{
+    psFree(object->exp_tag);
+}
+
+bool p4cInputExpCreateTable(psDB *dbh)
+{
+    psMetadata *md = psMetadataAlloc();
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4c_id", PS_DATA_S32, "Primary Key", 0)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p4c_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "exp_tag", PS_DATA_STRING, "Primary Key", "64")) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item exp_tag");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "p3_version", PS_DATA_S32, "Primary Key", 0)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p3_version");
+        psFree(md);
+        return false;
+    }
+
+    bool status = psDBCreateTable(dbh, P4CINPUTEXP_TABLE_NAME, md);
+
+    psFree(md);
+
+    return status;
+}
+
+bool p4cInputExpDropTable(psDB *dbh)
+{
+    return psDBDropTable(dbh, P4CINPUTEXP_TABLE_NAME);
+}
+
+bool p4cInputExpInsert(psDB * dbh, psS32 p4c_id, const char *exp_tag, psS32 p3_version)
+{
+    psMetadata *md = psMetadataAlloc();
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4c_id", PS_DATA_S32, NULL, p4c_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p4c_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "exp_tag", PS_DATA_STRING, NULL, exp_tag)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item exp_tag");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "p3_version", PS_DATA_S32, NULL, p3_version)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p3_version");
+        psFree(md);
+        return false;
+    }
+
+    bool status = psDBInsertOneRow(dbh, P4CINPUTEXP_TABLE_NAME, md);
+    psFree(md);
+
+    return status;
+}
+
+long long p4cInputExpDelete(psDB *dbh, const psMetadata *where, unsigned long long limit)
+{
+    long long       deleted = 0;
+
+    long long count = psDBDeleteRows(dbh, P4CINPUTEXP_TABLE_NAME, where, limit);
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4cInputExp");
+        return count;
+
+        deleted += count;
+    }
+
+    return deleted;
+}
+bool p4cInputExpInsertObject(psDB *dbh, p4cInputExpRow *object)
+{
+    return p4cInputExpInsert(dbh, object->p4c_id, object->exp_tag, object->p3_version);
+}
+
+bool p4cInputExpInsertObjects(psDB *dbh, psArray *objects)
+{
+    for (long i = 0; i < psArrayLength(objects); i++) {
+        if (!p4cInputExpInsertObject(dbh, objects->data[i])) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool p4cInputExpInsertFits(psDB *dbh, const psFits *fits)
+{
+    psArray         *rowSet;
+
+    // move to (the first?) extension named  P4CINPUTEXP_TABLE_NAME
+    if (!psFitsMoveExtName(fits, P4CINPUTEXP_TABLE_NAME)) {
+        psError(PS_ERR_UNKNOWN, true, "failed to find FITS extension %s", P4CINPUTEXP_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, P4CINPUTEXP_TABLE_NAME, rowSet)) {
+        psError(PS_ERR_UNKNOWN, false, "databse insert failed");
+        psFree(rowSet);
+        return false;
+    }
+
+    psFree(rowSet);
+
+    return true;
+}
+
+bool p4cInputExpSelectRowsFits(psDB *dbh, psFits *fits, const psMetadata *where, unsigned long long limit)
+{
+    psArray         *rowSet;
+
+    rowSet = psDBSelectRows(dbh, P4CINPUTEXP_TABLE_NAME, where, limit);
+    if (!rowSet) {
+        return false;
+    }
+
+    // output to fits
+    if (!psFitsWriteTable(fits, NULL, rowSet, P4CINPUTEXP_TABLE_NAME)) {
+        psError(PS_ERR_UNKNOWN, false, "FITS table write failed");
+        psFree(rowSet);
+        return false;
+    }
+
+    psFree(rowSet);
+
+    return true;
+}
+
+psMetadata *p4cInputExpMetadataFromObject(const p4cInputExpRow *object)
+{
+    psMetadata *md = psMetadataAlloc();
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4c_id", PS_DATA_S32, NULL, object->p4c_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p4c_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "exp_tag", PS_DATA_STRING, NULL, object->exp_tag)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item exp_tag");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "p3_version", PS_DATA_S32, NULL, object->p3_version)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p3_version");
+        psFree(md);
+        return false;
+    }
+
+
+    return md;
+}
+
+p4cInputExpRow *p4cInputExpObjectFromMetadata(psMetadata *md)
+{
+
+bool status = false;
+    psS32 p4c_id = psMetadataLookupS32(&status, md, "p4c_id");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item p4c_id");
+        return false;
+    }
+    char* exp_tag = psMetadataLookupPtr(&status, md, "exp_tag");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item exp_tag");
+        return false;
+    }
+    psS32 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 p4cInputExpRowAlloc(p4c_id, exp_tag, p3_version);
+}
+psArray *p4cInputExpSelectRowObjects(psDB *dbh, const psMetadata *where, unsigned long long limit)
+{
+    psArray         *rowSet;
+    psArray         *returnSet;
+    psU64           i;
+
+    rowSet = psDBSelectRows(dbh, P4CINPUTEXP_TABLE_NAME, where, limit);
+    if (!rowSet) {
+        return NULL;
+    }
+
+    // convert psMetadata rows to row objects
+
+    returnSet = psArrayAllocEmpty(rowSet->n);
+
+    for (i = 0; i < rowSet->n; i++) {
+        p4cInputExpRow *object = p4cInputExpObjectFromMetadata(rowSet->data[i]);
+        psArrayAdd(returnSet, 0, object);
+        psFree(object);
+    }
+
+    psFree(rowSet);
+
+    return returnSet;
+}
+bool p4cInputExpDeleteObject(psDB *dbh, const p4cInputExpRow *object)
+{
+    psMetadata *where = p4cInputExpMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, P4CINPUTEXP_TABLE_NAME, where, 0);
+    psFree(where);
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4cInputExp");
+        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, "p4cInputExpRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
+long long p4cInputExpDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
+{
+    long long       deleted = 0;
+
+    for (long long i = 0; i < objects->n; i++) {
+        p4cInputExpRow *object = objects->data[i];
+        psMetadata *where = p4cInputExpMetadataFromObject(object);
+        long long count = psDBDeleteRows(dbh, P4CINPUTEXP_TABLE_NAME, where, limit);
+        psFree(where);
+        if (count < 0) {
+            psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4cInputExp");
+            return count;
+        }
+
+        deleted += count;
+    }
+
+    return deleted;
+}
+bool p4cInputExpPrintObjects(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 = p4cInputExpMetadataFromObject(objects->data[i]);
+        if (!psMetadataAddMetadata(
+            output,
+            PS_LIST_TAIL,
+            P4CINPUTEXP_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;
+}
+bool p4cInputExpPrintObject(FILE *stream, p4cInputExpRow *object, bool mdcf)
+{
+    PS_ASSERT_PTR_NON_NULL(object, false);
+
+    psMetadata *md = p4cInputExpMetadataFromObject(object);
+
+    if (!ippdbPrintMetadataRaw(stream, md, mdcf)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print metadata");
+        psFree(md);
+    }
+
+    psFree(md);
+
+    return true;
+}
+static void p4MagicMaskImfileRowFree(p4MagicMaskImfileRow *object);
+
+p4MagicMaskImfileRow *p4MagicMaskImfileRowAlloc(psS32 p4c_id, const char *exp_tag, psS32 p3_version, const char *class_id, const char *uri)
+{
+    p4MagicMaskImfileRow *_object;
+
+    _object = psAlloc(sizeof(p4MagicMaskImfileRow));
+    psMemSetDeallocator(_object, (psFreeFunc)p4MagicMaskImfileRowFree);
+
+    _object->p4c_id = p4c_id;
+    _object->exp_tag = psStringCopy(exp_tag);
+    _object->p3_version = p3_version;
+    _object->class_id = psStringCopy(class_id);
+    _object->uri = psStringCopy(uri);
+
+    return _object;
+}
+
+static void p4MagicMaskImfileRowFree(p4MagicMaskImfileRow *object)
+{
+    psFree(object->exp_tag);
+    psFree(object->class_id);
+    psFree(object->uri);
+}
+
+bool p4MagicMaskImfileCreateTable(psDB *dbh)
+{
+    psMetadata *md = psMetadataAlloc();
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4c_id", PS_DATA_S32, "Primary Key", 0)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p4c_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "exp_tag", PS_DATA_STRING, "Primary Key", "64")) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item exp_tag");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "p3_version", PS_DATA_S32, "Primary Key", 0)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p3_version");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "class_id", PS_DATA_STRING, "Primary Key", "64")) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item class_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "uri", PS_DATA_STRING, NULL, "255")) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item uri");
+        psFree(md);
+        return false;
+    }
+
+    bool status = psDBCreateTable(dbh, P4MAGICMASKIMFILE_TABLE_NAME, md);
+
+    psFree(md);
+
+    return status;
+}
+
+bool p4MagicMaskImfileDropTable(psDB *dbh)
+{
+    return psDBDropTable(dbh, P4MAGICMASKIMFILE_TABLE_NAME);
+}
+
+bool p4MagicMaskImfileInsert(psDB * dbh, psS32 p4c_id, const char *exp_tag, psS32 p3_version, const char *class_id, const char *uri)
+{
+    psMetadata *md = psMetadataAlloc();
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4c_id", PS_DATA_S32, NULL, p4c_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p4c_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "exp_tag", PS_DATA_STRING, NULL, exp_tag)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item exp_tag");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "p3_version", PS_DATA_S32, NULL, p3_version)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p3_version");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "class_id", PS_DATA_STRING, NULL, class_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item class_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "uri", PS_DATA_STRING, NULL, uri)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item uri");
+        psFree(md);
+        return false;
+    }
+
+    bool status = psDBInsertOneRow(dbh, P4MAGICMASKIMFILE_TABLE_NAME, md);
+    psFree(md);
+
+    return status;
+}
+
+long long p4MagicMaskImfileDelete(psDB *dbh, const psMetadata *where, unsigned long long limit)
+{
+    long long       deleted = 0;
+
+    long long count = psDBDeleteRows(dbh, P4MAGICMASKIMFILE_TABLE_NAME, where, limit);
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4MagicMaskImfile");
+        return count;
+
+        deleted += count;
+    }
+
+    return deleted;
+}
+bool p4MagicMaskImfileInsertObject(psDB *dbh, p4MagicMaskImfileRow *object)
+{
+    return p4MagicMaskImfileInsert(dbh, object->p4c_id, object->exp_tag, object->p3_version, object->class_id, object->uri);
+}
+
+bool p4MagicMaskImfileInsertObjects(psDB *dbh, psArray *objects)
+{
+    for (long i = 0; i < psArrayLength(objects); i++) {
+        if (!p4MagicMaskImfileInsertObject(dbh, objects->data[i])) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool p4MagicMaskImfileInsertFits(psDB *dbh, const psFits *fits)
+{
+    psArray         *rowSet;
+
+    // move to (the first?) extension named  P4MAGICMASKIMFILE_TABLE_NAME
+    if (!psFitsMoveExtName(fits, P4MAGICMASKIMFILE_TABLE_NAME)) {
+        psError(PS_ERR_UNKNOWN, true, "failed to find FITS extension %s", P4MAGICMASKIMFILE_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, P4MAGICMASKIMFILE_TABLE_NAME, rowSet)) {
         psError(PS_ERR_UNKNOWN, false, "databse insert failed");
@@ -15646,6 +16529,6 @@
 {
     psMetadata *md = psMetadataAlloc();
-    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4_id", PS_DATA_S32, NULL, object->p4_id)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to add item p4_id");
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "p4c_id", PS_DATA_S32, NULL, object->p4c_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item p4c_id");
         psFree(md);
         return false;
@@ -15680,7 +16563,7 @@
 
 bool status = false;
-    psS32 p4_id = psMetadataLookupS32(&status, md, "p4_id");
-    if (!status) {
-        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item p4_id");
+    psS32 p4c_id = psMetadataLookupS32(&status, md, "p4c_id");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item p4c_id");
         return false;
     }
@@ -15706,5 +16589,5 @@
     }
 
-    return p4MagicMaskImfileRowAlloc(p4_id, exp_tag, p3_version, class_id, uri);
+    return p4MagicMaskImfileRowAlloc(p4c_id, exp_tag, p3_version, class_id, uri);
 }
 psArray *p4MagicMaskImfileSelectRowObjects(psDB *dbh, const psMetadata *where, unsigned long long limit)
@@ -15737,5 +16620,5 @@
     psMetadata *where = p4MagicMaskImfileMetadataFromObject(object);
     long long count = psDBDeleteRows(dbh, P4MAGICMASKIMFILE_TABLE_NAME, where, 0);
-    psFree(where)
+    psFree(where);
     if (count < 0) {
         psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4MagicMaskImfile");
@@ -15759,5 +16642,5 @@
         psMetadata *where = p4MagicMaskImfileMetadataFromObject(object);
         long long count = psDBDeleteRows(dbh, P4MAGICMASKIMFILE_TABLE_NAME, where, limit);
-        psFree(where)
+        psFree(where);
         if (count < 0) {
             psError(PS_ERR_UNKNOWN, true, "failed to delete row from p4MagicMaskImfile");
@@ -15816,2 +16699,806 @@
     return true;
 }
+static void skyCellRowFree(skyCellRow *object);
+
+skyCellRow *skyCellRowAlloc(const char *skycell_id, const char *tess_id, psF64 ra1, psF64 decl1, psF64 ra2, psF64 decl2, psF64 ra3, psF64 decl3, psF64 ra4, psF64 decl4)
+{
+    skyCellRow      *_object;
+
+    _object = psAlloc(sizeof(skyCellRow));
+    psMemSetDeallocator(_object, (psFreeFunc)skyCellRowFree);
+
+    _object->skycell_id = psStringCopy(skycell_id);
+    _object->tess_id = psStringCopy(tess_id);
+    _object->ra1 = ra1;
+    _object->decl1 = decl1;
+    _object->ra2 = ra2;
+    _object->decl2 = decl2;
+    _object->ra3 = ra3;
+    _object->decl3 = decl3;
+    _object->ra4 = ra4;
+    _object->decl4 = decl4;
+
+    return _object;
+}
+
+static void skyCellRowFree(skyCellRow *object)
+{
+    psFree(object->skycell_id);
+    psFree(object->tess_id);
+}
+
+bool skyCellCreateTable(psDB *dbh)
+{
+    psMetadata *md = psMetadataAlloc();
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "skycell_id", PS_DATA_STRING, "Primary Key", "64")) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item skycell_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "tess_id", PS_DATA_STRING, "Primary Key", "64")) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item tess_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "ra1", PS_DATA_F64, NULL, 0.0)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item ra1");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "decl1", PS_DATA_F64, NULL, 0.0)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item decl1");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "ra2", PS_DATA_F64, NULL, 0.0)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item ra2");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "decl2", PS_DATA_F64, NULL, 0.0)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item decl2");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "ra3", PS_DATA_F64, NULL, 0.0)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item ra3");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "decl3", PS_DATA_F64, NULL, 0.0)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item decl3");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "ra4", PS_DATA_F64, NULL, 0.0)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item ra4");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "decl4", PS_DATA_F64, NULL, 0.0)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item decl4");
+        psFree(md);
+        return false;
+    }
+
+    bool status = psDBCreateTable(dbh, SKYCELL_TABLE_NAME, md);
+
+    psFree(md);
+
+    return status;
+}
+
+bool skyCellDropTable(psDB *dbh)
+{
+    return psDBDropTable(dbh, SKYCELL_TABLE_NAME);
+}
+
+bool skyCellInsert(psDB * dbh, const char *skycell_id, const char *tess_id, psF64 ra1, psF64 decl1, psF64 ra2, psF64 decl2, psF64 ra3, psF64 decl3, psF64 ra4, psF64 decl4)
+{
+    psMetadata *md = psMetadataAlloc();
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "skycell_id", PS_DATA_STRING, NULL, skycell_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item skycell_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "tess_id", PS_DATA_STRING, NULL, tess_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item tess_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "ra1", PS_DATA_F64, NULL, ra1)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item ra1");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "decl1", PS_DATA_F64, NULL, decl1)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item decl1");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "ra2", PS_DATA_F64, NULL, ra2)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item ra2");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "decl2", PS_DATA_F64, NULL, decl2)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item decl2");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "ra3", PS_DATA_F64, NULL, ra3)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item ra3");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "decl3", PS_DATA_F64, NULL, decl3)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item decl3");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "ra4", PS_DATA_F64, NULL, ra4)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item ra4");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "decl4", PS_DATA_F64, NULL, decl4)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item decl4");
+        psFree(md);
+        return false;
+    }
+
+    bool status = psDBInsertOneRow(dbh, SKYCELL_TABLE_NAME, md);
+    psFree(md);
+
+    return status;
+}
+
+long long skyCellDelete(psDB *dbh, const psMetadata *where, unsigned long long limit)
+{
+    long long       deleted = 0;
+
+    long long count = psDBDeleteRows(dbh, SKYCELL_TABLE_NAME, where, limit);
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from skyCell");
+        return count;
+
+        deleted += count;
+    }
+
+    return deleted;
+}
+bool skyCellInsertObject(psDB *dbh, skyCellRow *object)
+{
+    return skyCellInsert(dbh, object->skycell_id, object->tess_id, object->ra1, object->decl1, object->ra2, object->decl2, object->ra3, object->decl3, object->ra4, object->decl4);
+}
+
+bool skyCellInsertObjects(psDB *dbh, psArray *objects)
+{
+    for (long i = 0; i < psArrayLength(objects); i++) {
+        if (!skyCellInsertObject(dbh, objects->data[i])) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool skyCellInsertFits(psDB *dbh, const psFits *fits)
+{
+    psArray         *rowSet;
+
+    // move to (the first?) extension named  SKYCELL_TABLE_NAME
+    if (!psFitsMoveExtName(fits, SKYCELL_TABLE_NAME)) {
+        psError(PS_ERR_UNKNOWN, true, "failed to find FITS extension %s", SKYCELL_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, SKYCELL_TABLE_NAME, rowSet)) {
+        psError(PS_ERR_UNKNOWN, false, "databse insert failed");
+        psFree(rowSet);
+        return false;
+    }
+
+    psFree(rowSet);
+
+    return true;
+}
+
+bool skyCellSelectRowsFits(psDB *dbh, psFits *fits, const psMetadata *where, unsigned long long limit)
+{
+    psArray         *rowSet;
+
+    rowSet = psDBSelectRows(dbh, SKYCELL_TABLE_NAME, where, limit);
+    if (!rowSet) {
+        return false;
+    }
+
+    // output to fits
+    if (!psFitsWriteTable(fits, NULL, rowSet, SKYCELL_TABLE_NAME)) {
+        psError(PS_ERR_UNKNOWN, false, "FITS table write failed");
+        psFree(rowSet);
+        return false;
+    }
+
+    psFree(rowSet);
+
+    return true;
+}
+
+psMetadata *skyCellMetadataFromObject(const skyCellRow *object)
+{
+    psMetadata *md = psMetadataAlloc();
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "skycell_id", PS_DATA_STRING, NULL, object->skycell_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item skycell_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "tess_id", PS_DATA_STRING, NULL, object->tess_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item tess_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "ra1", PS_DATA_F64, NULL, object->ra1)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item ra1");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "decl1", PS_DATA_F64, NULL, object->decl1)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item decl1");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "ra2", PS_DATA_F64, NULL, object->ra2)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item ra2");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "decl2", PS_DATA_F64, NULL, object->decl2)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item decl2");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "ra3", PS_DATA_F64, NULL, object->ra3)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item ra3");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "decl3", PS_DATA_F64, NULL, object->decl3)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item decl3");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "ra4", PS_DATA_F64, NULL, object->ra4)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item ra4");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "decl4", PS_DATA_F64, NULL, object->decl4)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item decl4");
+        psFree(md);
+        return false;
+    }
+
+
+    return md;
+}
+
+skyCellRow *skyCellObjectFromMetadata(psMetadata *md)
+{
+
+bool status = false;
+    char* skycell_id = psMetadataLookupPtr(&status, md, "skycell_id");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item skycell_id");
+        return false;
+    }
+    char* tess_id = psMetadataLookupPtr(&status, md, "tess_id");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item tess_id");
+        return false;
+    }
+    psF64 ra1 = psMetadataLookupF64(&status, md, "ra1");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item ra1");
+        return false;
+    }
+    psF64 decl1 = psMetadataLookupF64(&status, md, "decl1");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item decl1");
+        return false;
+    }
+    psF64 ra2 = psMetadataLookupF64(&status, md, "ra2");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item ra2");
+        return false;
+    }
+    psF64 decl2 = psMetadataLookupF64(&status, md, "decl2");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item decl2");
+        return false;
+    }
+    psF64 ra3 = psMetadataLookupF64(&status, md, "ra3");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item ra3");
+        return false;
+    }
+    psF64 decl3 = psMetadataLookupF64(&status, md, "decl3");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item decl3");
+        return false;
+    }
+    psF64 ra4 = psMetadataLookupF64(&status, md, "ra4");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item ra4");
+        return false;
+    }
+    psF64 decl4 = psMetadataLookupF64(&status, md, "decl4");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item decl4");
+        return false;
+    }
+
+    return skyCellRowAlloc(skycell_id, tess_id, ra1, decl1, ra2, decl2, ra3, decl3, ra4, decl4);
+}
+psArray *skyCellSelectRowObjects(psDB *dbh, const psMetadata *where, unsigned long long limit)
+{
+    psArray         *rowSet;
+    psArray         *returnSet;
+    psU64           i;
+
+    rowSet = psDBSelectRows(dbh, SKYCELL_TABLE_NAME, where, limit);
+    if (!rowSet) {
+        return NULL;
+    }
+
+    // convert psMetadata rows to row objects
+
+    returnSet = psArrayAllocEmpty(rowSet->n);
+
+    for (i = 0; i < rowSet->n; i++) {
+        skyCellRow *object = skyCellObjectFromMetadata(rowSet->data[i]);
+        psArrayAdd(returnSet, 0, object);
+        psFree(object);
+    }
+
+    psFree(rowSet);
+
+    return returnSet;
+}
+bool skyCellDeleteObject(psDB *dbh, const skyCellRow *object)
+{
+    psMetadata *where = skyCellMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, SKYCELL_TABLE_NAME, where, 0);
+    psFree(where);
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from skyCell");
+        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, "skyCellRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
+long long skyCellDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
+{
+    long long       deleted = 0;
+
+    for (long long i = 0; i < objects->n; i++) {
+        skyCellRow *object = objects->data[i];
+        psMetadata *where = skyCellMetadataFromObject(object);
+        long long count = psDBDeleteRows(dbh, SKYCELL_TABLE_NAME, where, limit);
+        psFree(where);
+        if (count < 0) {
+            psError(PS_ERR_UNKNOWN, true, "failed to delete row from skyCell");
+            return count;
+        }
+
+        deleted += count;
+    }
+
+    return deleted;
+}
+bool skyCellPrintObjects(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 = skyCellMetadataFromObject(objects->data[i]);
+        if (!psMetadataAddMetadata(
+            output,
+            PS_LIST_TAIL,
+            SKYCELL_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;
+}
+bool skyCellPrintObject(FILE *stream, skyCellRow *object, bool mdcf)
+{
+    PS_ASSERT_PTR_NON_NULL(object, false);
+
+    psMetadata *md = skyCellMetadataFromObject(object);
+
+    if (!ippdbPrintMetadataRaw(stream, md, mdcf)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print metadata");
+        psFree(md);
+    }
+
+    psFree(md);
+
+    return true;
+}
+static void skyCellMapRowFree(skyCellMapRow *object);
+
+skyCellMapRow *skyCellMapRowAlloc(const char *skycell_id, const char *tess_id, const char *exp_tag, const char *class_id)
+{
+    skyCellMapRow   *_object;
+
+    _object = psAlloc(sizeof(skyCellMapRow));
+    psMemSetDeallocator(_object, (psFreeFunc)skyCellMapRowFree);
+
+    _object->skycell_id = psStringCopy(skycell_id);
+    _object->tess_id = psStringCopy(tess_id);
+    _object->exp_tag = psStringCopy(exp_tag);
+    _object->class_id = psStringCopy(class_id);
+
+    return _object;
+}
+
+static void skyCellMapRowFree(skyCellMapRow *object)
+{
+    psFree(object->skycell_id);
+    psFree(object->tess_id);
+    psFree(object->exp_tag);
+    psFree(object->class_id);
+}
+
+bool skyCellMapCreateTable(psDB *dbh)
+{
+    psMetadata *md = psMetadataAlloc();
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "skycell_id", PS_DATA_STRING, "Primary Key", "64")) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item skycell_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "tess_id", PS_DATA_STRING, "Primary Key", "64")) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item tess_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "exp_tag", PS_DATA_STRING, "Primary Key", "64")) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item exp_tag");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "class_id", PS_DATA_STRING, "Primary Key", "64")) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item class_id");
+        psFree(md);
+        return false;
+    }
+
+    bool status = psDBCreateTable(dbh, SKYCELLMAP_TABLE_NAME, md);
+
+    psFree(md);
+
+    return status;
+}
+
+bool skyCellMapDropTable(psDB *dbh)
+{
+    return psDBDropTable(dbh, SKYCELLMAP_TABLE_NAME);
+}
+
+bool skyCellMapInsert(psDB * dbh, const char *skycell_id, const char *tess_id, const char *exp_tag, const char *class_id)
+{
+    psMetadata *md = psMetadataAlloc();
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "skycell_id", PS_DATA_STRING, NULL, skycell_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item skycell_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "tess_id", PS_DATA_STRING, NULL, tess_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item tess_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "exp_tag", PS_DATA_STRING, NULL, exp_tag)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item exp_tag");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "class_id", PS_DATA_STRING, NULL, class_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item class_id");
+        psFree(md);
+        return false;
+    }
+
+    bool status = psDBInsertOneRow(dbh, SKYCELLMAP_TABLE_NAME, md);
+    psFree(md);
+
+    return status;
+}
+
+long long skyCellMapDelete(psDB *dbh, const psMetadata *where, unsigned long long limit)
+{
+    long long       deleted = 0;
+
+    long long count = psDBDeleteRows(dbh, SKYCELLMAP_TABLE_NAME, where, limit);
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from skyCellMap");
+        return count;
+
+        deleted += count;
+    }
+
+    return deleted;
+}
+bool skyCellMapInsertObject(psDB *dbh, skyCellMapRow *object)
+{
+    return skyCellMapInsert(dbh, object->skycell_id, object->tess_id, object->exp_tag, object->class_id);
+}
+
+bool skyCellMapInsertObjects(psDB *dbh, psArray *objects)
+{
+    for (long i = 0; i < psArrayLength(objects); i++) {
+        if (!skyCellMapInsertObject(dbh, objects->data[i])) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool skyCellMapInsertFits(psDB *dbh, const psFits *fits)
+{
+    psArray         *rowSet;
+
+    // move to (the first?) extension named  SKYCELLMAP_TABLE_NAME
+    if (!psFitsMoveExtName(fits, SKYCELLMAP_TABLE_NAME)) {
+        psError(PS_ERR_UNKNOWN, true, "failed to find FITS extension %s", SKYCELLMAP_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, SKYCELLMAP_TABLE_NAME, rowSet)) {
+        psError(PS_ERR_UNKNOWN, false, "databse insert failed");
+        psFree(rowSet);
+        return false;
+    }
+
+    psFree(rowSet);
+
+    return true;
+}
+
+bool skyCellMapSelectRowsFits(psDB *dbh, psFits *fits, const psMetadata *where, unsigned long long limit)
+{
+    psArray         *rowSet;
+
+    rowSet = psDBSelectRows(dbh, SKYCELLMAP_TABLE_NAME, where, limit);
+    if (!rowSet) {
+        return false;
+    }
+
+    // output to fits
+    if (!psFitsWriteTable(fits, NULL, rowSet, SKYCELLMAP_TABLE_NAME)) {
+        psError(PS_ERR_UNKNOWN, false, "FITS table write failed");
+        psFree(rowSet);
+        return false;
+    }
+
+    psFree(rowSet);
+
+    return true;
+}
+
+psMetadata *skyCellMapMetadataFromObject(const skyCellMapRow *object)
+{
+    psMetadata *md = psMetadataAlloc();
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "skycell_id", PS_DATA_STRING, NULL, object->skycell_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item skycell_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "tess_id", PS_DATA_STRING, NULL, object->tess_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item tess_id");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "exp_tag", PS_DATA_STRING, NULL, object->exp_tag)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item exp_tag");
+        psFree(md);
+        return false;
+    }
+    if (!psMetadataAdd(md, PS_LIST_TAIL, "class_id", PS_DATA_STRING, NULL, object->class_id)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to add item class_id");
+        psFree(md);
+        return false;
+    }
+
+
+    return md;
+}
+
+skyCellMapRow *skyCellMapObjectFromMetadata(psMetadata *md)
+{
+
+bool status = false;
+    char* skycell_id = psMetadataLookupPtr(&status, md, "skycell_id");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item skycell_id");
+        return false;
+    }
+    char* tess_id = psMetadataLookupPtr(&status, md, "tess_id");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item tess_id");
+        return false;
+    }
+    char* exp_tag = psMetadataLookupPtr(&status, md, "exp_tag");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item exp_tag");
+        return false;
+    }
+    char* class_id = psMetadataLookupPtr(&status, md, "class_id");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "failed to lookup value for item class_id");
+        return false;
+    }
+
+    return skyCellMapRowAlloc(skycell_id, tess_id, exp_tag, class_id);
+}
+psArray *skyCellMapSelectRowObjects(psDB *dbh, const psMetadata *where, unsigned long long limit)
+{
+    psArray         *rowSet;
+    psArray         *returnSet;
+    psU64           i;
+
+    rowSet = psDBSelectRows(dbh, SKYCELLMAP_TABLE_NAME, where, limit);
+    if (!rowSet) {
+        return NULL;
+    }
+
+    // convert psMetadata rows to row objects
+
+    returnSet = psArrayAllocEmpty(rowSet->n);
+
+    for (i = 0; i < rowSet->n; i++) {
+        skyCellMapRow *object = skyCellMapObjectFromMetadata(rowSet->data[i]);
+        psArrayAdd(returnSet, 0, object);
+        psFree(object);
+    }
+
+    psFree(rowSet);
+
+    return returnSet;
+}
+bool skyCellMapDeleteObject(psDB *dbh, const skyCellMapRow *object)
+{
+    psMetadata *where = skyCellMapMetadataFromObject(object);
+    long long count = psDBDeleteRows(dbh, SKYCELLMAP_TABLE_NAME, where, 0);
+    psFree(where);
+    if (count < 0) {
+        psError(PS_ERR_UNKNOWN, true, "failed to delete row from skyCellMap");
+        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, "skyCellMapRow object matched more then one row.  Check your database schema");
+        return false;
+    }
+
+    return true;
+}
+long long skyCellMapDeleteRowObjects(psDB *dbh, const psArray *objects, unsigned long long limit)
+{
+    long long       deleted = 0;
+
+    for (long long i = 0; i < objects->n; i++) {
+        skyCellMapRow *object = objects->data[i];
+        psMetadata *where = skyCellMapMetadataFromObject(object);
+        long long count = psDBDeleteRows(dbh, SKYCELLMAP_TABLE_NAME, where, limit);
+        psFree(where);
+        if (count < 0) {
+            psError(PS_ERR_UNKNOWN, true, "failed to delete row from skyCellMap");
+            return count;
+        }
+
+        deleted += count;
+    }
+
+    return deleted;
+}
+bool skyCellMapPrintObjects(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 = skyCellMapMetadataFromObject(objects->data[i]);
+        if (!psMetadataAddMetadata(
+            output,
+            PS_LIST_TAIL,
+            SKYCELLMAP_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;
+}
+bool skyCellMapPrintObject(FILE *stream, skyCellMapRow *object, bool mdcf)
+{
+    PS_ASSERT_PTR_NON_NULL(object, false);
+
+    psMetadata *md = skyCellMapMetadataFromObject(object);
+
+    if (!ippdbPrintMetadataRaw(stream, md, mdcf)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print metadata");
+        psFree(md);
+    }
+
+    psFree(md);
+
+    return true;
+}
