Index: trunk/ippTools/configure.ac
===================================================================
--- trunk/ippTools/configure.ac	(revision 28429)
+++ trunk/ippTools/configure.ac	(revision 28486)
@@ -19,6 +19,7 @@
 PKG_CHECK_MODULES([PSMODULES], [psmodules >= 1.1.0])
 PKG_CHECK_MODULES([IPPDB], [ippdb >= 1.1.63]) 
+PKG_CHECK_MODULES([PPSTAMP], [ippdb >= 1.1.63]) 
 
-PXTOOLS_CFLAGS="${PSLIB_CFLAGS=} ${PSMODULES_CFLAGS=} ${IPPDB_CFLAGS=}"
+PXTOOLS_CFLAGS="${PSLIB_CFLAGS=} ${PSMODULES_CFLAGS=} ${PPSTAMP_CFLAGS=} ${IPPDB_CFLAGS=}"
 PXTOOLS_LIBS="${PSLIB_LIBS=} ${PSMODULES_LIBS=} ${IPPDB_LIBS=}"
 AC_SUBST(PXTOOLS_CFLAGS,[$PXTOOLS_CFLAGS])
Index: trunk/ippTools/share/Makefile.am
===================================================================
--- trunk/ippTools/share/Makefile.am	(revision 28429)
+++ trunk/ippTools/share/Makefile.am	(revision 28486)
@@ -4,334 +4,349 @@
 
 dist_pkgdata_DATA = \
-     addtool_checkminidvodbaddrun.sql \
-     addtool_donecleanup.sql \
-     addtool_find_cam_id.sql \
-     addtool_find_pendingexp.sql \
-     addtool_find_pendingmergeprocess.sql \
-     addtool_find_processedexp.sql \
-     addtool_find_minidvodbprocessed.sql \
-     addtool_find_minidvodbrun.sql \
-     addtool_pendingcleanupexp.sql \
-     addtool_pendingcleanuprun.sql \
-     addtool_queue_cam_id.sql \
-     addtool_queue_minidvodbrun.sql \
-     addtool_revertminidvodbprocessed.sql \
-     addtool_revertprocessedexp.sql \
-     camtool_addprocessedexp.sql \
-     camtool_donecleanup.sql \
-     camtool_find_chip_id.sql \
-     camtool_pendingexp.sql \
-     camtool_find_pendingimfile.sql \
-     camtool_find_processedexp.sql \
-     camtool_pendingcleanupexp.sql \
-     camtool_pendingcleanuprun.sql \
-     camtool_queue_chip_id.sql \
-     camtool_revertprocessedexp.sql \
-     camtool_export_run.sql \
-     camtool_export_processed_exp.sql \
-     chiptool_change_exp_state.sql \
-     chiptool_change_imfile_data_state.sql \
-     chiptool_completely_processed_exp.sql \
-     chiptool_coalesce_run.sql \
-     chiptool_definecopy.sql \
-     chiptool_donecleanup.sql \
-     chiptool_find_rawexp.sql \
-     chiptool_listrun.sql \
-     chiptool_pendingcleanupimfile.sql \
-     chiptool_pendingcleanuprun.sql \
-     chiptool_pendingimfile.sql \
-     chiptool_processedimfile.sql \
-     chiptool_revertprocessedimfile.sql \
-     chiptool_revertupdatedimfile.sql \
-     chiptool_run.sql \
-     chiptool_runstate.sql \
-     chiptool_setimfiletoupdate.sql \
-     chiptool_export_run.sql \
-     chiptool_export_imfile.sql \
-     chiptool_export_processed_imfile.sql \
-     chiptool_unmasked.sql \
-     detselect_search.sql \
-     detselect_select.sql \
-     dettool_addprocessedexp.sql \
-     dettool_childlessrun.sql \
-     dettool_definebydetrun.sql \
-     dettool_detrunsummary.sql \
-     dettool_find_completed_runs.sql \
-     dettool_input.sql \
-     dettool_normalizedexp.sql \
-     dettool_normalizedimfile.sql \
-     dettool_normalizedstat.sql \
-     dettool_pending.sql \
-     dettool_pendingcleanup_detrunsummary.sql \
-     dettool_pendingcleanup_normalizedexp.sql \
-     dettool_pendingcleanup_normalizedimfile.sql \
-     dettool_pendingcleanup_normalizedstat.sql \
-     dettool_pendingcleanup_processedexp.sql \
-     dettool_pendingcleanup_processedimfile.sql \
-     dettool_pendingcleanup_residexp.sql \
-     dettool_pendingcleanup_residimfile.sql \
-     dettool_pendingcleanup_stacked.sql \
-     dettool_processedimfile.sql \
-     dettool_raw.sql \
-     dettool_residexp.sql \
-     dettool_residimfile.sql \
-     dettool_revertdetrunsummary.sql \
-     dettool_revertnormalizedexp.sql \
-     dettool_revertnormalizedimfile.sql \
-     dettool_revertnormalizedstat.sql \
-     dettool_revertprocessedexp.sql \
-     dettool_revertprocessedimfile.sql \
-     dettool_revertresidexp.sql \
-     dettool_revertresidimfile.sql \
-     dettool_revertstacked.sql \
-     dettool_runs.sql \
-     dettool_stacked.sql \
-     dettool_start_new_iteration.sql \
-     dettool_stop_completed_correct_runs.sql \
-     dettool_tocorrectexp.sql \
-     dettool_tocorrectimfile.sql \
-     dettool_todetrunsummary.sql \
-     dettool_tonormalize.sql \
-     dettool_tonormalizedexp.sql \
-     dettool_tonormalizedstat.sql \
-     dettool_toprocessedexp.sql \
-     dettool_toprocessedimfile.sql \
-     dettool_toresidexp.sql \
-     dettool_toresidimfile.sql \
-     dettool_tostacked.sql \
-     difftool_change_skyfile_data_state.sql \
-     difftool_change_run_state.sql \
-     difftool_completed_runs.sql \
-     difftool_coalesce_run.sql \
-     difftool_definewarpstack_part1.sql \
-     difftool_definewarpstack_part2.sql \
-     difftool_definewarpstack_temp_create.sql \
-     difftool_definewarpwarp_temp_create.sql \
-     difftool_definewarpwarp_temp_insert.sql \
-     difftool_definewarpwarp_select.sql \
-     difftool_definewarpwarp_insert.sql \
-     difftool_definestackstack_part0.sql \
-     difftool_definestackstack_part1.sql \
-     difftool_donecleanup.sql \
-     difftool_export_input_skyfile.sql \
-     difftool_export_run.sql \
-     difftool_export_skyfile.sql \
-     difftool_inputskyfile.sql \
-     difftool_listrun.sql \
-     difftool_pendingcleanuprun.sql \
-     difftool_pendingcleanupskyfile.sql \
-     difftool_revertdiffskyfile_delete.sql \
-     difftool_revertdiffskyfile_updated.sql \
-     difftool_setskyfiletoupdate.sql \
-     difftool_skyfile.sql \
-     difftool_todiffskyfile.sql \
-     difftool_tosummary.sql \
-     difftool_addsummary.sql \
-     disttool_definebyquery_camera.sql \
-     disttool_definebyquery_chip.sql \
-     disttool_definebyquery_diff.sql \
-     disttool_definebyquery_fake.sql \
-     disttool_definebyquery_raw.sql \
-     disttool_definebyquery_stack.sql \
-     disttool_definebyquery_warp.sql \
-     disttool_definebyquery_SSdiff.sql \
-     disttool_defineinterest.sql \
-     disttool_listfilesets.sql \
-     disttool_listinterests.sql \
-     disttool_pending_camera.sql \
-     disttool_pending_chip.sql \
-     disttool_pending_diff.sql \
-     disttool_pending_fake.sql \
-     disttool_pending_raw.sql \
-     disttool_pending_stack.sql \
-     disttool_pending_warp.sql \
-     disttool_pending_SSdiff.sql \
-     disttool_pendingfileset.sql \
-     disttool_pendingdest.sql \
-     disttool_pendingcleanup.sql \
-     disttool_processedcomponent.sql \
-     disttool_queuercrun.sql \
-     disttool_revertrcrun.sql \
-     disttool_revertrun.sql \
-     disttool_revertcomponent.sql \
-     disttool_revertfileset.sql \
-     disttool_toadvance.sql \
-     disttool_updateinterest.sql \
-     disttool_updatercrun.sql \
-     dqstatstool_createbundle.sql \
-     dqstatstool_definebyquery.sql \
-     dqstatstool_get_contents.sql \
-     dqstatstool_get_run.sql \
-     faketool_change_exp_state.sql \
-     faketool_change_imfile_data_state.sql \
-     faketool_completely_processed_exp.sql \
-     faketool_donecleanup.sql \
-     faketool_export_processed_imfile.sql \
-     faketool_export_run.sql \
-     faketool_find_camrun.sql \
-     faketool_find_pendingexp.sql \
-     faketool_pendingcleanupimfile.sql \
-     faketool_pendingcleanuprun.sql \
-     faketool_pendingimfile.sql \
-     faketool_processedimfile.sql \
-     faketool_queue_cam_id.sql \
-     faketool_revertprocessedimfile.sql \
-     faketool_unmasked.sql \
-     flatcorr_chiprundone.sql \
-     flatcorr_camerarundone.sql \
-     flatcorr_pendingprocess.sql \
-     flatcorr_inputimfile.sql \
-     flatcorr_dropchip.sql \
-     flatcorr_dropcamera.sql \
-     magictool_addmask.sql \
-     magictool_restore_camera.sql \
-     magictool_restore_chip.sql \
-     magictool_restore_diff.sql \
-     magictool_restore_raw.sql \
-     magictool_restore_warp.sql \
-     magictool_create_tmp_warpcomplete.sql \
-     magictool_definebyquery_insert.sql \
-     magictool_definebyquery_select.sql \
-     magictool_inputs.sql \
-     magictool_inputskyfile.sql \
-     magictool_mask.sql \
-     magictool_tomask.sql \
-     magictool_toprocess_inputs.sql \
-     magictool_toprocess_runs.sql \
-     magictool_toprocess_tree.sql \
-     magictool_toskyfilemask.sql \
-     magictool_totree.sql \
-     magictool_diffskyfile.sql \
-     magictool_warpskyfile.sql \
-     magictool_chipprocessedimfile.sql \
-     magictool_rawimfile.sql \
-     magictool_revertnode.sql \
-     magictool_exposure.sql \
-     magicdstool_clearstatefaults.sql \
-     magicdstool_completed_runs.sql \
-     magicdstool_completedrevert.sql \
-     magicdstool_definebyquery_raw.sql \
-     magicdstool_definebyquery_chip.sql \
-     magicdstool_definebyquery_camera.sql \
-     magicdstool_definebyquery_warp.sql \
-     magicdstool_definebyquery_diff.sql \
-     magicdstool_definecopy_chip.sql \
-     magicdstool_definecopy_warp.sql \
-     magicdstool_getrunids.sql \
-     magicdstool_getskycells.sql \
-     magicdstool_revertdestreakedfile.sql \
-     magicdstool_tocleanup.sql \
-     magicdstool_todestreak_camera.sql \
-     magicdstool_todestreak_chip.sql \
-     magicdstool_todestreak_diff.sql \
-     magicdstool_todestreak_raw.sql \
-     magicdstool_todestreak_warp.sql \
-     magicdstool_toremove.sql \
-     magicdstool_torevert_raw.sql \
-     magicdstool_torevert_chip.sql \
-     magicdstool_torevert_camera.sql \
-     magicdstool_torevert_warp.sql \
-     magicdstool_torevert_diff.sql \
-     pstamptool_completedreq.sql \
-     pstamptool_datastore.sql \
-     pstamptool_getdependent.sql \
-     pstamptool_listjob.sql \
-     pstamptool_pendingcleanup.sql \
-     pstamptool_pendingdependent.sql \
-     pstamptool_pendingjob.sql \
-     pstamptool_pendingreq.sql \
-     pstamptool_project.sql \
-     pstamptool_revertdependent.sql \
-     pstamptool_revertjob.sql \
-     pstamptool_revertreq.sql \
-     pstamptool_revertreq_deletejobs.sql \
-     pstamptool_updatejob.sql \
-     pxadmin_create_tables.sql \
-     pxadmin_create_mirror_tables.sql \
-     pxadmin_drop_tables.sql \
-     pxadmin_update_version.sql \
-     pubtool_definerun.sql \
-     pubtool_pending.sql \
-     pubtool_revert.sql \
-     pztool_find_completed_exp.sql \
-     pztool_pendingimfile.sql \
-     pztool_revert_downloadimfile_faults.sql \
-     pztool_revert_fileset_faults.sql \
-     pztool_revertcopied.sql \
-     receivetool_list.sql \
-     receivetool_addfileset.sql \
-     receivetool_pendingfileset.sql \
-     receivetool_pendingfile.sql \
-     receivetool_revert.sql \
-     receivetool_toadvance.sql \
-     regtool_create_dup_table.sql \
-     regtool_export_exp.sql \
-     regtool_export_imfile.sql \
-     regtool_pendingexp.sql \
-     regtool_pendingimfile.sql \
-     regtool_populate_dup_table.sql \
-     regtool_processedexp.sql \
-     regtool_processedimfile.sql \
-     regtool_revertprocessedexp.sql \
-     regtool_revertprocessedimfile.sql \
-     regtool_updateprocessedimfile.sql \
-     regtool_pendingcompressimfile.sql \
-     regtool_finishcompressexp.sql \
-     regtool_updatebyquery.sql \
-     regtool_updatebyqueryimfile.sql \
-     stacktool_associationdefine_select.sql \
-     stacktool_definebyquery_insert.sql \
-     stacktool_definebyquery_insert_random_part1.sql \
-     stacktool_definebyquery_insert_random_part2.sql \
-     stacktool_definebyquery_select.sql \
-     stacktool_definebyquery_test.sql \
-     stacktool_donecleanup.sql \
-     stacktool_export_input_skyfile.sql \
-     stacktool_export_run.sql \
-     stacktool_export_sum_skyfile.sql \
-     stacktool_find_complete_warps.sql \
-     stacktool_inputskyfile.sql \
-     stacktool_pendingcleanuprun.sql \
-     stacktool_pendingcleanupskyfile.sql \
-     stacktool_revertsumskyfile_delete.sql \
-     stacktool_sumskyfile.sql \
-     stacktool_sassskyfile.sql \
-     stacktool_tosum.sql \
-     stacktool_tosummary.sql \
-     stacktool_addsummary.sql \
-     staticskytool_definebyquery_select.sql \
-     staticskytool_definebyquery_inputs.sql \
-     staticskytool_inputs.sql \
-     staticskytool_todo.sql \
-     staticskytool_result.sql \
-     staticskytool_revert.sql \
-     warptool_change_skyfile_data_state.sql \
-     warptool_change_run_state.sql \
-     warptool_definebyquery.sql \
-     warptool_donecleanup.sql \
-     warptool_exp.sql \
-     warptool_export_imfile.sql \
-     warptool_export_run.sql \
-     warptool_export_skyfile.sql \
-     warptool_export_skycell_map.sql \
-     warptool_finished_run_select.sql \
-     warptool_finish_run.sql \
-     warptool_coalesce_run.sql \
-     warptool_imfile.sql \
-     warptool_listrun.sql \
-     warptool_pendingcleanuprun.sql \
-     warptool_pendingcleanupskyfile.sql \
-     warptool_revertoverlap.sql \
-     warptool_revertwarped_delete.sql \
-     warptool_revertwarped_updated.sql \
-     warptool_runstate.sql \
-     warptool_scmap.sql \
-     warptool_setskyfiletoupdate.sql \
-     warptool_tooverlap.sql \
-     warptool_towarped.sql \
-     warptool_updateskyfile.sql \
-     warptool_warped.sql \
-     warptool_tosummary.sql \
-     warptool_addsummary.sql \
+	addtool_checkminidvodbaddrun.sql \
+	addtool_donecleanup.sql \
+	addtool_find_cam_id.sql \
+	addtool_find_pendingexp.sql \
+	addtool_find_pendingmergeprocess.sql \
+	addtool_find_processedexp.sql \
+	addtool_find_minidvodbprocessed.sql \
+	addtool_find_minidvodbrun.sql \
+	addtool_pendingcleanupexp.sql \
+	addtool_pendingcleanuprun.sql \
+	addtool_queue_cam_id.sql \
+	addtool_queue_minidvodbrun.sql \
+	addtool_revertminidvodbprocessed.sql \
+	addtool_revertprocessedexp.sql \
+	bgtool_advancechip.sql \
+	bgtool_advancewarp.sql \
+	bgtool_chipinputs.sql \
+	bgtool_chip.sql \
+	bgtool_cleanedchip.sql \
+	bgtool_cleanedwarp.sql \
+	bgtool_definechip.sql \
+	bgtool_definewarp.sql \
+	bgtool_revertchip.sql \
+	bgtool_revertwarp.sql \
+	bgtool_tochip.sql \
+	bgtool_tocleanchip.sql \
+	bgtool_tocleanwarp.sql \
+	bgtool_towarp.sql \
+	bgtool_warpinputs.sql \
+	bgtool_warp.sql \
+	camtool_donecleanup.sql \
+	camtool_find_chip_id.sql \
+	camtool_pendingexp.sql \
+	camtool_find_pendingimfile.sql \
+	camtool_find_processedexp.sql \
+	camtool_pendingcleanupexp.sql \
+	camtool_pendingcleanuprun.sql \
+	camtool_queue_chip_id.sql \
+	camtool_revertprocessedexp.sql \
+	camtool_export_run.sql \
+	camtool_export_processed_exp.sql \
+	chiptool_change_exp_state.sql \
+	chiptool_change_imfile_data_state.sql \
+	chiptool_completely_processed_exp.sql \
+	chiptool_coalesce_run.sql \
+	chiptool_definecopy.sql \
+	chiptool_donecleanup.sql \
+	chiptool_find_rawexp.sql \
+	chiptool_listrun.sql \
+	chiptool_pendingcleanupimfile.sql \
+	chiptool_pendingcleanuprun.sql \
+	chiptool_pendingimfile.sql \
+	chiptool_processedimfile.sql \
+	chiptool_revertprocessedimfile.sql \
+	chiptool_revertupdatedimfile.sql \
+	chiptool_run.sql \
+	chiptool_runstate.sql \
+	chiptool_setimfiletoupdate.sql \
+	chiptool_export_run.sql \
+	chiptool_export_imfile.sql \
+	chiptool_export_processed_imfile.sql \
+	chiptool_unmasked.sql \
+	detselect_search.sql \
+	detselect_select.sql \
+	dettool_addprocessedexp.sql \
+	dettool_childlessrun.sql \
+	dettool_definebydetrun.sql \
+	dettool_detrunsummary.sql \
+	dettool_find_completed_runs.sql \
+	dettool_input.sql \
+	dettool_normalizedexp.sql \
+	dettool_normalizedimfile.sql \
+	dettool_normalizedstat.sql \
+	dettool_pending.sql \
+	dettool_pendingcleanup_detrunsummary.sql \
+	dettool_pendingcleanup_normalizedexp.sql \
+	dettool_pendingcleanup_normalizedimfile.sql \
+	dettool_pendingcleanup_normalizedstat.sql \
+	dettool_pendingcleanup_processedexp.sql \
+	dettool_pendingcleanup_processedimfile.sql \
+	dettool_pendingcleanup_residexp.sql \
+	dettool_pendingcleanup_residimfile.sql \
+	dettool_pendingcleanup_stacked.sql \
+	dettool_processedimfile.sql \
+	dettool_raw.sql \
+	dettool_residexp.sql \
+	dettool_residimfile.sql \
+	dettool_revertdetrunsummary.sql \
+	dettool_revertnormalizedexp.sql \
+	dettool_revertnormalizedimfile.sql \
+	dettool_revertnormalizedstat.sql \
+	dettool_revertprocessedexp.sql \
+	dettool_revertprocessedimfile.sql \
+	dettool_revertresidexp.sql \
+	dettool_revertresidimfile.sql \
+	dettool_revertstacked.sql \
+	dettool_runs.sql \
+	dettool_stacked.sql \
+	dettool_start_new_iteration.sql \
+	dettool_stop_completed_correct_runs.sql \
+	dettool_tocorrectexp.sql \
+	dettool_tocorrectimfile.sql \
+	dettool_todetrunsummary.sql \
+	dettool_tonormalize.sql \
+	dettool_tonormalizedexp.sql \
+	dettool_tonormalizedstat.sql \
+	dettool_toprocessedexp.sql \
+	dettool_toprocessedimfile.sql \
+	dettool_toresidexp.sql \
+	dettool_toresidimfile.sql \
+	dettool_tostacked.sql \
+	difftool_change_skyfile_data_state.sql \
+	difftool_change_run_state.sql \
+	difftool_completed_runs.sql \
+	difftool_coalesce_run.sql \
+	difftool_definewarpstack_part1.sql \
+	difftool_definewarpstack_part2.sql \
+	difftool_definewarpstack_temp_create.sql \
+	difftool_definewarpwarp_temp_create.sql \
+	difftool_definewarpwarp_temp_insert.sql \
+	difftool_definewarpwarp_select.sql \
+	difftool_definewarpwarp_insert.sql \
+	difftool_definestackstack_part0.sql \
+	difftool_definestackstack_part1.sql \
+	difftool_donecleanup.sql \
+	difftool_export_input_skyfile.sql \
+	difftool_export_run.sql \
+	difftool_export_skyfile.sql \
+	difftool_inputskyfile.sql \
+	difftool_listrun.sql \
+	difftool_pendingcleanuprun.sql \
+	difftool_pendingcleanupskyfile.sql \
+	difftool_revertdiffskyfile_delete.sql \
+	difftool_revertdiffskyfile_updated.sql \
+	difftool_setskyfiletoupdate.sql \
+	difftool_skyfile.sql \
+	difftool_todiffskyfile.sql \
+	difftool_tosummary.sql \
+	difftool_addsummary.sql \
+	disttool_definebyquery_camera.sql \
+	disttool_definebyquery_chip.sql \
+	disttool_definebyquery_diff.sql \
+	disttool_definebyquery_fake.sql \
+	disttool_definebyquery_raw.sql \
+	disttool_definebyquery_stack.sql \
+	disttool_definebyquery_warp.sql \
+	disttool_definebyquery_SSdiff.sql \
+	disttool_defineinterest.sql \
+	disttool_listfilesets.sql \
+	disttool_listinterests.sql \
+	disttool_pending_camera.sql \
+	disttool_pending_chip.sql \
+	disttool_pending_diff.sql \
+	disttool_pending_fake.sql \
+	disttool_pending_raw.sql \
+	disttool_pending_stack.sql \
+	disttool_pending_warp.sql \
+	disttool_pending_SSdiff.sql \
+	disttool_pendingfileset.sql \
+	disttool_pendingdest.sql \
+	disttool_pendingcleanup.sql \
+	disttool_processedcomponent.sql \
+	disttool_queuercrun.sql \
+	disttool_revertrcrun.sql \
+	disttool_revertrun.sql \
+	disttool_revertcomponent.sql \
+	disttool_revertfileset.sql \
+	disttool_toadvance.sql \
+	disttool_updateinterest.sql \
+	disttool_updatercrun.sql \
+	dqstatstool_createbundle.sql \
+	dqstatstool_definebyquery.sql \
+	dqstatstool_get_contents.sql \
+	dqstatstool_get_run.sql \
+	faketool_change_exp_state.sql \
+	faketool_change_imfile_data_state.sql \
+	faketool_completely_processed_exp.sql \
+	faketool_donecleanup.sql \
+	faketool_export_processed_imfile.sql \
+	faketool_export_run.sql \
+	faketool_find_camrun.sql \
+	faketool_find_pendingexp.sql \
+	faketool_pendingcleanupimfile.sql \
+	faketool_pendingcleanuprun.sql \
+	faketool_pendingimfile.sql \
+	faketool_processedimfile.sql \
+	faketool_queue_cam_id.sql \
+	faketool_revertprocessedimfile.sql \
+	faketool_unmasked.sql \
+	flatcorr_chiprundone.sql \
+	flatcorr_camerarundone.sql \
+	flatcorr_pendingprocess.sql \
+	flatcorr_inputimfile.sql \
+	flatcorr_dropchip.sql \
+	flatcorr_dropcamera.sql \
+	magictool_addmask.sql \
+	magictool_restore_camera.sql \
+	magictool_restore_chip.sql \
+	magictool_restore_diff.sql \
+	magictool_restore_raw.sql \
+	magictool_restore_warp.sql \
+	magictool_create_tmp_warpcomplete.sql \
+	magictool_definebyquery_insert.sql \
+	magictool_definebyquery_select.sql \
+	magictool_inputs.sql \
+	magictool_inputskyfile.sql \
+	magictool_mask.sql \
+	magictool_tomask.sql \
+	magictool_toprocess_inputs.sql \
+	magictool_toprocess_runs.sql \
+	magictool_toprocess_tree.sql \
+	magictool_toskyfilemask.sql \
+	magictool_totree.sql \
+	magictool_diffskyfile.sql \
+	magictool_warpskyfile.sql \
+	magictool_chipprocessedimfile.sql \
+	magictool_rawimfile.sql \
+	magictool_revertnode.sql \
+	magictool_exposure.sql \
+	magicdstool_clearstatefaults.sql \
+	magicdstool_completed_runs.sql \
+	magicdstool_completedrevert.sql \
+	magicdstool_definebyquery_raw.sql \
+	magicdstool_definebyquery_chip.sql \
+	magicdstool_definebyquery_camera.sql \
+	magicdstool_definebyquery_warp.sql \
+	magicdstool_definebyquery_diff.sql \
+	magicdstool_definecopy_chip.sql \
+	magicdstool_definecopy_warp.sql \
+	magicdstool_getrunids.sql \
+	magicdstool_getskycells.sql \
+	magicdstool_revertdestreakedfile.sql \
+	magicdstool_tocleanup.sql \
+	magicdstool_todestreak_camera.sql \
+	magicdstool_todestreak_chip.sql \
+	magicdstool_todestreak_diff.sql \
+	magicdstool_todestreak_raw.sql \
+	magicdstool_todestreak_warp.sql \
+	magicdstool_toremove.sql \
+	magicdstool_torevert_raw.sql \
+	magicdstool_torevert_chip.sql \
+	magicdstool_torevert_camera.sql \
+	magicdstool_torevert_warp.sql \
+	magicdstool_torevert_diff.sql \
+	pstamptool_completedreq.sql \
+	pstamptool_datastore.sql \
+	pstamptool_getdependent.sql \
+	pstamptool_listjob.sql \
+	pstamptool_pendingcleanup.sql \
+	pstamptool_pendingdependent.sql \
+	pstamptool_pendingjob.sql \
+	pstamptool_pendingreq.sql \
+	pstamptool_project.sql \
+	pstamptool_revertdependent.sql \
+	pstamptool_revertjob.sql \
+	pstamptool_revertreq.sql \
+	pstamptool_revertreq_deletejobs.sql \
+	pstamptool_updatejob.sql \
+	pxadmin_create_tables.sql \
+	pxadmin_create_mirror_tables.sql \
+	pxadmin_drop_tables.sql \
+	pxadmin_update_version.sql \
+	pubtool_definerun.sql \
+	pubtool_pending.sql \
+	pubtool_revert.sql \
+	pztool_find_completed_exp.sql \
+	pztool_pendingimfile.sql \
+	pztool_revert_downloadimfile_faults.sql \
+	pztool_revert_fileset_faults.sql \
+	pztool_revertcopied.sql \
+	receivetool_list.sql \
+	receivetool_addfileset.sql \
+	receivetool_pendingfileset.sql \
+	receivetool_pendingfile.sql \
+	receivetool_revert.sql \
+	receivetool_toadvance.sql \
+	regtool_create_dup_table.sql \
+	regtool_export_exp.sql \
+	regtool_export_imfile.sql \
+	regtool_pendingexp.sql \
+	regtool_pendingimfile.sql \
+	regtool_populate_dup_table.sql \
+	regtool_processedexp.sql \
+	regtool_processedimfile.sql \
+	regtool_revertprocessedexp.sql \
+	regtool_revertprocessedimfile.sql \
+	regtool_updateprocessedimfile.sql \
+	regtool_pendingcompressimfile.sql \
+	regtool_finishcompressexp.sql \
+	regtool_updatebyquery.sql \
+	regtool_updatebyqueryimfile.sql \
+	stacktool_associationdefine_select.sql \
+	stacktool_definebyquery_insert.sql \
+	stacktool_definebyquery_insert_random_part1.sql \
+	stacktool_definebyquery_insert_random_part2.sql \
+	stacktool_definebyquery_select.sql \
+	stacktool_definebyquery_test.sql \
+	stacktool_donecleanup.sql \
+	stacktool_export_input_skyfile.sql \
+	stacktool_export_run.sql \
+	stacktool_export_sum_skyfile.sql \
+	stacktool_find_complete_warps.sql \
+	stacktool_inputskyfile.sql \
+	stacktool_pendingcleanuprun.sql \
+	stacktool_pendingcleanupskyfile.sql \
+	stacktool_revertsumskyfile_delete.sql \
+	stacktool_sumskyfile.sql \
+	stacktool_sassskyfile.sql \
+	stacktool_tosum.sql \
+	stacktool_tosummary.sql \
+	stacktool_addsummary.sql \
+	staticskytool_definebyquery_select.sql \
+	staticskytool_definebyquery_inputs.sql \
+	staticskytool_inputs.sql \
+	staticskytool_todo.sql \
+	staticskytool_result.sql \
+	staticskytool_revert.sql \
+	warptool_change_skyfile_data_state.sql \
+	warptool_change_run_state.sql \
+	warptool_definebyquery.sql \
+	warptool_donecleanup.sql \
+	warptool_exp.sql \
+	warptool_export_imfile.sql \
+	warptool_export_run.sql \
+	warptool_export_skyfile.sql \
+	warptool_export_skycell_map.sql \
+	warptool_finished_run_select.sql \
+	warptool_finish_run.sql \
+	warptool_coalesce_run.sql \
+	warptool_imfile.sql \
+	warptool_listrun.sql \
+	warptool_pendingcleanuprun.sql \
+	warptool_pendingcleanupskyfile.sql \
+	warptool_revertoverlap.sql \
+	warptool_revertwarped_delete.sql \
+	warptool_revertwarped_updated.sql \
+	warptool_runstate.sql \
+	warptool_scmap.sql \
+	warptool_setskyfiletoupdate.sql \
+	warptool_tooverlap.sql \
+	warptool_towarped.sql \
+	warptool_updateskyfile.sql \
+	warptool_warped.sql \
+	warptool_tosummary.sql \
+	warptool_addsummary.sql \
 	diffphottool_definerun.sql \
 	diffphottool_input.sql \
