4898794edd81be5285ea6e544acbedeaeb31bf78 max Tue Nov 23 08:10:57 2021 -0800 Fixing pointers to README file for license in all source code files. refs #27614 diff --git src/hg/lib/encode/encodeExp.c src/hg/lib/encode/encodeExp.c index 3eeb13a..ac97a5a 100644 --- src/hg/lib/encode/encodeExp.c +++ src/hg/lib/encode/encodeExp.c @@ -1,1144 +1,1144 @@ /* encodeExp.c was originally generated by the autoSql program, which also * generated encodeExp.h and encodeExp.sql. This module links the database and * the RAM representation of objects. */ /* Copyright (C) 2014 The Regents of the University of California - * See README in this or parent directory for licensing information. */ + * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */ #include "common.h" #include "linefile.h" #include "dystring.h" #include "jksql.h" #include "encode/encodeExp.h" // WARNING: autogen section has been manually updated to support fields that can be NULL void encodeExpStaticLoad(char **row, struct encodeExp *ret) /* Load a row from encodeExp table into ret. The contents of ret will * be replaced at the next call to this function. */ { ret->ix = sqlUnsigned(row[0]); ret->organism = row[1]; ret->lab = row[2]; ret->dataType = row[3]; ret->cellType = row[4]; ret->expVars = row[5]; ret->accession = row[6]; ret->updateTime = row[7]; } struct encodeExp *encodeExpLoadByQuery(struct sqlConnection *conn, char *query) /* Load all encodeExp from table that satisfy the query given. * Where query is of the form 'select * from example where something=something' * or 'select example.* from example, anotherTable where example.something = * anotherTable.something'. * Dispose of this with encodeExpFreeList(). */ { struct encodeExp *list = NULL, *el; struct sqlResult *sr; char **row; sr = sqlGetResult(conn, query); while ((row = sqlNextRow(sr)) != NULL) { el = encodeExpLoad(row); slAddHead(&list, el); } slReverse(&list); sqlFreeResult(&sr); return list; } // Forward declaration void encodeExpSaveToDb(struct sqlConnection *conn, struct encodeExp *el, char *tableName, int updateSize); struct encodeExp *encodeExpLoad(char **row) /* Load a encodeExp from row fetched with select * from encodeExp * from database. Dispose of this with encodeExpFree(). */ { struct encodeExp *ret; AllocVar(ret); ret->ix = sqlUnsigned(row[0]); ret->organism = cloneString(row[1]); ret->lab = cloneString(row[2]); ret->dataType = cloneString(row[3]); ret->cellType = cloneString(row[4]); ret->expVars = cloneString(row[5]); ret->accession = cloneString(row[6]); ret->updateTime = cloneString(row[7]); return ret; } struct encodeExp *encodeExpLoadAll(char *fileName) /* Load all encodeExp from a whitespace-separated file. * Dispose of this with encodeExpFreeList(). */ { struct encodeExp *list = NULL, *el; struct lineFile *lf = lineFileOpen(fileName, TRUE); char *row[8]; while (lineFileRow(lf, row)) { el = encodeExpLoad(row); slAddHead(&list, el); } lineFileClose(&lf); slReverse(&list); return list; } struct encodeExp *encodeExpLoadAllByChar(char *fileName, char chopper) /* Load all encodeExp from a chopper separated file. * Dispose of this with encodeExpFreeList(). */ { struct encodeExp *list = NULL, *el; struct lineFile *lf = lineFileOpen(fileName, TRUE); char *row[8]; while (lineFileNextCharRow(lf, chopper, row, ArraySize(row))) { el = encodeExpLoad(row); slAddHead(&list, el); } lineFileClose(&lf); slReverse(&list); return list; } struct encodeExp *encodeExpCommaIn(char **pS, struct encodeExp *ret) /* Create a encodeExp out of a comma separated string. * This will fill in ret if non-null, otherwise will * return a new encodeExp */ { char *s = *pS; if (ret == NULL) AllocVar(ret); ret->ix = sqlUnsignedComma(&s); ret->organism = sqlStringComma(&s); ret->lab = sqlStringComma(&s); ret->dataType = sqlStringComma(&s); ret->cellType = sqlStringComma(&s); ret->expVars = sqlStringComma(&s); ret->accession = sqlStringComma(&s); ret->updateTime = sqlStringComma(&s); *pS = s; return ret; } void encodeExpFree(struct encodeExp **pEl) /* Free a single dynamically allocated encodeExp such as created * with encodeExpLoad(). */ { struct encodeExp *el; if ((el = *pEl) == NULL) return; freeMem(el->organism); freeMem(el->lab); freeMem(el->dataType); freeMem(el->cellType); freeMem(el->expVars); freeMem(el->accession); freeMem(el->updateTime); freez(pEl); } void encodeExpFreeList(struct encodeExp **pList) /* Free a list of dynamically allocated encodeExp's */ { struct encodeExp *el, *next; for (el = *pList; el != NULL; el = next) { next = el->next; encodeExpFree(&el); } *pList = NULL; } void encodeExpOutput(struct encodeExp *el, FILE *f, char sep, char lastSep) /* Print out encodeExp. Separate fields with sep. Follow last field with lastSep. */ { fprintf(f, "%u", el->ix); fputc(sep,f); if (sep == ',') fputc('"',f); fprintf(f, "%s", el->organism); if (sep == ',') fputc('"',f); fputc(sep,f); if (sep == ',') fputc('"',f); fprintf(f, "%s", el->lab); if (sep == ',') fputc('"',f); fputc(sep,f); if (sep == ',') fputc('"',f); fprintf(f, "%s", el->dataType); if (sep == ',') fputc('"',f); fputc(sep,f); if (sep == ',') fputc('"',f); fprintf(f, "%s", el->cellType); if (sep == ',') fputc('"',f); fputc(sep,f); if (sep == ',') fputc('"',f); fprintf(f, "%s", el->expVars); if (sep == ',') fputc('"',f); fputc(sep,f); if (sep == ',') fputc('"',f); fprintf(f, "%s", el->accession); if (sep == ',') fputc('"',f); fputc(sep,f); if (sep == ',') fputc('"',f); fprintf(f, "%s", el->updateTime); if (sep == ',') fputc('"',f); fputc(lastSep,f); } void encodeExpJsonOutput(struct encodeExp *el, FILE *f) /* Print out encodeExp in JSON format. */ { fputc('{',f); fputc('"',f); fprintf(f,"ix"); fputc('"',f); fputc(':',f); fprintf(f, "%u", el->ix); fputc(',',f); fputc('"',f); fprintf(f,"organism"); fputc('"',f); fputc(':',f); fputc('"',f); fprintf(f, "%s", el->organism); fputc('"',f); fputc(',',f); fputc('"',f); fprintf(f,"lab"); fputc('"',f); fputc(':',f); fputc('"',f); fprintf(f, "%s", el->lab); fputc('"',f); fputc(',',f); fputc('"',f); fprintf(f,"dataType"); fputc('"',f); fputc(':',f); fputc('"',f); fprintf(f, "%s", el->dataType); fputc('"',f); fputc(',',f); fputc('"',f); fprintf(f,"cellType"); fputc('"',f); fputc(':',f); fputc('"',f); fprintf(f, "%s", el->cellType); fputc('"',f); fputc(',',f); fputc('"',f); fprintf(f,"expVars"); fputc('"',f); fputc(':',f); fputc('"',f); fprintf(f, "%s", el->expVars); fputc('"',f); fputc(',',f); fputc('"',f); fprintf(f,"accession"); fputc('"',f); fputc(':',f); fputc('"',f); fprintf(f, "%s", el->accession); fputc('"',f); fputc(',',f); fputc('"',f); fprintf(f,"updateTime"); fputc('"',f); fputc(':',f); fputc('"',f); fprintf(f, "%s", el->updateTime); fputc('"',f); fputc('}',f); } /* -------------------------------- End autoSql Generated Code -------------------------------- */ #include "hdb.h" #include "mdb.h" /* Schema in alternate format with additional properties. For each field, there is a 'get' function and an entry in the fields table. WARNING: Must parallel .sql */ /* BEGIN schema-dependent section */ void encodeExpJson(struct dyString *json, struct encodeExp *el) /* Print out encodeExp in JSON format. Manually converted from autoSql which outputs * to file pointer. */ // TODO: Extend autoSql to support in-mem version { dyStringPrintf(json, "{"); dyStringPrintf(json, "\"ix\":%u", el->ix); dyStringPrintf(json, ", "); dyStringPrintf(json, "\"organism\":\"%s\"", el->organism); dyStringPrintf(json, ", "); dyStringPrintf(json, "\"lab\":\"%s\"", el->lab); dyStringPrintf(json, ", "); dyStringPrintf(json, "\"dataType\":\"%s\"", el->dataType); dyStringPrintf(json, ", "); dyStringPrintf(json, "\"cellType\":\"%s\"", el->cellType); dyStringPrintf(json, ", "); dyStringPrintf(json, "\"expVars\":\"%s\"", el->expVars); dyStringPrintf(json, ", "); dyStringPrintf(json, "\"accession\":\"%s\"", el->accession); dyStringPrintf(json, "}"); } static char *encodeExpGetIx(struct encodeExp *exp) /* Return ix field of encodeExp */ { char buf[64]; safef(buf, sizeof(buf), "%d", exp->ix); return cloneString(buf); } static char *encodeExpGetOrganism(struct encodeExp *exp) /* Return organism field of encodeExp */ { return cloneString(exp->organism); } static char *encodeExpGetAccession(struct encodeExp *exp) /* Return accession field of encodeExp */ { return cloneString(exp->accession); } static char *encodeExpGetLab(struct encodeExp *exp) /* Return lab field of encodeExp */ { return cloneString(exp->lab); } static char *encodeExpGetDataType(struct encodeExp *exp) /* Return dataType field of encodeExp */ { return cloneString(exp->dataType); } static char *encodeExpGetCellType(struct encodeExp *exp) /* Return cellType field of encodeExp */ { return cloneString(exp->cellType); } static char *encodeExpGetExpVars(struct encodeExp *exp) /* Return expVars field of encodeExp */ { return cloneString(exp->expVars); } static char *encodeExpGetUpdateTime(struct encodeExp *exp) /* Return updateTime field of encodeExp */ { return cloneString(exp->updateTime); } typedef char * (*encodeExpGetFieldFunc)(struct encodeExp *exp); struct encodeExpField { char *name; encodeExpGetFieldFunc get; boolean required; } encodeExpField; struct encodeExpField encodeExpFields[] = { {ENCODE_EXP_FIELD_IX, &encodeExpGetIx, TRUE}, //required, set to 0 initially {ENCODE_EXP_FIELD_ORGANISM, &encodeExpGetOrganism, TRUE}, //required {ENCODE_EXP_FIELD_LAB, &encodeExpGetLab, TRUE}, //required {ENCODE_EXP_FIELD_DATA_TYPE, &encodeExpGetDataType, TRUE}, //required {ENCODE_EXP_FIELD_CELL_TYPE, &encodeExpGetCellType, TRUE}, //required {ENCODE_EXP_FIELD_FACTORS, &encodeExpGetExpVars, FALSE}, {ENCODE_EXP_FIELD_ACCESSION, &encodeExpGetAccession, FALSE}, {ENCODE_EXP_FIELD_UPDATE_TIME, &encodeExpGetUpdateTime, FALSE}, {NULL, 0, 0} }; static char *sqlCreate = "CREATE TABLE %s (\n" " ix int auto_increment, # auto-increment ID\n" " organism varchar(255) not null, # human | mouse\n" " lab varchar(255) not null, # lab name from ENCODE cv.ra\n" " dataType varchar(255) not null, # dataType from ENCODE cv.ra\n" " cellType varchar(255) not null, # cellType from ENCODE cv.ra\n" " expVars varchar(255), # var=value list of experiment-defining variables. May be NULL if none.\n" " accession varchar(255), # wgEncodeE[H|M]00000N or NULL if proposed but not yet approved\n" " updateTime timestamp default now() on update now(), # last update date-time" " #Indices\n" " PRIMARY KEY(ix)\n" ")"; /* History table approach from Peter Brawley, http://www.artfulsoftware.com */ static void encodExpAddHistoryTrigger(struct sqlConnection *conn, char *tableName, char *action) /* Create an SQL query to add a trigger to the history table for an encodeExp table */ { struct dyString *dy; char *which = NULL; if (sameString(action, "insert") || sameString(action, "update")) which = "NEW"; else if sameString(action, "delete") which = "OLD"; else errAbort("Invalid SQL trigger action: %s", action); dy = sqlDyStringCreate( "CREATE TRIGGER %s_%s AFTER %s ON %s FOR EACH ROW INSERT INTO %s%s VALUES \n" "(%s.ix, %s.organism, %s.lab, %s.dataType, %s.cellType, %s.expVars, %s.accession, NOW(), '%c', USER(), '')", tableName, action, action, tableName, tableName, ENCODE_EXP_HISTORY_TABLE_SUFFIX, which, which, which, which, which, which, which, toupper(action[0])); sqlUpdate(conn, dyStringCannibalize(&dy)); } static void encodExpDropHistoryTrigger(struct sqlConnection *conn, char *tableName, char *action) /* Drop history trigger from a table */ { struct dyString *dy; if (differentString(action, "insert") && differentString(action, "update") && differentString(action, "delete")) errAbort("Invalid SQL trigger action: %s", action); dy = sqlDyStringCreate("DROP TRIGGER IF EXISTS %s_%s", tableName, action); sqlUpdate(conn, dyStringCannibalize(&dy)); } static void encodExpAddTriggers(struct sqlConnection *conn, char *tableName) { /* Add history triggers to experiment table */ encodExpAddHistoryTrigger(conn, tableName, "insert"); encodExpAddHistoryTrigger(conn, tableName, "update"); encodExpAddHistoryTrigger(conn, tableName, "delete"); } static void encodeExpDropTriggers(struct sqlConnection *conn, char *tableName) { /* Drop history triggers from experiment table */ encodExpDropHistoryTrigger(conn, tableName, "insert"); encodExpDropHistoryTrigger(conn, tableName, "update"); encodExpDropHistoryTrigger(conn, tableName, "delete"); } void encodeExpTableRename(struct sqlConnection *conn, char *tableName, char *newTableName) /* Rename table and history table, updating triggers to match */ { char oldBuf[64]; char newBuf[64]; encodeExpDropTriggers(conn, tableName); sqlRenameTable(conn, tableName, newTableName); safef(oldBuf, sizeof oldBuf, "%s%s", tableName, ENCODE_EXP_HISTORY_TABLE_SUFFIX); safef(newBuf, sizeof newBuf, "%s%s", newTableName, ENCODE_EXP_HISTORY_TABLE_SUFFIX); sqlRenameTable(conn, oldBuf, newBuf); encodExpAddTriggers(conn, newTableName); } void encodeExpTableCopy(struct sqlConnection *conn, char *tableName, char *newTableName) /* Copy table and history table, updating triggers */ { char oldBuf[64]; char newBuf[64]; sqlCopyTable(conn, tableName, newTableName); safef(oldBuf, sizeof oldBuf, "%s%s", tableName, ENCODE_EXP_HISTORY_TABLE_SUFFIX); safef(newBuf, sizeof newBuf, "%s%s", newTableName, ENCODE_EXP_HISTORY_TABLE_SUFFIX); sqlCopyTable(conn, oldBuf, newBuf); encodExpAddTriggers(conn, newTableName); } void encodeExpTableDrop(struct sqlConnection *conn, char *tableName) { /* Drop an encodeExp table */ char buf[64]; encodeExpDropTriggers(conn, tableName); sqlDropTable(conn, tableName); safef(buf, sizeof buf, "%s%s", tableName, ENCODE_EXP_HISTORY_TABLE_SUFFIX); sqlDropTable(conn, buf); } #define ENCODE_EXP_HISTORY_FIELD_WHAT "action" #define ENCODE_EXP_HISTORY_FIELD_WHO "changedBy" #define ENCODE_EXP_HISTORY_FIELD_WHY "why" void encodeExpTableCreate(struct sqlConnection *conn, char *tableName) /* Create an encodeExp table */ { struct dyString *dy; dy = sqlDyStringCreate(sqlCreate, tableName); sqlRemakeTable(conn, tableName, dyStringCannibalize(&dy)); /* Create history table -- a clone with 3 additional columns (action, changedBy, why). * 'why' is only required for deletes * Remove auto-inc attribute on ix, and use ix and updateTime as primary key */ dy = sqlDyStringCreate("CREATE TABLE %s%s LIKE %s", tableName, ENCODE_EXP_HISTORY_TABLE_SUFFIX, tableName); sqlUpdate(conn, dyStringCannibalize(&dy)); dy = sqlDyStringCreate("ALTER TABLE %s%s ADD COLUMN %s CHAR(1) DEFAULT ''", tableName, ENCODE_EXP_HISTORY_TABLE_SUFFIX, ENCODE_EXP_HISTORY_FIELD_WHAT); sqlUpdate(conn, dyStringCannibalize(&dy)); dy = sqlDyStringCreate("ALTER TABLE %s%s ADD COLUMN %s VARCHAR(77) NOT NULL", tableName, ENCODE_EXP_HISTORY_TABLE_SUFFIX, ENCODE_EXP_HISTORY_FIELD_WHO); sqlUpdate(conn, dyStringCannibalize(&dy)); dy = sqlDyStringCreate("ALTER TABLE %s%s ADD COLUMN %s VARCHAR(255) NOT NULL", tableName, ENCODE_EXP_HISTORY_TABLE_SUFFIX, ENCODE_EXP_HISTORY_FIELD_WHY); sqlUpdate(conn, dyStringCannibalize(&dy)); dy = sqlDyStringCreate("ALTER TABLE %s%s MODIFY COLUMN %s INT DEFAULT 0", tableName, ENCODE_EXP_HISTORY_TABLE_SUFFIX, ENCODE_EXP_FIELD_IX); sqlUpdate(conn, dyStringCannibalize(&dy)); dy = sqlDyStringCreate("ALTER TABLE %s%s DROP PRIMARY KEY", tableName, ENCODE_EXP_HISTORY_TABLE_SUFFIX); sqlUpdate(conn, dyStringCannibalize(&dy)); //possible TODO: if we do need a primary key, will need to add a msec or autoinc column */ //alter table %s add idx int unsigned not null auto_increment, add primary key (idx); encodExpAddTriggers(conn, tableName); } int encodeExpIdMax(struct sqlConnection *conn) /* Return largest ix value */ { return sqlQuickNum(conn, NOSQLINJ "select max(ix) from " ENCODE_EXP_TABLE); } /* END schema-dependent section */ struct encodeExp *encodeExpLoadAllFromTable(struct sqlConnection *conn, char *tableName) /* Load all encodeExp in table */ { struct encodeExp *exps = NULL; if (!sqlTableExists(conn, tableName)) return NULL; struct dyString *dy = newDyString(0); sqlDyStringPrintf(dy, "select * from %s", tableName); exps = encodeExpLoadByQuery(conn, dyStringContents(dy)); dyStringFree(&dy); return exps; } static void encodeExpAddToLatestHistory(struct sqlConnection *conn, char *table, int id, char *field, char *value) /* Add user name to history table record */ { struct dyString *dy = sqlDyStringCreate( "select max(updateTime) from %s%s where %s='%d'", table, ENCODE_EXP_HISTORY_TABLE_SUFFIX, ENCODE_EXP_FIELD_IX, id); verbose(3, "%s\n", dy->string); char *updateTime = sqlQuickString(conn, dyStringCannibalize(&dy)); dy = sqlDyStringCreate( "update %s%s set %s='%s' where updateTime = '%s'", table, ENCODE_EXP_HISTORY_TABLE_SUFFIX, field, value, updateTime); verbose(3, "%s\n", dy->string); sqlUpdate(conn, dyStringCannibalize(&dy)); } static void encodeExpAddUserToLatestHistory(struct sqlConnection *conn, char *table, int id) /* Add user name to history table record */ { encodeExpAddToLatestHistory(conn, table, id, ENCODE_EXP_HISTORY_FIELD_WHO, getlogin()); } static void encodeExpAddWhyToLatestHistory(struct sqlConnection *conn, char *table, int id, char *why) /* Add comment to history table record */ { encodeExpAddToLatestHistory(conn, table, id, ENCODE_EXP_HISTORY_FIELD_WHY, why); } void encodeExpSaveToDb(struct sqlConnection *conn, struct encodeExp *el, char *tableName, int updateSize) /* Save encodeExp as a row to the table specified by tableName. * As blob fields may be arbitrary size updateSize specifies the approx size. * of a string that would contain the entire query. Automatically * escapes all simple strings (not arrays of string). */ { // NOTE: Manually updated to handle NULL fields, including setting NULL (for expVars and accession) struct dyString *update = newDyString(updateSize); sqlDyStringPrintf(update, "insert into %s set %s=%u, %s='%s', %s='%s', %s='%s', %s='%s'", tableName, ENCODE_EXP_FIELD_IX, el->ix, ENCODE_EXP_FIELD_ORGANISM, el->organism, ENCODE_EXP_FIELD_LAB, el->lab, ENCODE_EXP_FIELD_DATA_TYPE, el->dataType, ENCODE_EXP_FIELD_CELL_TYPE, el->cellType); // Note: The sql literal NULL is not quoted in the final sql string. sqlDyStringPrintf(update, ", %s=", ENCODE_EXP_FIELD_FACTORS); if (el->expVars == NULL) dyStringAppend(update, "NULL"); else sqlDyStringPrintf(update, "'%s'", el->expVars); sqlDyStringPrintf(update, ", %s=", ENCODE_EXP_FIELD_ACCESSION); if (el->accession == NULL) dyStringAppend(update, "NULL"); else sqlDyStringPrintf(update, "'%s'", el->accession); sqlGetLock(conn, ENCODE_EXP_TABLE_LOCK); sqlUpdate(conn, update->string); int id = sqlLastAutoId(conn); encodeExpAddUserToLatestHistory(conn, tableName, id); sqlReleaseLock(conn, ENCODE_EXP_TABLE_LOCK); freeDyString(&update); } struct encodeExp *encodeExpFromMdb(struct sqlConnection *conn, char *db, struct mdbObj *mdb) /* Create an encodeExp from an ENCODE metaDb object */ { if (!mdbObjIsEncode(mdb)) errAbort("Metadata object is not from ENCODE"); struct mdbVar *edVars = mdbObjFindEncodeEdvs(conn,mdb,FALSE); // exclude vars where val=None // To use shared metaDb: //struct mdbVar *edVars = mdbObjFindEncodeEdvPairs(conn, MDB_DEFAULT_NAME, mdb, FALSE); if (edVars == NULL) { // Not willing to make these erraborts at this time. char *composite = mdbObjFindValue(mdb,MDB_VAR_COMPOSITE); if (composite == NULL) verbose(1,"MDB object '%s' does not have a composite defined in user metaDb\n",mdb->obj); else verbose(1,"Experiment Defining Variables not defined for composite '%s' in user metaDb\n",composite); return NULL; } struct encodeExp *exp = encodeExpFromMdbVars(db, edVars); mdbVarsFree(&edVars); return exp; } struct encodeExp *encodeExpFromMdbVars(char *db, struct mdbVar *vars) // Creates and returns an encodeExp struct from mdbVars, but does not touch the table // Only Experiment Defining Variables should be in the list. { struct encodeExp *exp; AllocVar(exp); exp->ix = ENCODE_EXP_IX_UNDEFINED; // This exp is not yet defined if (db == NULL) errAbort("Missing assembly"); // FIXME: centralize treatment of organism/lower-casing exp->organism = hOrganism(db); strLower(exp->organism); struct slPair *varPairs = NULL; struct mdbVar *edv = vars; for (;edv != NULL; edv = edv->next) { if (sameWord(edv->var,MDB_VAR_LAB)) { assert(exp->lab == NULL); exp->lab = cvLabNormalize((char *)(edv->val)); } else if (sameWord(edv->var,MDB_VAR_DATATYPE)) { assert(exp->dataType == NULL); exp->dataType = cloneString((char *)(edv->val)); } else if (sameWord(edv->var,MDB_VAR_CELL)) { assert(exp->cellType == NULL); exp->cellType = cloneString((char *)(edv->val)); } else { // exclude uninformative EDV's if (differentString(MDB_VAL_ENCODE_EDV_NONE, (char *)(edv->val))) slPairAdd(&varPairs, edv->var, edv->val); // No need to clone } } // Be sure we have what we need if (exp->lab == NULL || exp->dataType == NULL) { verbose(1,"Experiment Defining Variables must contain '%s' and '%s'\n", MDB_VAR_LAB,MDB_VAR_DATATYPE); // Not willing to make this an errabort at this time. return NULL; } if (exp->cellType == NULL) // Okay if no cell exp->cellType = cloneString(ENCODE_EXP_NO_CELL); if (varPairs != NULL) { slPairSortCase(&varPairs); exp->expVars = slPairListToString(varPairs,FALSE); // don't bother adding quotes since EDVs // should not have spaces slPairFreeList(&varPairs); } return exp; } struct encodeExp *encodeExpFromRa(struct hash *ra) /* Load an encodeExp from a Ra hash. */ { char *rows[ENCODEEXP_NUM_COLS]; struct encodeExp *exp; int i; AllocVar(exp); for (i = 0; i < ENCODEEXP_NUM_COLS; i++) { struct encodeExpField *fp = &encodeExpFields[i]; assert(fp->name != NULL); char *val = hashFindVal(ra, fp->name); if (val == NULL && fp->required) errAbort("Required field \'%s\' not found in .ra:\n\n%s", fp->name, hashToRaString(ra)); rows[i] = cloneString(val); } encodeExpStaticLoad(rows, exp); return exp; } struct hash *encodeExpToRaFile(struct encodeExp *exp, FILE *f) /* Create a Ra hash from an encodeExp. Print to file if non NULL */ { struct hash *ra = hashNew(0); int i; for (i = 0; i < ENCODEEXP_NUM_COLS; i++) { struct encodeExpField *fp = &encodeExpFields[i]; assert(fp->name != NULL); char *val = fp->get(exp); if (val != NULL) { hashAdd(ra, fp->name, val); if (f != NULL) fprintf(f, "%s %s\n", fp->name, val); } } if (f != NULL) fputs("\n", f); return ra; } boolean encodeExpSame(struct encodeExp *exp, struct encodeExp *exp2) /* Return TRUE if two experiments are the same */ { int i; for (i = 0; i < ENCODEEXP_NUM_COLS; i++) { struct encodeExpField *fp = &encodeExpFields[i]; assert(fp->name != NULL); if (differentStringNullOk(fp->get(exp), fp->get(exp2))) return FALSE; } return TRUE; } struct hash *encodeExpToRa(struct encodeExp *exp) /* Create a Ra hash from an encodeExp */ { return encodeExpToRaFile(exp, NULL); } struct encodeExp *encodeExpGetByIdFromTable(struct sqlConnection *conn, char *tableName, int id) /* Return experiment specified by id from named table */ { struct dyString *query = NULL; query = sqlDyStringCreate("select * from %s where %s=\'%d\'", tableName, ENCODE_EXP_FIELD_IX, id); return encodeExpLoadByQuery(conn, dyStringCannibalize(&query)); } struct encodeExp *encodeExpGetById(struct sqlConnection *conn, int id) /* Return experiment specified by id from default table */ { return encodeExpGetByIdFromTable(conn, ENCODE_EXP_TABLE, id); } struct encodeExp *encodeExpGetByAccession(struct sqlConnection *conn, char *accession) /* Return experiment specified by accession from default table */ { if (accession == NULL || strlen(accession) <= encodeExpIdOffset()) return NULL; int id = atoi(accession + encodeExpIdOffset()); return encodeExpGetById(conn, id); } static char *encodeExpMakeAccession(struct encodeExp *exp) /* Make accession string from prefix + organism + id */ { char accession[64]; char org = '\0'; if (sameString(exp->organism, ENCODE_EXP_ORGANISM_HUMAN)) org = 'H'; else if (sameString(exp->organism, ENCODE_EXP_ORGANISM_MOUSE)) org = 'M'; else errAbort("Invalid organism %s", exp->organism); safef(accession, sizeof(accession), "%s%c%06d", ENCODE_EXP_ACC_PREFIX, org, exp->ix); return cloneString(accession); } int encodeExpIdOffset() { /* Length of prefix preceding experiment ID in the accession. Prefix is defined string + 1 for org character */ return strlen(ENCODE_EXP_ACC_PREFIX) + 1; } void encodeExpAdd(struct sqlConnection *conn, char *tableName, struct encodeExp *exp) /* Add encodeExp as a new row to the table specified by tableName. */ { encodeExpSaveToDb(conn, exp, tableName, 0); } static char *encodeExpAccession(struct sqlConnection *conn, char *tableName, int id, boolean add) /* Add or remove an accession from an experiment. This is done after the experiment definition is checked for validity. */ { struct dyString *query = NULL; char *accession = NULL; struct encodeExp *exp = NULL; char queryAcc[64]; sqlGetLock(conn, ENCODE_EXP_TABLE_LOCK); exp = encodeExpGetByIdFromTable(conn, tableName, id); if (exp == NULL) errAbort("Experiment id %d not found in table %s", id, tableName); if (add) { accession = encodeExpMakeAccession(exp); safef(queryAcc, sizeof(queryAcc), "\'%s\'", accession); } else safecpy(queryAcc, sizeof(queryAcc), "NULL"); query = sqlDyStringCreate("update %s set %s=%s where %s=%d", tableName, ENCODE_EXP_FIELD_ACCESSION, queryAcc, ENCODE_EXP_FIELD_IX, exp->ix); sqlUpdate(conn, dyStringCannibalize(&query)); encodeExpAddUserToLatestHistory(conn, tableName, id); sqlReleaseLock(conn, ENCODE_EXP_TABLE_LOCK); return accession; } char *encodeExpAddAccession(struct sqlConnection *conn, char *tableName, int id) /* Add accession field to an existing "temp" experiment. This is done * after experiment is determined to be valid. * Return the accession. */ { return encodeExpAccession(conn, tableName, id, TRUE); } void encodeExpSetAccession(struct encodeExp *exp, char *tableName) /* Adds accession field to an existing experiment, updating the table. */ { struct sqlConnection *conn = sqlConnect(ENCODE_EXP_DATABASE); exp->accession = encodeExpAccession(conn, tableName, exp->ix, TRUE); sqlDisconnect(&conn); } void encodeExpRemoveAccession(struct sqlConnection *conn, char *tableName, int id) /* Revoke an experiment by removing the accession. */ { encodeExpAccession(conn, tableName, id, FALSE); } boolean encodeExpIsAccessioned(struct encodeExp *exp) /* Determine if experiment has an accession (not unaccessioned or deaccessioned) */ { return encodeExpGetAccession(exp) != NULL; } void encodeExpRemove(struct sqlConnection *conn, char *tableName, struct encodeExp *exp, char *why) /* Delete row containing experiment from encodeExp. * WARNING: This is a management function, not for regular use. Accession must * not be present. In general, experiments should be reviewed before adding to table * rather than added and removed if problematic. */ { char query[256]; /* must match entry in table in all ways */ struct encodeExp *exp2 = encodeExpGetByIdFromTable(conn, tableName, exp->ix); if (encodeExpSame(exp, exp2)) { sqlSafef(query, sizeof(query), "delete from %s where %s=%d", tableName, ENCODE_EXP_FIELD_IX, exp->ix); sqlGetLock(conn, ENCODE_EXP_TABLE_LOCK); sqlUpdate(conn, query); encodeExpAddUserToLatestHistory(conn, tableName, exp->ix); encodeExpAddWhyToLatestHistory(conn, tableName, exp->ix, why); sqlReleaseLock(conn, ENCODE_EXP_TABLE_LOCK); } } boolean encodeExpIsFieldVar(char *var) /* Return true if var is a field in schema -- one of standard set (not an expVar) */ { if (var == NULL) return FALSE; return (sameString(var, ENCODE_EXP_FIELD_LAB) || sameString(var, ENCODE_EXP_FIELD_DATA_TYPE) || sameString(var, ENCODE_EXP_FIELD_CELL_TYPE)); } char *encodeExpGetVar(struct encodeExp *exp, char *var) /* Return value of an expVar, or NULL if not found */ { struct slPair *vars = slPairListFromString(exp->expVars, FALSE); return slPairFindVal(vars, var); } char *encodeExpGetField(struct encodeExp *exp, char *var) /* Return value of a field, whether part of schema or an expVar */ { if (var == NULL) return FALSE; int i; for (i = 0; i < ENCODEEXP_NUM_COLS; i++) { struct encodeExpField *fp = &encodeExpFields[i]; assert(fp->name != NULL); if (sameString(fp->name, var)) return fp->get(exp); } // not a schema field, it may be an expVar return encodeExpGetVar(exp, var); } static boolean cvTermIsValid(char *type, char *val) /* Determine if term is valid for CV type of term * TODO: This really belongs in cv.ra, but this limited version used just by encodeExp * For now, addng special cases as needed -- e.g. allow control term for antibody type */ { if (cvOneTermHash(type, val)) return TRUE; if (sameString(type, CV_TERM_ANTIBODY)) { if (cvOneTermHash(CV_TERM_CONTROL, val)) return TRUE; } return FALSE; } void encodeExpUpdate(struct sqlConnection *conn, char *tableName, int id, char *var, char *newVal, char *oldVal) /* Update field in encodeExp or var in expVars, identified by id with value. * If oldVal is non-NULL, verify it matches experiment, as a safety check. * OldVal of ENCODE_EXP_NO_VAR allows adding expVar. * TODO: Setting newVal to ENCODE_EXP_NO_VAR will remove expVar. * Abort if experiment is accessioned (must deaccession first) */ { char *val = NULL; struct dyString *dy = NULL; char *type = (char *)cvTermNormalized(var); if (type == NULL) errAbort("Attempt to update encodeExp experiment with unknown CV type %s", var); if (cvTermIsCvDefined(type)) { verbose(1, " var %s is cv defined\n", type); /* verify new value is valid term in CV */ if (!cvTermIsValid(type, newVal)) errAbort("Attempt to update encodeExp experiment with unknown CV term %s of type %s", newVal, var); } struct encodeExp *exp = encodeExpGetByIdFromTable(conn, tableName, id); if (exp == NULL) errAbort("Id %d not found in experiment table %s", id, tableName); if (exp->accession) errAbort("Id %d in table %s has accession", id, tableName); if (encodeExpIsFieldVar(var)) { /* check if old value matches */ if (oldVal) { struct hash *expRa = encodeExpToRa(exp); val = hashFindVal(expRa, var); if (val == NULL) errAbort("Field %s not found in id %d from table %s", var, id, tableName); if (differentString(val, oldVal)) errAbort("Mismatch: id %d has %s=%s, not %s in table %s", id, var, val, oldVal, tableName); } dy = sqlDyStringCreate("update %s set %s=\'%s\' ", tableName, var, newVal); } else { /* must be an expVar -- extract all expVars for this experiment */ struct slPair *varPairs = slPairListFromString(exp->expVars,FALSE); struct slPair *pair = slPairFind(varPairs, var); if (pair != NULL) { /* change the designated var */ if (oldVal) { // TODO: remove expVar if newVal == None val = (char *)pair->val; if (differentString(val, oldVal)) errAbort("Mismatch: id %d has %s=%s, not %s in table %s", id, var, val, oldVal, tableName); } pair->val = newVal; } else { // this var not found in this experiment - add new var if (oldVal && differentString(oldVal, ENCODE_EXP_NO_VAR)) { errAbort("Attempt to change expVar %s from value %s not found in experiment %d", var, oldVal, id); } verbose(3, "Adding %s=%s to experiment %d\n", var, newVal, id); slPairAdd(&varPairs, var, newVal); slPairSortCase(&varPairs); verbose(1, "WARNING: not verifying %s is valid expVar for this experiment\n", var); } char *expVars = slPairListToString(varPairs, FALSE); dy = sqlDyStringCreate("update %s set %s=\'%s\' ", tableName, ENCODE_EXP_FIELD_FACTORS, expVars); } dyStringPrintf(dy, " where ix=%d", id); sqlGetLock(conn, ENCODE_EXP_TABLE_LOCK); sqlUpdate(conn, dyStringCannibalize(&dy)); encodeExpAddUserToLatestHistory(conn, tableName, id); sqlReleaseLock(conn, ENCODE_EXP_TABLE_LOCK); } char *encodeExpKey(struct encodeExp *exp) /* Create a hash key from an encodeExp */ { struct dyString *dy = newDyString(0); dyStringPrintf(dy, "lab:%s dataType:%s cellType:%s", exp->lab, exp->dataType, exp->cellType); if (exp->expVars != NULL) dyStringPrintf(dy, " expVars:%s", exp->expVars); return dyStringCannibalize(&dy); } char *encodeExpVars(struct encodeExp *exp) // Create a string of all experiment defining vars and vals as "lab=UW dataType=ChipSeq ..." // WARNING: May be missing var=None if the var was added after composite had defined exps. { struct dyString *dy = newDyString(0); dyStringPrintf(dy, "%s=%s %s=%s", MDB_VAR_LAB, exp->lab, MDB_VAR_DATATYPE, exp->dataType ); if (exp->cellType != NULL) dyStringPrintf(dy, " %s=%s", MDB_VAR_CELL, exp->cellType); if (exp->expVars != NULL) dyStringPrintf(dy, " %s", exp->expVars); return dyStringCannibalize(&dy); } struct encodeExp *encodeExpGetFromTable(char *organism, char *lab, char *dataType, char *cell, struct slPair *varPairs, char *table) /* Return experiments matching args in named experiment table. * Organism, Lab and DataType must be non-null */ { struct encodeExp *exps = NULL; if (organism == NULL || lab == NULL || dataType == NULL) errAbort("Need organism, lab, and dataType to query experiment table"); if (cell == NULL) cell = ENCODE_EXP_NO_CELL; struct sqlConnection *conn = sqlConnect(ENCODE_EXP_DATABASE); struct dyString *dy = sqlDyStringCreate( "select * from %s where %s=\'%s\' and %s=\'%s\' and %s=\'%s\' and %s=\'%s\' and %s", table, ENCODE_EXP_FIELD_ORGANISM, organism, ENCODE_EXP_FIELD_LAB, lab, ENCODE_EXP_FIELD_DATA_TYPE, dataType, ENCODE_EXP_FIELD_CELL_TYPE, cell, ENCODE_EXP_FIELD_FACTORS); /* construct expVars string var=val from pairs */ if (varPairs == NULL) dyStringAppend(dy, " is NULL"); else { dyStringAppend(dy, "="); dyStringQuoteString(dy, '\'', slPairListToString(varPairs, FALSE)); } verbose(4, "query: %s\n", dy->string); exps = encodeExpLoadByQuery(conn, dyStringCannibalize(&dy)); sqlDisconnect(&conn); return exps; } struct encodeExp *encodeExpGet(char *organism, char *lab, char *dataType, char *cell, struct slPair *varPairs) /* Return experiments matching args in default experiment table. * Organism, Lab and DataType must be non-null */ { return encodeExpGetFromTable(organism, lab, dataType, cell, varPairs, ENCODE_EXP_TABLE); } struct encodeExp *encodeExpGetByMdbVarsFromTable(char *db, struct mdbVar *vars, char *table) /* Return experiments by looking up mdb var list from the named experiment table */ { struct encodeExp *exp = encodeExpFromMdbVars(db,vars); // don't expect quoted EDVs which should always be simple tokens. struct slPair *edvVars = slPairListFromString(exp->expVars,FALSE); struct encodeExp *expFound = encodeExpGetFromTable(exp->organism,exp->lab,exp->dataType,exp->cellType,edvVars,table); // No longer needed encodeExpFree(&exp); if (edvVars != NULL) slPairFreeValsAndList(&edvVars); return expFound; } struct encodeExp *encodeExpGetByMdbVars(char *db, struct mdbVar *vars) /* Return experiments by looking up mdb var list from the default experiment table */ { return encodeExpGetByMdbVarsFromTable(db, vars, ENCODE_EXP_TABLE); } struct encodeExp *encodeExpGetOrCreateByMdbVarsFromTable(char *db, struct mdbVar *vars, char *table) // Return experiment looked up or created from the mdb var list from the named experiment table. { struct encodeExp *exp = encodeExpFromMdbVars(db,vars); // don't expect quoted EDVs which should always be simple tokens. struct slPair *edvVars = slPairListFromString(exp->expVars,FALSE); struct encodeExp *expFound = encodeExpGetFromTable(exp->organism,exp->lab,exp->dataType,exp->cellType,edvVars,table); if (expFound == NULL) { struct sqlConnection *conn = sqlConnect(ENCODE_EXP_DATABASE); encodeExpAdd(conn, table, exp); sqlDisconnect(&conn); expFound = encodeExpGetFromTable(exp->organism,exp->lab,exp->dataType,exp->cellType, edvVars,table); } encodeExpFree(&exp); slPairFreeValsAndList(&edvVars); return expFound; } int encodeExpExists(char *db, struct mdbVar *vars) /* Return TRUE if at least one experiment exists for these vars */ { struct encodeExp *exp = encodeExpGetByMdbVars(db, vars); int found = (exp != NULL); freez(&exp); return found; } char *encodeExpGetAccessionByMdbVars(char *db, struct mdbVar *vars) /* Return accession of (first) experiment matching vars, or NULL if not found */ { struct encodeExp *exp = encodeExpGetByMdbVars(db, vars); char *acc = encodeExpGetAccession(exp); freez(&exp); return acc; }