IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Jun 2, 2010, 4:33:05 PM (16 years ago)
Author:
Paul Price
Message:

Adding first cut at bgtool, to implement background restoration pipeline.

Location:
branches/pap/ippTools/src
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • branches/pap/ippTools/src

    • Property svn:ignore
      •  

        old new  
        3939warptool
        4040staticskytool
         41
         42bgtool
  • branches/pap/ippTools/src/bgtool.c

    r28188 r28199  
    11/*
    2  * warptool.c
     2 * bgtool.c
    33 *
    4  * Copyright (C) 2006  Joshua Hoblitt
     4 * Copyright (C) 2006-2010  Joshua Hoblitt, Paul Price
    55 *
    66 * This program is free software; you can redistribute it and/or modify it
     
    2929
    3030#include "pxtools.h"
    31 #include "warptool.h"
     31#include "bgtool.h"
    3232
    3333static bool definechipMode(pxConfig *config);
    3434static bool updatechipMode(pxConfig *config);
    3535static bool tochipMode(pxConfig *config);
    36 static bool chipInputsMode(pxConfig *config);
     36static bool chipinputsMode(pxConfig *config);
    3737static bool addchipMode(pxConfig *config);
    3838static bool chipMode(pxConfig *config);
     
    4242static bool updatewarpMode(pxConfig *config);
    4343static bool towarpMode(pxConfig *config);
    44 static bool warpInputsMode(pxConfig *config);
     44static bool warpinputsMode(pxConfig *config);
    4545static bool addwarpMode(pxConfig *config);
    4646static bool warpMode(pxConfig *config);
     
    5656static bool importwarpMode(pxConfig *config);
    5757
     58// Tables to import/export
     59typedef struct {
     60    const char *name;                   // Table name
     61    void* (*parse)();                   // Parsing function
     62    bool (*insert)();                   // Insertion function
     63} tableData;
     64static const tableData chipTables[] = {
     65    { "chipBackgroundRun", (void*)&chipBackgroundRunObjectFromMetadata, &chipBackgroundRunInsertObject },
     66    { "chipBackgroundImfile", (void*)&chipBackgroundImfileObjectFromMetadata, &chipBackgroundImfileInsertObject },
     67    { NULL, NULL, NULL }
     68};
     69static const tableData warpTables[] = {
     70    { "warpBackgroundRun", (void*)&warpBackgroundRunObjectFromMetadata, &warpBackgroundRunInsertObject },
     71    { "warpBackgroundImfile", (void*)&warpBackgroundSkyfileObjectFromMetadata, &warpBackgroundSkyfileInsertObject },
     72    { NULL, NULL, NULL }
     73};
     74
     75
    5876# define MODECASE(caseName, func) \
    5977    case caseName: \
     
    7795        MODECASE(BGTOOL_MODE_UPDATECHIP,  updatechipMode);
    7896        MODECASE(BGTOOL_MODE_TOCHIP,      tochipMode);
    79         MODECASE(BGTOOL_MODE_CHIPINPUTS,  chipInputsMode);
     97        MODECASE(BGTOOL_MODE_CHIPINPUTS,  chipinputsMode);
    8098        MODECASE(BGTOOL_MODE_ADDCHIP,     addchipMode);
    8199        MODECASE(BGTOOL_MODE_CHIP,        chipMode);
     
    85103        MODECASE(BGTOOL_MODE_UPDATEWARP,  updatewarpMode);
    86104        MODECASE(BGTOOL_MODE_TOWARP,      towarpMode);
    87         MODECASE(BGTOOL_MODE_WARPINPUTS,  warpInputsMode);
     105        MODECASE(BGTOOL_MODE_WARPINPUTS,  warpinputsMode);
    88106        MODECASE(BGTOOL_MODE_ADDWARP,     addwarpMode);
    89107        MODECASE(BGTOOL_MODE_WARP,        warpMode);
     
    119137    exit(exit_status);
    120138}
     139
     140//////////////////////////////////////////////////////////////////////////////////////////////////////////////
     141// General functions
     142//////////////////////////////////////////////////////////////////////////////////////////////////////////////
     143
     144static bool exportTables(pxConfig *config, // Configuration (with DB handle)
     145                         const char *filename, // Filename to which to write
     146                         const tableData tables[], // Tables to export (NULL terminated)
     147                         const psMetadata *where, // WHERE restrictions
     148                         bool clean               // Write as cleaned?
     149                         )
     150{
     151    PS_ASSERT_PTR_NON_NULL(config, false);
     152
     153    FILE *file = fopen(filename, "w");
     154    if (!file) {
     155        psError(PXTOOLS_ERR_SYS, true, "failed to open output file %s", filename);
     156        return false;
     157    }
     158
     159    if (!pxExportVersion(config, file)) {
     160        psError(psErrorCodeLast(), false, "failed to write dbversion to output file %s", filename);
     161        return false;
     162    }
     163
     164    for (int i = 0; tables[i].name; i++) {
     165        const char *name = tables[i].name; // Name of table
     166        psString query = NULL;
     167        psStringAppend(&query, "SELECT * FROM %s", name);
     168
     169        if (psListLength(where->list)) {
     170            psString whereClause = psDBGenerateWhereSQL(where, NULL);
     171            psStringAppend(&query, " WHERE %s", whereClause);
     172            psFree(whereClause);
     173        }
     174
     175        if (!p_psDBRunQuery(config->dbh, query)) {
     176            psError(psErrorCodeLast(), false, "database error");
     177            psFree(query);
     178            return false;
     179        }
     180        psFree(query);
     181
     182        psArray *output = p_psDBFetchResult(config->dbh);
     183        if (!output) {
     184            psError(psErrorCodeLast(), false, "database error");
     185            return false;
     186        }
     187        if (!psArrayLength(output)) {
     188            psError(PXTOOLS_ERR_CONFIG, true, "no rows found");
     189            psFree(output);
     190            return false;
     191        }
     192
     193        if (clean &&
     194            (strcmp(name, "chipBackgroundRun") == 0 ||
     195             strcmp(name, "warpBackgroundRun") == 0) &&
     196            !pxSetStateCleaned(name, "state", output)) {
     197            psFree(output);
     198            psError(psErrorCodeLast(), false, "pxSetStateClean failed for table %s", name);
     199            return false;
     200        }
     201
     202        if (!ippdbPrintMetadatas(file, output, name, true)) {
     203            psError(psErrorCodeLast(), false, "failed to print array");
     204            psFree(output);
     205            return false;
     206        }
     207        psFree(output);
     208    }
     209    fclose(file);
     210
     211    return true;
     212}
     213
     214static bool importTables(pxConfig *config, // Configuration
     215                        const char *filename, //
     216                        const tableData tables[] // Tables to read in
     217                        )
     218{
     219    PS_ASSERT_PTR_NON_NULL(config, false);
     220
     221    unsigned int badLines = 0;          // Number of bad lines
     222    psMetadata *input = psMetadataConfigRead(NULL, &badLines, filename, false); // Input file contents
     223    if (!input) {
     224        psError(psErrorCodeLast(), false, "Unable to parse input file %s", filename);
     225        return false;
     226    }
     227    if (badLines > 0) {
     228        psWarning("%d bad lines encountered when parsing %s", badLines, filename);
     229    }
     230
     231    if (!pxCheckImportVersion(config, input)) {
     232        psError(psErrorCodeLast(), false, "pxCheckImportVersion failed");
     233        return false;
     234    }
     235
     236    // Import primary table
     237    for (int i = 0; tables[i].name; i++) {
     238        const char *name = tables[i].name; // Name of table
     239        psMetadataItem *item = psMetadataLookup(input, name); // Item from input
     240        psAssert(item, "%s not in input", name);
     241        psAssert(item->type == PS_DATA_METADATA_MULTI, "%s not MULTI type", name);
     242        psAssert(psListLength(item->data.list) == 1, "%s has multiple entries", name);
     243        psMetadataItem *entry = psListGet(item->data.list, PS_LIST_HEAD); // Entry of interest
     244        void *data = tables[i].parse(entry);                             // Parsed entry
     245        if (!data) {
     246            psError(PXTOOLS_ERR_CONFIG, false, "Unable to parse entry %s", name);
     247            psFree(input);
     248            return false;
     249        }
     250        if (!tables[0].insert(config->dbh, data)) {
     251            psError(psErrorCodeLast(), false, "Unable to insert entry %s", name);
     252            psFree(input);
     253            return false;
     254        }
     255    }
     256
     257    psFree(input);
     258
     259    return true;
     260}
     261
     262//////////////////////////////////////////////////////////////////////////////////////////////////////////////
     263// Functions for chip stage
     264//////////////////////////////////////////////////////////////////////////////////////////////////////////////
    121265
    122266static bool definechipMode(pxConfig *config)
     
    293437
    294438    psMetadata *where = psMetadataAlloc();
    295     PXOPT_COPY_S64(config->args, where, "-chip_bg_id", "chipBackgroundRun.warp_id",   "==");
     439    PXOPT_COPY_S64(config->args, where, "-chip_bg_id", "chipBackgroundRun.chip_bg_id",   "==");
    296440    PXOPT_COPY_STR(config->args, where, "-state",      "chipBackgroundRun.state",     "==");
    297441    PXOPT_COPY_STR(config->args, where, "-data_group", "chipBackgroundRun.data_group","LIKE");
     
    312456    }
    313457
    314     psString query = psStringCopy("UPDATE chipBackgroundRun "
    315                                   "JOIN chipBackgroundImfile USING(chip_bg_id) "
    316                                   "JOIN chipRun USING(chip_id) "
    317                                   "JOIN rawExp USING(exp_id)");
    318 
    319     // pxUpdateRun gets parameters from config->args and updates
     458    psString query = psStringCopy("UPDATE chipBackgroundRun JOIN chipBackgroundImfile USING(chip_bg_id)");
    320459    bool result = pxUpdateRun(config, where, &query, "chipBackgroundRun", "chip_bg_id",
    321460                              "chipBackgroundImfile", true);
     
    352491    psFree(where);
    353492
    354     psString limitString = psStringCopy("\nORDER BY priority DESC, warp_id");
     493    psString limitString = psStringCopy("\nORDER BY priority DESC, chip_bg_id");
    355494    if (limit) {
    356         // We apply the limit to both sides of the UNION to avoid slow queries
    357         // and to the query itself to satisfy the user's requested limit
    358495        psStringAppend(&limitString, "%s", psDBGenerateLimitSQL(limit));
    359496        psStringAppend(&query, " %s", limitString);
     
    394531
    395532
    396 
    397 
    398 
    399 
    400 
    401 
    402 
    403 
    404 
    405 
    406 
    407 
    408 
    409 
    410 
    411 
    412 
    413 
    414 
    415 
    416 
    417 
    418 
    419 
    420 
    421 
    422 
    423 
    424 
    425 static bool chipMode(pxConfig *config)
    426 {
    427     PS_ASSERT_PTR_NON_NULL(config, false);
    428 
    429     psMetadata *where = psMetadataAlloc();
    430     PXOPT_COPY_S64(config->args, where, "-warp_id", "warp_id", "==");
    431     PXOPT_COPY_S64(config->args, where, "-fake_id", "fake_id", "==");
     533static bool chipinputsMode(pxConfig *config)
     534{
     535    PS_ASSERT_PTR_NON_NULL(config, false);
     536
     537    psMetadata *where = psMetadataAlloc();
     538    PXOPT_COPY_S64(config->args, where, "-chip_bg_id", "chipBackgroundRun.chip_bg_id", "==");
     539    PXOPT_COPY_STR(config->args, where, "-class_id", "chipProcessedImfile.class_id", "==");
    432540
    433541    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
     
    435543
    436544    // find all rawImfiles matching the default query
    437     psString query = pxDataGet("warptool_imfile.sql");
     545    psString query = pxDataGet("bgtool_chipinputs.sql");
    438546    if (!query) {
    439         psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
     547        psError(psErrorCodeLast(), false, "failed to retreive SQL statement");
    440548        return false;
    441549    }
    442550
    443551    if (psListLength(where->list)) {
    444         psString whereClause = psDBGenerateWhereConditionSQL(where, "warpRun");
     552        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
    445553        psStringAppend(&query, " AND %s", whereClause);
    446554        psFree(whereClause);
     
    448556    psFree(where);
    449557
    450     // treat limit == 0 as "no limit"
    451558    if (limit) {
    452559        psString limitString = psDBGenerateLimitSQL(limit);
     
    456563
    457564    if (!p_psDBRunQuery(config->dbh, query)) {
    458         psError(PS_ERR_UNKNOWN, false, "database error");
     565        psError(psErrorCodeLast(), false, "database error");
    459566        psFree(query);
    460567        return false;
     
    464571    psArray *output = p_psDBFetchResult(config->dbh);
    465572    if (!output) {
    466         psErrorCode err = psErrorCodeLast();
    467         switch (err) {
    468             case PS_ERR_DB_CLIENT:
    469                 psError(PXTOOLS_ERR_SYS, false, "database error");
    470             case PS_ERR_DB_SERVER:
    471                 psError(PXTOOLS_ERR_PROG, false, "database error");
    472             default:
    473                 psError(PXTOOLS_ERR_PROG, false, "unknown error");
    474         }
    475 
     573        psError(psErrorCodeLast(), false, "database error");
    476574        return false;
    477575    }
    478576    if (!psArrayLength(output)) {
    479         psTrace("warptool", PS_LOG_INFO, "no rows found");
     577        psTrace("bgtool", PS_LOG_INFO, "no rows found");
    480578        psFree(output);
    481579        return true;
    482580    }
    483 
    484     if (psArrayLength(output)) {
    485         // negative simple so the default is true
    486         if (!ippdbPrintMetadatas(stdout, output, "warpInputImfile", !simple)) {
    487             psError(PS_ERR_UNKNOWN, false, "failed to print array");
    488             psFree(output);
    489             return false;
    490         }
     581    if (!ippdbPrintMetadatas(stdout, output, "chipBackgroundImfile", !simple)) {
     582        psError(psErrorCodeLast(), false, "failed to print array");
     583        psFree(output);
     584        return false;
    491585    }
    492586
     
    497591
    498592
    499 static bool tooverlapMode(pxConfig *config)
    500 {
    501     PS_ASSERT_PTR_NON_NULL(config, false);
    502 
    503     psMetadata *where = psMetadataAlloc();
    504     PXOPT_COPY_S64(config->args, where, "-warp_id", "warp_id", "==");
    505     pxAddLabelSearchArgs (config, where, "-label", "label", "==");
    506 
     593static bool addchipMode(pxConfig *config)
     594{
     595    PS_ASSERT_PTR_NON_NULL(config, false);
     596
     597    PXOPT_LOOKUP_S64(chip_bg_id, config->args, "-chip_bg_id", true, false);
     598    PXOPT_LOOKUP_STR(class_id, config->args, "-class_id", true, false);
     599    PXOPT_LOOKUP_STR(path_base, config->args, "-path_base", true, false);
     600
     601    // optional
     602
     603    PXOPT_LOOKUP_S64(magicked, config->args, "-set_magicked", false, false);
     604    PXOPT_LOOKUP_F32(dtime_script, config->args, "-dtime_script", false, false);
     605    PXOPT_LOOKUP_STR(hostname, config->args, "-hostname", false, false);
     606    PXOPT_LOOKUP_S16(quality, config->args, "-quality", false, false);
     607    PXOPT_LOOKUP_S16(fault, config->args, "-fault", false, false);
     608    PXOPT_LOOKUP_STR(ver_pslib, config->args, "-ver_pslib", false, false);
     609    PXOPT_LOOKUP_STR(ver_psmodules, config->args, "-ver_psmodules", false, false);
     610    PXOPT_LOOKUP_STR(ver_ppbackground, config->args, "-ver_ppbackground", false, false);
     611    PXOPT_LOOKUP_STR(ver_ppstats, config->args, "-ver_ppstats", false, false);
     612    PXOPT_LOOKUP_F64(bg, config->args, "-bg", false, false);
     613    PXOPT_LOOKUP_F64(bg_stdev, config->args, "-bg_stdev", false, false);
     614    PXOPT_LOOKUP_S32(maskfrac_npix, config->args, "-maskfrac_npix", false, false);
     615    PXOPT_LOOKUP_F32(maskfrac_static, config->args, "-maskfrac_static", false, false);
     616    PXOPT_LOOKUP_F32(maskfrac_dynamic, config->args, "-maskfrac_dynamic", false, false);
     617    PXOPT_LOOKUP_F32(maskfrac_magic, config->args, "-maskfrac_magic", false, false);
     618    PXOPT_LOOKUP_F32(maskfrac_advisory, config->args, "-maskfrac_advisory", false, false);
     619
     620    psString ver_code = pxMergeCodeVersions(ver_pslib, ver_psmodules);
     621    ver_code = pxMergeCodeVersions(ver_code, ver_ppbackground);
     622    ver_code = pxMergeCodeVersions(ver_code, ver_ppstats);
     623
     624    if (!psDBTransaction(config->dbh)) {
     625        psError(PS_ERR_UNKNOWN, false, "database error");
     626        return false;
     627    }
     628
     629    if (!chipBackgroundImfileInsert(config->dbh, chip_bg_id, class_id, path_base, magicked, dtime_script,
     630                                    hostname, quality, fault, ver_code, bg, bg_stdev, maskfrac_npix,
     631                                    maskfrac_static, maskfrac_dynamic, maskfrac_magic, maskfrac_advisory)) {
     632        psError(psErrorCodeLast(), false, "database error");
     633        if (!psDBRollback(config->dbh)) {
     634            psError(psErrorCodeLast(), false, "database error");
     635        }
     636        return false;
     637    }
     638
     639    if (!psDBCommit(config->dbh)) {
     640        psError(psErrorCodeLast(), false, "database error");
     641        return false;
     642    }
     643
     644    return true;
     645}
     646
     647static bool chipMode(pxConfig *config)
     648{
     649    PS_ASSERT_PTR_NON_NULL(config, false);
     650
     651    psMetadata *where = psMetadataAlloc();
     652    PXOPT_COPY_S64(config->args, where, "-chip_bg_id",    "chipBackgroundRun.chip_bg_id", "==");
     653    PXOPT_COPY_STR(config->args, where, "-class_id", "chipBackgroundImfile.class_id", "==");
     654    pxAddLabelSearchArgs(config, where, "-label",   "chipBackgroundRun.label", "LIKE");
     655    pxAddLabelSearchArgs(config, where, "-data_group",   "chipBackgroundRun.data_group", "LIKE");
     656    pxAddLabelSearchArgs(config, where, "-dist_group",   "chipBackgroundRun.data_group", "LIKE");
     657
     658    PXOPT_LOOKUP_BOOL(all, config->args, "-all", false);
    507659    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
    508660    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
    509661
    510662    // find all rawImfiles matching the default query
    511     psString query = pxDataGet("warptool_tooverlap.sql");
     663    psString query = pxDataGet("bgtool_chip.sql");
    512664    if (!query) {
    513         psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
     665        psError(psErrorCodeLast(), false, "failed to retreive SQL statement");
     666        return false;
     667    }
     668
     669    psString magicWhere = NULL;
     670    if (!pxmagicAddWhere(config, &magicWhere, "chipBackgroundImfile")) {
     671        psError(psErrorCodeLast(), false, "pxMagicAddWhere failed");
     672        return false;
     673    }
     674    if (!pxspaceAddWhere(config, &magicWhere, "rawExp")) {
     675        psError(psErrorCodeLast(), false, "pxSpaceAddWhere failed");
    514676        return false;
    515677    }
    516678
    517679    if (psListLength(where->list)) {
    518         psString whereClause = psDBGenerateWhereConditionSQL(where, "warpRun");
    519         psStringAppend(&query, " AND %s", whereClause);
     680        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
     681        psStringAppend(&query, " WHERE %s", whereClause);
    520682        psFree(whereClause);
    521     }
    522     psFree(where);
    523 
    524     // treat limit == 0 as "no limit"
     683    } else if (!all && !magicWhere) {
     684        psError(PXTOOLS_ERR_CONFIG, true, "search parameters or -all are required");
     685        return false;
     686    }
     687    if (magicWhere) {
     688        psStringAppend(&query, "%s %s", psListLength(where->list) ? "AND" : "WHERE", magicWhere);
     689    }
     690    psFree(magicWhere);
     691    psFree(where);
     692
    525693    if (limit) {
    526694        psString limitString = psDBGenerateLimitSQL(limit);
     
    530698
    531699    if (!p_psDBRunQuery(config->dbh, query)) {
     700        psError(psErrorCodeLast(), false, "database error");
     701        psFree(query);
     702        return false;
     703    }
     704    psFree(query);
     705
     706    psArray *output = p_psDBFetchResult(config->dbh);
     707    if (!output) {
     708        psError(psErrorCodeLast(), false, "database error");
     709        return false;
     710    }
     711    if (!psArrayLength(output)) {
     712        psTrace("bgtool", PS_LOG_INFO, "no rows found");
     713        psFree(output);
     714        return true;
     715    }
     716    if (psArrayLength(output)) {
     717        if (!ippdbPrintMetadatas(stdout, output, "chipBackgroundImfile", !simple)) {
     718            psError(psErrorCodeLast(), false, "failed to print array");
     719            psFree(output);
     720            return false;
     721        }
     722    }
     723    psFree(output);
     724
     725    return true;
     726}
     727
     728
     729static bool advancechipMode(pxConfig *config)
     730{
     731    PS_ASSERT_PTR_NON_NULL(config, false);
     732
     733    psMetadata *where = psMetadataAlloc();
     734    PXOPT_COPY_S64(config->args, where, "-chip_bg_id", "chip_bg_id", "==");
     735    pxAddLabelSearchArgs(config, where, "-label", "label", "==");
     736
     737    psString select = pxDataGet("bgtool_advancechip.sql");
     738    if (!select) {
     739        psError(psErrorCodeLast(), false, "failed to retrieve SQL statement");
     740        return false;
     741    }
     742
     743    psString selectWhere = psStringCopy("");
     744    if (psListLength(where->list)) {
     745        psString whereClause = psDBGenerateWhereSQL(where, NULL);
     746        psStringAppend(&selectWhere, "\n WHERE %s", whereClause);
     747        psFree(whereClause);
     748    }
     749    psFree(where);
     750
     751    if (!psDBTransaction(config->dbh)) {
     752        psError(psErrorCodeLast(), false, "database error");
     753        return false;
     754    }
     755
     756    if (!p_psDBRunQueryF(config->dbh, select, selectWhere)) {
     757        psError(psErrorCodeLast(), false, "database error");
     758        psFree(select);
     759        psFree(selectWhere);
     760        if (!psDBRollback(config->dbh)) {
     761            psError(psErrorCodeLast(), false, "database error");
     762        }
     763        return false;
     764    }
     765    psFree(select);
     766    psFree(selectWhere);
     767
     768    psArray *output = p_psDBFetchResult(config->dbh);
     769    if (!output) {
     770        psError(psErrorCodeLast(), false, "database error");
     771        if (!psDBRollback(config->dbh)) {
     772            psError(psErrorCodeLast(), false, "database error");
     773        }
     774        return false;
     775    }
     776    if (!psArrayLength(output)) {
     777        psTrace("bgtool", PS_LOG_INFO, "no rows found");
     778        psFree(output);
     779        return true;
     780    }
     781
     782    for (long i = 0; i < psArrayLength(output); i++) {
     783        psMetadata *row = output->data[i];
     784        bool status = true;             // Status of MD lookup
     785        psS64 chip_bg_id = psMetadataLookupS64(&status, row, "chip_bg_id");
     786        if (!status) {
     787            psError(PXTOOLS_ERR_PROG, true, "failed to look up value for chip_bg_id");
     788            psFree(output);
     789            if (!psDBRollback(config->dbh)) {
     790                psError(psErrorCodeLast(), false, "database error");
     791            }
     792            return false;
     793        }
     794        psS64 magicked = psMetadataLookupS64(&status, row, "magicked");
     795        if (!status) {
     796            psError(PXTOOLS_ERR_PROG, true, "failed to look up value for magicked");
     797            psFree(output);
     798            if (!psDBRollback(config->dbh)) {
     799                psError(psErrorCodeLast(), false, "database error");
     800            }
     801            return false;
     802        }
     803
     804        if (!p_psDBRunQueryF(config->dbh,
     805                             "UPDATE chipBackgroundRun "
     806                             "SET state = 'full', magicked = %" PRId64 " "
     807                             " WHERE chip_bg_id = %" PRId64,
     808                             chip_bg_id, magicked)) {
     809            psError(psErrorCodeLast(), false, "database error");
     810            psFree(output);
     811            if (!psDBRollback(config->dbh)) {
     812                psError(psErrorCodeLast(), false, "database error");
     813            }
     814            return false;
     815        }
     816
     817        psS64 numUpdated = psDBAffectedRows(config->dbh);
     818        if (numUpdated != 1) {
     819            psError(PXTOOLS_ERR_PROG, true, "should have affected 1 row");
     820            if (!psDBRollback(config->dbh)) {
     821                psError(psErrorCodeLast(), false, "database error");
     822            }
     823            psFree(output);
     824            return false;
     825        }
     826    }
     827    psFree(output);
     828
     829    if (!psDBCommit(config->dbh)) {
     830        psError(psErrorCodeLast(), false, "database error");
     831        return false;
     832    }
     833
     834    return true;
     835}
     836
     837static bool revertchipMode(pxConfig *config)
     838{
     839    PS_ASSERT_PTR_NON_NULL(config, false);
     840
     841    psMetadata *where = psMetadataAlloc();
     842    PXOPT_COPY_S64(config->args, where, "-chip_bg_id", "chipBackgroundRun.chip_bg_id", "==");
     843    PXOPT_COPY_STR(config->args, where, "-class_id", "chipBackgroundImfile.class_id", "==");
     844    pxAddLabelSearchArgs(config, where, "-label", "chipBackgroundRun.label", "==");
     845    PXOPT_COPY_S16(config->args, where, "-fault", "chipBackgroundImfile.fault", "==");
     846
     847    if (!psListLength(where->list) && !psMetadataLookupBool(NULL, config->args, "-all")) {
     848        psFree(where);
     849        psError(PXTOOLS_ERR_CONFIG, true, "search parameters are required");
     850        return false;
     851    }
     852
     853    psString query = pxDataGet("bgtool_revertchip.sql");
     854    if (!query) {
     855        psError(psErrorCodeLast(), false, "failed to retreive SQL statement");
     856        return false;
     857    }
     858
     859    if (psListLength(where->list)) {
     860        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
     861        psStringAppend(&query, " AND %s", whereClause);
     862        psFree(whereClause);
     863    }
     864    psFree(where);
     865
     866    if (!p_psDBRunQuery(config->dbh, query)) {
    532867        psError(PS_ERR_UNKNOWN, false, "database error");
    533868        psFree(query);
     
    536871    psFree(query);
    537872
    538     psArray *output = p_psDBFetchResult(config->dbh);
    539     if (!output) {
    540         psErrorCode err = psErrorCodeLast();
    541         switch (err) {
    542             case PS_ERR_DB_CLIENT:
    543                 psError(PXTOOLS_ERR_SYS, false, "database error");
    544             case PS_ERR_DB_SERVER:
    545                 psError(PXTOOLS_ERR_PROG, false, "database error");
    546             default:
    547                 psError(PXTOOLS_ERR_PROG, false, "unknown error");
    548         }
    549 
    550         return false;
    551     }
    552     if (!psArrayLength(output)) {
    553         psTrace("warptool", PS_LOG_INFO, "no rows found");
    554         psFree(output);
    555         return true;
    556     }
    557 
    558     if (psArrayLength(output)) {
    559         // negative simple so the default is true
    560         if (!ippdbPrintMetadatas(stdout, output, "warpRun", !simple)) {
    561             psError(PS_ERR_UNKNOWN, false, "failed to print array");
    562             psFree(output);
    563             return false;
    564         }
    565     }
    566 
    567     psFree(output);
    568 
    569     return true;
    570 }
    571 
    572 
    573 static bool addoverlapMode(pxConfig *config)
    574 {
    575     PS_ASSERT_PTR_NON_NULL(config, false);
    576 
    577     PXOPT_LOOKUP_STR(mapfile, config->args, "-mapfile", false, false);
    578     PXOPT_LOOKUP_S64(warp_id, config->args, "-warp_id", false, false);
    579     PXOPT_LOOKUP_S16(fault, config->args, "-fault", false, false);
    580 
    581     if (!psDBTransaction(config->dbh)) {
    582         psError(PS_ERR_UNKNOWN, false, "database error");
    583         return false;
    584     }
    585 
    586     if (fault == 0) {
    587         if (!parseAndInsertSkyCellMap(config, mapfile)) {
    588             psError(PS_ERR_UNKNOWN, false, "failed to inject mapfile: %s into the database", mapfile);
    589             // rollback
    590             if (!psDBRollback(config->dbh)) {
    591                 psError(PS_ERR_UNKNOWN, false, "database error");
    592             }
    593             return false;
    594         }
    595     } else {
    596         warpSkyCellMapInsert(config->dbh,
    597             warp_id,
    598             "faulted",   // skycell_id
    599             "faulted",   // tess_id
    600             "faulted",   // class_id
    601             fault    // fault
    602         );
    603     }
    604 
    605     // point of no return
    606     if (!psDBCommit(config->dbh)) {
    607         psError(PS_ERR_UNKNOWN, false, "database error");
    608         return false;
    609     }
    610 
    611     return true;
    612 }
    613 
    614 static bool revertoverlapMode(pxConfig *config)
    615 {
    616     PS_ASSERT_PTR_NON_NULL(config, false);
    617 
    618     psMetadata *where = psMetadataAlloc();
    619     PXOPT_COPY_S64(config->args, where, "-warp_id",    "warpSkyCellMap.warp_id", "==");
    620     PXOPT_COPY_STR(config->args, where, "-skycell_id", "warpSkyCellMap.skycell_id", "==");
    621     PXOPT_COPY_STR(config->args, where, "-tess_id",    "warpSkyCellMap.tess_id", "==");
    622     pxAddLabelSearchArgs (config, where, "-label",     "warpRun.label", "==");
    623     PXOPT_COPY_S16(config->args, where, "-fault",      "warpSkyCellMap.fault", "==");
    624 
    625     if (!psListLength(where->list)
    626         && !psMetadataLookupBool(NULL, config->args, "-all")) {
    627         psFree(where);
    628         psError(PXTOOLS_ERR_CONFIG, false, "search parameters are required");
    629         return false;
    630     }
    631 
    632     int numDeleted;                     // Number deleted
    633     {
    634         psString query = pxDataGet("warptool_revertoverlap.sql");
    635         if (!query) {
    636             psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
    637             if (!psDBRollback(config->dbh)) {
    638                 psError(PS_ERR_UNKNOWN, false, "database error");
    639             }
    640             return false;
    641         }
    642 
    643         if (psListLength(where->list)) {
    644             psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
    645             psStringAppend(&query, " AND %s", whereClause);
    646             psFree(whereClause);
    647         }
    648 
    649         if (!p_psDBRunQuery(config->dbh, query)) {
    650             psError(PS_ERR_UNKNOWN, false, "database error");
    651             psFree(query);
    652             if (!psDBRollback(config->dbh)) {
    653                 psError(PS_ERR_UNKNOWN, false, "database error");
    654             }
    655             return false;
    656         }
    657         psFree(query);
    658 
    659         numDeleted = psDBAffectedRows(config->dbh);
    660     }
    661 
    662     psLogMsg("warptool", PS_LOG_INFO, "Deleted %d warpSkycellMap", numDeleted);
    663 
    664     psFree(where);
    665 
    666     return true;
    667 }
    668 
    669 
    670 
    671 static bool parseAndInsertSkyCellMap(pxConfig *config, const char *mapfile)
    672 {
    673     unsigned int nFail = 0;
    674     psMetadata *imfiles = psMetadataAlloc();
    675     psMetadata *skycells = psMetadataConfigRead(NULL, &nFail, mapfile, false);
    676     if (!skycells) {
    677         psError(PS_ERR_UNKNOWN, false, "failed to parse mapfile: %s", mapfile);
    678         return false;
    679     }
    680     if (nFail) {
    681         psError(PS_ERR_UNKNOWN, false, "there were %d errors parsing mapfile: %s", nFail, mapfile);
    682         psFree(skycells);
    683         psFree(imfiles);
    684         return false;
    685     }
    686 
    687     psMetadataItem *item = NULL;
    688     psMetadataIterator *iter = psMetadataIteratorAlloc(skycells, 0, NULL);
    689     while ((item = psMetadataGetAndIncrement(iter))) {
    690         if (item->type != PS_DATA_METADATA) {
    691             psError(PS_ERR_UNKNOWN, false, "mapfile: %s is in the wrong format", mapfile);
    692             psFree(iter);
    693             psFree(skycells);
    694             psFree(imfiles);
    695             return false;
    696         }
    697 
    698         psMetadata *sc = item->data.md;
    699         // this conversion isn't strictly nessicary but it's an easy way of
    700         // validating the format
    701         warpSkyCellMapRow *row = warpSkyCellMapObjectFromMetadata(sc);
    702         if (!row) {
    703             psError(PS_ERR_UNKNOWN, false, "failed to convert mapfile: %s metdata entry into a warpSkyCellMap object", mapfile);
    704             psFree(iter);
    705             psFree(skycells);
    706             psFree(imfiles);
    707             return false;
    708         }
    709         psMetadataAddS64(imfiles, PS_LIST_TAIL, row->skycell_id, PS_META_REPLACE, "", row->warp_id);
    710 
    711         if (!warpSkyCellMapInsertObject(config->dbh, row)) {
    712             psErrorCode err = psErrorCodeLast();
    713             switch (err) {
    714                 case PS_ERR_DB_CLIENT:
    715                     psError(PXTOOLS_ERR_SYS, false, "database error");
    716                 case PS_ERR_DB_SERVER:
    717                     psError(PXTOOLS_ERR_PROG, false, "database error");
    718                 default:
    719                     psError(PXTOOLS_ERR_PROG, false, "unknown error");
    720             }
    721             psFree(row);
    722             psFree(iter);
    723             psFree(skycells);
    724             psFree(imfiles);
    725             return false;
    726         }
    727 
    728         psFree(row);
    729     }
    730     psFree(iter);
    731 
    732     // create warp_skyfile_ids for the output skyfiles
    733     psString query = "INSERT INTO warpImfile VALUES(%" PRId64 ", '%s', 0)";
    734     iter = psMetadataIteratorAlloc(imfiles, 0, NULL);
    735     while ((item = psMetadataGetAndIncrement(iter))) {
    736         psString skycell_id = item->name;
    737         psS64 warp_id = item->data.S64;
    738 
    739         if (!p_psDBRunQueryF(config->dbh, query, warp_id, skycell_id)) {
    740             psError(PS_ERR_UNKNOWN, false, "database error");
    741             return false;
    742         }
    743     }
    744     psFree(iter);
    745     psFree(skycells);
    746     psFree(imfiles);
    747 
    748     return true;
    749 }
    750 
    751 
    752 static bool scmapMode(pxConfig *config)
    753 {
    754     PS_ASSERT_PTR_NON_NULL(config, false);
    755 
    756     psMetadata *where = psMetadataAlloc();
    757     PXOPT_COPY_S64(config->args, where, "-warp_id", "warp_id", "==");
    758     PXOPT_COPY_STR(config->args, where, "-skycell_id", "skycell_id", "==");
    759     PXOPT_COPY_STR(config->args, where, "-tess_id", "tess_id", "==");
    760     PXOPT_COPY_STR(config->args, where, "-class_id", "class_id", "==");
     873    int numDeleted = psDBAffectedRows(config->dbh);
     874    psLogMsg("bgtool", PS_LOG_INFO, "Deleted %d chipBackgroundImfiles", numDeleted);
     875
     876    return true;
     877}
     878
     879static bool tocleanchipMode(pxConfig *config)
     880{
     881    PS_ASSERT_PTR_NON_NULL(config, NULL);
    761882
    762883    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
    763884    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
    764885
    765     // find all rawImfiles matching the default query
    766     psString query = pxDataGet("warptool_scmap.sql");
     886    psMetadata *where = psMetadataAlloc();
     887    pxAddLabelSearchArgs(config, where, "-label", "chipBackgroundRun.label", "==");
     888
     889    psString query = pxDataGet("bgtool_tocleanchip.sql");
    767890    if (!query) {
    768         psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
    769         return false;
    770     }
    771 
    772     if (psListLength(where->list)) {
    773         psString whereClause = psDBGenerateWhereConditionSQL(where, "warpSkyCellMap");
     891        psError(psErrorCodeLast(), false, "failed to retreive SQL statement");
     892        return false;
     893    }
     894
     895    if (where && psListLength(where->list)) {
     896        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
    774897        psStringAppend(&query, " AND %s", whereClause);
    775898        psFree(whereClause);
     
    777900    psFree(where);
    778901
    779     // treat limit == 0 as "no limit"
    780902    if (limit) {
    781903        psString limitString = psDBGenerateLimitSQL(limit);
     
    785907
    786908    if (!p_psDBRunQuery(config->dbh, query)) {
    787         psError(PS_ERR_UNKNOWN, false, "database error");
     909        psError(psErrorCodeLast(), false, "database error");
    788910        psFree(query);
    789911        return false;
     
    793915    psArray *output = p_psDBFetchResult(config->dbh);
    794916    if (!output) {
    795         psErrorCode err = psErrorCodeLast();
    796         switch (err) {
    797             case PS_ERR_DB_CLIENT:
    798                 psError(PXTOOLS_ERR_SYS, false, "database error");
    799             case PS_ERR_DB_SERVER:
    800                 psError(PXTOOLS_ERR_PROG, false, "database error");
    801             default:
    802                 psError(PXTOOLS_ERR_PROG, false, "unknown error");
    803         }
    804 
     917        psError(psErrorCodeLast(), false, "database error");
    805918        return false;
    806919    }
    807920    if (!psArrayLength(output)) {
    808         psTrace("warptool", PS_LOG_INFO, "no rows found");
     921        psTrace("bgtool", PS_LOG_INFO, "no rows found");
    809922        psFree(output);
    810923        return true;
    811924    }
    812925
    813     if (psArrayLength(output)) {
     926    // negative simple so the default is true
     927    if (!ippdbPrintMetadatas(stdout, output, "chipBackgroundRun", !simple)) {
     928        psError(psErrorCodeLast(), false, "failed to print array");
     929        psFree(output);
     930        return false;
     931    }
     932    psFree(output);
     933
     934    return true;
     935}
     936
     937static bool cleanedchipMode(pxConfig *config)
     938{
     939    PS_ASSERT_PTR_NON_NULL(config, false);
     940
     941    psMetadata *where = psMetadataAlloc();
     942    PXOPT_COPY_S64(config->args, where, "-chip_bg_id", "chipBackgroundRun.chip_bg_id", "==");
     943
     944    PXOPT_LOOKUP_STR(state, config->args, "-state", true, false);
     945    if (!pxIsValidCleanedState(state)) {
     946        psError(PXTOOLS_ERR_CONFIG, true, "Invalid state: %s", state);
     947        return false;
     948    }
     949
     950    if (!psListLength(where->list)) {
     951        psError(PXTOOLS_ERR_CONFIG, true, "No search restrictions set.");
     952        return false;
     953    }
     954
     955    psString query = pxDataGet("bgtool_cleanedchip.sql");
     956    if (!query) {
     957        psError(psErrorCodeLast(), false, "failed to retreive SQL statement");
     958        return false;
     959    }
     960
     961    {
     962        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
     963        psStringAppend(&query, " AND %s", whereClause);
     964        psFree(whereClause);
     965    }
     966    psFree(where);
     967
     968    if (!p_psDBRunQueryF(config->dbh, query, state)) {
     969        psError(psErrorCodeLast(), false, "database error");
     970        return false;
     971    }
     972    psFree(query);
     973
     974    return true;
     975}
     976
     977static bool exportchipMode(pxConfig *config)
     978{
     979    PS_ASSERT_PTR_NON_NULL(config, false);
     980
     981    PXOPT_LOOKUP_S64(chip_bg_id, config->args, "-chip_bg_id", true,  false);
     982    PXOPT_LOOKUP_STR(outfile, config->args, "-outfile", true,  false);
     983    PXOPT_LOOKUP_BOOL(clean,  config->args, "-clean", false);
     984
     985    psMetadata *where = psMetadataAlloc();
     986    PXOPT_COPY_S64(config->args, where, "-chip_bg_id", "chip_bg_id", "==");
     987
     988    bool status = exportTables(config, outfile, chipTables, where, clean);
     989
     990    psFree(where);
     991    return status;
     992}
     993
     994static bool importchipMode(pxConfig *config)
     995{
     996    PXOPT_LOOKUP_STR(infile, config->args, "-infile", true,  false);
     997
     998    return importTables(config, infile, chipTables);
     999}
     1000
     1001//////////////////////////////////////////////////////////////////////////////////////////////////////////////
     1002// Functions for warp stage
     1003//////////////////////////////////////////////////////////////////////////////////////////////////////////////
     1004
     1005static bool definewarpMode(pxConfig *config)
     1006{
     1007    PS_ASSERT_PTR_NON_NULL(config, NULL);
     1008
     1009    psMetadata *where = psMetadataAlloc();
     1010    PXOPT_COPY_S64(config->args,   where, "-warp_id",            "warpRun.warp_id",       "==");
     1011    PXOPT_COPY_S64(config->args,   where, "-exp_id",             "rawExp.exp_id",         "==");
     1012    PXOPT_COPY_STR(config->args,   where, "-exp_name",           "rawExp.exp_name",       "==");
     1013    PXOPT_COPY_STR(config->args,   where, "-inst",               "rawExp.camera",         "==");
     1014    PXOPT_COPY_STR(config->args,   where, "-telescope",          "rawExp.telescope",      "==");
     1015    PXOPT_COPY_TIME(config->args,  where, "-dateobs_begin",      "rawExp.dateobs",        ">=");
     1016    PXOPT_COPY_TIME(config->args,  where, "-dateobs_end",        "rawExp.dateobs",        "<=");
     1017    PXOPT_COPY_STR(config->args,   where, "-exp_tag",            "rawExp.exp_tag",        "==");
     1018    PXOPT_COPY_STR(config->args,   where, "-exp_type",           "rawExp.exp_type",       "==");
     1019    PXOPT_COPY_STR(config->args,   where, "-filelevel",          "rawExp.filelevel",      "==");
     1020    PXOPT_COPY_STR(config->args,   where, "-filter",             "rawExp.filter",         "==");
     1021    PXOPT_COPY_F64(config->args,   where, "-airmass_min",        "rawExp.airmass",        ">=");
     1022    PXOPT_COPY_F64(config->args,   where, "-airmass_max",        "rawExp.airmass",        "<");
     1023    PXOPT_COPY_RADEC(config->args, where, "-ra_min",             "rawExp.ra",             ">=");
     1024    PXOPT_COPY_RADEC(config->args, where, "-ra_max",             "rawExp.ra",             "<");
     1025    PXOPT_COPY_RADEC(config->args, where, "-decl_min",           "rawExp.decl",           ">=");
     1026    PXOPT_COPY_RADEC(config->args, where, "-decl_max",           "rawExp.decl",           "<");
     1027    PXOPT_COPY_F32(config->args,   where, "-exp_time_min",       "rawExp.exp_time",       ">=");
     1028    PXOPT_COPY_F32(config->args,   where, "-exp_time_max",       "rawExp.exp_time",       "<");
     1029    PXOPT_COPY_F32(config->args,   where, "-sat_pixel_frac_min", "rawExp.sat_pixel_frac", ">=");
     1030    PXOPT_COPY_F32(config->args,   where, "-sat_pixel_frac_max", "rawExp.sat_pixel_frac", "<");
     1031    PXOPT_COPY_F64(config->args,   where, "-bg_min",             "rawExp.bg",             ">=");
     1032    PXOPT_COPY_F64(config->args,   where, "-bg_max",             "rawExp.bg",             "<");
     1033    PXOPT_COPY_F64(config->args,   where, "-bg_stdev_min",       "rawExp.bg_stdev",       ">=");
     1034    PXOPT_COPY_F64(config->args,   where, "-bg_stdev_max",       "rawExp.bg_stdev",       "<");
     1035    PXOPT_COPY_F64(config->args,   where, "-bg_mean_stdev_min",  "rawExp.bg_mean_stdev",  ">=");
     1036    PXOPT_COPY_F64(config->args,   where, "-bg_mean_stdev_max",  "rawExp.bg_mean_stdev",  "<");
     1037    PXOPT_COPY_F64(config->args,   where, "-alt_min",            "rawExp.alt",            ">=");
     1038    PXOPT_COPY_F64(config->args,   where, "-alt_max",            "rawExp.alt",            "<");
     1039    PXOPT_COPY_F64(config->args,   where, "-az_min",             "rawExp.az",             ">=");
     1040    PXOPT_COPY_F64(config->args,   where, "-az_max",             "rawExp.az",             "<");
     1041    PXOPT_COPY_F32(config->args,   where, "-ccd_temp_min",       "rawExp.ccd_temp",       ">=");
     1042    PXOPT_COPY_F32(config->args,   where, "-ccd_temp_max",       "rawExp.ccd_temp",       "<");
     1043    PXOPT_COPY_F64(config->args,   where, "-posang_min",         "rawExp.posang",         ">=");
     1044    PXOPT_COPY_F64(config->args,   where, "-posang_max",         "rawExp.posang",         "<");
     1045    PXOPT_COPY_STR(config->args,   where, "-object",             "rawExp.object",         "==");
     1046    PXOPT_COPY_STR(config->args,   where, "-comment",            "rawExp.comment",        "LIKE");
     1047    PXOPT_COPY_STR(config->args,   where, "-obs_mode",           "rawExp.obs_mode",       "LIKE");
     1048    PXOPT_COPY_F32(config->args,   where, "-sun_angle_min",      "rawExp.sun_angle",      ">=");
     1049    PXOPT_COPY_F32(config->args,   where, "-sun_angle_max",      "rawExp.sun_angle",      "<");
     1050    pxAddLabelSearchArgs(config,   where, "-warp_label",         "warpRun.label",         "==");
     1051    pxAddLabelSearchArgs(config,   where, "-bg_label",           "chipBackgroundRun.label", "==");
     1052
     1053    if (!psListLength(where->list) && !psMetadataLookupBool(NULL, config->args, "-all")) {
     1054        psFree(where);
     1055        psError(PXTOOLS_ERR_CONFIG, true, "search parameters are required");
     1056        return false;
     1057    }
     1058
     1059    PXOPT_LOOKUP_STR(workdir, config->args, "-set_workdir", true, false);
     1060    PXOPT_LOOKUP_STR(label, config->args, "-set_label", false, false);
     1061    PXOPT_LOOKUP_STR(data_group, config->args, "-set_data_group", false, false);
     1062    PXOPT_LOOKUP_STR(dist_group, config->args, "-set_dist_group", false, false);
     1063    PXOPT_LOOKUP_STR(reduction, config->args, "-set_reduction", false, false);
     1064    PXOPT_LOOKUP_STR(note, config->args, "-set_note", false, false);
     1065    PXOPT_LOOKUP_TIME(registered, config->args, "-registered", false, false);
     1066    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
     1067    PXOPT_LOOKUP_BOOL(pretend, config->args, "-pretend", false);
     1068
     1069    // Get warp runs to promote to warpBackgroundRun
     1070
     1071    psString query = pxDataGet("bgtool_definewarp.sql"); // Query to execute
     1072    if (!query) {
     1073        psError(psErrorCodeLast(), false, "failed to retreive SQL statement");
     1074        psFree(where);
     1075        return false;
     1076    }
     1077
     1078    if (psListLength(where->list)) {
     1079        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
     1080        psStringAppend(&query, "AND %s", whereClause);
     1081        psFree(whereClause);
     1082    }
     1083    psFree(where);
     1084
     1085    if (!psDBTransaction(config->dbh)) {
     1086        psError(psErrorCodeLast(), false, "database error");
     1087        return false;
     1088    }
     1089
     1090    if (!p_psDBRunQuery(config->dbh, query)) {
     1091        psError(psErrorCodeLast(), false, "database error");
     1092        psFree(query);
     1093        if (!psDBRollback(config->dbh)) {
     1094            psError(psErrorCodeLast(), false, "database error");
     1095        }
     1096        return false;
     1097    }
     1098    psFree(query);
     1099
     1100    psArray *output = p_psDBFetchResult(config->dbh); // Matching rows
     1101    if (!output) {
     1102        psError(psErrorCodeLast(), false, "database error");
     1103        if (!psDBRollback(config->dbh)) {
     1104            psError(psErrorCodeLast(), false, "database error");
     1105        }
     1106        return false;
     1107    }
     1108    if (!psArrayLength(output)) {
     1109        psTrace("bgtool", PS_LOG_INFO, "no rows found");
     1110        psFree(output);
     1111        if (!psDBRollback(config->dbh)) {
     1112            psError(psErrorCodeLast(), false, "database error");
     1113        }
     1114        return true;
     1115    }
     1116
     1117    if (pretend) {
    8141118        // negative simple so the default is true
    815         if (!ippdbPrintMetadatas(stdout, output, "warpSkyCellMap", !simple)) {
    816             psError(PS_ERR_UNKNOWN, false, "failed to print array");
    817             psFree(output);
    818             return false;
    819         }
    820     }
    821 
     1119        if (!ippdbPrintMetadatas(stdout, output, "warpRun", !simple)) {
     1120            psError(psErrorCodeLast(), false, "failed to print array");
     1121            psFree(output);
     1122            if (!psDBRollback(config->dbh)) {
     1123                psError(psErrorCodeLast(), false, "database error");
     1124            }
     1125            return false;
     1126        }
     1127        psFree(output);
     1128        return true;
     1129    }
     1130
     1131    for (long i = 0; i < psArrayLength(output); i++) {
     1132        psMetadata *md = output->data[i];
     1133
     1134        psS64 chip_bg_id = psMetadataLookupS64(NULL, md, "chip_bg_id");
     1135
     1136        warpRunRow *row = warpRunObjectFromMetadata(md);
     1137        if (!row) {
     1138            psError(psErrorCodeLast(), false, "failed to convert metadata into fakeRun");
     1139            psFree(output);
     1140            if (!psDBRollback(config->dbh)) {
     1141                psError(psErrorCodeLast(), false, "database error");
     1142            }
     1143            return false;
     1144        }
     1145
     1146        if (!warpBackgroundRunInsert(config->dbh, 0, row->warp_id, chip_bg_id, "new",
     1147                                     workdir     ? workdir    : row->workdir,
     1148                                     label       ? label      : row->label,
     1149                                     data_group  ? data_group : row->data_group,
     1150                                     dist_group  ? dist_group : row->dist_group,
     1151                                     reduction   ? reduction  : row->reduction,
     1152                                     note        ? note       : row->note,
     1153                                     NULL)) {
     1154            psError(psErrorCodeLast(), false, "database error");
     1155            psFree(row);
     1156            if (!psDBRollback(config->dbh)) {
     1157                psError(psErrorCodeLast(), false, "database error");
     1158            }
     1159            return false;
     1160        }
     1161        psFree(row);
     1162    }
    8221163    psFree(output);
    8231164
    824     return true;
    825 }
    826 
    827 static bool towarpedMode(pxConfig *config)
    828 {
    829     PS_ASSERT_PTR_NON_NULL(config, false);
    830 
    831     psMetadata *where = psMetadataAlloc();
    832     PXOPT_COPY_S64(config->args, where, "-warp_id", "warpSkyCellMap.warp_id", "==");
    833     pxAddLabelSearchArgs (config, where, "-label", "warpRun.label", "==");
     1165    if (!psDBCommit(config->dbh)) {
     1166        psError(psErrorCodeLast(), false, "database error");
     1167            if (!psDBRollback(config->dbh)) {
     1168                psError(psErrorCodeLast(), false, "database error");
     1169            }
     1170        return false;
     1171    }
     1172
     1173    return true;
     1174}
     1175
     1176static bool updatewarpMode(pxConfig *config)
     1177{
     1178    PS_ASSERT_PTR_NON_NULL(config, false);
     1179
     1180    psMetadata *where = psMetadataAlloc();
     1181    PXOPT_COPY_S64(config->args, where, "-warp_bg_id", "warpBackgroundRun.warp_bg_id",   "==");
     1182    PXOPT_COPY_STR(config->args, where, "-state",      "warpBackgroundRun.state",     "==");
     1183    PXOPT_COPY_STR(config->args, where, "-data_group", "warpBackgroundRun.data_group","LIKE");
     1184    PXOPT_COPY_STR(config->args, where, "-dist_group", "warpBackgroundRun.dist_group","LIKE");
     1185    pxAddLabelSearchArgs(config,  where, "-label",     "warpBackgroundRun.label",     "LIKE");
     1186    PXOPT_COPY_TIME(config->args, where, "-registered_begin", "warpBackgroundRun.registered",  ">=");
     1187    PXOPT_COPY_TIME(config->args, where, "-registered_end",   "warpBackgroundRun.registered",  "<");
     1188
     1189    PXOPT_LOOKUP_BOOL(destreaked, config->args, "-destreaked", false);
     1190    if (destreaked) {
     1191        psMetadataAddS64(where, PS_LIST_TAIL, "warpBackgroundRun.magicked", PS_META_DUPLICATE_OK, ">", 0);
     1192    }
     1193
     1194    if (!psListLength(where->list)) {
     1195        psFree(where);
     1196        psError(PXTOOLS_ERR_CONFIG, false, "search parameters are required");
     1197        return false;
     1198    }
     1199
     1200    psString query = psStringCopy("UPDATE warpBackgroundRun JOIN warpBackgroundSkyfile USING(warp_bg_id)");
     1201    bool result = pxUpdateRun(config, where, &query, "warpBackgroundRun", "warp_bg_id",
     1202                              "warpBackgroundSkyfile", true);
     1203
     1204    psFree(query);
     1205    psFree(where);
     1206
     1207    return result;
     1208}
     1209
     1210static bool towarpMode(pxConfig *config)
     1211{
     1212    PS_ASSERT_PTR_NON_NULL(config, false);
     1213
     1214    psMetadata *where = psMetadataAlloc();
     1215    PXOPT_COPY_S64(config->args, where, "-warp_bg_id", "warpBackgroundRun.warp_bg_id", "==");
     1216    pxAddLabelSearchArgs (config, where, "-label", "warpBackgroundRun.label", "==");
    8341217
    8351218    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
    8361219    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
    8371220
    838     // find all rawImfiles matching the default query
    839     psString query = pxDataGet("warptool_towarped.sql");
     1221    psString query = pxDataGet("bgtool_towarp.sql");
    8401222    if (!query) {
    841         psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
     1223        psError(psErrorCodeLast(), false, "failed to retreive SQL statement");
    8421224        return false;
    8431225    }
     
    8511233    psFree(where);
    8521234
    853     // treat limit == 0 as "no limit"
    854     psString limitString = psStringCopy("\nORDER BY priority DESC, warp_id");
     1235    psString limitString = psStringCopy("\nORDER BY priority DESC, warp_bg_id");
    8551236    if (limit) {
    856         // We apply the limit to both sides of the UNION to avoid slow queries
    857         // and to the query itself to satisfy the user's requested limit
    8581237        psStringAppend(&limitString, "%s", psDBGenerateLimitSQL(limit));
    8591238        psStringAppend(&query, " %s", limitString);
     
    8611240
    8621241    if (!p_psDBRunQueryF(config->dbh, query, whereStr, limitString, whereStr,  limitString)) {
    863         psError(PS_ERR_UNKNOWN, false, "database error");
     1242        psError(psErrorCodeLast(), false, "database error");
    8641243        psFree(query);
    8651244        return false;
     
    8711250    psArray *output = p_psDBFetchResult(config->dbh);
    8721251    if (!output) {
    873         psErrorCode err = psErrorCodeLast();
    874         switch (err) {
    875             case PS_ERR_DB_CLIENT:
    876                 psError(PXTOOLS_ERR_SYS, false, "database error");
    877             case PS_ERR_DB_SERVER:
    878                 psError(PXTOOLS_ERR_PROG, false, "database error");
    879             default:
    880                 psError(PXTOOLS_ERR_PROG, false, "unknown error");
    881         }
    882 
     1252        psError(psErrorCodeLast(), false, "Unable to fetch result of query %s", query);
    8831253        return false;
    8841254    }
    8851255    if (!psArrayLength(output)) {
    886         psTrace("warptool", PS_LOG_INFO, "no rows found");
     1256        psTrace("bgtool", PS_LOG_INFO, "no rows found");
    8871257        psFree(output);
    8881258        return true;
     
    8901260
    8911261    if (psArrayLength(output)) {
    892         // negative simple so the default is true
    893         if (!ippdbPrintMetadatas(stdout, output, "warpPendingSkyCell", !simple)) {
    894             psError(PS_ERR_UNKNOWN, false, "failed to print array");
     1262        if (!ippdbPrintMetadatas(stdout, output, "warpBackgroundRun", !simple)) {
     1263            psError(psErrorCodeLast(), false, "failed to print array");
    8951264            psFree(output);
    8961265            return false;
     
    9041273
    9051274
    906 static bool addwarpedMode(pxConfig *config)
    907 {
    908     PS_ASSERT_PTR_NON_NULL(config, false);
    909 
    910     PXOPT_LOOKUP_S64(warp_id, config->args, "-warp_id", true, false);
     1275static bool warpinputsMode(pxConfig *config)
     1276{
     1277    PS_ASSERT_PTR_NON_NULL(config, false);
     1278
     1279    psMetadata *where = psMetadataAlloc();
     1280    PXOPT_COPY_S64(config->args, where, "-warp_bg_id", "warpBackgroundRun.warp_bg_id", "==");
     1281    PXOPT_COPY_STR(config->args, where, "-skycell_id", "warpProcessedSkyfile.skycell_id", "==");
     1282
     1283    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
     1284    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
     1285
     1286    // find all rawImfiles matching the default query
     1287    psString query = pxDataGet("bgtool_warpinputs.sql");
     1288    if (!query) {
     1289        psError(psErrorCodeLast(), false, "failed to retreive SQL statement");
     1290        return false;
     1291    }
     1292
     1293    if (psListLength(where->list)) {
     1294        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
     1295        psStringAppend(&query, " AND %s", whereClause);
     1296        psFree(whereClause);
     1297    }
     1298    psFree(where);
     1299
     1300    if (limit) {
     1301        psString limitString = psDBGenerateLimitSQL(limit);
     1302        psStringAppend(&query, " %s", limitString);
     1303        psFree(limitString);
     1304    }
     1305
     1306    if (!p_psDBRunQuery(config->dbh, query)) {
     1307        psError(psErrorCodeLast(), false, "database error");
     1308        psFree(query);
     1309        return false;
     1310    }
     1311    psFree(query);
     1312
     1313    psArray *output = p_psDBFetchResult(config->dbh);
     1314    if (!output) {
     1315        psError(psErrorCodeLast(), false, "database error");
     1316        return false;
     1317    }
     1318    if (!psArrayLength(output)) {
     1319        psTrace("bgtool", PS_LOG_INFO, "no rows found");
     1320        psFree(output);
     1321        return true;
     1322    }
     1323    if (!ippdbPrintMetadatas(stdout, output, "chipBackgroundSkyfile", !simple)) {
     1324        psError(psErrorCodeLast(), false, "failed to print array");
     1325        psFree(output);
     1326        return false;
     1327    }
     1328
     1329    psFree(output);
     1330
     1331    return true;
     1332}
     1333
     1334
     1335static bool addwarpMode(pxConfig *config)
     1336{
     1337    PS_ASSERT_PTR_NON_NULL(config, false);
     1338
     1339    PXOPT_LOOKUP_S64(warp_bg_id, config->args, "-warp_bg_id", true, false);
    9111340    PXOPT_LOOKUP_STR(skycell_id, config->args, "-skycell_id", true, false);
    912     PXOPT_LOOKUP_STR(tess_id, config->args, "-tess_id", true, false);
     1341    PXOPT_LOOKUP_STR(path_base, config->args, "-path_base", true, false);
    9131342
    9141343    // optional
    915     PXOPT_LOOKUP_STR(uri, config->args, "-uri", false, false);
    916     PXOPT_LOOKUP_STR(path_base, config->args, "-path_base", false, false);
     1344
     1345    PXOPT_LOOKUP_S64(magicked, config->args, "-set_magicked", false, false);
     1346    PXOPT_LOOKUP_F32(dtime_script, config->args, "-dtime_script", false, false);
     1347    PXOPT_LOOKUP_STR(hostname, config->args, "-hostname", false, false);
     1348    PXOPT_LOOKUP_S16(quality, config->args, "-quality", false, false);
     1349    PXOPT_LOOKUP_S16(fault, config->args, "-fault", false, false);
     1350    PXOPT_LOOKUP_STR(ver_pslib, config->args, "-ver_pslib", false, false);
     1351    PXOPT_LOOKUP_STR(ver_psmodules, config->args, "-ver_psmodules", false, false);
     1352    PXOPT_LOOKUP_STR(ver_ppbackground, config->args, "-ver_ppbackground", false, false);
     1353    PXOPT_LOOKUP_STR(ver_ppstats, config->args, "-ver_ppstats", false, false);
    9171354    PXOPT_LOOKUP_F64(bg, config->args, "-bg", false, false);
    9181355    PXOPT_LOOKUP_F64(bg_stdev, config->args, "-bg_stdev", false, false);
    919     PXOPT_LOOKUP_F32(dtime_warp, config->args, "-dtime_warp", false, false);
    920     PXOPT_LOOKUP_F32(dtime_script, config->args, "-dtime_script", false, false);
    921     PXOPT_LOOKUP_S32(xmin, config->args, "-xmin", false, false);
    922     PXOPT_LOOKUP_S32(xmax, config->args, "-xmax", false, false);
    923     PXOPT_LOOKUP_S32(ymin, config->args, "-ymin", false, false);
    924     PXOPT_LOOKUP_S32(ymax, config->args, "-ymax", false, false);
    925     PXOPT_LOOKUP_STR(hostname, config->args, "-hostname", false, false);
    926     PXOPT_LOOKUP_F32(good_frac, config->args, "-good_frac", false, false);
    927     PXOPT_LOOKUP_S64(magicked, config->args, "-set_magicked", false, false);
    928 
    929     PXOPT_LOOKUP_STR(ver_pslib, config->args, "-ver_pslib", false, false);
    930     PXOPT_LOOKUP_STR(ver_psmodules, config->args, "-ver_psmodules", false, false);
    931     PXOPT_LOOKUP_STR(ver_psphot, config->args, "-ver_psphot", false, false);
    932     PXOPT_LOOKUP_STR(ver_ppstats, config->args, "-ver_ppstats", false, false);
    933     PXOPT_LOOKUP_STR(ver_pswarp, config->args, "-ver_pswarp", false, false);
    934     PXOPT_LOOKUP_STR(ver_streaks, config->args, "-ver_streaks", false, false);
    935 
    9361356    PXOPT_LOOKUP_S32(maskfrac_npix, config->args, "-maskfrac_npix", false, false);
    9371357    PXOPT_LOOKUP_F32(maskfrac_static, config->args, "-maskfrac_static", false, false);
     
    9401360    PXOPT_LOOKUP_F32(maskfrac_advisory, config->args, "-maskfrac_advisory", false, false);
    9411361
    942     psTrace("czw.test",1,"Received versions: pslib %s psmodules %s psphot %s ppstats %s pswarp %s streaks %s\n",
    943             ver_pslib,ver_psmodules,ver_psphot,ver_ppstats,ver_pswarp,ver_streaks);
    944     psString ver_code = NULL;
    945     if ((ver_pslib)&&(ver_psmodules)) {
    946       ver_code = pxMergeCodeVersions(ver_pslib,ver_psmodules);
    947     }
    948     if (ver_psphot) {
    949       ver_code = pxMergeCodeVersions(ver_code,ver_psphot);
    950     }
    951     if (ver_ppstats) {
    952       ver_code = pxMergeCodeVersions(ver_code,ver_ppstats);
    953     }
    954     if (ver_pswarp) {
    955       ver_code = pxMergeCodeVersions(ver_code,ver_pswarp);
    956     }
    957     if (ver_streaks) {
    958       ver_code = pxMergeCodeVersions(ver_code,ver_streaks);
    959     }
    960 
    961     // default values
    962     PXOPT_LOOKUP_S16(fault, config->args, "-fault", false, false);
    963     PXOPT_LOOKUP_S16(quality, config->args, "-quality", false, false);
    964 
    965 
    966 
    967     // we don't want to insert the last skyfile in a run but then not mark the
    968     // run as 'stop'
     1362    psString ver_code = pxMergeCodeVersions(ver_pslib, ver_psmodules);
     1363    ver_code = pxMergeCodeVersions(ver_code, ver_ppbackground);
     1364    ver_code = pxMergeCodeVersions(ver_code, ver_ppstats);
     1365
    9691366    if (!psDBTransaction(config->dbh)) {
    9701367        psError(PS_ERR_UNKNOWN, false, "database error");
     
    9721369    }
    9731370
    974     // XXX need to validate that this coresponds to an warpInputImfile
    975     if (!warpSkyfileInsert(config->dbh,
    976                            warp_id,
    977                            skycell_id,
    978                            tess_id,
    979                            uri,
    980                            path_base,
    981                            "full",      // data_state
    982                            bg,
    983                            bg_stdev,
    984                            dtime_warp,
    985                            dtime_script,
    986                            hostname,
    987                            good_frac,
    988                            xmin,
    989                            xmax,
    990                            ymin,
    991                            ymax,
    992                            fault,
    993                            quality,
    994                            magicked,
    995                            ver_code,
    996                            maskfrac_npix,
    997                            maskfrac_static,
    998                            maskfrac_dynamic,
    999                            maskfrac_magic,
    1000                            maskfrac_advisory
    1001         )) {
     1371    if (!warpBackgroundSkyfileInsert(config->dbh, warp_bg_id, skycell_id, path_base, magicked, dtime_script,
     1372                                    hostname, quality, fault, ver_code, bg, bg_stdev, maskfrac_npix,
     1373                                    maskfrac_static, maskfrac_dynamic, maskfrac_magic, maskfrac_advisory)) {
     1374        psError(psErrorCodeLast(), false, "database error");
    10021375        if (!psDBRollback(config->dbh)) {
    1003             psError(PS_ERR_UNKNOWN, false, "database error");
    1004         }
    1005         psError(PS_ERR_UNKNOWN, false, "database error");
    1006         return false;
    1007     }
    1008 
    1009     // point of no return
     1376            psError(psErrorCodeLast(), false, "database error");
     1377        }
     1378        return false;
     1379    }
     1380
    10101381    if (!psDBCommit(config->dbh)) {
    1011         psError(PS_ERR_UNKNOWN, false, "database error");
    1012         return false;
    1013     }
    1014 
    1015     return true;
    1016 }
    1017 
    1018 static bool advancerunMode(pxConfig *config)
    1019 {
    1020     PS_ASSERT_PTR_NON_NULL(config, false);
    1021 
    1022     psMetadata *where = psMetadataAlloc();
    1023     PXOPT_COPY_S64(config->args, where, "-warp_id", "warp_id", "==");
    1024     pxAddLabelSearchArgs (config, where, "-label", "label", "==");
    1025 
    1026     PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
    1027 
    1028     psString query = pxDataGet("warptool_finished_run_select.sql");
    1029     if (!query) {
    1030         psError(PXTOOLS_ERR_SYS, false, "failed to retrieve SQL statement");
    1031         return false;
    1032     }
    1033 
    1034     if (psListLength(where->list)) {
    1035         psString whereClause = psDBGenerateWhereSQL(where, NULL);
    1036         psStringAppend(&query, " %s", whereClause);
    1037         psFree(whereClause);
    1038     }
    1039     psFree(where);
    1040 
    1041     if (!p_psDBRunQuery(config->dbh, query)) {
    1042         psError(PS_ERR_UNKNOWN, false, "database error");
    1043         psFree(query);
    1044         return false;
    1045     }
    1046     psFree(query);
    1047 
    1048     psArray *output = p_psDBFetchResult(config->dbh);
    1049     if (!output) {
    1050         psError(PS_ERR_UNKNOWN, false, "database error");
    1051         return false;
    1052     }
    1053     if (!psArrayLength(output)) {
    1054         psTrace("warptool", PS_LOG_INFO, "no rows found");
    1055         psFree(output);
    1056         return true;
    1057     }
    1058 
    1059     query = pxDataGet("warptool_finish_run.sql");
    1060     for (long i = 0; i < psArrayLength(output); i++) {
    1061         psMetadata *row = output->data[i];
    1062 
    1063         bool status;
    1064         psS64 warp_id = psMetadataLookupS64(&status, row, "warp_id");
    1065 
    1066         psString software_ver = NULL;
    1067         psS64 maskfrac_npix = 0;
    1068         psF32 maskfrac_static = 0;
    1069         psF32 maskfrac_dynamic = 0;
    1070         psF32 maskfrac_magic = 0;
    1071         psF32 maskfrac_advisory = 0;
    1072 
    1073         // Calculate run level masking and software state
    1074         if (!pxCoalesceRunStatus(config,"warptool_coalesce_run.sql",warp_id,
    1075                                  &software_ver,&maskfrac_npix,
    1076                                  &maskfrac_static,&maskfrac_dynamic,
    1077                                  &maskfrac_magic,&maskfrac_advisory)) {
    1078           psError(PS_ERR_UNKNOWN, false, "failed to generate run level statistics");
    1079           psFree(output);
    1080           if (!psDBRollback(config->dbh)) {
    1081             psError(PS_ERR_UNKNOWN, false, "database error");
    1082           }
    1083           return(false);
    1084         }
    1085         // Set warpRun.software_ver to the appropriate value    if (
    1086         if (software_ver) {
    1087           if (!pxSetRunSoftware(config, "warpRun", "warp_id", warp_id, software_ver)) {
    1088             psError(PS_ERR_UNKNOWN, false, "failed to set warpRun.software_ver for warp_id: %" PRId64,
    1089                     warp_id);
    1090             psFree(output);
    1091             if (!psDBRollback(config->dbh)) {
    1092               psError(PS_ERR_UNKNOWN, false, "database error");
    1093             }
    1094             return(false);
    1095           }
    1096         }
    1097         // Set warpRun.maskfrac* to the appropriate values.
    1098         if (maskfrac_npix) {
    1099           if (!pxSetRunMaskfrac(config, "warpRun", "warp_id", warp_id, maskfrac_npix, maskfrac_static,
    1100                                 maskfrac_dynamic, maskfrac_magic, maskfrac_advisory)) {
    1101             psError(PS_ERR_UNKNOWN, false, "failed to set warpRun.software_ver for warp_id: %" PRId64,
    1102                     warp_id);
    1103             psFree(output);
    1104             if (!psDBRollback(config->dbh)) {
    1105               psError(PS_ERR_UNKNOWN, false, "database error");
    1106             }
    1107             return(false);
    1108           }
    1109         }
    1110 
    1111 
    1112         if (!status) {
    1113             psError(PS_ERR_UNKNOWN, false, "failed to look up value for warp_id");
    1114             psFree(output);
    1115             psFree(query);
    1116             return false;
    1117         }
    1118         psS64 magicked = psMetadataLookupS64(&status, row, "magicked");
    1119         if (!status) {
    1120             psError(PS_ERR_UNKNOWN, false, "failed to look up value for magicked");
    1121             psFree(output);
    1122             psFree(query);
    1123             return false;
    1124         }
    1125         if (!p_psDBRunQueryF(config->dbh, query, magicked, warp_id)) {
    1126             psError(PS_ERR_UNKNOWN, false, "database error");
    1127             psFree(output);
    1128             psFree(query);
    1129             return false;
    1130         }
    1131 
    1132         psS64 numUpdated = psDBAffectedRows(config->dbh);
    1133 
    1134         if (numUpdated != 1) {
    1135             psError(PS_ERR_UNKNOWN, false, "should have affected 1 row");
    1136             psFree(query);
    1137             psFree(output);
    1138             return false;
    1139         }
    1140     }
    1141     psFree(output);
    1142     psFree(query);
    1143 
    1144     return true;
    1145 }
    1146 
    1147 bool warpCompletedRuns(pxConfig *config)
    1148 {
    1149     PS_ASSERT_PTR_NON_NULL(config, false);
    1150 
    1151     psString query = pxDataGet("warptool_finished_run_select.sql");
    1152     if (!query) {
    1153         psError(PXTOOLS_ERR_SYS, false, "failed to retrieve SQL statement");
    1154         return false;
    1155     }
    1156 
    1157     if (!p_psDBRunQuery(config->dbh, query)) {
    1158         psError(PS_ERR_UNKNOWN, false, "database error");
    1159         psFree(query);
    1160         return false;
    1161     }
    1162     psFree(query);
    1163 
    1164     psArray *output = p_psDBFetchResult(config->dbh);
    1165     if (!output) {
    1166         psError(PS_ERR_UNKNOWN, false, "database error");
    1167         return false;
    1168     }
    1169     if (!psArrayLength(output)) {
    1170         psTrace("warptool", PS_LOG_INFO, "no rows found");
    1171         psFree(output);
    1172         return true;
    1173     }
    1174 
    1175     query = pxDataGet("warptool_finish_run.sql");
    1176     for (long i = 0; i < psArrayLength(output); i++) {
    1177         psMetadata *row = output->data[i];
    1178 
    1179         bool status;
    1180         psS64 warp_id = psMetadataLookupS64(&status, row, "warp_id");
    1181         if (!status) {
    1182             psError(PS_ERR_UNKNOWN, false, "failed to look up value for warp_id");
    1183             psFree(output);
    1184             psFree(query);
    1185             return false;
    1186         }
    1187         psS32 magicked = psMetadataLookupS64(&status, row, "magicked");
    1188         if (!status) {
    1189             psError(PS_ERR_UNKNOWN, false, "failed to look up value for magicked");
    1190             psFree(output);
    1191             psFree(query);
    1192             return false;
    1193         }
    1194         if (!p_psDBRunQueryF(config->dbh, query, magicked, warp_id)) {
    1195             psError(PS_ERR_UNKNOWN, false, "database error");
    1196             psFree(output);
    1197             psFree(query);
    1198             return false;
    1199         }
    1200 
    1201         psS64 numUpdated = psDBAffectedRows(config->dbh);
    1202 
    1203         if (numUpdated != 1) {
    1204             psError(PS_ERR_UNKNOWN, false, "should have affected 1 row");
    1205             psFree(query);
    1206             psFree(output);
    1207             return false;
    1208         }
    1209     }
    1210     psFree(output);
    1211     psFree(query);
    1212 
    1213     return true;
    1214 }
    1215 
    1216 static bool warpedMode(pxConfig *config)
    1217 {
    1218     PS_ASSERT_PTR_NON_NULL(config, false);
    1219 
    1220     psMetadata *where = psMetadataAlloc();
    1221     PXOPT_COPY_S64(config->args, where, "-warp_id",    "warpSkyfile.warp_id", "==");
    1222     PXOPT_COPY_STR(config->args, where, "-skycell_id", "warpSkyfile.skycell_id", "==");
    1223     PXOPT_COPY_S64(config->args, where, "-warp_skyfile_id", "warpImfile.warp_skyfile_id", "==");
    1224     PXOPT_COPY_STR(config->args, where, "-skycell_id", "warpSkyfile.skycell_id", "==");
    1225     PXOPT_COPY_STR(config->args, where, "-tess_id",    "warpSkyfile.tess_id", "==");
    1226     PXOPT_COPY_S64(config->args, where, "-exp_id",     "rawExp.exp_id", "==");
    1227     PXOPT_COPY_STR(config->args, where, "-exp_name",   "rawExp.exp_name", "==");
    1228     PXOPT_COPY_S64(config->args, where, "-fake_id",    "fakeRun.fake_id", "==");
    1229     PXOPT_COPY_TIME(config->args, where, "-dateobs_begin", "rawExp.dateobs",  ">=");
    1230     PXOPT_COPY_TIME(config->args, where, "-dateobs_end",   "rawExp.dateobs",  "<=");
    1231     PXOPT_COPY_STR(config->args, where, "-filter",    "rawExp.filter", "LIKE");
    1232     PXOPT_COPY_S64(config->args, where, "-magicked", "warpSkyfile.magicked", "==");
    1233     pxAddLabelSearchArgs (config, where, "-label",   "warpRun.label", "LIKE");
    1234     pxAddLabelSearchArgs (config, where, "-data_group",   "warpRun.data_group", "LIKE");
     1382        psError(psErrorCodeLast(), false, "database error");
     1383        return false;
     1384    }
     1385
     1386    return true;
     1387}
     1388
     1389static bool warpMode(pxConfig *config)
     1390{
     1391    PS_ASSERT_PTR_NON_NULL(config, false);
     1392
     1393    psMetadata *where = psMetadataAlloc();
     1394    PXOPT_COPY_S64(config->args, where, "-warp_bg_id",    "warpBackgroundRun.warp_bg_id", "==");
     1395    PXOPT_COPY_STR(config->args, where, "-skycell_id", "warpBackgroundSkyfile.skycell_id", "==");
     1396    pxAddLabelSearchArgs(config, where, "-label",   "warpBackgroundRun.label", "LIKE");
     1397    pxAddLabelSearchArgs(config, where, "-data_group",   "warpBackgroundRun.data_group", "LIKE");
     1398    pxAddLabelSearchArgs(config, where, "-dist_group",   "warpBackgroundRun.data_group", "LIKE");
    12351399
    12361400    PXOPT_LOOKUP_BOOL(all, config->args, "-all", false);
    1237 
    12381401    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
    12391402    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
    12401403
    12411404    // find all rawImfiles matching the default query
    1242     psString query = pxDataGet("warptool_warped.sql");
     1405    psString query = pxDataGet("bgtool_warp.sql");
    12431406    if (!query) {
    1244         psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
    1245         return false;
    1246     }
    1247 
    1248     // generate where strings for arguments that require extra processing
    1249     // beyond PXOPT_COPY*
    1250     psString where2 = NULL;
    1251     if (!pxmagicAddWhere(config, &where2, "warpSkyfile")) {
     1407        psError(psErrorCodeLast(), false, "failed to retreive SQL statement");
     1408        return false;
     1409    }
     1410
     1411    psString magicWhere = NULL;
     1412    if (!pxmagicAddWhere(config, &magicWhere, "warpBackgroundSkyfile")) {
    12521413        psError(psErrorCodeLast(), false, "pxMagicAddWhere failed");
    12531414        return false;
    12541415    }
    1255     if (!pxspaceAddWhere(config, &where2, "rawExp")) {
     1416    if (!pxspaceAddWhere(config, &magicWhere, "rawExp")) {
    12561417        psError(psErrorCodeLast(), false, "pxSpaceAddWhere failed");
    12571418        return false;
     
    12621423        psStringAppend(&query, " WHERE %s", whereClause);
    12631424        psFree(whereClause);
    1264     } else if (!all && !where2) {
     1425    } else if (!all && !magicWhere) {
    12651426        psError(PXTOOLS_ERR_CONFIG, true, "search parameters or -all are required");
    12661427        return false;
    12671428    }
    1268 
    1269     if (where2) {
    1270         if (psListLength(where->list)) {
    1271             psStringAppend(&query, " %s", where2);
    1272         } else {
    1273             psStringAppend(&query, " WHERE 1 %s", where2);
    1274         }
    1275     }
    1276     psFree(where);
    1277 
    1278     // treat limit == 0 as "no limit"
     1429    if (magicWhere) {
     1430        psStringAppend(&query, "%s %s", psListLength(where->list) ? "AND" : "WHERE", magicWhere);
     1431    }
     1432    psFree(magicWhere);
     1433    psFree(where);
     1434
    12791435    if (limit) {
    12801436        psString limitString = psDBGenerateLimitSQL(limit);
     
    12841440
    12851441    if (!p_psDBRunQuery(config->dbh, query)) {
    1286         psError(PS_ERR_UNKNOWN, false, "database error");
     1442        psError(psErrorCodeLast(), false, "database error");
    12871443        psFree(query);
    12881444        return false;
     
    12921448    psArray *output = p_psDBFetchResult(config->dbh);
    12931449    if (!output) {
    1294         psErrorCode err = psErrorCodeLast();
    1295         switch (err) {
    1296             case PS_ERR_DB_CLIENT:
    1297                 psError(PXTOOLS_ERR_SYS, false, "database error");
    1298             case PS_ERR_DB_SERVER:
    1299                 psError(PXTOOLS_ERR_PROG, false, "database error");
    1300             default:
    1301                 psError(PXTOOLS_ERR_PROG, false, "unknown error");
    1302         }
    1303 
     1450        psError(psErrorCodeLast(), false, "database error");
    13041451        return false;
    13051452    }
    13061453    if (!psArrayLength(output)) {
    1307         psTrace("warptool", PS_LOG_INFO, "no rows found");
     1454        psTrace("bgtool", PS_LOG_INFO, "no rows found");
    13081455        psFree(output);
    13091456        return true;
    13101457    }
    1311 
    13121458    if (psArrayLength(output)) {
    1313         // negative simple so the default is true
    1314         if (!ippdbPrintMetadatas(stdout, output, "warpSkyfile", !simple)) {
    1315             psError(PS_ERR_UNKNOWN, false, "failed to print array");
    1316             psFree(output);
    1317             return false;
    1318         }
    1319     }
    1320 
     1459        if (!ippdbPrintMetadatas(stdout, output, "warpBackgroundSkyfile", !simple)) {
     1460            psError(psErrorCodeLast(), false, "failed to print array");
     1461            psFree(output);
     1462            return false;
     1463        }
     1464    }
    13211465    psFree(output);
    13221466
     
    13251469
    13261470
    1327 static bool revertwarpedMode(pxConfig *config)
    1328 {
    1329     PS_ASSERT_PTR_NON_NULL(config, false);
    1330 
    1331     psMetadata *where = psMetadataAlloc();
    1332     PXOPT_COPY_S64(config->args, where, "-warp_id",    "warpSkyfile.warp_id", "==");
    1333     PXOPT_COPY_STR(config->args, where, "-skycell_id", "warpSkyfile.skycell_id", "==");
    1334     PXOPT_COPY_STR(config->args, where, "-tess_id",    "warpSkyfile.tess_id", "==");
    1335     PXOPT_COPY_STR(config->args, where, "-reduction",  "rawExp.reduction", "==");
    1336     pxAddLabelSearchArgs (config, where, "-label",     "warpRun.label", "==");
    1337     PXOPT_COPY_S16(config->args, where, "-fault",      "warpSkyfile.fault", "==");
    1338 
    1339     if (!psListLength(where->list)
    1340         && !psMetadataLookupBool(NULL, config->args, "-all")) {
     1471static bool advancewarpMode(pxConfig *config)
     1472{
     1473    PS_ASSERT_PTR_NON_NULL(config, false);
     1474
     1475    psMetadata *where = psMetadataAlloc();
     1476    PXOPT_COPY_S64(config->args, where, "-warp_bg_id", "warp_bg_id", "==");
     1477    pxAddLabelSearchArgs(config, where, "-label", "label", "==");
     1478
     1479    psString select = pxDataGet("bgtool_advancewarp.sql");
     1480    if (!select) {
     1481        psError(psErrorCodeLast(), false, "failed to retrieve SQL statement");
     1482        return false;
     1483    }
     1484
     1485    psString selectWhere = psStringCopy("");
     1486    if (psListLength(where->list)) {
     1487        psString whereClause = psDBGenerateWhereSQL(where, NULL);
     1488        psStringAppend(&selectWhere, "\n WHERE %s", whereClause);
     1489        psFree(whereClause);
     1490    }
     1491    psFree(where);
     1492
     1493    if (!psDBTransaction(config->dbh)) {
     1494        psError(psErrorCodeLast(), false, "database error");
     1495        return false;
     1496    }
     1497
     1498    if (!p_psDBRunQueryF(config->dbh, select, selectWhere)) {
     1499        psError(psErrorCodeLast(), false, "database error");
     1500        psFree(select);
     1501        psFree(selectWhere);
     1502        if (!psDBRollback(config->dbh)) {
     1503            psError(psErrorCodeLast(), false, "database error");
     1504        }
     1505        return false;
     1506    }
     1507    psFree(select);
     1508    psFree(selectWhere);
     1509
     1510    psArray *output = p_psDBFetchResult(config->dbh);
     1511    if (!output) {
     1512        psError(psErrorCodeLast(), false, "database error");
     1513        if (!psDBRollback(config->dbh)) {
     1514            psError(psErrorCodeLast(), false, "database error");
     1515        }
     1516        return false;
     1517    }
     1518    if (!psArrayLength(output)) {
     1519        psTrace("bgtool", PS_LOG_INFO, "no rows found");
     1520        psFree(output);
     1521        return true;
     1522    }
     1523
     1524    for (long i = 0; i < psArrayLength(output); i++) {
     1525        psMetadata *row = output->data[i];
     1526        bool status = true;             // Status of MD lookup
     1527        psS64 warp_bg_id = psMetadataLookupS64(&status, row, "warp_bg_id");
     1528        if (!status) {
     1529            psError(PXTOOLS_ERR_PROG, true, "failed to look up value for warp_bg_id");
     1530            psFree(output);
     1531            if (!psDBRollback(config->dbh)) {
     1532                psError(psErrorCodeLast(), false, "database error");
     1533            }
     1534            return false;
     1535        }
     1536        psS64 magicked = psMetadataLookupS64(&status, row, "magicked");
     1537        if (!status) {
     1538            psError(PXTOOLS_ERR_PROG, true, "failed to look up value for magicked");
     1539            psFree(output);
     1540            if (!psDBRollback(config->dbh)) {
     1541                psError(psErrorCodeLast(), false, "database error");
     1542            }
     1543            return false;
     1544        }
     1545
     1546        if (!p_psDBRunQueryF(config->dbh,
     1547                             "UPDATE warpBackgroundRun "
     1548                             "SET state = 'full', magicked = %" PRId64 " "
     1549                             " WHERE warp_bg_id = %" PRId64,
     1550                             warp_bg_id, magicked)) {
     1551            psError(psErrorCodeLast(), false, "database error");
     1552            psFree(output);
     1553            if (!psDBRollback(config->dbh)) {
     1554                psError(psErrorCodeLast(), false, "database error");
     1555            }
     1556            return false;
     1557        }
     1558
     1559        psS64 numUpdated = psDBAffectedRows(config->dbh);
     1560        if (numUpdated != 1) {
     1561            psError(PXTOOLS_ERR_PROG, true, "should have affected 1 row");
     1562            if (!psDBRollback(config->dbh)) {
     1563                psError(psErrorCodeLast(), false, "database error");
     1564            }
     1565            psFree(output);
     1566            return false;
     1567        }
     1568    }
     1569    psFree(output);
     1570
     1571    if (!psDBCommit(config->dbh)) {
     1572        psError(psErrorCodeLast(), false, "database error");
     1573        return false;
     1574    }
     1575
     1576    return true;
     1577}
     1578
     1579static bool revertwarpMode(pxConfig *config)
     1580{
     1581    PS_ASSERT_PTR_NON_NULL(config, false);
     1582
     1583    psMetadata *where = psMetadataAlloc();
     1584    PXOPT_COPY_S64(config->args, where, "-warp_bg_id", "warpBackgroundRun.warp_bg_id", "==");
     1585    PXOPT_COPY_STR(config->args, where, "-skycell_id", "warpBackgroundSkyfile.skycell_id", "==");
     1586    pxAddLabelSearchArgs(config, where, "-label", "warpBackgroundRun.label", "==");
     1587    PXOPT_COPY_S16(config->args, where, "-fault", "warpBackgroundSkyfile.fault", "==");
     1588
     1589    if (!psListLength(where->list) && !psMetadataLookupBool(NULL, config->args, "-all")) {
    13411590        psFree(where);
    1342         psError(PXTOOLS_ERR_CONFIG, false, "search parameters are required");
    1343         return false;
    1344     }
    1345 
    1346     psString query = pxDataGet("warptool_revertwarped_delete.sql");
     1591        psError(PXTOOLS_ERR_CONFIG, true, "search parameters are required");
     1592        return false;
     1593    }
     1594
     1595    psString query = pxDataGet("bgtool_revertwarp.sql");
    13471596    if (!query) {
    1348         psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
    1349         return false;
    1350     }
    1351     psString query_updated = pxDataGet("warptool_revertwarped_updated.sql");
    1352     if (!query_updated) {
    1353         psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
     1597        psError(psErrorCodeLast(), false, "failed to retreive SQL statement");
    13541598        return false;
    13551599    }
     
    13581602        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
    13591603        psStringAppend(&query, " AND %s", whereClause);
    1360         psStringAppend(&query_updated, " AND %s", whereClause);
    13611604        psFree(whereClause);
    13621605    }
     
    13711614
    13721615    int numDeleted = psDBAffectedRows(config->dbh);
    1373 
    1374     psLogMsg("warptool", PS_LOG_INFO, "Deleted %d warpSkyfiles", numDeleted);
    1375 
    1376     // fix any faulted warpSkyfiles in data_state 'update'
    1377 
    1378     if (!p_psDBRunQuery(config->dbh, query_updated)) {
    1379         psError(PS_ERR_UNKNOWN, false, "database error");
    1380         psFree(query_updated);
    1381         return false;
    1382     }
    1383     psFree(query_updated);
    1384 
    1385     int numUpdated = psDBAffectedRows(config->dbh);
    1386 
    1387     psLogMsg("warptool", PS_LOG_INFO, "Updated %d warpSkyfiles", numUpdated);
    1388 
    1389     return true;
    1390 }
    1391 
    1392 
    1393 static bool blockMode(pxConfig *config)
    1394 {
    1395     PS_ASSERT_PTR_NON_NULL(config, false);
    1396 
    1397     PXOPT_LOOKUP_STR(label, config->args, "-label", true, false);
    1398 
    1399     if (!warpMaskInsert(config->dbh, label)) {
    1400         psError(PS_ERR_UNKNOWN, false, "database error");
    1401         return false;
    1402     }
    1403 
    1404     return true;
    1405 }
    1406 
    1407 
    1408 static bool maskedMode(pxConfig *config)
    1409 {
    1410     PS_ASSERT_PTR_NON_NULL(config, false);
    1411 
    1412     PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
    1413 
    1414     psString query = psStringCopy("SELECT * FROM warpMask");
    1415 
    1416     if (!p_psDBRunQuery(config->dbh, query)) {
    1417         psError(PS_ERR_UNKNOWN, false, "database error");
    1418         psFree(query);
    1419         return false;
    1420     }
    1421     psFree(query);
    1422 
    1423     psArray *output = p_psDBFetchResult(config->dbh);
    1424     if (!output) {
    1425         psError(PS_ERR_UNKNOWN, false, "database error");
    1426         return false;
    1427     }
    1428     if (!psArrayLength(output)) {
    1429         psTrace("warpool", PS_LOG_INFO, "no rows found");
    1430         psFree(output);
    1431         return true;
    1432     }
    1433 
    1434     // negative simple so the default is true
    1435     if (!ippdbPrintMetadatas(stdout, output, "warpMask", !simple)) {
    1436         psError(PS_ERR_UNKNOWN, false, "failed to print array");
    1437         psFree(output);
    1438         return false;
    1439     }
    1440 
    1441     psFree(output);
    1442 
    1443     return true;
    1444 }
    1445 
    1446 static bool unblockMode(pxConfig *config)
    1447 {
    1448     PS_ASSERT_PTR_NON_NULL(config, false);
    1449 
    1450     PXOPT_LOOKUP_STR(label, config->args, "-label", true, false);
    1451 
    1452     char *query = "DELETE FROM warpMask WHERE label = '%s'";
    1453 
    1454     if (!p_psDBRunQueryF(config->dbh, query, label)) {
    1455         psError(PS_ERR_UNKNOWN, false, "database error");
    1456         return false;
    1457     }
    1458 
    1459     return true;
    1460 }
    1461 
    1462 static bool pendingcleanuprunMode(pxConfig *config)
     1616    psLogMsg("bgtool", PS_LOG_INFO, "Deleted %d warpBackgroundSkyfiles", numDeleted);
     1617
     1618    return true;
     1619}
     1620
     1621static bool tocleanwarpMode(pxConfig *config)
    14631622{
    14641623    PS_ASSERT_PTR_NON_NULL(config, NULL);
     
    14681627
    14691628    psMetadata *where = psMetadataAlloc();
    1470     pxAddLabelSearchArgs (config, where, "-label", "warpRun.label", "==");
    1471 
    1472     psString query = pxDataGet("warptool_pendingcleanuprun.sql");
     1629    pxAddLabelSearchArgs(config, where, "-label", "warpBackgroundRun.label", "==");
     1630
     1631    psString query = pxDataGet("bgtool_tocleanwarp.sql");
    14731632    if (!query) {
    1474         psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
     1633        psError(psErrorCodeLast(), false, "failed to retreive SQL statement");
    14751634        return false;
    14761635    }
     
    14831642    psFree(where);
    14841643
    1485     // treat limit == 0 as "no limit"
    14861644    if (limit) {
    14871645        psString limitString = psDBGenerateLimitSQL(limit);
     
    14911649
    14921650    if (!p_psDBRunQuery(config->dbh, query)) {
    1493         psError(PS_ERR_UNKNOWN, false, "database error");
     1651        psError(psErrorCodeLast(), false, "database error");
    14941652        psFree(query);
    14951653        return false;
     
    14991657    psArray *output = p_psDBFetchResult(config->dbh);
    15001658    if (!output) {
    1501         psError(PS_ERR_UNKNOWN, false, "database error");
     1659        psError(psErrorCodeLast(), false, "database error");
    15021660        return false;
    15031661    }
    15041662    if (!psArrayLength(output)) {
    1505         psTrace("warptool", PS_LOG_INFO, "no rows found");
     1663        psTrace("bgtool", PS_LOG_INFO, "no rows found");
    15061664        psFree(output);
    15071665        return true;
     
    15091667
    15101668    // negative simple so the default is true
    1511     if (!ippdbPrintMetadatas(stdout, output, "warpPendingCleanupRun", !simple)) {
    1512         psError(PS_ERR_UNKNOWN, false, "failed to print array");
    1513         psFree(output);
    1514         return false;
    1515     }
    1516 
     1669    if (!ippdbPrintMetadatas(stdout, output, "warpBackgroundRun", !simple)) {
     1670        psError(psErrorCodeLast(), false, "failed to print array");
     1671        psFree(output);
     1672        return false;
     1673    }
    15171674    psFree(output);
    15181675
     
    15201677}
    15211678
    1522 
    1523 static bool pendingcleanupwarpMode(pxConfig *config)
    1524 {
    1525     PS_ASSERT_PTR_NON_NULL(config, NULL);
    1526 
    1527     PXOPT_LOOKUP_S64(warp_id, config->args, "-warp_id", true, false);
    1528     PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
    1529     PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
    1530 
    1531     psMetadata *where = psMetadataAlloc();
    1532     PXOPT_COPY_S64(config->args, where, "-warp_id", "warp_id", "==");
    1533     pxAddLabelSearchArgs (config, where, "-label", "warpRun.label", "==");
    1534 
    1535     psString query = pxDataGet("warptool_pendingcleanupskyfile.sql");
     1679static bool cleanedwarpMode(pxConfig *config)
     1680{
     1681    PS_ASSERT_PTR_NON_NULL(config, false);
     1682
     1683    psMetadata *where = psMetadataAlloc();
     1684    PXOPT_COPY_S64(config->args, where, "-warp_bg_id", "warpBackgroundRun.warp_bg_id", "==");
     1685
     1686    PXOPT_LOOKUP_STR(state, config->args, "-state", true, false);
     1687    if (!pxIsValidCleanedState(state)) {
     1688        psError(PXTOOLS_ERR_CONFIG, true, "Invalid state: %s", state);
     1689        return false;
     1690    }
     1691
     1692    if (!psListLength(where->list)) {
     1693        psError(PXTOOLS_ERR_CONFIG, true, "No search restrictions set.");
     1694        return false;
     1695    }
     1696
     1697    psString query = pxDataGet("bgtool_cleanedwarp.sql");
    15361698    if (!query) {
    1537         psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
    1538         return false;
    1539     }
    1540 
    1541     if (where && psListLength(where->list)) {
     1699        psError(psErrorCodeLast(), false, "failed to retreive SQL statement");
     1700        return false;
     1701    }
     1702
     1703    {
    15421704        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
    15431705        psStringAppend(&query, " AND %s", whereClause);
     
    15461708    psFree(where);
    15471709
    1548     // treat limit == 0 as "no limit"
    1549     if (limit) {
    1550         psString limitString = psDBGenerateLimitSQL(limit);
    1551         psStringAppend(&query, " %s", limitString);
    1552         psFree(limitString);
    1553     }
    1554 
    1555     if (!p_psDBRunQuery(config->dbh, query)) {
    1556         psError(PS_ERR_UNKNOWN, false, "database error");
    1557         psFree(query);
     1710    if (!p_psDBRunQueryF(config->dbh, query, state)) {
     1711        psError(psErrorCodeLast(), false, "database error");
    15581712        return false;
    15591713    }
    15601714    psFree(query);
    15611715
    1562     psArray *output = p_psDBFetchResult(config->dbh);
    1563     if (!output) {
    1564         psError(PS_ERR_UNKNOWN, false, "database error");
    1565         return false;
    1566     }
    1567     if (!psArrayLength(output)) {
    1568         psTrace("warptool", PS_LOG_INFO, "no rows found");
    1569         psFree(output);
    1570         return true;
    1571     }
    1572 
    1573     // negative simple so the default is true
    1574     if (!ippdbPrintMetadatas(stdout, output, "warpPendingCleanupWarp", !simple)) {
    1575         psError(PS_ERR_UNKNOWN, false, "failed to print array");
    1576         psFree(output);
    1577         return false;
    1578     }
    1579 
    1580     psFree(output);
    1581 
    1582     return true;
    1583 }
    1584 
    1585 
    1586 static bool donecleanupMode(pxConfig *config)
    1587 {
    1588     PS_ASSERT_PTR_NON_NULL(config, NULL);
    1589 
    1590     PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
    1591     PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
    1592 
    1593     psMetadata *where = psMetadataAlloc();
    1594     PXOPT_COPY_STR(config->args, where, "-label", "label", "==");
    1595 
    1596     psString query = pxDataGet("warptool_donecleanup.sql");
    1597     if (!query) {
    1598         psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
    1599         return false;
    1600     }
    1601 
    1602     if (where && psListLength(where->list)) {
    1603         psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
    1604         psStringAppend(&query, " AND %s", whereClause);
    1605         psFree(whereClause);
    1606     }
    1607     psFree(where);
    1608 
    1609     // treat limit == 0 as "no limit"
    1610     if (limit) {
    1611         psString limitString = psDBGenerateLimitSQL(limit);
    1612         psStringAppend(&query, " %s", limitString);
    1613         psFree(limitString);
    1614     }
    1615 
    1616     if (!p_psDBRunQuery(config->dbh, query)) {
    1617         psError(PS_ERR_UNKNOWN, false, "database error");
    1618         psFree(query);
    1619         return false;
    1620     }
    1621     psFree(query);
    1622 
    1623     psArray *output = p_psDBFetchResult(config->dbh);
    1624     if (!output) {
    1625         psError(PS_ERR_UNKNOWN, false, "database error");
    1626         return false;
    1627     }
    1628     if (!psArrayLength(output)) {
    1629         psTrace("warptool", PS_LOG_INFO, "no rows found");
    1630         psFree(output);
    1631         return true;
    1632     }
    1633 
    1634     // negative simple so the default is true
    1635     if (!ippdbPrintMetadatas(stdout, output, "warpDoneCleanup", !simple)) {
    1636         psError(PS_ERR_UNKNOWN, false, "failed to print array");
    1637         psFree(output);
    1638         return false;
    1639     }
    1640 
    1641     psFree(output);
    1642 
    1643     return true;
    1644 }
    1645 
    1646 
    1647 // update warpSkyfile.data_state to given value.
    1648 // afterwards, if all skfyiles in the run have the new state, update the state for the run as well
    1649 // shared code for the modes -tocleanedskyfile -tofullskyfile -topurgedskyfile
    1650 
    1651 static bool change_skyfile_data_state(pxConfig *config, psString data_state, psString run_state)
    1652 {
    1653     PS_ASSERT_PTR_NON_NULL(config, false);
    1654 
    1655     // warp_id, skycell_id are required
    1656     PXOPT_LOOKUP_S64(warp_id, config->args, "-warp_id", true, false);
    1657     PXOPT_LOOKUP_STR(skycell_id, config->args, "-skycell_id", true, false);
    1658 
    1659     psString query = pxDataGet("warptool_change_skyfile_data_state.sql");
    1660 
    1661     if (!psDBTransaction(config->dbh)) {
    1662         psError(PS_ERR_UNKNOWN, false, "database error");
    1663         return false;
    1664     }
    1665 
    1666     psString set_magicked_skyfile = psStringCopy("");
    1667     psString set_magicked_run = psStringCopy("");
    1668     if (!strcmp(data_state, "full")) {
    1669         // magicked is only an argument for for -tofullskyfile
    1670         PXOPT_LOOKUP_S64(magicked, config->args, "-set_magicked", false, false);
    1671         if (magicked) {
    1672             psStringAppend(&set_magicked_skyfile, "\n , warpSkyfile.magicked = %" PRId64, magicked);
    1673             psStringAppend(&set_magicked_run, "\n,  warpRun.magicked = %" PRId64, magicked);
    1674         }
    1675     } else if (!strcmp(data_state, "cleaned") || !strcmp(data_state, "purged")) {
    1676         // if magicked is currently nonzero set it to -1
    1677         // Set warpRun.magicked when the first skyfile is cleaned
    1678         psStringAppend(&set_magicked_skyfile, "\n, warpSkyfile.magicked = IF(warpSkyfile.magicked = 0, 0, -1), warpRun.magicked = IF(warpRun.magicked = 0, 0, -1)");
    1679     }
    1680 
    1681     if (!p_psDBRunQueryF(config->dbh, query, data_state, set_magicked_skyfile, warp_id, skycell_id)) {
    1682         psError(PS_ERR_UNKNOWN, false, "database error");
    1683         // rollback
    1684         if (!psDBRollback(config->dbh)) {
    1685             psError(PS_ERR_UNKNOWN, false, "database error");
    1686         }
    1687         psError(PS_ERR_UNKNOWN, false, "database error");
    1688         return false;
    1689     }
    1690     psFree(query);
    1691     psFree(set_magicked_skyfile);
    1692 
    1693     query = pxDataGet("warptool_change_run_state.sql");
    1694     if (!p_psDBRunQueryF(config->dbh, query, data_state, set_magicked_run, warp_id, data_state)) {
    1695         // rollback
    1696         if (!psDBRollback(config->dbh)) {
    1697             psError(PS_ERR_UNKNOWN, false, "database error");
    1698         }
    1699         psError(PS_ERR_UNKNOWN, false, "database error");
    1700         return false;
    1701     }
    1702     psFree(set_magicked_run);
    1703 
    1704     if (!psDBCommit(config->dbh)) {
    1705         psError(PS_ERR_UNKNOWN, false, "database error");
    1706         return false;
    1707     }
    1708 
    1709     return true;
    1710 }
    1711 static bool tocleanedskyfileMode(pxConfig *config)
    1712 {
    1713     return change_skyfile_data_state(config, "cleaned", "goto_cleaned");
    1714 }
    1715 static bool tofullskyfileMode(pxConfig *config)
    1716 {
    1717     return change_skyfile_data_state(config, "full", "update");
    1718 }
    1719 static bool topurgedskyfileMode(pxConfig *config)
    1720 {
    1721     return change_skyfile_data_state(config, "purged", "goto_purged");
    1722 }
    1723 static bool toscrubbedskyfileMode(pxConfig *config)
    1724 {
    1725      return change_skyfile_data_state(config, "scrubbed", "goto_scrubbed");
    1726 }
    1727 
    1728 static bool updateskyfileMode(pxConfig *config)
    1729 {
    1730     PS_ASSERT_PTR_NON_NULL(config, false);
    1731 
    1732     // warp_id, skycell_id, fault are required
    1733     PXOPT_LOOKUP_S64(warp_id, config->args, "-warp_id", true, false);
    1734     PXOPT_LOOKUP_STR(skycell_id, config->args, "-skycell_id", true, false);
    1735     PXOPT_LOOKUP_S16(fault, config->args, "-fault", false, false);
    1736     PXOPT_LOOKUP_STR(state, config->args, "-set_state", false, false);
    1737 
    1738     if (!state) {
    1739       psString query = pxDataGet("warptool_updateskyfile.sql");
    1740 
    1741       if (!p_psDBRunQueryF(config->dbh, query, fault, warp_id, skycell_id)) {
    1742         psError(PS_ERR_UNKNOWN, false, "database error");
    1743         return false;
    1744       }
    1745       psFree(query);
    1746     }
    1747     else {
    1748       if (strcmp(state,"error_cleaned") == 0) {
    1749         change_skyfile_data_state(config,"error_cleaned","goto_cleaned");
    1750       }
    1751       else if (strcmp(state, "error_scrubbed") == 0) {
    1752         change_skyfile_data_state(config,"error_scrubbed","goto_scrubbed");
    1753       }
    1754       else if (strcmp(state, "error_purged") == 0) {
    1755         change_skyfile_data_state(config,"error_purged","goto_purged");
    1756       }
    1757       else {
    1758         psError(PS_ERR_UNKNOWN, false, "unhandled state given");
    1759         return(false);
    1760       }
    1761     }
    1762 
    1763     return true;
    1764 }
    1765 
    1766 bool exportrunMode(pxConfig *config)
    1767 {
    1768   typedef struct ExportTable {
    1769     char tableName[80];
    1770     char sqlFilename[80];
    1771   } ExportTable;
    1772 
    1773     PS_ASSERT_PTR_NON_NULL(config, NULL);
    1774 
    1775     PXOPT_LOOKUP_S64(det_id,  config->args, "-warp_id", true,  false);
     1716    return true;
     1717}
     1718
     1719static bool exportwarpMode(pxConfig *config)
     1720{
     1721    PS_ASSERT_PTR_NON_NULL(config, false);
     1722
     1723    PXOPT_LOOKUP_S64(warp_bg_id, config->args, "-warp_bg_id", true,  false);
    17761724    PXOPT_LOOKUP_STR(outfile, config->args, "-outfile", true,  false);
    1777     PXOPT_LOOKUP_U64(limit,   config->args, "-limit",   false, false);
    17781725    PXOPT_LOOKUP_BOOL(clean,  config->args, "-clean", false);
    17791726
    1780     FILE *f = fopen (outfile, "w");
    1781     if (f == NULL) {
    1782         psError(PS_ERR_UNKNOWN, false, "failed to open output file");
    1783         return false;
    1784     }
    1785 
    1786     if (!pxExportVersion(config, f)) {
    1787         psError(PS_ERR_UNKNOWN, false, "failed to write dbversion output file");
    1788         return false;
    1789     }
    1790     psMetadata *where = psMetadataAlloc();
    1791     PXOPT_COPY_S64(config->args, where, "-warp_id", "warp_id", "==");
    1792 
    1793     ExportTable tables [] = {
    1794       {"warpRun", "warptool_export_run.sql"},
    1795       {"warpImfile", "warptool_export_imfile.sql"},
    1796       {"warpSkyfile", "warptool_export_skyfile.sql"},
    1797       {"warpSkyCellMap", "warptool_export_skycell_map.sql"},
    1798     };
    1799 
    1800     int numTables = sizeof(tables)/sizeof(tables[0]);
    1801 
    1802     for (int i=0; i < numTables; i++) {
    1803       psString query = pxDataGet(tables[i].sqlFilename);
    1804       if (!query) {
    1805           psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
    1806           return false;
    1807       }
    1808 
    1809       if (where && psListLength(where->list)) {
    1810           psString whereClause = psDBGenerateWhereSQL(where, NULL);
    1811           psStringAppend(&query, " %s", whereClause);
    1812           psFree(whereClause);
    1813       }
    1814 
    1815       // treat limit == 0 as "no limit"
    1816       if (limit) {
    1817         psString limitString = psDBGenerateLimitSQL(limit);
    1818         psStringAppend(&query, " %s", limitString);
    1819         psFree(limitString);
    1820       }
    1821 
    1822       if (!p_psDBRunQuery(config->dbh, query)) {
    1823         psError(PS_ERR_UNKNOWN, false, "database error");
    1824         psFree(query);
    1825         return false;
    1826       }
    1827       psFree(query);
    1828 
    1829       psArray *output = p_psDBFetchResult(config->dbh);
    1830       if (!output) {
    1831           psError(PS_ERR_UNKNOWN, false, "database error");
    1832           return false;
    1833       }
    1834       if (!psArrayLength(output)) {
    1835         psError(PS_ERR_UNKNOWN, true, "no rows found");
    1836         psFree(output);
    1837         return false;
    1838       }
    1839 
    1840     if (clean) {
    1841         bool success = true;
    1842         if (!strcmp(tables[i].tableName, "warpRun")) {
    1843             success = pxSetStateCleaned("warpRun", "state", output);
    1844         } else if (!strcmp(tables[i].tableName, "warpSkyfile")) {
    1845             success = pxSetStateCleaned("warpSkyfile", "data_state", output);
    1846         }
    1847         if (!success) {
    1848             psFree(output);
    1849             psError(PS_ERR_UNKNOWN, false, "pxSetStateClean failed for table %s",  tables[i].tableName);
    1850             return false;
    1851         }
    1852     }
    1853 
    1854       // we must write the export table in non-simple (true) format
    1855       if (!ippdbPrintMetadatas(f, output, tables[i].tableName, true)) {
    1856         psError(PS_ERR_UNKNOWN, false, "failed to print array");
    1857         psFree(output);
    1858         return false;
    1859       }
    1860       psFree(output);
    1861     }
    1862 
    1863     fclose (f);
    1864 
    1865     return true;
    1866 }
    1867 
    1868 bool importrunMode(pxConfig *config)
    1869 {
    1870   unsigned int nFail;
    1871 
    1872   int numImportTables = 3;
    1873 
    1874   char tables[3] [80] = {"warpImfile", "warpSkyfile", "warpSkyCellMap"};
    1875 
    1876   PS_ASSERT_PTR_NON_NULL(config, NULL);
    1877 
    1878   PXOPT_LOOKUP_STR(infile, config->args, "-infile", true,  false);
    1879 
    1880   psMetadata *input = psMetadataConfigRead (NULL, &nFail, infile, false);
    1881 
    1882 #ifdef notdef
    1883   fprintf (stderr, "---- input ----\n");
    1884   psMetadataPrint (stderr, input, 1);
    1885 #endif
    1886 
    1887   if (!pxCheckImportVersion(config, input)) {
    1888       psError(PS_ERR_UNKNOWN, false, "pxCheckImportVersion failed");
    1889       return false;
    1890   }
    1891 
    1892   psMetadataItem *item = psMetadataLookup (input, "warpRun");
    1893   psAssert (item, "entry not in input?");
    1894   psAssert (item->type == PS_DATA_METADATA_MULTI, "entry not multi?");
    1895 
    1896   psMetadataItem *entry = psListGet (item->data.list, 0);
    1897   assert (entry);
    1898   assert (entry->type == PS_DATA_METADATA);
    1899   warpRunRow *warpRun = warpRunObjectFromMetadata (entry->data.md);
    1900   warpRunInsertObject (config->dbh, warpRun);
    1901 
    1902   // fprintf (stdout, "---- warp run ----\n");
    1903   // psMetadataPrint (stderr, entry->data.md, 1);
    1904 
    1905   for (int i = 0; i < numImportTables; i++) {
    1906     item = psMetadataLookup (input, tables[i]);
    1907     psAssert (item, "entry not in input?");
    1908     psAssert (item->type == PS_DATA_METADATA_MULTI, "entry not multi?");
    1909 
    1910     switch (i) {
    1911       case 0:
    1912         for (int i = 0; i < item->data.list->n; i++) {
    1913           entry = psListGet (item->data.list, i);
    1914           assert (entry);
    1915           assert (entry->type == PS_DATA_METADATA);
    1916           warpImfileRow *warpImfile = warpImfileObjectFromMetadata (entry->data.md);
    1917           warpImfileInsertObject (config->dbh, warpImfile);
    1918 
    1919           // fprintf (stdout, "---- row %d ----\n", i);
    1920           // psMetadataPrint (stderr, entry->data.md, 1);
    1921         }
    1922         break;
    1923 
    1924       case 1:
    1925         for (int i = 0; i < item->data.list->n; i++) {
    1926           entry = psListGet (item->data.list, i);
    1927           assert (entry);
    1928           assert (entry->type == PS_DATA_METADATA);
    1929           warpSkyfileRow *warpSkyfile = warpSkyfileObjectFromMetadata (entry->data.md);
    1930           warpSkyfileInsertObject (config->dbh, warpSkyfile);
    1931 
    1932           // fprintf (stdout, "---- row %d ----\n", i);
    1933           // psMetadataPrint (stderr, entry->data.md, 1);
    1934         }
    1935         break;
    1936 
    1937       case 2:
    1938         for (int i = 0; i < item->data.list->n; i++) {
    1939           entry = psListGet (item->data.list, i);
    1940           assert (entry);
    1941           assert (entry->type == PS_DATA_METADATA);
    1942           warpSkyCellMapRow *warpSkyCellMap = warpSkyCellMapObjectFromMetadata (entry->data.md);
    1943           warpSkyCellMapInsertObject (config->dbh, warpSkyCellMap);
    1944 
    1945           // fprintf (stdout, "---- row %d ----\n", i);
    1946           // psMetadataPrint (stderr, entry->data.md, 1);
    1947         }
    1948         break;
    1949     }
    1950   }
    1951   return true;
    1952 }
    1953 
    1954 static bool runstateMode(pxConfig *config)
    1955 {
    1956     PS_ASSERT_PTR_NON_NULL(config, false);
    1957 
    1958     psMetadata *where = psMetadataAlloc();
    1959     PXOPT_COPY_S64(config->args, where, "-warp_id",    "warpRun.warp_id", "==");
    1960     PXOPT_COPY_S64(config->args, where, "-exp_id",     "rawExp.exp_id", "==");
    1961     PXOPT_COPY_STR(config->args, where, "-exp_name",   "rawExp.exp_name", "==");
    1962     pxAddLabelSearchArgs (config, where, "-label",     "warpRun.label", "LIKE");
    1963 
    1964 //    PXOPT_LOOKUP_BOOL(all, config->args, "-all", false);
    1965     PXOPT_LOOKUP_BOOL(no_magic, config->args, "-no_magic", false);
    1966 
    1967     PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
    1968     PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
    1969 
    1970     psString query = pxDataGet("warptool_runstate.sql");
    1971     if (!query) {
    1972         psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
    1973         return false;
    1974     }
    1975 
    1976     if (psListLength(where->list)) {
    1977         psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
    1978         psStringAppend(&query, " WHERE %s", whereClause);
    1979         psFree(whereClause);
    1980     } else {
    1981         psError(PXTOOLS_ERR_CONFIG, true, "search parameters or -all are required");
    1982         return false;
    1983     }
    1984     psFree(where);
    1985 
    1986     // treat limit == 0 as "no limit"
    1987     if (limit) {
    1988         psString limitString = psDBGenerateLimitSQL(limit);
    1989         psStringAppend(&query, " %s", limitString);
    1990         psFree(limitString);
    1991     }
    1992 
    1993     if (!p_psDBRunQuery(config->dbh, query)) {
    1994         psError(PS_ERR_UNKNOWN, false, "database error");
    1995         psFree(query);
    1996         return false;
    1997     }
    1998     psFree(query);
    1999 
    2000     psArray *output = p_psDBFetchResult(config->dbh);
    2001     if (!output) {
    2002         psErrorCode err = psErrorCodeLast();
    2003         switch (err) {
    2004             case PS_ERR_DB_CLIENT:
    2005                 psError(PXTOOLS_ERR_SYS, false, "database error");
    2006             case PS_ERR_DB_SERVER:
    2007                 psError(PXTOOLS_ERR_PROG, false, "database error");
    2008             default:
    2009                 psError(PXTOOLS_ERR_PROG, false, "unknown error");
    2010         }
    2011 
    2012         return false;
    2013     }
    2014     if (!psArrayLength(output)) {
    2015         psTrace("warptool", PS_LOG_INFO, "no rows found");
    2016         psFree(output);
    2017         return true;
    2018     }
    2019 
    2020     if (psArrayLength(output)) {
    2021         // negative simple so the default is true
    2022         if (!ippdbPrintMetadatas(stdout, output, "warpRunState", !simple)) {
    2023             psError(PS_ERR_UNKNOWN, false, "failed to print array");
    2024             psFree(output);
    2025             return false;
    2026         }
    2027     }
    2028 
    2029     psFree(output);
    2030 
    2031     return true;
    2032 }
    2033 
    2034 static bool listrunMode(pxConfig *config)
    2035 {
    2036     PS_ASSERT_PTR_NON_NULL(config, false);
    2037 
    2038     psMetadata *where = psMetadataAlloc();
    2039     PXOPT_COPY_S64(config->args, where, "-warp_id",    "warpRun.warp_id", "==");
    2040     PXOPT_COPY_STR(config->args, where, "-tess_id",    "warpRun.tess_id", "==");
    2041     PXOPT_COPY_STR(config->args, where, "-state",      "warpRun.state", "==");
    2042     PXOPT_COPY_S64(config->args, where, "-exp_id",     "rawExp.exp_id", "==");
    2043     PXOPT_COPY_STR(config->args, where, "-exp_name",   "rawExp.exp_name", "==");
    2044     PXOPT_COPY_S64(config->args, where, "-fake_id",    "fakeRun.fake_id", "==");
    2045     PXOPT_COPY_TIME(config->args, where, "-dateobs_begin", "rawExp.dateobs",  ">=");
    2046     PXOPT_COPY_TIME(config->args, where, "-dateobs_end",   "rawExp.dateobs",  "<=");
    2047     PXOPT_COPY_STR(config->args, where, "-filter",    "rawExp.filter", "LIKE");
    2048     PXOPT_COPY_S64(config->args, where, "-magicked", "warpRun.magicked", "==");
    2049     pxAddLabelSearchArgs (config, where, "-label",   "warpRun.label", "LIKE");
    2050     pxAddLabelSearchArgs (config, where, "-data_group",   "warpRun.data_group", "LIKE");
    2051     pxAddLabelSearchArgs (config, where, "-dist_group",   "warpRun.dist_group", "LIKE");
    2052 
    2053     PXOPT_LOOKUP_BOOL(all, config->args, "-all", false);
    2054 
    2055     PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
    2056     PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
    2057     PXOPT_LOOKUP_BOOL(pstamp_order, config->args, "-pstamp_order", false);
    2058 
    2059     // find all rawImfiles matching the default query
    2060     psString query = pxDataGet("warptool_listrun.sql");
    2061     if (!query) {
    2062         psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
    2063         return false;
    2064     }
    2065 
    2066     // generate where strings for arguments that require extra processing
    2067     // beyond PXOPT_COPY*
    2068     psString where2 = NULL;
    2069     if (!pxmagicAddWhere(config, &where2, "warpRun")) {
    2070         psError(psErrorCodeLast(), false, "pxMagicAddWhere failed");
    2071         return false;
    2072     }
    2073     if (!pxspaceAddWhere(config, &where2, "rawExp")) {
    2074         psError(psErrorCodeLast(), false, "pxSpaceAddWhere failed");
    2075         return false;
    2076     }
    2077 
    2078     if (psListLength(where->list)) {
    2079         psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
    2080         psStringAppend(&query, " WHERE %s", whereClause);
    2081         psFree(whereClause);
    2082     } else if (!all && !where2) {
    2083         psError(PXTOOLS_ERR_CONFIG, true, "search parameters or -all are required");
    2084         return false;
    2085     }
    2086 
    2087     if (where2) {
    2088         if (psListLength(where->list)) {
    2089             psStringAppend(&query, " %s", where2);
    2090         } else {
    2091             psStringAppend(&query, " WHERE 1 %s", where2);
    2092         }
    2093     }
    2094     psFree(where);
    2095 
    2096     if (pstamp_order) {
    2097         // put runs in order of exposure id with newest chip Runs first
    2098         // The postage stamp parser depends on this behavior
    2099         psStringAppend(&query, "\nORDER by exp_id, warp_id DESC");
    2100     }
    2101 
    2102 
    2103     // treat limit == 0 as "no limit"
    2104     if (limit) {
    2105         psString limitString = psDBGenerateLimitSQL(limit);
    2106         psStringAppend(&query, " %s", limitString);
    2107         psFree(limitString);
    2108     }
    2109 
    2110     if (!p_psDBRunQuery(config->dbh, query)) {
    2111         psError(PS_ERR_UNKNOWN, false, "database error");
    2112         psFree(query);
    2113         return false;
    2114     }
    2115     psFree(query);
    2116 
    2117     psArray *output = p_psDBFetchResult(config->dbh);
    2118     if (!output) {
    2119         psErrorCode err = psErrorCodeLast();
    2120         switch (err) {
    2121             case PS_ERR_DB_CLIENT:
    2122                 psError(PXTOOLS_ERR_SYS, false, "database error");
    2123             case PS_ERR_DB_SERVER:
    2124                 psError(PXTOOLS_ERR_PROG, false, "database error");
    2125             default:
    2126                 psError(PXTOOLS_ERR_PROG, false, "unknown error");
    2127         }
    2128 
    2129         return false;
    2130     }
    2131     if (!psArrayLength(output)) {
    2132         psTrace("warptool", PS_LOG_INFO, "no rows found");
    2133         psFree(output);
    2134         return true;
    2135     }
    2136 
    2137     if (psArrayLength(output)) {
    2138         // negative simple so the default is true
    2139         if (!ippdbPrintMetadatas(stdout, output, "warpRun", !simple)) {
    2140             psError(PS_ERR_UNKNOWN, false, "failed to print array");
    2141             psFree(output);
    2142             return false;
    2143         }
    2144     }
    2145 
    2146     psFree(output);
    2147 
    2148     return true;
    2149 }
    2150 
    2151 // a very specfic function to queue a cleaned warpSkyfile to be updated
    2152 static bool setskyfiletoupdateMode(pxConfig *config)
    2153 {
    2154     PS_ASSERT_PTR_NON_NULL(config, NULL);
    2155 
    2156     PXOPT_LOOKUP_S64(warp_id, config->args, "-warp_id", true, false);
    2157     PXOPT_LOOKUP_STR(skycell_id, config->args, "-skycell_id", false, false);
    2158     PXOPT_LOOKUP_STR(label, config->args, "-set_label", false, false);
    2159 
    2160     psString query = pxDataGet("warptool_setskyfiletoupdate.sql");
    2161     if (!query) {
    2162         psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
    2163         return false;
    2164     }
    2165 
    2166     psString setHook = psStringCopy("");
    2167     if (label) {
    2168         psStringAppend(&setHook, "\n , warpRun.label = '%s'", label);
    2169     }
    2170 
    2171     if (skycell_id) {
    2172         psStringAppend(&query, " AND (warpSkyfile.skycell_id = '%s')", skycell_id);
    2173     }
    2174 
    2175     if (!p_psDBRunQueryF(config->dbh, query, setHook, warp_id)) {
    2176         psError(PS_ERR_UNKNOWN, false, "database error");
    2177         return false;
    2178     }
    2179 
    2180     psFree(setHook);
    2181     psFree(query);
    2182 
    2183     return true;
    2184 }
     1727    psMetadata *where = psMetadataAlloc();
     1728    PXOPT_COPY_S64(config->args, where, "-warp_bg_id", "warp_bg_id", "==");
     1729
     1730    bool status = exportTables(config, outfile, warpTables, where, clean);
     1731
     1732    psFree(where);
     1733    return status;
     1734}
     1735
     1736static bool importwarpMode(pxConfig *config)
     1737{
     1738    PXOPT_LOOKUP_STR(infile, config->args, "-infile", true,  false);
     1739
     1740    return importTables(config, infile, warpTables);
     1741}
Note: See TracChangeset for help on using the changeset viewer.