Index: trunk/ippTools/share/bgtool_advancechip.sql
===================================================================
--- trunk/ippTools/share/bgtool_advancechip.sql	(revision 28486)
+++ trunk/ippTools/share/bgtool_advancechip.sql	(revision 28486)
@@ -0,0 +1,15 @@
+SELECT DISTINCT
+    chipBackgroundRun.chip_bg_id,
+    chipBackgroundImfile.magicked
+FROM chipBackgroundRun
+JOIN chipProcessedImfile USING(chip_id)
+LEFT JOIN chipBackgroundImfile USING(chip_bg_id, class_id)
+WHERE chipBackgroundRun.state = 'new'
+    AND chipProcessedImfile.quality = 0
+    AND chipProcessedImfile.fault = 0
+-- WHERE hook %s
+GROUP BY chip_bg_id
+HAVING
+    COUNT(chipBackgroundImfile.class_id) = COUNT(chipProcessedImfile.class_id)
+    AND SUM(IF(chipBackgroundImfile.fault > 0, 1, 0)) = 0
+    AND SUM(IF(chipBackgroundImfile.quality > 0, 1, 0)) != COUNT(*)
Index: trunk/ippTools/share/bgtool_advancewarp.sql
===================================================================
--- trunk/ippTools/share/bgtool_advancewarp.sql	(revision 28486)
+++ trunk/ippTools/share/bgtool_advancewarp.sql	(revision 28486)
@@ -0,0 +1,15 @@
+SELECT DISTINCT
+    warpBackgroundRun.warp_bg_id,
+    warpBackgroundSkyfile.magicked
+FROM warpBackgroundRun
+JOIN warpSkyfile USING(warp_id)
+LEFT JOIN warpBackgroundSkyfile USING(warp_bg_id, skycell_id)
+WHERE warpBackgroundRun.state = 'new'
+    AND warpSkyfile.quality = 0
+    AND warpSkyfile.fault = 0
+-- WHERE hook %s
+GROUP BY warp_bg_id
+HAVING
+    COUNT(warpBackgroundSkyfile.skycell_id) = COUNT(warpSkyfile.skycell_id)
+    AND SUM(IF(warpBackgroundSkyfile.fault > 0, 1, 0)) = 0
+    AND SUM(IF(warpBackgroundSkyfile.quality > 0, 1, 0)) != COUNT(*)
Index: trunk/ippTools/share/bgtool_chip.sql
===================================================================
--- trunk/ippTools/share/bgtool_chip.sql	(revision 28486)
+++ trunk/ippTools/share/bgtool_chip.sql	(revision 28486)
@@ -0,0 +1,17 @@
+SELECT
+    chipBackgroundImfile.*,
+    chipBackgroundRun.state,
+    chipBackgroundRun.workdir,
+    chipBackgroundRun.label,
+    rawExp.exp_id,
+    rawExp.exp_name,
+    rawExp.camera,
+    rawExp.filter,
+    rawExp.dateobs,
+    rawExp.ra,
+    rawExp.decl,
+    rawExp.exp_time
+FROM chipBackgroundRun
+JOIN chipBackgroundImfile USING(chip_bg_id)
+JOIN chipRun USING(chip_id)
+JOIN rawExp USING(exp_id)
Index: trunk/ippTools/share/bgtool_chipinputs.sql
===================================================================
--- trunk/ippTools/share/bgtool_chipinputs.sql	(revision 28486)
+++ trunk/ippTools/share/bgtool_chipinputs.sql	(revision 28486)
@@ -0,0 +1,8 @@
+SELECT
+    chipProcessedImfile.*
+FROM chipBackgroundRun
+JOIN chipRun USING(chip_id)
+JOIN chipProcessedImfile USING(chip_id)
+WHERE chipRun.state = 'full'
+    AND chipProcessedImfile.fault = 0
+    AND chipProcessedImfile.quality = 0
Index: trunk/ippTools/share/bgtool_cleanedchip.sql
===================================================================
--- trunk/ippTools/share/bgtool_cleanedchip.sql	(revision 28486)
+++ trunk/ippTools/share/bgtool_cleanedchip.sql	(revision 28486)
@@ -0,0 +1,3 @@
+UPDATE chipBackgroundRun
+SET state = '%s'
+WHERE state IN ('goto_cleaned', 'goto_scrubbed', 'goto_purged')
Index: trunk/ippTools/share/bgtool_cleanedwarp.sql
===================================================================
--- trunk/ippTools/share/bgtool_cleanedwarp.sql	(revision 28486)
+++ trunk/ippTools/share/bgtool_cleanedwarp.sql	(revision 28486)
@@ -0,0 +1,3 @@
+UPDATE warpBackgroundRun
+SET state = '%s'
+WHERE state IN ('goto_cleaned', 'goto_scrubbed', 'goto_purged')
Index: trunk/ippTools/share/bgtool_definechip.sql
===================================================================
--- trunk/ippTools/share/bgtool_definechip.sql	(revision 28486)
+++ trunk/ippTools/share/bgtool_definechip.sql	(revision 28486)
@@ -0,0 +1,6 @@
+SELECT
+    chipRun.*
+FROM chipRun
+JOIN rawExp USING(exp_id)
+LEFT JOIN chipBackgroundRun USING(chip_id)
+WHERE chipRun.state = 'full'
Index: trunk/ippTools/share/bgtool_definewarp.sql
===================================================================
--- trunk/ippTools/share/bgtool_definewarp.sql	(revision 28486)
+++ trunk/ippTools/share/bgtool_definewarp.sql	(revision 28486)
@@ -0,0 +1,11 @@
+SELECT
+    warpRun.*,
+    chipBackgroundRun.chip_bg_id
+FROM warpRun
+JOIN fakeRun USING(fake_id)
+JOIN camRun USING(cam_id)
+JOIN chipRun USING(chip_id)
+JOIN chipBackgroundRun USING(chip_id)
+JOIN rawExp USING(exp_id)
+LEFT JOIN warpBackgroundRun USING(chip_bg_id)
+WHERE chipBackgroundRun.state = 'full'
Index: trunk/ippTools/share/bgtool_revertchip.sql
===================================================================
--- trunk/ippTools/share/bgtool_revertchip.sql	(revision 28486)
+++ trunk/ippTools/share/bgtool_revertchip.sql	(revision 28486)
@@ -0,0 +1,4 @@
+DELETE chipBackgroundImfile
+FROM chipBackgroundRun
+JOIN chipBackgroundImfile USING(chip_bg_id)
+WHERE chipBackgroundImfile.fault != 0
Index: trunk/ippTools/share/bgtool_revertwarp.sql
===================================================================
--- trunk/ippTools/share/bgtool_revertwarp.sql	(revision 28486)
+++ trunk/ippTools/share/bgtool_revertwarp.sql	(revision 28486)
@@ -0,0 +1,4 @@
+DELETE warpBackgroundSkyfile
+FROM warpBackgroundRun
+JOIN warpBackgroundSkyfile USING(warp_bg_id)
+WHERE warpBackgroundSkyfile.fault != 0
Index: trunk/ippTools/share/bgtool_tochip.sql
===================================================================
--- trunk/ippTools/share/bgtool_tochip.sql	(revision 28486)
+++ trunk/ippTools/share/bgtool_tochip.sql	(revision 28486)
@@ -0,0 +1,18 @@
+SELECT
+    chipBackgroundRun.*,
+    class_id,
+    rawExp.exp_tag,
+    rawExp.camera
+FROM chipBackgroundRun
+JOIN chipRun USING(chip_id)
+JOIN rawExp USING(exp_id)
+JOIN chipProcessedImfile USING(chip_id)
+LEFT JOIN chipBackgroundImfile USING(chip_bg_id, class_id)
+LEFT JOIN Label ON chipBackgroundRun.label = Label.label
+WHERE chipBackgroundImfile.chip_bg_id IS NULL
+    AND chipRun.state = 'full'
+    AND chipProcessedImfile.fault = 0
+    AND chipProcessedImfile.quality = 0
+    AND (Label.active OR Label.active IS NULL)
+-- WHERE hook %s
+ORDER BY priority DESC, chip_bg_id
Index: trunk/ippTools/share/bgtool_tocleanchip.sql
===================================================================
--- trunk/ippTools/share/bgtool_tocleanchip.sql	(revision 28486)
+++ trunk/ippTools/share/bgtool_tocleanchip.sql	(revision 28486)
@@ -0,0 +1,9 @@
+SELECT
+    chipBackgroundRun.chip_bg_id,
+    chipBackgroundRun.state,
+    rawExp.camera
+FROM chipBackgroundRun
+JOIN chipRun USING(chip_id)
+JOIN rawExp USING(exp_id)
+WHERE chipBackgroundRun.state IN ('goto_cleaned', 'goto_scrubbed', 'goto_purged')
+
Index: trunk/ippTools/share/bgtool_tocleanwarp.sql
===================================================================
--- trunk/ippTools/share/bgtool_tocleanwarp.sql	(revision 28486)
+++ trunk/ippTools/share/bgtool_tocleanwarp.sql	(revision 28486)
@@ -0,0 +1,12 @@
+SELECT
+    warpBackgroundRun.warp_bg_id,
+    warpBackgroundRun.state,
+    rawExp.camera
+FROM warpBackgroundRun
+JOIN warpRun USING(warp_id)
+JOIN fakeRun USING(fake_id)
+JOIN camRun USING(cam_id)
+JOIN chipRun USING(chip_id)
+JOIN rawExp USING(exp_id)
+WHERE warpBackgroundRun.state IN ('goto_cleaned', 'goto_scrubbed', 'goto_purged')
+
Index: trunk/ippTools/share/bgtool_towarp.sql
===================================================================
--- trunk/ippTools/share/bgtool_towarp.sql	(revision 28486)
+++ trunk/ippTools/share/bgtool_towarp.sql	(revision 28486)
@@ -0,0 +1,23 @@
+SELECT
+    warpBackgroundRun.*,
+    warpRun.tess_id,
+    skycell_id,
+    rawExp.exp_tag,
+    rawExp.camera
+FROM warpBackgroundRun
+JOIN warpRun USING(warp_id)
+JOIN warpSkyCellMap USING(warp_id)
+JOIN warpSkyfile USING(warp_id, skycell_id)
+JOIN chipBackgroundRun USING(chip_bg_id)
+JOIN chipBackgroundImfile USING(chip_bg_id, class_id)
+JOIN chipRun USING(chip_id)
+JOIN rawExp USING(exp_id)
+LEFT JOIN warpBackgroundSkyfile USING(warp_bg_id, skycell_id)
+LEFT JOIN Label ON Label.label = warpBackgroundRun.label
+WHERE warpBackgroundSkyfile.warp_bg_id IS NULL
+    AND chipBackgroundRun.state = 'full'
+    AND chipBackgroundImfile.fault = 0
+    AND chipBackgroundImfile.quality = 0
+    AND (Label.active OR Label.active IS NULL)
+-- WHERE hook %s
+ORDER BY priority DESC, chip_bg_id
Index: trunk/ippTools/share/bgtool_warp.sql
===================================================================
--- trunk/ippTools/share/bgtool_warp.sql	(revision 28486)
+++ trunk/ippTools/share/bgtool_warp.sql	(revision 28486)
@@ -0,0 +1,20 @@
+SELECT
+    warpBackgroundSkyfile.*,
+    warpBackgroundRun.state,
+    warpBackgroundRun.workdir,
+    warpBackgroundRun.label,
+    rawExp.exp_id,
+    rawExp.exp_name,
+    rawExp.camera,
+    rawExp.filter,
+    rawExp.dateobs,
+    rawExp.ra,
+    rawExp.decl,
+    rawExp.exp_time
+FROM warpBackgroundRun
+JOIN warpBackgroundImfile USING(warp_bg_id)
+JOIN warpRun USING(warp_id)
+JOIN fakeRun USING(fake_id)
+JOIN camRun USING(cam_id)
+JOIN chipRun USING(chip_id)
+JOIN rawExp USING(exp_id)
Index: trunk/ippTools/share/bgtool_warpinputs.sql
===================================================================
--- trunk/ippTools/share/bgtool_warpinputs.sql	(revision 28486)
+++ trunk/ippTools/share/bgtool_warpinputs.sql	(revision 28486)
@@ -0,0 +1,17 @@
+SELECT
+    chipBackgroundImfile.path_base AS chip_path_base,
+    camProcessedExp.path_base AS cam_path_base
+FROM warpBackgroundRun
+JOIN warpRun USING(warp_id)
+JOIN warpSkyCellMap USING(warp_id)
+JOIN warpSkyfile USING(warp_id, skycell_id)
+JOIN chipBackgroundRun USING(chip_bg_id)
+JOIN chipBackgroundImfile USING(chip_bg_id, class_id)
+JOIN fakeRun USING(fake_id)
+JOIN camProcessedExp USING(cam_id)
+WHERE warpRun.state = 'full'
+    AND warpSkyfile.fault = 0
+    AND warpSkyfile.quality = 0
+    AND chipBackgroundRun.state = 'full'
+    AND chipBackgroundImfile.fault = 0
+    AND chipBackgroundImfile.quality = 0
Index: trunk/ippTools/share/pxadmin_create_tables.sql
===================================================================
--- trunk/ippTools/share/pxadmin_create_tables.sql	(revision 28429)
+++ trunk/ippTools/share/pxadmin_create_tables.sql	(revision 28486)
@@ -1715,4 +1715,6 @@
 ) ENGINE=innodb DEFAULT CHARSET=latin1;
 
+
+-- Processing labels with their priorities
 CREATE TABLE Label (
     label       VARCHAR(64),
@@ -1723,4 +1725,101 @@
     KEY(priority),
     KEY(active)
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
+-- Tables to support background restoration
+
+-- Background replacement on a chipRun
+CREATE TABLE chipBackgroundRun (
+    chip_bg_id BIGINT AUTO_INCREMENT, -- unique identifier
+    chip_id BIGINT NOT NULL,          -- link to chipRun
+    state VARCHAR(64) NOT NULL,       -- state of run (new, full, etc.)
+    workdir VARCHAR(255) NOT NULL,    -- working directory
+    label VARCHAR(64),                -- processing label
+    data_group VARCHAR(64),           -- group for data
+    dist_group VARCHAR(64),           -- group for distribution
+    reduction VARCHAR(64),    -- reduction class (for altering recipe)
+    note VARCHAR(255),        -- note
+    registered TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- time run was registered
+    magicked BIGINT DEFAULT 0 NOT NULL, -- magic status
+    PRIMARY KEY(chip_bg_id),
+    KEY(chip_id),
+    KEY(state),
+    KEY(label),
+    KEY(data_group),
+    KEY(dist_group),
+    FOREIGN KEY(chip_id) REFERENCES chipRun(chip_id)
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
+-- Results of background replacement from chipBackgroundRun
+CREATE TABLE chipBackgroundImfile (
+    chip_bg_id BIGINT NOT NULL,        -- unique identifier
+    class_id VARCHAR(64) NOT NULL,     -- class (component) identifier
+    path_base VARCHAR(255) NOT NULL,   -- root name for outputs
+    magicked BIGINT,                   -- magic_id if magicked
+    dtime_script FLOAT,                -- elapsed time for script
+    hostname VARCHAR(64) NOT NULL,     -- host that executed script
+    quality SMALLINT NOT NULL,         -- bad quality flag
+    fault SMALLINT NOT NULL,           -- fault code
+    software_ver VARCHAR(16),          -- software version
+    bg FLOAT,                          -- background level
+    bg_stdev FLOAT,                    -- stdev of background
+    maskfrac_npix FLOAT,               -- Number of pixels masked
+    maskfrac_static FLOAT,             -- Fraction masked static
+    maskfrac_dynamic FLOAT,            -- Fraction masked dynamic
+    maskfrac_magic FLOAT,              -- Fraction masked magic
+    maskfrac_advisory FLOAT,           -- Fraction masked advisory
+    PRIMARY KEY(chip_bg_id,class_id),
+    KEY(fault),
+    KEY(quality),
+    FOREIGN KEY(chip_bg_id) REFERENCES chipBackgroundRun(chip_bg_id)
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
+-- Background replacement on a warpRun (utilising chipBackgroundRun)
+CREATE TABLE warpBackgroundRun (
+    warp_bg_id BIGINT AUTO_INCREMENT, -- unique identifier
+    warp_id BIGINT NOT NULL,          -- link to warpRun
+    chip_bg_id BIGINT NOT NULL,       -- link to chipBackgroundRun
+    state VARCHAR(64) NOT NULL,       -- state of run (new, full, etc.)
+    workdir VARCHAR(255) NOT NULL,    -- working directory
+    label VARCHAR(64),                -- processing label
+    data_group VARCHAR(64),           -- group for data
+    dist_group VARCHAR(64),           -- group for distribution
+    reduction VARCHAR(64),    -- reduction class (for altering recipe)
+    note VARCHAR(255),        -- note
+    registered TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- time run was registered
+    magicked BIGINT DEFAULT 0 NOT NULL, -- magic status
+    PRIMARY KEY(warp_bg_id),
+    KEY(warp_id),
+    KEY(chip_bg_id),
+    KEY(state),
+    KEY(label),
+    KEY(data_group),
+    KEY(dist_group),
+    FOREIGN KEY(warp_id) REFERENCES warpRun(warp_id),
+    FOREIGN KEY(chip_bg_id) REFERENCES chipBackgroundRun(chip_bg_id)
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
+-- Results of background replacement from warpBackgroundRun
+CREATE TABLE warpBackgroundSkyfile (
+    warp_bg_id BIGINT NOT NULL,        -- unique identifier
+    skycell_id VARCHAR(64) NOT NULL,   -- skycell identifier
+    path_base VARCHAR(255) NOT NULL,   -- root name for outputs
+    magicked BIGINT,                   -- magic_id if magicked
+    dtime_script FLOAT,                -- elapsed time for script
+    hostname VARCHAR(64) NOT NULL,     -- host that executed script
+    quality SMALLINT NOT NULL,         -- bad quality flag
+    fault SMALLINT NOT NULL,           -- fault code
+    software_ver VARCHAR(16),          -- software version
+    bg FLOAT,                          -- background level
+    bg_stdev FLOAT,                    -- stdev of background
+    maskfrac_npix FLOAT,               -- Number of pixels masked
+    maskfrac_static FLOAT,             -- Fraction masked static
+    maskfrac_dynamic FLOAT,            -- Fraction masked dynamic
+    maskfrac_magic FLOAT,              -- Fraction masked magic
+    maskfrac_advisory FLOAT,           -- Fraction masked advisory
+    PRIMARY KEY(warp_bg_id,skycell_id),
+    KEY(fault),
+    KEY(quality),
+    FOREIGN KEY(warp_bg_id) REFERENCES warpBackgroundRun(warp_bg_id)
 ) ENGINE=innodb DEFAULT CHARSET=latin1;
 
Index: trunk/ippTools/share/pxadmin_drop_tables.sql
===================================================================
--- trunk/ippTools/share/pxadmin_drop_tables.sql	(revision 28429)
+++ trunk/ippTools/share/pxadmin_drop_tables.sql	(revision 28486)
@@ -91,4 +91,8 @@
 DROP TABLE IF EXISTS Label;
 DROP TABLE IF EXISTS pstampWebRequest;
+DROP TABLE IF EXISTS chipBackgroundRun;
+DROP TABLE IF EXISTS chipBackgroundImfile;
+DROP TABLE IF EXISTS warpBackgroundRun;
+DROP TABLE IF EXISTS warpBackgroundSkyfile;
 DROP TABLE IF EXISTS diffPhotRun;
 DROP TABLE IF EXISTS diffPhotSkyfile;
Index: trunk/ippTools/src/Makefile.am
===================================================================
--- trunk/ippTools/src/Makefile.am	(revision 28429)
+++ trunk/ippTools/src/Makefile.am	(revision 28486)
@@ -1,4 +1,5 @@
 bin_PROGRAMS = \
 	addtool \
+	bgtool \
 	caltool \
 	camtool \
@@ -48,4 +49,5 @@
 noinst_HEADERS = \
 	addtool.h \
+	bgtool.h \
 	caltool.h \
 	camtool.h \
@@ -117,4 +119,10 @@
     addtoolConfig.c
 
+bgtool_CFLAGS = $(PSLIB_CFLAGS) $(PSMODULES_CFLAGS) $(IPPDB_CFLAGS)
+bgtool_LDADD = $(PSLIB_LIBS) $(PSMODULES_LIBS) $(IPPDB_LIBS) libpxtools.la
+bgtool_SOURCES = \
+    bgtool.c \
+    bgtoolConfig.c
+
 caltool_CFLAGS = $(PSLIB_CFLAGS) $(PSMODULES_CFLAGS) $(IPPDB_CFLAGS)
 caltool_LDADD = $(PSLIB_LIBS) $(PSMODULES_LIBS) $(IPPDB_LIBS) libpxtools.la
Index: trunk/ippTools/src/bgtool.c
===================================================================
--- trunk/ippTools/src/bgtool.c	(revision 28486)
+++ trunk/ippTools/src/bgtool.c	(revision 28486)
@@ -0,0 +1,1799 @@
+/*
+ * bgtool.c
+ *
+ * Copyright (C) 2006-2010  Joshua Hoblitt, Paul Price
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVB_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+#include <ippdb.h>
+
+#include "pxtools.h"
+#include "bgtool.h"
+
+static bool definechipMode(pxConfig *config);
+static bool updatechipMode(pxConfig *config);
+static bool tochipMode(pxConfig *config);
+static bool chipinputsMode(pxConfig *config);
+static bool addchipMode(pxConfig *config);
+static bool chipMode(pxConfig *config);
+static bool advancechipMode(pxConfig *config);
+static bool revertchipMode(pxConfig *config);
+static bool definewarpMode(pxConfig *config);
+static bool updatewarpMode(pxConfig *config);
+static bool towarpMode(pxConfig *config);
+static bool warpinputsMode(pxConfig *config);
+static bool addwarpMode(pxConfig *config);
+static bool warpMode(pxConfig *config);
+static bool advancewarpMode(pxConfig *config);
+static bool revertwarpMode(pxConfig *config);
+static bool tocleanchipMode(pxConfig *config);
+static bool cleanedchipMode(pxConfig *config);
+static bool tocleanwarpMode(pxConfig *config);
+static bool cleanedwarpMode(pxConfig *config);
+static bool exportchipMode(pxConfig *config);
+static bool importchipMode(pxConfig *config);
+static bool exportwarpMode(pxConfig *config);
+static bool importwarpMode(pxConfig *config);
+
+// Tables to import/export
+typedef struct {
+    const char *name;                   // Table name
+    void* (*parse)();                   // Parsing function
+    bool (*insert)();                   // Insertion function
+} tableData;
+static const tableData chipTables[] = {
+    { "chipBackgroundRun", (void*)&chipBackgroundRunObjectFromMetadata, &chipBackgroundRunInsertObject },
+    { "chipBackgroundImfile", (void*)&chipBackgroundImfileObjectFromMetadata, &chipBackgroundImfileInsertObject },
+    { NULL, NULL, NULL }
+};
+static const tableData warpTables[] = {
+    { "warpBackgroundRun", (void*)&warpBackgroundRunObjectFromMetadata, &warpBackgroundRunInsertObject },
+    { "warpBackgroundImfile", (void*)&warpBackgroundSkyfileObjectFromMetadata, &warpBackgroundSkyfileInsertObject },
+    { NULL, NULL, NULL }
+};
+
+
+# define MODECASE(caseName, func) \
+    case caseName: \
+    if (!func(config)) { \
+        goto FAIL; \
+    } \
+    break;
+
+int main(int argc, char **argv)
+{
+    psLibInit(NULL);
+
+    pxConfig *config = bgtoolConfig(NULL, argc, argv);
+    if (!config) {
+        psError(PXTOOLS_ERR_CONFIG, false, "failed to configure");
+        goto FAIL;
+    }
+
+    switch (config->mode) {
+        MODECASE(BGTOOL_MODE_DEFINECHIP,  definechipMode);
+        MODECASE(BGTOOL_MODE_UPDATECHIP,  updatechipMode);
+        MODECASE(BGTOOL_MODE_TOCHIP,      tochipMode);
+        MODECASE(BGTOOL_MODE_CHIPINPUTS,  chipinputsMode);
+        MODECASE(BGTOOL_MODE_ADDCHIP,     addchipMode);
+        MODECASE(BGTOOL_MODE_CHIP,        chipMode);
+        MODECASE(BGTOOL_MODE_ADVANCECHIP, advancechipMode);
+        MODECASE(BGTOOL_MODE_REVERTCHIP,  revertchipMode);
+        MODECASE(BGTOOL_MODE_DEFINEWARP,  definewarpMode);
+        MODECASE(BGTOOL_MODE_UPDATEWARP,  updatewarpMode);
+        MODECASE(BGTOOL_MODE_TOWARP,      towarpMode);
+        MODECASE(BGTOOL_MODE_WARPINPUTS,  warpinputsMode);
+        MODECASE(BGTOOL_MODE_ADDWARP,     addwarpMode);
+        MODECASE(BGTOOL_MODE_WARP,        warpMode);
+        MODECASE(BGTOOL_MODE_ADVANCEWARP, advancewarpMode);
+        MODECASE(BGTOOL_MODE_REVERTWARP,  revertwarpMode);
+        MODECASE(BGTOOL_MODE_TOCLEANCHIP, tocleanchipMode);
+        MODECASE(BGTOOL_MODE_CLEANEDCHIP, cleanedchipMode);
+        MODECASE(BGTOOL_MODE_TOCLEANWARP, tocleanwarpMode);
+        MODECASE(BGTOOL_MODE_CLEANEDWARP, cleanedwarpMode);
+        MODECASE(BGTOOL_MODE_EXPORTCHIP,  exportchipMode);
+        MODECASE(BGTOOL_MODE_IMPORTCHIP,  importchipMode);
+        MODECASE(BGTOOL_MODE_EXPORTWARP,  exportwarpMode);
+        MODECASE(BGTOOL_MODE_IMPORTWARP,  importwarpMode);
+
+        default:
+            psAbort("invalid option (this should not happen)");
+    }
+
+    psFree(config);
+    pmConfigDone();
+    psLibFinalize();
+
+    exit(EXIT_SUCCESS);
+
+FAIL:
+    psErrorStackPrint(stderr, "\n");
+    int exit_status = pxerrorGetExitStatus();
+
+    psFree(config);
+    pmConfigDone();
+    psLibFinalize();
+
+    exit(exit_status);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// General functions
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+static bool exportTables(pxConfig *config, // Configuration (with DB handle)
+                         const char *filename, // Filename to which to write
+                         const tableData tables[], // Tables to export (NULL terminated)
+                         const psMetadata *where, // WHERE restrictions
+                         bool clean               // Write as cleaned?
+                         )
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    FILE *file = fopen(filename, "w");
+    if (!file) {
+        psError(PXTOOLS_ERR_SYS, true, "failed to open output file %s", filename);
+        return false;
+    }
+
+    if (!pxExportVersion(config, file)) {
+        psError(psErrorCodeLast(), false, "failed to write dbversion to output file %s", filename);
+        return false;
+    }
+
+    for (int i = 0; tables[i].name; i++) {
+        const char *name = tables[i].name; // Name of table
+        psString query = NULL;
+        psStringAppend(&query, "SELECT * FROM %s", name);
+
+        if (psListLength(where->list)) {
+            psString whereClause = psDBGenerateWhereSQL(where, NULL);
+            psStringAppend(&query, " %s", whereClause);
+            psFree(whereClause);
+        }
+
+        if (!p_psDBRunQuery(config->dbh, query)) {
+            psError(psErrorCodeLast(), false, "database error");
+            psFree(query);
+            return false;
+        }
+        psFree(query);
+
+        psArray *output = p_psDBFetchResult(config->dbh);
+        if (!output) {
+            psError(psErrorCodeLast(), false, "database error");
+            return false;
+        }
+        if (!psArrayLength(output)) {
+            psError(PXTOOLS_ERR_CONFIG, true, "no rows found");
+            psFree(output);
+            return false;
+        }
+
+        if (clean &&
+            (strcmp(name, "chipBackgroundRun") == 0 ||
+             strcmp(name, "warpBackgroundRun") == 0) &&
+            !pxSetStateCleaned(name, "state", output)) {
+            psFree(output);
+            psError(psErrorCodeLast(), false, "pxSetStateClean failed for table %s", name);
+            return false;
+        }
+
+        if (!ippdbPrintMetadatas(file, output, name, true)) {
+            psError(psErrorCodeLast(), false, "failed to print array");
+            psFree(output);
+            return false;
+        }
+        psFree(output);
+    }
+    fclose(file);
+
+    return true;
+}
+
+static bool importTables(pxConfig *config, // Configuration
+                        const char *filename, //
+                        const tableData tables[] // Tables to read in
+                        )
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    unsigned int badLines = 0;          // Number of bad lines
+    psMetadata *input = psMetadataConfigRead(NULL, &badLines, filename, false); // Input file contents
+    if (!input) {
+        psError(psErrorCodeLast(), false, "Unable to parse input file %s", filename);
+        return false;
+    }
+    if (badLines > 0) {
+        psWarning("%d bad lines encountered when parsing %s", badLines, filename);
+    }
+
+    if (!pxCheckImportVersion(config, input)) {
+        psError(psErrorCodeLast(), false, "pxCheckImportVersion failed");
+        return false;
+    }
+
+    // Import primary table
+    for (int i = 0; tables[i].name; i++) {
+        const char *name = tables[i].name; // Name of table
+        psMetadataItem *item = psMetadataLookup(input, name); // Item from input
+        psAssert(item, "%s not in input", name);
+        psAssert(item->type == PS_DATA_METADATA_MULTI, "%s not MULTI type", name);
+        psAssert(psListLength(item->data.list) == 1, "%s has multiple entries", name);
+        psMetadataItem *entry = psListGet(item->data.list, PS_LIST_HEAD); // Entry of interest
+        void *data = tables[i].parse(entry);                             // Parsed entry
+        if (!data) {
+            psError(PXTOOLS_ERR_CONFIG, false, "Unable to parse entry %s", name);
+            psFree(input);
+            return false;
+        }
+        if (!tables[0].insert(config->dbh, data)) {
+            psError(psErrorCodeLast(), false, "Unable to insert entry %s", name);
+            psFree(input);
+            return false;
+        }
+    }
+
+    psFree(input);
+
+    return true;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Functions for chip stage
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+static bool definechipMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args,   where, "-chip_id",            "chipRun.chip_id",       "==");
+    PXOPT_COPY_S64(config->args,   where, "-exp_id",             "rawExp.exp_id",         "==");
+    PXOPT_COPY_STR(config->args,   where, "-exp_name",           "rawExp.exp_name",       "==");
+    PXOPT_COPY_STR(config->args,   where, "-inst",               "rawExp.camera",         "==");
+    PXOPT_COPY_STR(config->args,   where, "-telescope",          "rawExp.telescope",      "==");
+    PXOPT_COPY_TIME(config->args,  where, "-dateobs_begin",      "rawExp.dateobs",        ">=");
+    PXOPT_COPY_TIME(config->args,  where, "-dateobs_end",        "rawExp.dateobs",        "<=");
+    PXOPT_COPY_STR(config->args,   where, "-exp_tag",            "rawExp.exp_tag",        "==");
+    PXOPT_COPY_STR(config->args,   where, "-exp_type",           "rawExp.exp_type",       "==");
+    PXOPT_COPY_STR(config->args,   where, "-filelevel",          "rawExp.filelevel",      "==");
+    PXOPT_COPY_STR(config->args,   where, "-filter",             "rawExp.filter",         "==");
+    PXOPT_COPY_F64(config->args,   where, "-airmass_min",        "rawExp.airmass",        ">=");
+    PXOPT_COPY_F64(config->args,   where, "-airmass_max",        "rawExp.airmass",        "<");
+    PXOPT_COPY_RADEC(config->args, where, "-ra_min",             "rawExp.ra",             ">=");
+    PXOPT_COPY_RADEC(config->args, where, "-ra_max",             "rawExp.ra",             "<");
+    PXOPT_COPY_RADEC(config->args, where, "-decl_min",           "rawExp.decl",           ">=");
+    PXOPT_COPY_RADEC(config->args, where, "-decl_max",           "rawExp.decl",           "<");
+    PXOPT_COPY_F32(config->args,   where, "-exp_time_min",       "rawExp.exp_time",       ">=");
+    PXOPT_COPY_F32(config->args,   where, "-exp_time_max",       "rawExp.exp_time",       "<");
+    PXOPT_COPY_F32(config->args,   where, "-sat_pixel_frac_min", "rawExp.sat_pixel_frac", ">=");
+    PXOPT_COPY_F32(config->args,   where, "-sat_pixel_frac_max", "rawExp.sat_pixel_frac", "<");
+    PXOPT_COPY_F64(config->args,   where, "-bg_min",             "rawExp.bg",             ">=");
+    PXOPT_COPY_F64(config->args,   where, "-bg_max",             "rawExp.bg",             "<");
+    PXOPT_COPY_F64(config->args,   where, "-bg_stdev_min",       "rawExp.bg_stdev",       ">=");
+    PXOPT_COPY_F64(config->args,   where, "-bg_stdev_max",       "rawExp.bg_stdev",       "<");
+    PXOPT_COPY_F64(config->args,   where, "-bg_mean_stdev_min",  "rawExp.bg_mean_stdev",  ">=");
+    PXOPT_COPY_F64(config->args,   where, "-bg_mean_stdev_max",  "rawExp.bg_mean_stdev",  "<");
+    PXOPT_COPY_F64(config->args,   where, "-alt_min",            "rawExp.alt",            ">=");
+    PXOPT_COPY_F64(config->args,   where, "-alt_max",            "rawExp.alt",            "<");
+    PXOPT_COPY_F64(config->args,   where, "-az_min",             "rawExp.az",             ">=");
+    PXOPT_COPY_F64(config->args,   where, "-az_max",             "rawExp.az",             "<");
+    PXOPT_COPY_F32(config->args,   where, "-ccd_temp_min",       "rawExp.ccd_temp",       ">=");
+    PXOPT_COPY_F32(config->args,   where, "-ccd_temp_max",       "rawExp.ccd_temp",       "<");
+    PXOPT_COPY_F64(config->args,   where, "-posang_min",         "rawExp.posang",         ">=");
+    PXOPT_COPY_F64(config->args,   where, "-posang_max",         "rawExp.posang",         "<");
+    PXOPT_COPY_STR(config->args,   where, "-object",             "rawExp.object",         "==");
+    PXOPT_COPY_STR(config->args,   where, "-comment",            "rawExp.comment",        "LIKE");
+    PXOPT_COPY_STR(config->args,   where, "-obs_mode",           "rawExp.obs_mode",       "LIKE");
+    PXOPT_COPY_F32(config->args,   where, "-sun_angle_min",      "rawExp.sun_angle",      ">=");
+    PXOPT_COPY_F32(config->args,   where, "-sun_angle_max",      "rawExp.sun_angle",      "<");
+    pxAddLabelSearchArgs(config,   where, "-label",              "chipRun.label",         "==");
+
+    if (!psListLength(where->list) && !psMetadataLookupBool(NULL, config->args, "-all")) {
+        psFree(where);
+        psError(PXTOOLS_ERR_CONFIG, true, "search parameters are required");
+        return false;
+    }
+
+    PXOPT_LOOKUP_BOOL(rerun, config->args, "-rerun", false);
+    PXOPT_LOOKUP_STR(workdir, config->args, "-set_workdir", false, false);
+    PXOPT_LOOKUP_STR(label, config->args, "-set_label", false, false);
+    PXOPT_LOOKUP_STR(data_group, config->args, "-set_data_group", false, false);
+    PXOPT_LOOKUP_STR(dist_group, config->args, "-set_dist_group", false, false);
+    PXOPT_LOOKUP_STR(reduction, config->args, "-set_reduction", false, false);
+    PXOPT_LOOKUP_STR(note, config->args, "-set_note", false, false);
+    PXOPT_LOOKUP_TIME(registered, config->args, "-registered", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+    PXOPT_LOOKUP_BOOL(pretend, config->args, "-pretend", false);
+
+    // Get chip runs to promote to chipBackgroundRun
+
+    psString query = pxDataGet("bgtool_definechip.sql"); // Query to execute
+    if (!query) {
+        psError(psErrorCodeLast(), false, "failed to retreive SQL statement");
+        psFree(where);
+        return false;
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, "\nAND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    if (!rerun) {
+        psStringAppend(&query, "\nAND chipBackgroundRun.chip_bg_id IS NULL");
+        if (label) {
+            psStringAppend(&query,
+                           "\nAND (chipBackgroundRun.label = '%s'"
+                           " OR chipBackgroundRun.label IS NULL",
+                           label);
+        }
+        if (data_group) {
+            psStringAppend(&query,
+                           "\nAND (chipBackgroundRun.data_group = '%s'"
+                           " OR chipBackgroundRun.data_group IS NULL",
+                           data_group);
+        }
+        if (dist_group) {
+            psStringAppend(&query,
+                           "\nAND (chipBackgroundRun.dist_group = '%s'"
+                           " OR chipBackgroundRun.dist_group IS NULL",
+                           dist_group);
+        }
+    }
+
+    if (!psDBTransaction(config->dbh)) {
+        psError(psErrorCodeLast(), false, "database error");
+        return false;
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(psErrorCodeLast(), false, "database error");
+        psFree(query);
+        if (!psDBRollback(config->dbh)) {
+            psError(psErrorCodeLast(), false, "database error");
+        }
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh); // Matching rows
+    if (!output) {
+        psError(psErrorCodeLast(), false, "database error");
+        if (!psDBRollback(config->dbh)) {
+            psError(psErrorCodeLast(), false, "database error");
+        }
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("bgtool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        if (!psDBRollback(config->dbh)) {
+            psError(psErrorCodeLast(), false, "database error");
+        }
+        return true;
+    }
+
+    if (pretend) {
+        // negative simple so the default is true
+        if (!ippdbPrintMetadatas(stdout, output, "chipRun", !simple)) {
+            psError(psErrorCodeLast(), false, "failed to print array");
+            psFree(output);
+            if (!psDBRollback(config->dbh)) {
+                psError(psErrorCodeLast(), false, "database error");
+            }
+            return false;
+        }
+        psFree(output);
+        return true;
+    }
+
+    for (long i = 0; i < psArrayLength(output); i++) {
+        psMetadata *md = output->data[i];
+
+        chipRunRow *row = chipRunObjectFromMetadata(md);
+        if (!row) {
+            psError(psErrorCodeLast(), false, "failed to convert metadata into fakeRun");
+            psFree(output);
+            if (!psDBRollback(config->dbh)) {
+                psError(psErrorCodeLast(), false, "database error");
+            }
+            return false;
+        }
+
+        if (!chipBackgroundRunInsert(config->dbh, 0, row->chip_id, "new",
+                                     workdir     ? workdir    : row->workdir,
+                                     label       ? label      : row->label,
+                                     data_group  ? data_group : row->data_group,
+                                     dist_group  ? dist_group : row->dist_group,
+                                     reduction   ? reduction  : row->reduction,
+                                     note        ? note       : row->note,
+                                     NULL, 0)) {
+            psError(psErrorCodeLast(), false, "database error");
+            psFree(row);
+            if (!psDBRollback(config->dbh)) {
+                psError(psErrorCodeLast(), false, "database error");
+            }
+            return false;
+        }
+        psFree(row);
+    }
+    psFree(output);
+
+    if (!psDBCommit(config->dbh)) {
+        psError(psErrorCodeLast(), false, "database error");
+            if (!psDBRollback(config->dbh)) {
+                psError(psErrorCodeLast(), false, "database error");
+            }
+        return false;
+    }
+
+    return true;
+}
+
+static bool updatechipMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-chip_bg_id", "chipBackgroundRun.chip_bg_id",   "==");
+    PXOPT_COPY_STR(config->args, where, "-state",      "chipBackgroundRun.state",     "==");
+    PXOPT_COPY_STR(config->args, where, "-data_group", "chipBackgroundRun.data_group","LIKE");
+    PXOPT_COPY_STR(config->args, where, "-dist_group", "chipBackgroundRun.dist_group","LIKE");
+    pxAddLabelSearchArgs(config,  where, "-label",     "chipBackgroundRun.label",     "LIKE");
+    PXOPT_COPY_TIME(config->args, where, "-registered_begin", "chipBackgroundRun.registered",  ">=");
+    PXOPT_COPY_TIME(config->args, where, "-registered_end",   "chipBackgroundRun.registered",  "<");
+
+    PXOPT_LOOKUP_BOOL(destreaked, config->args, "-destreaked", false);
+    if (destreaked) {
+        psMetadataAddS64(where, PS_LIST_TAIL, "chipBackgroundRun.magicked", PS_META_DUPLICATE_OK, ">", 0);
+    }
+
+    if (!psListLength(where->list)) {
+        psFree(where);
+        psError(PXTOOLS_ERR_CONFIG, false, "search parameters are required");
+        return false;
+    }
+
+    psString query = psStringCopy("UPDATE chipBackgroundRun JOIN chipBackgroundImfile USING(chip_bg_id)");
+    bool result = pxUpdateRun(config, where, &query, "chipBackgroundRun", "chip_bg_id",
+                              "chipBackgroundImfile", true);
+
+    psFree(query);
+    psFree(where);
+
+    return result;
+}
+
+static bool tochipMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-chip_bg_id", "chipBackgroundRun.chip_bg_id", "==");
+    pxAddLabelSearchArgs(config, where, "-label", "chipBackgroundRun.label", "==");
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psString query = pxDataGet("bgtool_tochip.sql");
+    if (!query) {
+        psError(psErrorCodeLast(), false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    psString whereStr = psStringCopy("");
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&whereStr, "\n AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQueryF(config->dbh, query, whereStr)) {
+        psError(psErrorCodeLast(), false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(whereStr);
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(psErrorCodeLast(), false, "Unable to fetch result of query %s", query);
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("bgtool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    if (psArrayLength(output)) {
+        if (!ippdbPrintMetadatas(stdout, output, "chipBackgroundRun", !simple)) {
+            psError(psErrorCodeLast(), false, "failed to print array");
+            psFree(output);
+            return false;
+        }
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+
+static bool chipinputsMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-chip_bg_id", "chipBackgroundRun.chip_bg_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-class_id", "chipProcessedImfile.class_id", "==");
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    // find all rawImfiles matching the default query
+    psString query = pxDataGet("bgtool_chipinputs.sql");
+    if (!query) {
+        psError(psErrorCodeLast(), false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(psErrorCodeLast(), false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(psErrorCodeLast(), false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("bgtool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+    if (!ippdbPrintMetadatas(stdout, output, "chipBackgroundImfile", !simple)) {
+        psError(psErrorCodeLast(), false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+
+static bool addchipMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    PXOPT_LOOKUP_S64(chip_bg_id, config->args, "-chip_bg_id", true, false);
+    PXOPT_LOOKUP_STR(class_id, config->args, "-class_id", true, false);
+    PXOPT_LOOKUP_STR(path_base, config->args, "-path_base", true, false);
+
+    // optional
+
+    PXOPT_LOOKUP_S64(magicked, config->args, "-set_magicked", false, false);
+    PXOPT_LOOKUP_F32(dtime_script, config->args, "-dtime_script", false, false);
+    PXOPT_LOOKUP_STR(hostname, config->args, "-hostname", false, false);
+    PXOPT_LOOKUP_S16(quality, config->args, "-quality", false, false);
+    PXOPT_LOOKUP_S16(fault, config->args, "-fault", false, false);
+    PXOPT_LOOKUP_STR(ver_pslib, config->args, "-ver_pslib", false, false);
+    PXOPT_LOOKUP_STR(ver_psmodules, config->args, "-ver_psmodules", false, false);
+    PXOPT_LOOKUP_STR(ver_ppbackground, config->args, "-ver_ppbackground", false, false);
+    PXOPT_LOOKUP_STR(ver_ppstats, config->args, "-ver_ppstats", false, false);
+    PXOPT_LOOKUP_F64(bg, config->args, "-bg", false, false);
+    PXOPT_LOOKUP_F64(bg_stdev, config->args, "-bg_stdev", false, false);
+    PXOPT_LOOKUP_S32(maskfrac_npix, config->args, "-maskfrac_npix", false, false);
+    PXOPT_LOOKUP_F32(maskfrac_static, config->args, "-maskfrac_static", false, false);
+    PXOPT_LOOKUP_F32(maskfrac_dynamic, config->args, "-maskfrac_dynamic", false, false);
+    PXOPT_LOOKUP_F32(maskfrac_magic, config->args, "-maskfrac_magic", false, false);
+    PXOPT_LOOKUP_F32(maskfrac_advisory, config->args, "-maskfrac_advisory", false, false);
+
+    psString ver_code = pxMergeCodeVersions(ver_pslib, ver_psmodules);
+    ver_code = pxMergeCodeVersions(ver_code, ver_ppbackground);
+    ver_code = pxMergeCodeVersions(ver_code, ver_ppstats);
+
+    if (!psDBTransaction(config->dbh)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+
+    if (!chipBackgroundImfileInsert(config->dbh, chip_bg_id, class_id, path_base, magicked, dtime_script,
+                                    hostname, quality, fault, ver_code, bg, bg_stdev, maskfrac_npix,
+                                    maskfrac_static, maskfrac_dynamic, maskfrac_magic, maskfrac_advisory)) {
+        psError(psErrorCodeLast(), false, "database error");
+        if (!psDBRollback(config->dbh)) {
+            psError(psErrorCodeLast(), false, "database error");
+        }
+        return false;
+    }
+
+    if (!psDBCommit(config->dbh)) {
+        psError(psErrorCodeLast(), false, "database error");
+        return false;
+    }
+
+    return true;
+}
+
+static bool chipMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-chip_bg_id",    "chipBackgroundRun.chip_bg_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-class_id", "chipBackgroundImfile.class_id", "==");
+    pxAddLabelSearchArgs(config, where, "-label",   "chipBackgroundRun.label", "LIKE");
+    pxAddLabelSearchArgs(config, where, "-data_group",   "chipBackgroundRun.data_group", "LIKE");
+    pxAddLabelSearchArgs(config, where, "-dist_group",   "chipBackgroundRun.data_group", "LIKE");
+
+    PXOPT_LOOKUP_BOOL(all, config->args, "-all", false);
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    // find all rawImfiles matching the default query
+    psString query = pxDataGet("bgtool_chip.sql");
+    if (!query) {
+        psError(psErrorCodeLast(), false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    psString magicWhere = NULL;
+    if (!pxmagicAddWhere(config, &magicWhere, "chipBackgroundImfile")) {
+        psError(psErrorCodeLast(), false, "pxMagicAddWhere failed");
+        return false;
+    }
+    if (!pxspaceAddWhere(config, &magicWhere, "rawExp")) {
+        psError(psErrorCodeLast(), false, "pxSpaceAddWhere failed");
+        return false;
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " WHERE %s", whereClause);
+        psFree(whereClause);
+    } else if (!all && !magicWhere) {
+        psError(PXTOOLS_ERR_CONFIG, true, "search parameters or -all are required");
+        return false;
+    }
+    if (magicWhere) {
+        psStringAppend(&query, "%s %s", psListLength(where->list) ? "AND" : "WHERE", magicWhere);
+    }
+    psFree(magicWhere);
+    psFree(where);
+
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(psErrorCodeLast(), false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(psErrorCodeLast(), false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("bgtool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+    if (psArrayLength(output)) {
+        if (!ippdbPrintMetadatas(stdout, output, "chipBackgroundImfile", !simple)) {
+            psError(psErrorCodeLast(), false, "failed to print array");
+            psFree(output);
+            return false;
+        }
+    }
+    psFree(output);
+
+    return true;
+}
+
+
+static bool advancechipMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-chip_bg_id", "chip_bg_id", "==");
+    pxAddLabelSearchArgs(config, where, "-label", "label", "==");
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+
+    psString select = pxDataGet("bgtool_advancechip.sql");
+    if (!select) {
+        psError(psErrorCodeLast(), false, "failed to retrieve SQL statement");
+        return false;
+    }
+
+    psString selectWhere = psStringCopy("");
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&selectWhere, "\n AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&select, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!psDBTransaction(config->dbh)) {
+        psError(psErrorCodeLast(), false, "database error");
+        return false;
+    }
+
+    if (!p_psDBRunQueryF(config->dbh, select, selectWhere)) {
+        psError(psErrorCodeLast(), false, "database error");
+        psFree(select);
+        psFree(selectWhere);
+        if (!psDBRollback(config->dbh)) {
+            psError(psErrorCodeLast(), false, "database error");
+        }
+        return false;
+    }
+    psFree(select);
+    psFree(selectWhere);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(psErrorCodeLast(), false, "database error");
+        if (!psDBRollback(config->dbh)) {
+            psError(psErrorCodeLast(), false, "database error");
+        }
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("bgtool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    for (long i = 0; i < psArrayLength(output); i++) {
+        psMetadata *row = output->data[i];
+        bool status = true;             // Status of MD lookup
+        psS64 chip_bg_id = psMetadataLookupS64(&status, row, "chip_bg_id");
+        if (!status) {
+            psError(PXTOOLS_ERR_PROG, true, "failed to look up value for chip_bg_id");
+            psFree(output);
+            if (!psDBRollback(config->dbh)) {
+                psError(psErrorCodeLast(), false, "database error");
+            }
+            return false;
+        }
+        psS64 magicked = psMetadataLookupS64(&status, row, "magicked");
+        if (!status) {
+            psError(PXTOOLS_ERR_PROG, true, "failed to look up value for magicked");
+            psFree(output);
+            if (!psDBRollback(config->dbh)) {
+                psError(psErrorCodeLast(), false, "database error");
+            }
+            return false;
+        }
+
+        if (!p_psDBRunQueryF(config->dbh,
+                             "UPDATE chipBackgroundRun "
+                             "SET state = 'full', magicked = %" PRId64 " "
+                             " WHERE chip_bg_id = %" PRId64,
+                             magicked, chip_bg_id)) {
+            psError(psErrorCodeLast(), false, "database error");
+            psFree(output);
+            if (!psDBRollback(config->dbh)) {
+                psError(psErrorCodeLast(), false, "database error");
+            }
+            return false;
+        }
+
+        psS64 numUpdated = psDBAffectedRows(config->dbh);
+        if (numUpdated != 1) {
+            psError(PXTOOLS_ERR_PROG, true, "should have affected 1 row");
+            if (!psDBRollback(config->dbh)) {
+                psError(psErrorCodeLast(), false, "database error");
+            }
+            psFree(output);
+            return false;
+        }
+    }
+    psFree(output);
+
+    if (!psDBCommit(config->dbh)) {
+        psError(psErrorCodeLast(), false, "database error");
+        return false;
+    }
+
+    return true;
+}
+
+static bool revertchipMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-chip_bg_id", "chipBackgroundRun.chip_bg_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-class_id", "chipBackgroundImfile.class_id", "==");
+    pxAddLabelSearchArgs(config, where, "-label", "chipBackgroundRun.label", "==");
+    PXOPT_COPY_S16(config->args, where, "-fault", "chipBackgroundImfile.fault", "==");
+
+    if (!psListLength(where->list) && !psMetadataLookupBool(NULL, config->args, "-all")) {
+        psFree(where);
+        psError(PXTOOLS_ERR_CONFIG, true, "search parameters are required");
+        return false;
+    }
+
+    psString query = pxDataGet("bgtool_revertchip.sql");
+    if (!query) {
+        psError(psErrorCodeLast(), false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    int numDeleted = psDBAffectedRows(config->dbh);
+    psLogMsg("bgtool", PS_LOG_INFO, "Deleted %d chipBackgroundImfiles", numDeleted);
+
+    return true;
+}
+
+static bool tocleanchipMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    pxAddLabelSearchArgs(config, where, "-label", "chipBackgroundRun.label", "==");
+
+    psString query = pxDataGet("bgtool_tocleanchip.sql");
+    if (!query) {
+        psError(psErrorCodeLast(), false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(psErrorCodeLast(), false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(psErrorCodeLast(), false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("bgtool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "chipBackgroundRun", !simple)) {
+        psError(psErrorCodeLast(), false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+    psFree(output);
+
+    return true;
+}
+
+static bool cleanedchipMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-chip_bg_id", "chipBackgroundRun.chip_bg_id", "==");
+
+    PXOPT_LOOKUP_STR(state, config->args, "-state", true, false);
+    if (!pxIsValidCleanedState(state)) {
+        psError(PXTOOLS_ERR_CONFIG, true, "Invalid state: %s", state);
+        return false;
+    }
+
+    if (!psListLength(where->list)) {
+        psError(PXTOOLS_ERR_CONFIG, true, "No search restrictions set.");
+        return false;
+    }
+
+    psString query = pxDataGet("bgtool_cleanedchip.sql");
+    if (!query) {
+        psError(psErrorCodeLast(), false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    if (!p_psDBRunQueryF(config->dbh, query, state)) {
+        psError(psErrorCodeLast(), false, "database error");
+        return false;
+    }
+    psFree(query);
+
+    return true;
+}
+
+static bool exportchipMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    PXOPT_LOOKUP_S64(chip_bg_id, config->args, "-chip_bg_id", true,  false);
+    PXOPT_LOOKUP_STR(outfile, config->args, "-outfile", true,  false);
+    PXOPT_LOOKUP_BOOL(clean,  config->args, "-clean", false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-chip_bg_id", "chip_bg_id", "==");
+
+    bool status = exportTables(config, outfile, chipTables, where, clean);
+
+    psFree(where);
+    return status;
+}
+
+static bool importchipMode(pxConfig *config)
+{
+    PXOPT_LOOKUP_STR(infile, config->args, "-infile", true,  false);
+
+    return importTables(config, infile, chipTables);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Functions for warp stage
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+static bool definewarpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args,   where, "-warp_id",            "warpRun.warp_id",       "==");
+    PXOPT_COPY_S64(config->args,   where, "-exp_id",             "rawExp.exp_id",         "==");
+    PXOPT_COPY_STR(config->args,   where, "-exp_name",           "rawExp.exp_name",       "==");
+    PXOPT_COPY_STR(config->args,   where, "-inst",               "rawExp.camera",         "==");
+    PXOPT_COPY_STR(config->args,   where, "-telescope",          "rawExp.telescope",      "==");
+    PXOPT_COPY_TIME(config->args,  where, "-dateobs_begin",      "rawExp.dateobs",        ">=");
+    PXOPT_COPY_TIME(config->args,  where, "-dateobs_end",        "rawExp.dateobs",        "<=");
+    PXOPT_COPY_STR(config->args,   where, "-exp_tag",            "rawExp.exp_tag",        "==");
+    PXOPT_COPY_STR(config->args,   where, "-exp_type",           "rawExp.exp_type",       "==");
+    PXOPT_COPY_STR(config->args,   where, "-filelevel",          "rawExp.filelevel",      "==");
+    PXOPT_COPY_STR(config->args,   where, "-filter",             "rawExp.filter",         "==");
+    PXOPT_COPY_F64(config->args,   where, "-airmass_min",        "rawExp.airmass",        ">=");
+    PXOPT_COPY_F64(config->args,   where, "-airmass_max",        "rawExp.airmass",        "<");
+    PXOPT_COPY_RADEC(config->args, where, "-ra_min",             "rawExp.ra",             ">=");
+    PXOPT_COPY_RADEC(config->args, where, "-ra_max",             "rawExp.ra",             "<");
+    PXOPT_COPY_RADEC(config->args, where, "-decl_min",           "rawExp.decl",           ">=");
+    PXOPT_COPY_RADEC(config->args, where, "-decl_max",           "rawExp.decl",           "<");
+    PXOPT_COPY_F32(config->args,   where, "-exp_time_min",       "rawExp.exp_time",       ">=");
+    PXOPT_COPY_F32(config->args,   where, "-exp_time_max",       "rawExp.exp_time",       "<");
+    PXOPT_COPY_F32(config->args,   where, "-sat_pixel_frac_min", "rawExp.sat_pixel_frac", ">=");
+    PXOPT_COPY_F32(config->args,   where, "-sat_pixel_frac_max", "rawExp.sat_pixel_frac", "<");
+    PXOPT_COPY_F64(config->args,   where, "-bg_min",             "rawExp.bg",             ">=");
+    PXOPT_COPY_F64(config->args,   where, "-bg_max",             "rawExp.bg",             "<");
+    PXOPT_COPY_F64(config->args,   where, "-bg_stdev_min",       "rawExp.bg_stdev",       ">=");
+    PXOPT_COPY_F64(config->args,   where, "-bg_stdev_max",       "rawExp.bg_stdev",       "<");
+    PXOPT_COPY_F64(config->args,   where, "-bg_mean_stdev_min",  "rawExp.bg_mean_stdev",  ">=");
+    PXOPT_COPY_F64(config->args,   where, "-bg_mean_stdev_max",  "rawExp.bg_mean_stdev",  "<");
+    PXOPT_COPY_F64(config->args,   where, "-alt_min",            "rawExp.alt",            ">=");
+    PXOPT_COPY_F64(config->args,   where, "-alt_max",            "rawExp.alt",            "<");
+    PXOPT_COPY_F64(config->args,   where, "-az_min",             "rawExp.az",             ">=");
+    PXOPT_COPY_F64(config->args,   where, "-az_max",             "rawExp.az",             "<");
+    PXOPT_COPY_F32(config->args,   where, "-ccd_temp_min",       "rawExp.ccd_temp",       ">=");
+    PXOPT_COPY_F32(config->args,   where, "-ccd_temp_max",       "rawExp.ccd_temp",       "<");
+    PXOPT_COPY_F64(config->args,   where, "-posang_min",         "rawExp.posang",         ">=");
+    PXOPT_COPY_F64(config->args,   where, "-posang_max",         "rawExp.posang",         "<");
+    PXOPT_COPY_STR(config->args,   where, "-object",             "rawExp.object",         "==");
+    PXOPT_COPY_STR(config->args,   where, "-comment",            "rawExp.comment",        "LIKE");
+    PXOPT_COPY_STR(config->args,   where, "-obs_mode",           "rawExp.obs_mode",       "LIKE");
+    PXOPT_COPY_F32(config->args,   where, "-sun_angle_min",      "rawExp.sun_angle",      ">=");
+    PXOPT_COPY_F32(config->args,   where, "-sun_angle_max",      "rawExp.sun_angle",      "<");
+    pxAddLabelSearchArgs(config,   where, "-warp_label",         "warpRun.label",         "==");
+    pxAddLabelSearchArgs(config,   where, "-bg_label",           "chipBackgroundRun.label", "==");
+
+    if (!psListLength(where->list) && !psMetadataLookupBool(NULL, config->args, "-all")) {
+        psFree(where);
+        psError(PXTOOLS_ERR_CONFIG, true, "search parameters are required");
+        return false;
+    }
+
+    PXOPT_LOOKUP_BOOL(rerun, config->args, "-rerun", false);
+    PXOPT_LOOKUP_STR(workdir, config->args, "-set_workdir", false, false);
+    PXOPT_LOOKUP_STR(label, config->args, "-set_label", false, false);
+    PXOPT_LOOKUP_STR(data_group, config->args, "-set_data_group", false, false);
+    PXOPT_LOOKUP_STR(dist_group, config->args, "-set_dist_group", false, false);
+    PXOPT_LOOKUP_STR(reduction, config->args, "-set_reduction", false, false);
+    PXOPT_LOOKUP_STR(note, config->args, "-set_note", false, false);
+    PXOPT_LOOKUP_TIME(registered, config->args, "-registered", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+    PXOPT_LOOKUP_BOOL(pretend, config->args, "-pretend", false);
+
+    // Get warp runs to promote to warpBackgroundRun
+
+    psString query = pxDataGet("bgtool_definewarp.sql"); // Query to execute
+    if (!query) {
+        psError(psErrorCodeLast(), false, "failed to retreive SQL statement");
+        psFree(where);
+        return false;
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, "AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    if (!rerun) {
+        psStringAppend(&query, "\nAND warpBackgroundRun.warp_bg_id IS NULL");
+        if (label) {
+            psStringAppend(&query,
+                           "\nAND (warpBackgroundRun.label = '%s'"
+                           " OR warpBackgroundRun.label IS NULL",
+                           label);
+        }
+        if (data_group) {
+            psStringAppend(&query,
+                           "\nAND (warpBackgroundRun.data_group = '%s'"
+                           " OR warpBackgroundRun.data_group IS NULL",
+                           data_group);
+        }
+        if (dist_group) {
+            psStringAppend(&query,
+                           "\nAND (warpBackgroundRun.dist_group = '%s'"
+                           " OR warpBackgroundRun.dist_group IS NULL",
+                           dist_group);
+        }
+    }
+
+    if (!psDBTransaction(config->dbh)) {
+        psError(psErrorCodeLast(), false, "database error");
+        return false;
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(psErrorCodeLast(), false, "database error");
+        psFree(query);
+        if (!psDBRollback(config->dbh)) {
+            psError(psErrorCodeLast(), false, "database error");
+        }
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh); // Matching rows
+    if (!output) {
+        psError(psErrorCodeLast(), false, "database error");
+        if (!psDBRollback(config->dbh)) {
+            psError(psErrorCodeLast(), false, "database error");
+        }
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("bgtool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        if (!psDBRollback(config->dbh)) {
+            psError(psErrorCodeLast(), false, "database error");
+        }
+        return true;
+    }
+
+    if (pretend) {
+        // negative simple so the default is true
+        if (!ippdbPrintMetadatas(stdout, output, "warpRun", !simple)) {
+            psError(psErrorCodeLast(), false, "failed to print array");
+            psFree(output);
+            if (!psDBRollback(config->dbh)) {
+                psError(psErrorCodeLast(), false, "database error");
+            }
+            return false;
+        }
+        psFree(output);
+        return true;
+    }
+
+    for (long i = 0; i < psArrayLength(output); i++) {
+        psMetadata *md = output->data[i];
+
+        psS64 chip_bg_id = psMetadataLookupS64(NULL, md, "chip_bg_id");
+
+        warpRunRow *row = warpRunObjectFromMetadata(md);
+        if (!row) {
+            psError(psErrorCodeLast(), false, "failed to convert metadata into fakeRun");
+            psFree(output);
+            if (!psDBRollback(config->dbh)) {
+                psError(psErrorCodeLast(), false, "database error");
+            }
+            return false;
+        }
+
+        if (!warpBackgroundRunInsert(config->dbh, 0, row->warp_id, chip_bg_id, "new",
+                                     workdir     ? workdir    : row->workdir,
+                                     label       ? label      : row->label,
+                                     data_group  ? data_group : row->data_group,
+                                     dist_group  ? dist_group : row->dist_group,
+                                     reduction   ? reduction  : row->reduction,
+                                     note        ? note       : row->note,
+                                     NULL, 0)) {
+            psError(psErrorCodeLast(), false, "database error");
+            psFree(row);
+            if (!psDBRollback(config->dbh)) {
+                psError(psErrorCodeLast(), false, "database error");
+            }
+            return false;
+        }
+        psFree(row);
+    }
+    psFree(output);
+
+    if (!psDBCommit(config->dbh)) {
+        psError(psErrorCodeLast(), false, "database error");
+            if (!psDBRollback(config->dbh)) {
+                psError(psErrorCodeLast(), false, "database error");
+            }
+        return false;
+    }
+
+    return true;
+}
+
+static bool updatewarpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-warp_bg_id", "warpBackgroundRun.warp_bg_id",   "==");
+    PXOPT_COPY_STR(config->args, where, "-state",      "warpBackgroundRun.state",     "==");
+    PXOPT_COPY_STR(config->args, where, "-data_group", "warpBackgroundRun.data_group","LIKE");
+    PXOPT_COPY_STR(config->args, where, "-dist_group", "warpBackgroundRun.dist_group","LIKE");
+    pxAddLabelSearchArgs(config,  where, "-label",     "warpBackgroundRun.label",     "LIKE");
+    PXOPT_COPY_TIME(config->args, where, "-registered_begin", "warpBackgroundRun.registered",  ">=");
+    PXOPT_COPY_TIME(config->args, where, "-registered_end",   "warpBackgroundRun.registered",  "<");
+
+    PXOPT_LOOKUP_BOOL(destreaked, config->args, "-destreaked", false);
+    if (destreaked) {
+        psMetadataAddS64(where, PS_LIST_TAIL, "warpBackgroundRun.magicked", PS_META_DUPLICATE_OK, ">", 0);
+    }
+
+    if (!psListLength(where->list)) {
+        psFree(where);
+        psError(PXTOOLS_ERR_CONFIG, false, "search parameters are required");
+        return false;
+    }
+
+    psString query = psStringCopy("UPDATE warpBackgroundRun JOIN warpBackgroundSkyfile USING(warp_bg_id)");
+    bool result = pxUpdateRun(config, where, &query, "warpBackgroundRun", "warp_bg_id",
+                              "warpBackgroundSkyfile", true);
+
+    psFree(query);
+    psFree(where);
+
+    return result;
+}
+
+static bool towarpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-warp_bg_id", "warpBackgroundRun.warp_bg_id", "==");
+    pxAddLabelSearchArgs (config, where, "-label", "warpBackgroundRun.label", "==");
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psString query = pxDataGet("bgtool_towarp.sql");
+    if (!query) {
+        psError(psErrorCodeLast(), false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    psString whereStr = psStringCopy("");
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&whereStr, "\n AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQueryF(config->dbh, query, whereStr)) {
+        psError(psErrorCodeLast(), false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(whereStr);
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(psErrorCodeLast(), false, "Unable to fetch result of query %s", query);
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("bgtool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    if (psArrayLength(output)) {
+        if (!ippdbPrintMetadatas(stdout, output, "warpBackgroundRun", !simple)) {
+            psError(psErrorCodeLast(), false, "failed to print array");
+            psFree(output);
+            return false;
+        }
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+
+static bool warpinputsMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-warp_bg_id", "warpBackgroundRun.warp_bg_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-skycell_id", "skycell_id", "==");
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    // find all rawImfiles matching the default query
+    psString query = pxDataGet("bgtool_warpinputs.sql");
+    if (!query) {
+        psError(psErrorCodeLast(), false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(psErrorCodeLast(), false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(psErrorCodeLast(), false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("bgtool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+    if (!ippdbPrintMetadatas(stdout, output, "chipBackgroundSkyfile", !simple)) {
+        psError(psErrorCodeLast(), false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+
+static bool addwarpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    PXOPT_LOOKUP_S64(warp_bg_id, config->args, "-warp_bg_id", true, false);
+    PXOPT_LOOKUP_STR(skycell_id, config->args, "-skycell_id", true, false);
+    PXOPT_LOOKUP_STR(path_base, config->args, "-path_base", true, false);
+
+    // optional
+
+    PXOPT_LOOKUP_S64(magicked, config->args, "-set_magicked", false, false);
+    PXOPT_LOOKUP_F32(dtime_script, config->args, "-dtime_script", false, false);
+    PXOPT_LOOKUP_STR(hostname, config->args, "-hostname", false, false);
+    PXOPT_LOOKUP_S16(quality, config->args, "-quality", false, false);
+    PXOPT_LOOKUP_S16(fault, config->args, "-fault", false, false);
+    PXOPT_LOOKUP_STR(ver_pslib, config->args, "-ver_pslib", false, false);
+    PXOPT_LOOKUP_STR(ver_psmodules, config->args, "-ver_psmodules", false, false);
+    PXOPT_LOOKUP_STR(ver_pswarp, config->args, "-ver_pswarp", false, false);
+    PXOPT_LOOKUP_STR(ver_ppstats, config->args, "-ver_ppstats", false, false);
+    PXOPT_LOOKUP_F64(bg, config->args, "-bg", false, false);
+    PXOPT_LOOKUP_F64(bg_stdev, config->args, "-bg_stdev", false, false);
+    PXOPT_LOOKUP_S32(maskfrac_npix, config->args, "-maskfrac_npix", false, false);
+    PXOPT_LOOKUP_F32(maskfrac_static, config->args, "-maskfrac_static", false, false);
+    PXOPT_LOOKUP_F32(maskfrac_dynamic, config->args, "-maskfrac_dynamic", false, false);
+    PXOPT_LOOKUP_F32(maskfrac_magic, config->args, "-maskfrac_magic", false, false);
+    PXOPT_LOOKUP_F32(maskfrac_advisory, config->args, "-maskfrac_advisory", false, false);
+
+    psString ver_code = pxMergeCodeVersions(ver_pslib, ver_psmodules);
+    ver_code = pxMergeCodeVersions(ver_code, ver_pswarp);
+    ver_code = pxMergeCodeVersions(ver_code, ver_ppstats);
+
+    if (!psDBTransaction(config->dbh)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+
+    if (!warpBackgroundSkyfileInsert(config->dbh, warp_bg_id, skycell_id, path_base, magicked, dtime_script,
+                                    hostname, quality, fault, ver_code, bg, bg_stdev, maskfrac_npix,
+                                    maskfrac_static, maskfrac_dynamic, maskfrac_magic, maskfrac_advisory)) {
+        psError(psErrorCodeLast(), false, "database error");
+        if (!psDBRollback(config->dbh)) {
+            psError(psErrorCodeLast(), false, "database error");
+        }
+        return false;
+    }
+
+    if (!psDBCommit(config->dbh)) {
+        psError(psErrorCodeLast(), false, "database error");
+        return false;
+    }
+
+    return true;
+}
+
+static bool warpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-warp_bg_id",    "warpBackgroundRun.warp_bg_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-skycell_id", "warpBackgroundSkyfile.skycell_id", "==");
+    pxAddLabelSearchArgs(config, where, "-label",   "warpBackgroundRun.label", "LIKE");
+    pxAddLabelSearchArgs(config, where, "-data_group",   "warpBackgroundRun.data_group", "LIKE");
+    pxAddLabelSearchArgs(config, where, "-dist_group",   "warpBackgroundRun.data_group", "LIKE");
+
+    PXOPT_LOOKUP_BOOL(all, config->args, "-all", false);
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    // find all rawImfiles matching the default query
+    psString query = pxDataGet("bgtool_warp.sql");
+    if (!query) {
+        psError(psErrorCodeLast(), false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    psString magicWhere = NULL;
+    if (!pxmagicAddWhere(config, &magicWhere, "warpBackgroundSkyfile")) {
+        psError(psErrorCodeLast(), false, "pxMagicAddWhere failed");
+        return false;
+    }
+    if (!pxspaceAddWhere(config, &magicWhere, "rawExp")) {
+        psError(psErrorCodeLast(), false, "pxSpaceAddWhere failed");
+        return false;
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " WHERE %s", whereClause);
+        psFree(whereClause);
+    } else if (!all && !magicWhere) {
+        psError(PXTOOLS_ERR_CONFIG, true, "search parameters or -all are required");
+        return false;
+    }
+    if (magicWhere) {
+        psStringAppend(&query, "%s %s", psListLength(where->list) ? "AND" : "WHERE", magicWhere);
+    }
+    psFree(magicWhere);
+    psFree(where);
+
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(psErrorCodeLast(), false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(psErrorCodeLast(), false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("bgtool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+    if (psArrayLength(output)) {
+        if (!ippdbPrintMetadatas(stdout, output, "warpBackgroundSkyfile", !simple)) {
+            psError(psErrorCodeLast(), false, "failed to print array");
+            psFree(output);
+            return false;
+        }
+    }
+    psFree(output);
+
+    return true;
+}
+
+
+static bool advancewarpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-warp_bg_id", "warp_bg_id", "==");
+    pxAddLabelSearchArgs(config, where, "-label", "label", "==");
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+
+    psString select = pxDataGet("bgtool_advancewarp.sql");
+    if (!select) {
+        psError(psErrorCodeLast(), false, "failed to retrieve SQL statement");
+        return false;
+    }
+
+    psString selectWhere = psStringCopy("");
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&selectWhere, "\n AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&select, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!psDBTransaction(config->dbh)) {
+        psError(psErrorCodeLast(), false, "database error");
+        return false;
+    }
+
+    if (!p_psDBRunQueryF(config->dbh, select, selectWhere)) {
+        psError(psErrorCodeLast(), false, "database error");
+        psFree(select);
+        psFree(selectWhere);
+        if (!psDBRollback(config->dbh)) {
+            psError(psErrorCodeLast(), false, "database error");
+        }
+        return false;
+    }
+    psFree(select);
+    psFree(selectWhere);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(psErrorCodeLast(), false, "database error");
+        if (!psDBRollback(config->dbh)) {
+            psError(psErrorCodeLast(), false, "database error");
+        }
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("bgtool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    for (long i = 0; i < psArrayLength(output); i++) {
+        psMetadata *row = output->data[i];
+        bool status = true;             // Status of MD lookup
+        psS64 warp_bg_id = psMetadataLookupS64(&status, row, "warp_bg_id");
+        if (!status) {
+            psError(PXTOOLS_ERR_PROG, true, "failed to look up value for warp_bg_id");
+            psFree(output);
+            if (!psDBRollback(config->dbh)) {
+                psError(psErrorCodeLast(), false, "database error");
+            }
+            return false;
+        }
+        psS64 magicked = psMetadataLookupS64(&status, row, "magicked");
+        if (!status) {
+            psError(PXTOOLS_ERR_PROG, true, "failed to look up value for magicked");
+            psFree(output);
+            if (!psDBRollback(config->dbh)) {
+                psError(psErrorCodeLast(), false, "database error");
+            }
+            return false;
+        }
+
+        if (!p_psDBRunQueryF(config->dbh,
+                             "UPDATE warpBackgroundRun "
+                             "SET state = 'full', magicked = %" PRId64 " "
+                             " WHERE warp_bg_id = %" PRId64,
+                             magicked, warp_bg_id)) {
+            psError(psErrorCodeLast(), false, "database error");
+            psFree(output);
+            if (!psDBRollback(config->dbh)) {
+                psError(psErrorCodeLast(), false, "database error");
+            }
+            return false;
+        }
+
+        psS64 numUpdated = psDBAffectedRows(config->dbh);
+        if (numUpdated != 1) {
+            psError(PXTOOLS_ERR_PROG, true, "should have affected 1 row");
+            if (!psDBRollback(config->dbh)) {
+                psError(psErrorCodeLast(), false, "database error");
+            }
+            psFree(output);
+            return false;
+        }
+    }
+    psFree(output);
+
+    if (!psDBCommit(config->dbh)) {
+        psError(psErrorCodeLast(), false, "database error");
+        return false;
+    }
+
+    return true;
+}
+
+static bool revertwarpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-warp_bg_id", "warpBackgroundRun.warp_bg_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-skycell_id", "warpBackgroundSkyfile.skycell_id", "==");
+    pxAddLabelSearchArgs(config, where, "-label", "warpBackgroundRun.label", "==");
+    PXOPT_COPY_S16(config->args, where, "-fault", "warpBackgroundSkyfile.fault", "==");
+
+    if (!psListLength(where->list) && !psMetadataLookupBool(NULL, config->args, "-all")) {
+        psFree(where);
+        psError(PXTOOLS_ERR_CONFIG, true, "search parameters are required");
+        return false;
+    }
+
+    psString query = pxDataGet("bgtool_revertwarp.sql");
+    if (!query) {
+        psError(psErrorCodeLast(), false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    int numDeleted = psDBAffectedRows(config->dbh);
+    psLogMsg("bgtool", PS_LOG_INFO, "Deleted %d warpBackgroundSkyfiles", numDeleted);
+
+    return true;
+}
+
+static bool tocleanwarpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    pxAddLabelSearchArgs(config, where, "-label", "warpBackgroundRun.label", "==");
+
+    psString query = pxDataGet("bgtool_tocleanwarp.sql");
+    if (!query) {
+        psError(psErrorCodeLast(), false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(psErrorCodeLast(), false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(psErrorCodeLast(), false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("bgtool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "warpBackgroundRun", !simple)) {
+        psError(psErrorCodeLast(), false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+    psFree(output);
+
+    return true;
+}
+
+static bool cleanedwarpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-warp_bg_id", "warpBackgroundRun.warp_bg_id", "==");
+
+    PXOPT_LOOKUP_STR(state, config->args, "-state", true, false);
+    if (!pxIsValidCleanedState(state)) {
+        psError(PXTOOLS_ERR_CONFIG, true, "Invalid state: %s", state);
+        return false;
+    }
+
+    if (!psListLength(where->list)) {
+        psError(PXTOOLS_ERR_CONFIG, true, "No search restrictions set.");
+        return false;
+    }
+
+    psString query = pxDataGet("bgtool_cleanedwarp.sql");
+    if (!query) {
+        psError(psErrorCodeLast(), false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    if (!p_psDBRunQueryF(config->dbh, query, state)) {
+        psError(psErrorCodeLast(), false, "database error");
+        return false;
+    }
+    psFree(query);
+
+    return true;
+}
+
+static bool exportwarpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    PXOPT_LOOKUP_S64(warp_bg_id, config->args, "-warp_bg_id", true,  false);
+    PXOPT_LOOKUP_STR(outfile, config->args, "-outfile", true,  false);
+    PXOPT_LOOKUP_BOOL(clean,  config->args, "-clean", false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-warp_bg_id", "warp_bg_id", "==");
+
+    bool status = exportTables(config, outfile, warpTables, where, clean);
+
+    psFree(where);
+    return status;
+}
+
+static bool importwarpMode(pxConfig *config)
+{
+    PXOPT_LOOKUP_STR(infile, config->args, "-infile", true,  false);
+
+    return importTables(config, infile, warpTables);
+}
Index: trunk/ippTools/src/bgtool.h
===================================================================
--- trunk/ippTools/src/bgtool.h	(revision 28486)
+++ trunk/ippTools/src/bgtool.h	(revision 28486)
@@ -0,0 +1,59 @@
+/*
+ * bgtool.h
+ *
+ * Copyright (C) 2006-2010  Joshua Hoblitt, Paul Price
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef BGTOOL_H
+#define BGTOOL_H 1
+
+#include "pxtools.h"
+
+typedef enum {
+    BGTOOL_MODE_NONE           = 0x0,
+    // Chip stage
+    BGTOOL_MODE_DEFINECHIP,
+    BGTOOL_MODE_UPDATECHIP,
+    BGTOOL_MODE_TOCHIP,
+    BGTOOL_MODE_CHIPINPUTS,
+    BGTOOL_MODE_ADDCHIP,
+    BGTOOL_MODE_CHIP,
+    BGTOOL_MODE_ADVANCECHIP,
+    BGTOOL_MODE_REVERTCHIP,
+    // Warp stage
+    BGTOOL_MODE_DEFINEWARP,
+    BGTOOL_MODE_UPDATEWARP,
+    BGTOOL_MODE_TOWARP,
+    BGTOOL_MODE_WARPINPUTS,
+    BGTOOL_MODE_ADDWARP,
+    BGTOOL_MODE_WARP,
+    BGTOOL_MODE_ADVANCEWARP,
+    BGTOOL_MODE_REVERTWARP,
+    // Cleanups
+    BGTOOL_MODE_TOCLEANCHIP,
+    BGTOOL_MODE_CLEANEDCHIP,
+    BGTOOL_MODE_TOCLEANWARP,
+    BGTOOL_MODE_CLEANEDWARP,
+    // Exporting
+    BGTOOL_MODE_EXPORTCHIP,
+    BGTOOL_MODE_IMPORTCHIP,
+    BGTOOL_MODE_EXPORTWARP,
+    BGTOOL_MODE_IMPORTWARP,
+} bgtoolMode;
+
+pxConfig *bgtoolConfig(pxConfig *config, int argc, char **argv);
+
+#endif // BGTOOL_H
Index: trunk/ippTools/src/bgtoolConfig.c
===================================================================
--- trunk/ippTools/src/bgtoolConfig.c	(revision 28486)
+++ trunk/ippTools/src/bgtoolConfig.c	(revision 28486)
@@ -0,0 +1,420 @@
+/*
+ * bgtoolConfig.c
+ *
+ * Copyright (C) 2006-2010  Joshua Hoblitt, Paul Price
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdint.h>
+
+#include <psmodules.h>
+
+#include "pxtools.h"
+#include "bgtool.h"
+
+pxConfig *bgtoolConfig(pxConfig *config, int argc, char **argv)
+{
+    if (!config) {
+        config = pxConfigAlloc();
+    }
+
+    pmConfigReadParamsSet(false);
+
+    // setup site config
+    config->modules = pmConfigRead(&argc, argv, NULL);
+    if (!config->modules) {
+        psError(psErrorCodeLast(), false, "Can't find site configuration");
+        psFree(config);
+        return NULL;
+    }
+
+    psTime *now = psTimeGetNow(PS_TIME_TAI);
+
+    // -definechip
+    psMetadata *definechipArgs = psMetadataAlloc();
+    psMetadataAddS64(definechipArgs, PS_LIST_TAIL, "-chip_id", 0, "search by chip_id", 0);
+    psMetadataAddS64(definechipArgs, PS_LIST_TAIL, "-exp_id", 0, "search by exp_id", 0);
+    psMetadataAddStr(definechipArgs, PS_LIST_TAIL, "-exp_name", 0, "search by exp_name", NULL);
+    psMetadataAddStr(definechipArgs, PS_LIST_TAIL, "-inst", 0, "search for camera", NULL);
+    psMetadataAddStr(definechipArgs, PS_LIST_TAIL, "-telescope", 0, "search for telescope", NULL);
+    psMetadataAddTime(definechipArgs, PS_LIST_TAIL, "-dateobs_begin", 0, "search for exposures by time (>=)", NULL);
+    psMetadataAddTime(definechipArgs, PS_LIST_TAIL, "-dateobs_end", 0, "search for exposures by time (<)", NULL);
+    psMetadataAddStr(definechipArgs, PS_LIST_TAIL, "-exp_tag", 0, "search by exp_tag", NULL);
+    psMetadataAddStr(definechipArgs, PS_LIST_TAIL, "-exp_type", 0, "search by exp_type", NULL);
+    psMetadataAddStr(definechipArgs, PS_LIST_TAIL, "-filelevel", 0, "search by filelevel", NULL);
+    psMetadataAddStr(definechipArgs, PS_LIST_TAIL, "-filter", 0, "search for filter", NULL);
+    psMetadataAddF64(definechipArgs, PS_LIST_TAIL, "-airmass_min", 0, "search by min airmass", NAN);
+    psMetadataAddF64(definechipArgs, PS_LIST_TAIL, "-airmass_max", 0, "search by max airmass", NAN);
+    psMetadataAddF64(definechipArgs, PS_LIST_TAIL, "-ra_min", 0, "search by min RA (degrees) ", NAN);
+    psMetadataAddF64(definechipArgs, PS_LIST_TAIL, "-ra_max", 0, "search by max RA (degrees) ", NAN);
+    psMetadataAddF64(definechipArgs, PS_LIST_TAIL, "-decl_min", 0, "search by min DEC (degrees)", NAN);
+    psMetadataAddF64(definechipArgs, PS_LIST_TAIL, "-decl_max", 0, "search by max DEC (degrees)", NAN);
+    psMetadataAddF32(definechipArgs, PS_LIST_TAIL, "-exp_time_min", 0, "search by min exposure time", NAN);
+    psMetadataAddF32(definechipArgs, PS_LIST_TAIL, "-exp_time_max", 0, "search by max exposure time", NAN);
+    psMetadataAddF32(definechipArgs, PS_LIST_TAIL, "-sat_pixel_frac_min", 0, "search by min fraction of saturated pixels", NAN);
+    psMetadataAddF32(definechipArgs, PS_LIST_TAIL, "-sat_pixel_frac_max", 0, "search by max fraction of saturated pixels", NAN);
+    psMetadataAddF64(definechipArgs, PS_LIST_TAIL, "-bg_min", 0, "search by min background", NAN);
+    psMetadataAddF64(definechipArgs, PS_LIST_TAIL, "-bg_max", 0, "search by max background", NAN);
+    psMetadataAddF64(definechipArgs, PS_LIST_TAIL, "-bg_stdev_min", 0, "search by min background standard deviation", NAN);
+    psMetadataAddF64(definechipArgs, PS_LIST_TAIL, "-bg_stdev_max", 0, "search by max background standard deviation", NAN);
+    psMetadataAddF64(definechipArgs, PS_LIST_TAIL, "-bg_mean_stdev_min", 0, "search by min background mean standard deviation (across imfiles)", NAN);
+    psMetadataAddF64(definechipArgs, PS_LIST_TAIL, "-bg_mean_stdev_max", 0, "search by max background mean standard deviation (across imfiles)", NAN);
+    psMetadataAddF64(definechipArgs, PS_LIST_TAIL, "-alt_min", 0, "search by min altitude", NAN);
+    psMetadataAddF64(definechipArgs, PS_LIST_TAIL, "-alt_max", 0, "search by max altitude", NAN);
+    psMetadataAddF64(definechipArgs, PS_LIST_TAIL, "-az_min", 0, "search by min azimuth ", NAN);
+    psMetadataAddF64(definechipArgs, PS_LIST_TAIL, "-az_max", 0, "search by max azimuth ", NAN);
+    psMetadataAddF32(definechipArgs, PS_LIST_TAIL, "-ccd_temp_min", 0, "search by min ccd tempature", NAN);
+    psMetadataAddF32(definechipArgs, PS_LIST_TAIL, "-ccd_temp_max", 0, "search by max ccd tempature", NAN);
+    psMetadataAddF64(definechipArgs, PS_LIST_TAIL, "-posang_min", 0, "search by min rotator position angle", NAN);
+    psMetadataAddF64(definechipArgs, PS_LIST_TAIL, "-posang_max", 0, "search by max rotator position angle", NAN);
+    psMetadataAddStr(definechipArgs, PS_LIST_TAIL, "-object", 0, "search by exposure object", NULL);
+    psMetadataAddStr(definechipArgs, PS_LIST_TAIL, "-comment", 0, "search by comment field (LIKE comparison)", NULL);
+    psMetadataAddStr(definechipArgs, PS_LIST_TAIL, "-obs_mode", 0, "search by observation mode", NULL);
+    psMetadataAddF32(definechipArgs, PS_LIST_TAIL, "-sun_angle_min", 0, "search by min solar angle", NAN);
+    psMetadataAddF32(definechipArgs, PS_LIST_TAIL, "-sun_angle_max", 0, "search by max solar angle", NAN);
+    psMetadataAddStr(definechipArgs, PS_LIST_TAIL, "-label", PS_META_DUPLICATE_OK, "search on chipRun label", NULL);
+    psMetadataAddBool(definechipArgs, PS_LIST_TAIL, "-rerun", 0, "re-run data?", false);
+    psMetadataAddStr(definechipArgs, PS_LIST_TAIL, "-set_workdir", 0, "define workdir", NULL);
+    psMetadataAddStr(definechipArgs, PS_LIST_TAIL, "-set_label", 0, "define label", NULL);
+    psMetadataAddStr(definechipArgs, PS_LIST_TAIL, "-set_reduction", 0, "define reduction class", NULL);
+    psMetadataAddStr(definechipArgs, PS_LIST_TAIL, "-set_data_group", 0, "define data group", NULL);
+    psMetadataAddStr(definechipArgs, PS_LIST_TAIL, "-set_dist_group", 0, "define dist group", NULL);
+    psMetadataAddStr(definechipArgs, PS_LIST_TAIL, "-set_note", 0, "define note", NULL);
+
+    psMetadataAddTime(definechipArgs, PS_LIST_TAIL, "-registered", 0, "time detrend run was registered", now);
+    psMetadataAddBool(definechipArgs, PS_LIST_TAIL, "-simple", 0, "use the simple output format", false);
+    psMetadataAddBool(definechipArgs, PS_LIST_TAIL, "-pretend", 0, "do not actually modify the database", false);
+
+    // -updatechip
+    psMetadata *updatechipArgs = psMetadataAlloc();
+    psMetadataAddS64(updatechipArgs, PS_LIST_TAIL, "-chip_bg_id", 0, "search by chip_bg_id", 0);
+    psMetadataAddStr(updatechipArgs, PS_LIST_TAIL, "-state", 0, "search by state", NULL);
+    psMetadataAddStr(updatechipArgs, PS_LIST_TAIL, "-label", PS_META_DUPLICATE_OK, "search by label (LIKE comparison)", NULL);
+    psMetadataAddStr(updatechipArgs, PS_LIST_TAIL, "-data_group", 0, "search by data_group (LIKE comparison)", NULL);
+    psMetadataAddStr(updatechipArgs, PS_LIST_TAIL, "-dist_group", 0, "search by dist_group (LIKE comparison)", NULL);
+    psMetadataAddTime(updatechipArgs, PS_LIST_TAIL, "-registered_begin", 0, "search by registration time (>=)", NULL);
+    psMetadataAddTime(updatechipArgs, PS_LIST_TAIL, "-registered_end", 0, "search by registration time (<)", NULL);
+    psMetadataAddBool(updatechipArgs, PS_LIST_TAIL, "-destreaked", 0, "search for runs that have been destreaked", false);
+    psMetadataAddBool(updatechipArgs, PS_LIST_TAIL, "-pretend", 0, "only pretend to run the query", false);
+    psMetadataAddStr(updatechipArgs, PS_LIST_TAIL, "-set_state", 0, "define new state", NULL);
+    psMetadataAddStr(updatechipArgs, PS_LIST_TAIL, "-set_label", 0, "define new value for label", 0);
+    psMetadataAddStr(updatechipArgs, PS_LIST_TAIL, "-set_data_group", 0, "define new data_group", NULL);
+    psMetadataAddStr(updatechipArgs, PS_LIST_TAIL, "-set_dist_group", 0, "define new dist_group", NULL);
+    psMetadataAddStr(updatechipArgs, PS_LIST_TAIL, "-set_note", 0, "define new note", NULL);
+
+    // -tochip
+    psMetadata *tochipArgs = psMetadataAlloc();
+    psMetadataAddS64(tochipArgs, PS_LIST_TAIL, "-chip_bg_id", 0, "search by chip_bg_id", 0);
+    psMetadataAddStr(tochipArgs, PS_LIST_TAIL, "-label", PS_META_DUPLICATE_OK, "search by label", NULL);
+    psMetadataAddU64(tochipArgs, PS_LIST_TAIL, "-limit",  0, "limit result set to N items", 0);
+    psMetadataAddBool(tochipArgs, PS_LIST_TAIL, "-simple",  0, "use the simple output format", false);
+
+    // -chipinputs
+    psMetadata *chipinputsArgs = psMetadataAlloc();
+    psMetadataAddS64(chipinputsArgs, PS_LIST_TAIL, "-chip_bg_id", 0, "search by chip_bg_id", 0);
+    psMetadataAddStr(chipinputsArgs, PS_LIST_TAIL, "-class_id", 0, "search by class_id", 0);
+    psMetadataAddU64(chipinputsArgs, PS_LIST_TAIL, "-limit",  0, "limit result set to N items", 0);
+    psMetadataAddBool(chipinputsArgs, PS_LIST_TAIL, "-simple",  0, "use the simple output format", false);
+
+    // -addchip
+    psMetadata *addchipArgs = psMetadataAlloc();
+    psMetadataAddS64(addchipArgs, PS_LIST_TAIL, "-chip_bg_id", 0, "define chip_bg_id (required)", 0);
+    psMetadataAddStr(addchipArgs, PS_LIST_TAIL, "-class_id", 0, "define class_id (required)", NULL);
+
+    psMetadataAddStr(addchipArgs, PS_LIST_TAIL, "-path_base", 0, "define base output location (required)", NULL);
+    psMetadataAddS64(addchipArgs, PS_LIST_TAIL, "-set_magicked",  0, "define if this skycell has been magicked", 0);
+    psMetadataAddF32(addchipArgs, PS_LIST_TAIL, "-dtime_script", 0, "define elapsed time in script (seconds)", NAN);
+    psMetadataAddStr(addchipArgs, PS_LIST_TAIL, "-hostname", 0, "define hostname", NULL);
+    psMetadataAddS16(addchipArgs, PS_LIST_TAIL, "-quality", 0, "set quality", 0);
+    psMetadataAddS16(addchipArgs, PS_LIST_TAIL, "-fault",  0, "set fault code", 0);
+    psMetadataAddStr(addchipArgs, PS_LIST_TAIL, "-ver_pslib", 0, "define psLib version", NULL);
+    psMetadataAddStr(addchipArgs, PS_LIST_TAIL, "-ver_psmodules", 0, "define psModules version", NULL);
+    psMetadataAddStr(addchipArgs, PS_LIST_TAIL, "-ver_ppbackground", 0, "define ppBackground version", NULL);
+    psMetadataAddStr(addchipArgs, PS_LIST_TAIL, "-ver_ppstats", 0, "define ppStats version", NULL);
+    psMetadataAddF64(addchipArgs, PS_LIST_TAIL, "-bg", 0, "define exposure background", NAN);
+    psMetadataAddF64(addchipArgs, PS_LIST_TAIL, "-bg_stdev", 0, "define exposure background stdev", NAN);
+    psMetadataAddS32(addchipArgs, PS_LIST_TAIL, "-maskfrac_npix", 0, "define number of pixels used for maskstats", 0);
+    psMetadataAddF32(addchipArgs, PS_LIST_TAIL, "-maskfrac_static", 0, "define static mask fraction", NAN);
+    psMetadataAddF32(addchipArgs, PS_LIST_TAIL, "-maskfrac_dynamic", 0, "define dynamic mask fraction", NAN);
+    psMetadataAddF32(addchipArgs, PS_LIST_TAIL, "-maskfrac_magic", 0, "define magic mask fraction", NAN);
+    psMetadataAddF32(addchipArgs, PS_LIST_TAIL, "-maskfrac_advisory", 0, "define advisory mask fraction", NAN);
+
+    // -chip
+    psMetadata *chipArgs = psMetadataAlloc();
+    psMetadataAddS64(chipArgs, PS_LIST_TAIL, "-chip_bg_id", 0, "search by chip_bg_id", 0);
+    psMetadataAddStr(chipArgs, PS_LIST_TAIL, "-class_id", 0, "search by class_id", NULL);
+    psMetadataAddS16(chipArgs, PS_LIST_TAIL, "-fault",  0, "search by fault code", 0);
+    psMetadataAddStr(chipArgs, PS_LIST_TAIL, "-label", PS_META_DUPLICATE_OK, "search by label", NULL);
+    psMetadataAddStr(chipArgs, PS_LIST_TAIL, "-data_group", PS_META_DUPLICATE_OK, "search by data_group", NULL);
+    psMetadataAddStr(chipArgs, PS_LIST_TAIL, "-dist_group", PS_META_DUPLICATE_OK, "search by dist_group", NULL);
+    pxmagicAddArguments(chipArgs);
+    psMetadataAddBool(chipArgs, PS_LIST_TAIL, "-all", 0, "search without arguments", false);
+    psMetadataAddU64(chipArgs, PS_LIST_TAIL, "-limit", 0, "limit result set to N items", 0);
+    psMetadataAddBool(chipArgs, PS_LIST_TAIL, "-simple", 0, "use the simple output format", false);
+
+    // -advancechip
+    psMetadata *advancechipArgs = psMetadataAlloc();
+    psMetadataAddS64(advancechipArgs, PS_LIST_TAIL, "-chip_bg_id", 0, "search by chip_bg_id", 0);
+    psMetadataAddStr(advancechipArgs, PS_LIST_TAIL, "-label", PS_META_DUPLICATE_OK, "search by label ", NULL);
+    psMetadataAddU64(advancechipArgs, PS_LIST_TAIL, "-limit", 0, "search limit", 0);
+
+    // -revertchip
+    psMetadata *revertchipArgs = psMetadataAlloc();
+    psMetadataAddS64(revertchipArgs, PS_LIST_TAIL, "-chip_bg_id", 0, "search by chip_bg_id", 0);
+    psMetadataAddStr(revertchipArgs, PS_LIST_TAIL, "-class_id",  0, "search by class_id", NULL);
+    psMetadataAddStr(revertchipArgs, PS_LIST_TAIL, "-label", PS_META_DUPLICATE_OK, "search by label", NULL);
+    psMetadataAddS16(revertchipArgs, PS_LIST_TAIL, "-fault", 0, "search by fault code", 0);
+    psMetadataAddBool(revertchipArgs, PS_LIST_TAIL, "-all", 0, "allow everything to be queued without search terms", false);
+
+    // -tocleanchip
+    psMetadata *tocleanchipArgs = psMetadataAlloc();
+    psMetadataAddStr(tocleanchipArgs, PS_LIST_TAIL, "-label", PS_META_DUPLICATE_OK, "list blocks for specified label", NULL);
+    psMetadataAddBool(tocleanchipArgs, PS_LIST_TAIL, "-simple", 0, "use the simple output format", false);
+    psMetadataAddU64(tocleanchipArgs, PS_LIST_TAIL, "-limit", 0, "limit result set to N items", 0);
+
+    // -cleanedchip
+    psMetadata *cleanedchipArgs = psMetadataAlloc();
+    psMetadataAddS64(cleanedchipArgs, PS_LIST_TAIL, "-chip_bg_id", 0, "search by chip_bg_id", 0);
+    psMetadataAddStr(cleanedchipArgs, PS_LIST_TAIL, "-state", 0, "cleaned state to set", NULL);
+
+    // -exportchip
+    psMetadata *exportchipArgs = psMetadataAlloc();
+    psMetadataAddS64(exportchipArgs, PS_LIST_TAIL, "-chip_bg_id", 0, "export this chip_bg_id (required)", 0);
+    psMetadataAddStr(exportchipArgs, PS_LIST_TAIL, "-outfile", 0, "export to this file (required)", NULL);
+    psMetadataAddBool(exportchipArgs, PS_LIST_TAIL, "-clean", 0, "export run in cleaned state", false);
+
+    // -importchip
+    psMetadata *importchipArgs = psMetadataAlloc();
+    psMetadataAddStr(importchipArgs, PS_LIST_TAIL, "-infile",  0, "import from this file (required)", NULL);
+
+
+
+    // -definewarp
+    psMetadata *definewarpArgs = psMetadataAlloc();
+    psMetadataAddS64(definewarpArgs, PS_LIST_TAIL, "-warp_id", 0, "search by warp_id", 0);
+    psMetadataAddS64(definewarpArgs, PS_LIST_TAIL, "-exp_id", 0, "search by exp_id", 0);
+    psMetadataAddStr(definewarpArgs, PS_LIST_TAIL, "-exp_name", 0, "search by exp_name", NULL);
+    psMetadataAddStr(definewarpArgs, PS_LIST_TAIL, "-inst", 0, "search for camera", NULL);
+    psMetadataAddStr(definewarpArgs, PS_LIST_TAIL, "-telescope", 0, "search for telescope", NULL);
+    psMetadataAddTime(definewarpArgs, PS_LIST_TAIL, "-dateobs_begin", 0, "search for exposures by time (>=)", NULL);
+    psMetadataAddTime(definewarpArgs, PS_LIST_TAIL, "-dateobs_end", 0, "search for exposures by time (<)", NULL);
+    psMetadataAddStr(definewarpArgs, PS_LIST_TAIL, "-exp_tag", 0, "search by exp_tag", NULL);
+    psMetadataAddStr(definewarpArgs, PS_LIST_TAIL, "-exp_type", 0, "search by exp_type", NULL);
+    psMetadataAddStr(definewarpArgs, PS_LIST_TAIL, "-filelevel", 0, "search by filelevel", NULL);
+    psMetadataAddStr(definewarpArgs, PS_LIST_TAIL, "-filter", 0, "search for filter", NULL);
+    psMetadataAddF64(definewarpArgs, PS_LIST_TAIL, "-airmass_min", 0, "search by min airmass", NAN);
+    psMetadataAddF64(definewarpArgs, PS_LIST_TAIL, "-airmass_max", 0, "search by max airmass", NAN);
+    psMetadataAddF64(definewarpArgs, PS_LIST_TAIL, "-ra_min", 0, "search by min RA (degrees) ", NAN);
+    psMetadataAddF64(definewarpArgs, PS_LIST_TAIL, "-ra_max", 0, "search by max RA (degrees) ", NAN);
+    psMetadataAddF64(definewarpArgs, PS_LIST_TAIL, "-decl_min", 0, "search by min DEC (degrees)", NAN);
+    psMetadataAddF64(definewarpArgs, PS_LIST_TAIL, "-decl_max", 0, "search by max DEC (degrees)", NAN);
+    psMetadataAddF32(definewarpArgs, PS_LIST_TAIL, "-exp_time_min", 0, "search by min exposure time", NAN);
+    psMetadataAddF32(definewarpArgs, PS_LIST_TAIL, "-exp_time_max", 0, "search by max exposure time", NAN);
+    psMetadataAddF32(definewarpArgs, PS_LIST_TAIL, "-sat_pixel_frac_min", 0, "search by min fraction of saturated pixels", NAN);
+    psMetadataAddF32(definewarpArgs, PS_LIST_TAIL, "-sat_pixel_frac_max", 0, "search by max fraction of saturated pixels", NAN);
+    psMetadataAddF64(definewarpArgs, PS_LIST_TAIL, "-bg_min", 0, "search by min background", NAN);
+    psMetadataAddF64(definewarpArgs, PS_LIST_TAIL, "-bg_max", 0, "search by max background", NAN);
+    psMetadataAddF64(definewarpArgs, PS_LIST_TAIL, "-bg_stdev_min", 0, "search by min background standard deviation", NAN);
+    psMetadataAddF64(definewarpArgs, PS_LIST_TAIL, "-bg_stdev_max", 0, "search by max background standard deviation", NAN);
+    psMetadataAddF64(definewarpArgs, PS_LIST_TAIL, "-bg_mean_stdev_min", 0, "search by min background mean standard deviation (across imfiles)", NAN);
+    psMetadataAddF64(definewarpArgs, PS_LIST_TAIL, "-bg_mean_stdev_max", 0, "search by max background mean standard deviation (across imfiles)", NAN);
+    psMetadataAddF64(definewarpArgs, PS_LIST_TAIL, "-alt_min", 0, "search by min altitude", NAN);
+    psMetadataAddF64(definewarpArgs, PS_LIST_TAIL, "-alt_max", 0, "search by max altitude", NAN);
+    psMetadataAddF64(definewarpArgs, PS_LIST_TAIL, "-az_min", 0, "search by min azimuth ", NAN);
+    psMetadataAddF64(definewarpArgs, PS_LIST_TAIL, "-az_max", 0, "search by max azimuth ", NAN);
+    psMetadataAddF32(definewarpArgs, PS_LIST_TAIL, "-ccd_temp_min", 0, "search by min ccd tempature", NAN);
+    psMetadataAddF32(definewarpArgs, PS_LIST_TAIL, "-ccd_temp_max", 0, "search by max ccd tempature", NAN);
+    psMetadataAddF64(definewarpArgs, PS_LIST_TAIL, "-posang_min", 0, "search by min rotator position angle", NAN);
+    psMetadataAddF64(definewarpArgs, PS_LIST_TAIL, "-posang_max", 0, "search by max rotator position angle", NAN);
+    psMetadataAddStr(definewarpArgs, PS_LIST_TAIL, "-object", 0, "search by exposure object", NULL);
+    psMetadataAddStr(definewarpArgs, PS_LIST_TAIL, "-comment", 0, "search by comment field (LIKE comparison)", NULL);
+    psMetadataAddStr(definewarpArgs, PS_LIST_TAIL, "-obs_mode", 0, "search by observation mode", NULL);
+    psMetadataAddF32(definewarpArgs, PS_LIST_TAIL, "-sun_angle_min", 0, "search by min solar angle", NAN);
+    psMetadataAddF32(definewarpArgs, PS_LIST_TAIL, "-sun_angle_max", 0, "search by max solar angle", NAN);
+    psMetadataAddStr(definewarpArgs, PS_LIST_TAIL, "-warp_label", PS_META_DUPLICATE_OK, "search on warpRun label", NULL);
+    psMetadataAddStr(definewarpArgs, PS_LIST_TAIL, "-bg_label", PS_META_DUPLICATE_OK, "search on warpBackgroundRun label", NULL);
+    psMetadataAddBool(definewarpArgs, PS_LIST_TAIL, "-rerun", 0, "rerun data?", false);
+    psMetadataAddStr(definewarpArgs, PS_LIST_TAIL, "-set_workdir", 0, "define workdir", NULL);
+    psMetadataAddStr(definewarpArgs, PS_LIST_TAIL, "-set_label", 0, "define label", NULL);
+    psMetadataAddStr(definewarpArgs, PS_LIST_TAIL, "-set_reduction", 0, "define reduction class", NULL);
+    psMetadataAddStr(definewarpArgs, PS_LIST_TAIL, "-set_data_group", 0, "define data group", NULL);
+    psMetadataAddStr(definewarpArgs, PS_LIST_TAIL, "-set_dist_group", 0, "define dist group", NULL);
+    psMetadataAddStr(definewarpArgs, PS_LIST_TAIL, "-set_note", 0, "define note", NULL);
+
+    psMetadataAddTime(definewarpArgs, PS_LIST_TAIL, "-registered", 0, "time detrend run was registered", now);
+    psMetadataAddBool(definewarpArgs, PS_LIST_TAIL, "-simple", 0, "use the simple output format", false);
+    psMetadataAddBool(definewarpArgs, PS_LIST_TAIL, "-pretend", 0, "do not actually modify the database", false);
+
+    // -updatewarp
+    psMetadata *updatewarpArgs = psMetadataAlloc();
+    psMetadataAddS64(updatewarpArgs, PS_LIST_TAIL, "-warp_bg_id", 0, "search by warp_bg_id", 0);
+    psMetadataAddStr(updatewarpArgs, PS_LIST_TAIL, "-state", 0, "search by state", NULL);
+    psMetadataAddStr(updatewarpArgs, PS_LIST_TAIL, "-label", PS_META_DUPLICATE_OK, "search by label (LIKE comparison)", NULL);
+    psMetadataAddStr(updatewarpArgs, PS_LIST_TAIL, "-data_group", 0, "search by data_group (LIKE comparison)", NULL);
+    psMetadataAddStr(updatewarpArgs, PS_LIST_TAIL, "-dist_group", 0, "search by dist_group (LIKE comparison)", NULL);
+    psMetadataAddTime(updatewarpArgs, PS_LIST_TAIL, "-registered_begin", 0, "search by registration time (>=)", NULL);
+    psMetadataAddTime(updatewarpArgs, PS_LIST_TAIL, "-registered_end", 0, "search by registration time (<)", NULL);
+    psMetadataAddBool(updatewarpArgs, PS_LIST_TAIL, "-destreaked", 0, "search for runs that have been destreaked", false);
+    psMetadataAddBool(updatewarpArgs, PS_LIST_TAIL, "-pretend", 0, "only pretend to run the query", false);
+    psMetadataAddStr(updatewarpArgs, PS_LIST_TAIL, "-set_state", 0, "define new state", NULL);
+    psMetadataAddStr(updatewarpArgs, PS_LIST_TAIL, "-set_label", 0, "define new value for label", 0);
+    psMetadataAddStr(updatewarpArgs, PS_LIST_TAIL, "-set_data_group", 0, "define new data_group", NULL);
+    psMetadataAddStr(updatewarpArgs, PS_LIST_TAIL, "-set_dist_group", 0, "define new dist_group", NULL);
+    psMetadataAddStr(updatewarpArgs, PS_LIST_TAIL, "-set_note", 0, "define new note", NULL);
+
+    // -towarp
+    psMetadata *towarpArgs = psMetadataAlloc();
+    psMetadataAddS64(towarpArgs, PS_LIST_TAIL, "-warp_bg_id", 0, "search by warp_bg_id", 0);
+    psMetadataAddStr(towarpArgs, PS_LIST_TAIL, "-label", PS_META_DUPLICATE_OK, "search by label", NULL);
+    psMetadataAddU64(towarpArgs, PS_LIST_TAIL, "-limit",  0, "limit result set to N items", 0);
+    psMetadataAddBool(towarpArgs, PS_LIST_TAIL, "-simple",  0, "use the simple output format", false);
+
+    // -warpinputs
+    psMetadata *warpinputsArgs = psMetadataAlloc();
+    psMetadataAddS64(warpinputsArgs, PS_LIST_TAIL, "-warp_bg_id", 0, "search by warp_bg_id", 0);
+    psMetadataAddStr(warpinputsArgs, PS_LIST_TAIL, "-skycell_id", 0, "search by skycell_id", 0);
+    psMetadataAddU64(warpinputsArgs, PS_LIST_TAIL, "-limit",  0, "limit result set to N items", 0);
+    psMetadataAddBool(warpinputsArgs, PS_LIST_TAIL, "-simple",  0, "use the simple output format", false);
+
+    // -addwarp
+    psMetadata *addwarpArgs = psMetadataAlloc();
+    psMetadataAddS64(addwarpArgs, PS_LIST_TAIL, "-warp_bg_id", 0, "define warp_bg_id (required)", 0);
+    psMetadataAddStr(addwarpArgs, PS_LIST_TAIL, "-skycell_id", 0, "define skycell_id (required)", NULL);
+
+    psMetadataAddStr(addwarpArgs, PS_LIST_TAIL, "-path_base", 0, "define base output location", 0);
+    psMetadataAddS64(addwarpArgs, PS_LIST_TAIL, "-set_magicked",  0, "define if this skycell has been magicked", 0);
+    psMetadataAddF32(addwarpArgs, PS_LIST_TAIL, "-dtime_script", 0, "define elapsed time in script (seconds)", NAN);
+    psMetadataAddStr(addwarpArgs, PS_LIST_TAIL, "-hostname", 0, "define hostname", 0);
+    psMetadataAddS16(addwarpArgs, PS_LIST_TAIL, "-quality", 0, "set quality", 0);
+    psMetadataAddS16(addwarpArgs, PS_LIST_TAIL, "-fault",  0, "set fault code", 0);
+    psMetadataAddStr(addwarpArgs, PS_LIST_TAIL, "-ver_pslib", 0, "define psLib version", NULL);
+    psMetadataAddStr(addwarpArgs, PS_LIST_TAIL, "-ver_psmodules", 0, "define psModules version", NULL);
+    psMetadataAddStr(addwarpArgs, PS_LIST_TAIL, "-ver_pswarp", 0, "define pswarp version", NULL);
+    psMetadataAddStr(addwarpArgs, PS_LIST_TAIL, "-ver_ppstats", 0, "define ppStats version", NULL);
+    psMetadataAddF64(addwarpArgs, PS_LIST_TAIL, "-bg", 0, "define exposure background", NAN);
+    psMetadataAddF64(addwarpArgs, PS_LIST_TAIL, "-bg_stdev", 0, "define exposure background stdev", NAN);
+    psMetadataAddS32(addwarpArgs, PS_LIST_TAIL, "-maskfrac_npix", 0, "define number of pixels used for maskstats", 0);
+    psMetadataAddF32(addwarpArgs, PS_LIST_TAIL, "-maskfrac_static", 0, "define static mask fraction", NAN);
+    psMetadataAddF32(addwarpArgs, PS_LIST_TAIL, "-maskfrac_dynamic", 0, "define dynamic mask fraction", NAN);
+    psMetadataAddF32(addwarpArgs, PS_LIST_TAIL, "-maskfrac_magic", 0, "define magic mask fraction", NAN);
+    psMetadataAddF32(addwarpArgs, PS_LIST_TAIL, "-maskfrac_advisory", 0, "define advisory mask fraction", NAN);
+
+    // -warp
+    psMetadata *warpArgs = psMetadataAlloc();
+    psMetadataAddS64(warpArgs, PS_LIST_TAIL, "-warp_bg_id", 0, "search by warp_bg_id", 0);
+    psMetadataAddStr(warpArgs, PS_LIST_TAIL, "-skycell_id", 0, "search by skycell_id", NULL);
+    psMetadataAddS16(warpArgs, PS_LIST_TAIL, "-fault",  0, "search by fault code", 0);
+    psMetadataAddStr(warpArgs, PS_LIST_TAIL, "-label", PS_META_DUPLICATE_OK, "search by label", NULL);
+    psMetadataAddStr(warpArgs, PS_LIST_TAIL, "-data_group", PS_META_DUPLICATE_OK, "search by data_group", NULL);
+    psMetadataAddStr(warpArgs, PS_LIST_TAIL, "-dist_group", PS_META_DUPLICATE_OK, "search by dist_group", NULL);
+    pxmagicAddArguments(warpArgs);
+    psMetadataAddBool(warpArgs, PS_LIST_TAIL, "-all", 0, "search without arguments", false);
+    psMetadataAddU64(warpArgs, PS_LIST_TAIL, "-limit", 0, "limit result set to N items", 0);
+    psMetadataAddBool(warpArgs, PS_LIST_TAIL, "-simple", 0, "use the simple output format", false);
+
+    // -advancewarp
+    psMetadata *advancewarpArgs = psMetadataAlloc();
+    psMetadataAddS64(advancewarpArgs, PS_LIST_TAIL, "-warp_bg_id", 0, "search by warp_bg_id", 0);
+    psMetadataAddStr(advancewarpArgs, PS_LIST_TAIL, "-label", PS_META_DUPLICATE_OK, "search by label ", NULL);
+    psMetadataAddU64(advancewarpArgs, PS_LIST_TAIL, "-limit", 0, "search limit", 0);
+
+    // -revertwarp
+    psMetadata *revertwarpArgs = psMetadataAlloc();
+    psMetadataAddS64(revertwarpArgs, PS_LIST_TAIL, "-warp_bg_id", 0, "search by warp_bg_id", 0);
+    psMetadataAddStr(revertwarpArgs, PS_LIST_TAIL, "-skycell_id",  0, "search by skycell_id", NULL);
+    psMetadataAddStr(revertwarpArgs, PS_LIST_TAIL, "-label", PS_META_DUPLICATE_OK, "search by label", NULL);
+    psMetadataAddS16(revertwarpArgs, PS_LIST_TAIL, "-fault", 0, "search by fault code", 0);
+    psMetadataAddBool(revertwarpArgs, PS_LIST_TAIL, "-all", 0, "allow everything to be queued without search terms", false);
+
+    // -tocleanwarp
+    psMetadata *tocleanwarpArgs = psMetadataAlloc();
+    psMetadataAddStr(tocleanwarpArgs, PS_LIST_TAIL, "-label", PS_META_DUPLICATE_OK, "list blocks for specified label", NULL);
+    psMetadataAddBool(tocleanwarpArgs, PS_LIST_TAIL, "-simple", 0, "use the simple output format", false);
+    psMetadataAddU64(tocleanwarpArgs, PS_LIST_TAIL, "-limit", 0, "limit result set to N items", 0);
+
+    // -cleanedwarp
+    psMetadata *cleanedwarpArgs = psMetadataAlloc();
+    psMetadataAddS64(cleanedwarpArgs, PS_LIST_TAIL, "-warp_bg_id", 0, "search by warp_bg_id", 0);
+    psMetadataAddStr(cleanedwarpArgs, PS_LIST_TAIL, "-state", 0, "cleaned state to set", NULL);
+
+    // -exportwarp
+    psMetadata *exportwarpArgs = psMetadataAlloc();
+    psMetadataAddS64(exportwarpArgs, PS_LIST_TAIL, "-warp_bg_id", 0, "export this warp_bg_id (required)", 0);
+    psMetadataAddStr(exportwarpArgs, PS_LIST_TAIL, "-outfile", 0, "export to this file (required)", NULL);
+    psMetadataAddBool(exportwarpArgs, PS_LIST_TAIL, "-clean", 0, "export run in cleaned state", false);
+
+    // -importwarp
+    psMetadata *importwarpArgs = psMetadataAlloc();
+    psMetadataAddStr(importwarpArgs, PS_LIST_TAIL, "-infile",  0, "import from this file (required)", NULL);
+
+
+
+    psFree(now);
+    psMetadata *argSets = psMetadataAlloc();
+    psMetadata *modes   = psMetadataAlloc();
+
+    PXOPT_ADD_MODE("-definechip",  "", BGTOOL_MODE_DEFINECHIP,  definechipArgs);
+    PXOPT_ADD_MODE("-updatechip",  "", BGTOOL_MODE_UPDATECHIP,  updatechipArgs);
+    PXOPT_ADD_MODE("-tochip",      "", BGTOOL_MODE_TOCHIP,      tochipArgs);
+    PXOPT_ADD_MODE("-chipinputs",  "", BGTOOL_MODE_CHIPINPUTS,  chipinputsArgs);
+    PXOPT_ADD_MODE("-addchip",     "", BGTOOL_MODE_ADDCHIP,     addchipArgs);
+    PXOPT_ADD_MODE("-chip",        "", BGTOOL_MODE_CHIP,        chipArgs);
+    PXOPT_ADD_MODE("-advancechip", "", BGTOOL_MODE_ADVANCECHIP, advancechipArgs);
+    PXOPT_ADD_MODE("-revertchip",  "", BGTOOL_MODE_REVERTCHIP,  revertchipArgs);
+    PXOPT_ADD_MODE("-tocleanchip", "", BGTOOL_MODE_TOCLEANCHIP, tocleanchipArgs);
+    PXOPT_ADD_MODE("-cleanedchip", "", BGTOOL_MODE_CLEANEDCHIP, cleanedchipArgs);
+    PXOPT_ADD_MODE("-exportchip",  "", BGTOOL_MODE_EXPORTCHIP,  exportchipArgs);
+    PXOPT_ADD_MODE("-importchip",  "", BGTOOL_MODE_IMPORTCHIP,  importchipArgs);
+
+    PXOPT_ADD_MODE("-definewarp",  "", BGTOOL_MODE_DEFINEWARP,  definewarpArgs);
+    PXOPT_ADD_MODE("-updatewarp",  "", BGTOOL_MODE_UPDATEWARP,  updatewarpArgs);
+    PXOPT_ADD_MODE("-towarp",      "", BGTOOL_MODE_TOWARP,      towarpArgs);
+    PXOPT_ADD_MODE("-warpinputs",  "", BGTOOL_MODE_WARPINPUTS,  warpinputsArgs);
+    PXOPT_ADD_MODE("-addwarp",     "", BGTOOL_MODE_ADDWARP,     addwarpArgs);
+    PXOPT_ADD_MODE("-warp",        "", BGTOOL_MODE_WARP,        warpArgs);
+    PXOPT_ADD_MODE("-advancewarp", "", BGTOOL_MODE_ADVANCEWARP, advancewarpArgs);
+    PXOPT_ADD_MODE("-revertwarp",  "", BGTOOL_MODE_REVERTWARP,  revertwarpArgs);
+    PXOPT_ADD_MODE("-tocleanwarp", "", BGTOOL_MODE_TOCLEANWARP, tocleanwarpArgs);
+    PXOPT_ADD_MODE("-cleanedwarp", "", BGTOOL_MODE_CLEANEDWARP, cleanedwarpArgs);
+    PXOPT_ADD_MODE("-exportwarp",  "", BGTOOL_MODE_EXPORTWARP,  exportwarpArgs);
+    PXOPT_ADD_MODE("-importwarp",  "", BGTOOL_MODE_IMPORTWARP,  importwarpArgs);
+
+    if (!pxGetOptions(stderr, argc, argv, config, modes, argSets)) {
+        psError(PS_ERR_UNKNOWN, true, "option parsing failed");
+        psFree(argSets);
+        psFree(modes);
+        psFree(config);
+        return NULL;
+    }
+
+    psFree(argSets);
+    psFree(modes);
+
+    // define Database handle, if used
+    // do this last so we don't setup a connection before CLI options are
+    // validated
+    config->dbh = psMemIncrRefCounter(pmConfigDB(config->modules));
+    if (!config->dbh) {
+        psError(PS_ERR_UNKNOWN, false, "Can't configure database");
+        psFree(config);
+        return NULL;
+    }
+
+    return config;
+}
Index: trunk/ippTools/src/pxtools.c
===================================================================
--- trunk/ippTools/src/pxtools.c	(revision 28429)
+++ trunk/ippTools/src/pxtools.c	(revision 28486)
@@ -48,4 +48,14 @@
 }
 
+bool pxIsValidCleanedState(const char *state)
+{
+    PS_ASSERT_PTR_NON_NULL(state, false);
+
+    if (!strcmp(state, "cleaned")) return true;
+    if (!strcmp(state, "purged")) return true;
+    if (!strcmp(state, "scrubbed")) return true;
+    return false;
+}
+
 psString pxMergeCodeVersions(psString version1, psString version2)
 {
@@ -211,9 +221,9 @@
 
 // change the value for tableName.columName from 'full' to 'cleaned' if necessary
-bool pxSetStateCleaned(const psString tableName, const psString columnName, psArray *rows)
+bool pxSetStateCleaned(const char *tableName, const char *columnName, psArray *rows)
 {
     for (long i = 0; i < psArrayLength(rows); i++) {
         psMetadata *row = rows->data[i];
-        psString state = psMetadataLookupStr(NULL, row, columnName);
+        const char *state = psMetadataLookupStr(NULL, row, columnName);
         if (!state) {
             psError(PS_ERR_PROGRAMMING, false, "%s not found in row %ld of table %s",
Index: trunk/ippTools/src/pxtools.h
===================================================================
--- trunk/ippTools/src/pxtools.h	(revision 28429)
+++ trunk/ippTools/src/pxtools.h	(revision 28486)
@@ -53,20 +53,21 @@
 
 bool pxIsValidState(const char *state);
+bool pxIsValidCleanedState(const char *state);
 psString pxMergeCodeVersions(psString version1, psString version2);
 bool pxCoalesceRunStatus(pxConfig *config, const psString dbQFile, psS64 stage_id, psString *software_ver,
-			 psS64 *maskfrac_npix, psF32 *maskfrac_static, psF32 *maskfrac_dynamic,
-			 psF32 *maskfrac_magic, psF32 *maskfrac_advisory);
+                         psS64 *maskfrac_npix, psF32 *maskfrac_static, psF32 *maskfrac_dynamic,
+                         psF32 *maskfrac_magic, psF32 *maskfrac_advisory);
 bool pxSetRunSoftware(pxConfig *config, const psString tableName, const psString stage_id_name, const psS64 stage_id,
-		      psString software_ver);
+                      psString software_ver);
 bool pxSetRunMaskfrac(pxConfig *config, const psString tableName, const psString stage_id_name, const psS64 stage_id,
-		      psS64 maskfrac_npix, psF32 maskfrac_static, psF32 maskfrac_dynamic,
-		      psF32 maskfrac_magic, psF32 maskfrac_advisory);
+                      psS64 maskfrac_npix, psF32 maskfrac_static, psF32 maskfrac_dynamic,
+                      psF32 maskfrac_magic, psF32 maskfrac_advisory);
 bool pxCamSetRunMaskfrac(pxConfig *config, const psString tableName, const psString stage_id_name, const psS64 stage_id,
-			 psS64 maskfrac_ref_npix, psF32 maskfrac_ref_static, psF32 maskfrac_ref_dynamic,
-			 psF32 maskfrac_ref_magic, psF32 maskfrac_ref_advisory,
-			 psS64 maskfrac_max_npix, psF32 maskfrac_max_static, psF32 maskfrac_max_dynamic,
-			 psF32 maskfrac_max_magic, psF32 maskfrac_max_advisory);
-
-bool pxSetStateCleaned(const psString tableName, const psString columnName, psArray *rows);
+                         psS64 maskfrac_ref_npix, psF32 maskfrac_ref_static, psF32 maskfrac_ref_dynamic,
+                         psF32 maskfrac_ref_magic, psF32 maskfrac_ref_advisory,
+                         psS64 maskfrac_max_npix, psF32 maskfrac_max_static, psF32 maskfrac_max_dynamic,
+                         psF32 maskfrac_max_magic, psF32 maskfrac_max_advisory);
+
+bool pxSetStateCleaned(const char *tableName, const char *columnName, psArray *rows);
 bool pxAddLabelSearchArgs (pxConfig *config, psMetadata *where, char *field, char *name, char *op);
 
