src/hg/instinct/bioInt2/bioIntDb.c 1.2

1.2 2009/03/21 19:54:10 jsanborn
added routine to set cohorts
Index: src/hg/instinct/bioInt2/bioIntDb.c
===================================================================
RCS file: /projects/compbio/cvsroot/kent/src/hg/instinct/bioInt2/bioIntDb.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -b -B -U 4 -r1.1 -r1.2
--- src/hg/instinct/bioInt2/bioIntDb.c	20 Mar 2009 06:06:31 -0000	1.1
+++ src/hg/instinct/bioInt2/bioIntDb.c	21 Mar 2009 19:54:10 -0000	1.2
@@ -1080,8 +1080,331 @@
 if (sep == ',') fputc('"',f);
 fputc(lastSep,f);
 }
 
+void cohortsStaticLoad(char **row, struct cohorts *ret)
+/* Load a row from cohorts table into ret.  The contents of ret will
+ * be replaced at the next call to this function. */
+{
+
+ret->id = sqlUnsigned(row[0]);
+ret->name = row[1];
+}
+
+struct cohorts *cohortsLoad(char **row)
+/* Load a cohorts from row fetched with select * from cohorts
+ * from database.  Dispose of this with cohortsFree(). */
+{
+struct cohorts *ret;
+
+AllocVar(ret);
+ret->id = sqlUnsigned(row[0]);
+ret->name = cloneString(row[1]);
+return ret;
+}
+
+struct cohorts *cohortsLoadAll(char *fileName) 
+/* Load all cohorts from a whitespace-separated file.
+ * Dispose of this with cohortsFreeList(). */
+{
+struct cohorts *list = NULL, *el;
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+char *row[2];
+
+while (lineFileRow(lf, row))
+    {
+    el = cohortsLoad(row);
+    slAddHead(&list, el);
+    }
+lineFileClose(&lf);
+slReverse(&list);
+return list;
+}
+
+struct cohorts *cohortsLoadAllByChar(char *fileName, char chopper) 
+/* Load all cohorts from a chopper separated file.
+ * Dispose of this with cohortsFreeList(). */
+{
+struct cohorts *list = NULL, *el;
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+char *row[2];
+
+while (lineFileNextCharRow(lf, chopper, row, ArraySize(row)))
+    {
+    el = cohortsLoad(row);
+    slAddHead(&list, el);
+    }
+lineFileClose(&lf);
+slReverse(&list);
+return list;
+}
+
+struct cohorts *cohortsLoadByQuery(struct sqlConnection *conn, char *query)
+/* Load all cohorts 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 cohortsFreeList(). */
+{
+struct cohorts *list = NULL, *el;
+struct sqlResult *sr;
+char **row;
+
+sr = sqlGetResult(conn, query);
+while ((row = sqlNextRow(sr)) != NULL)
+    {
+    el = cohortsLoad(row);
+    slAddHead(&list, el);
+    }
+slReverse(&list);
+sqlFreeResult(&sr);
+return list;
+}
+
+void cohortsSaveToDb(struct sqlConnection *conn, struct cohorts *el, char *tableName, int updateSize)
+/* Save cohorts 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. Arrays of native types are
+ * converted to comma separated strings and loaded as such, User defined types are
+ * inserted as NULL. Note that strings must be escaped to allow insertion into the database.
+ * For example "autosql's features include" --> "autosql\'s features include" 
+ * If worried about this use cohortsSaveToDbEscaped() */
+{
+struct dyString *update = newDyString(updateSize);
+dyStringPrintf(update, "insert into %s values ( %u,'%s')", 
+	tableName,  el->id,  el->name);
+sqlUpdate(conn, update->string);
+freeDyString(&update);
+}
+
+void cohortsSaveToDbEscaped(struct sqlConnection *conn, struct cohorts *el, char *tableName, int updateSize)
+/* Save cohorts 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) but may be slower than cohortsSaveToDb().
+ * For example automatically copies and converts: 
+ * "autosql's features include" --> "autosql\'s features include" 
+ * before inserting into database. */ 
+{
+struct dyString *update = newDyString(updateSize);
+char  *name;
+name = sqlEscapeString(el->name);
+
+dyStringPrintf(update, "insert into %s values ( %u,'%s')", 
+	tableName,  el->id,  name);
+sqlUpdate(conn, update->string);
+freeDyString(&update);
+freez(&name);
+}
+
+struct cohorts *cohortsCommaIn(char **pS, struct cohorts *ret)
+/* Create a cohorts out of a comma separated string. 
+ * This will fill in ret if non-null, otherwise will
+ * return a new cohorts */
+{
+char *s = *pS;
+
+if (ret == NULL)
+    AllocVar(ret);
+ret->id = sqlUnsignedComma(&s);
+ret->name = sqlStringComma(&s);
+*pS = s;
+return ret;
+}
+
+void cohortsFree(struct cohorts **pEl)
+/* Free a single dynamically allocated cohorts such as created
+ * with cohortsLoad(). */
+{
+struct cohorts *el;
+
+if ((el = *pEl) == NULL) return;
+freeMem(el->name);
+freez(pEl);
+}
+
+void cohortsFreeList(struct cohorts **pList)
+/* Free a list of dynamically allocated cohorts's */
+{
+struct cohorts *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    cohortsFree(&el);
+    }
+*pList = NULL;
+}
+
+void cohortsOutput(struct cohorts *el, FILE *f, char sep, char lastSep) 
+/* Print out cohorts.  Separate fields with sep. Follow last field with lastSep. */
+{
+fprintf(f, "%u", el->id);
+fputc(sep,f);
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->name);
+if (sep == ',') fputc('"',f);
+fputc(lastSep,f);
+}
+
+void datasetCohortStaticLoad(char **row, struct datasetCohort *ret)
+/* Load a row from datasetCohort table into ret.  The contents of ret will
+ * be replaced at the next call to this function. */
+{
+
+ret->dataset_id = sqlUnsigned(row[0]);
+ret->cohort_id = sqlUnsigned(row[1]);
+}
+
+struct datasetCohort *datasetCohortLoad(char **row)
+/* Load a datasetCohort from row fetched with select * from datasetCohort
+ * from database.  Dispose of this with datasetCohortFree(). */
+{
+struct datasetCohort *ret;
+
+AllocVar(ret);
+ret->dataset_id = sqlUnsigned(row[0]);
+ret->cohort_id = sqlUnsigned(row[1]);
+return ret;
+}
+
+struct datasetCohort *datasetCohortLoadAll(char *fileName) 
+/* Load all datasetCohort from a whitespace-separated file.
+ * Dispose of this with datasetCohortFreeList(). */
+{
+struct datasetCohort *list = NULL, *el;
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+char *row[2];
+
+while (lineFileRow(lf, row))
+    {
+    el = datasetCohortLoad(row);
+    slAddHead(&list, el);
+    }
+lineFileClose(&lf);
+slReverse(&list);
+return list;
+}
+
+struct datasetCohort *datasetCohortLoadAllByChar(char *fileName, char chopper) 
+/* Load all datasetCohort from a chopper separated file.
+ * Dispose of this with datasetCohortFreeList(). */
+{
+struct datasetCohort *list = NULL, *el;
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+char *row[2];
+
+while (lineFileNextCharRow(lf, chopper, row, ArraySize(row)))
+    {
+    el = datasetCohortLoad(row);
+    slAddHead(&list, el);
+    }
+lineFileClose(&lf);
+slReverse(&list);
+return list;
+}
+
+struct datasetCohort *datasetCohortLoadByQuery(struct sqlConnection *conn, char *query)
+/* Load all datasetCohort 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 datasetCohortFreeList(). */
+{
+struct datasetCohort *list = NULL, *el;
+struct sqlResult *sr;
+char **row;
+
+sr = sqlGetResult(conn, query);
+while ((row = sqlNextRow(sr)) != NULL)
+    {
+    el = datasetCohortLoad(row);
+    slAddHead(&list, el);
+    }
+slReverse(&list);
+sqlFreeResult(&sr);
+return list;
+}
+
+void datasetCohortSaveToDb(struct sqlConnection *conn, struct datasetCohort *el, char *tableName, int updateSize)
+/* Save datasetCohort 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. Arrays of native types are
+ * converted to comma separated strings and loaded as such, User defined types are
+ * inserted as NULL. Note that strings must be escaped to allow insertion into the database.
+ * For example "autosql's features include" --> "autosql\'s features include" 
+ * If worried about this use datasetCohortSaveToDbEscaped() */
+{
+struct dyString *update = newDyString(updateSize);
+dyStringPrintf(update, "insert into %s values ( %u,%u)", 
+	tableName,  el->dataset_id,  el->cohort_id);
+sqlUpdate(conn, update->string);
+freeDyString(&update);
+}
+
+void datasetCohortSaveToDbEscaped(struct sqlConnection *conn, struct datasetCohort *el, char *tableName, int updateSize)
+/* Save datasetCohort 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) but may be slower than datasetCohortSaveToDb().
+ * For example automatically copies and converts: 
+ * "autosql's features include" --> "autosql\'s features include" 
+ * before inserting into database. */ 
+{
+struct dyString *update = newDyString(updateSize);
+dyStringPrintf(update, "insert into %s values ( %u,%u)", 
+	tableName,  el->dataset_id,  el->cohort_id);
+sqlUpdate(conn, update->string);
+freeDyString(&update);
+}
+
+struct datasetCohort *datasetCohortCommaIn(char **pS, struct datasetCohort *ret)
+/* Create a datasetCohort out of a comma separated string. 
+ * This will fill in ret if non-null, otherwise will
+ * return a new datasetCohort */
+{
+char *s = *pS;
+
+if (ret == NULL)
+    AllocVar(ret);
+ret->dataset_id = sqlUnsignedComma(&s);
+ret->cohort_id = sqlUnsignedComma(&s);
+*pS = s;
+return ret;
+}
+
+void datasetCohortFree(struct datasetCohort **pEl)
+/* Free a single dynamically allocated datasetCohort such as created
+ * with datasetCohortLoad(). */
+{
+struct datasetCohort *el;
+
+if ((el = *pEl) == NULL) return;
+freez(pEl);
+}
+
+void datasetCohortFreeList(struct datasetCohort **pList)
+/* Free a list of dynamically allocated datasetCohort's */
+{
+struct datasetCohort *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    datasetCohortFree(&el);
+    }
+*pList = NULL;
+}
+
+void datasetCohortOutput(struct datasetCohort *el, FILE *f, char sep, char lastSep) 
+/* Print out datasetCohort.  Separate fields with sep. Follow last field with lastSep. */
+{
+fprintf(f, "%u", el->dataset_id);
+fputc(sep,f);
+fprintf(f, "%u", el->cohort_id);
+fputc(lastSep,f);
+}
+
 void geneLookupStaticLoad(char **row, struct geneLookup *ret)
 /* Load a row from geneLookup table into ret.  The contents of ret will
  * be replaced at the next call to this function. */
 {
@@ -2490,14 +2813,369 @@
 if (sep == ',') fputc('"',f);
 fputc(lastSep,f);
 }
 
+void analysesStaticLoad(char **row, struct analyses *ret)
+/* Load a row from analyses table into ret.  The contents of ret will
+ * be replaced at the next call to this function. */
+{
+
+ret->id = sqlUnsigned(row[0]);
+ret->cohort_id = sqlUnsigned(row[1]);
+ret->module = row[2];
+ret->result_table = row[3];
+}
+
+struct analyses *analysesLoad(char **row)
+/* Load a analyses from row fetched with select * from analyses
+ * from database.  Dispose of this with analysesFree(). */
+{
+struct analyses *ret;
+
+AllocVar(ret);
+ret->id = sqlUnsigned(row[0]);
+ret->cohort_id = sqlUnsigned(row[1]);
+ret->module = cloneString(row[2]);
+ret->result_table = cloneString(row[3]);
+return ret;
+}
+
+struct analyses *analysesLoadAll(char *fileName) 
+/* Load all analyses from a whitespace-separated file.
+ * Dispose of this with analysesFreeList(). */
+{
+struct analyses *list = NULL, *el;
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+char *row[4];
+
+while (lineFileRow(lf, row))
+    {
+    el = analysesLoad(row);
+    slAddHead(&list, el);
+    }
+lineFileClose(&lf);
+slReverse(&list);
+return list;
+}
+
+struct analyses *analysesLoadAllByChar(char *fileName, char chopper) 
+/* Load all analyses from a chopper separated file.
+ * Dispose of this with analysesFreeList(). */
+{
+struct analyses *list = NULL, *el;
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+char *row[4];
+
+while (lineFileNextCharRow(lf, chopper, row, ArraySize(row)))
+    {
+    el = analysesLoad(row);
+    slAddHead(&list, el);
+    }
+lineFileClose(&lf);
+slReverse(&list);
+return list;
+}
+
+struct analyses *analysesLoadByQuery(struct sqlConnection *conn, char *query)
+/* Load all analyses 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 analysesFreeList(). */
+{
+struct analyses *list = NULL, *el;
+struct sqlResult *sr;
+char **row;
+
+sr = sqlGetResult(conn, query);
+while ((row = sqlNextRow(sr)) != NULL)
+    {
+    el = analysesLoad(row);
+    slAddHead(&list, el);
+    }
+slReverse(&list);
+sqlFreeResult(&sr);
+return list;
+}
+
+void analysesSaveToDb(struct sqlConnection *conn, struct analyses *el, char *tableName, int updateSize)
+/* Save analyses 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. Arrays of native types are
+ * converted to comma separated strings and loaded as such, User defined types are
+ * inserted as NULL. Note that strings must be escaped to allow insertion into the database.
+ * For example "autosql's features include" --> "autosql\'s features include" 
+ * If worried about this use analysesSaveToDbEscaped() */
+{
+struct dyString *update = newDyString(updateSize);
+dyStringPrintf(update, "insert into %s values ( %u,%u,'%s','%s')", 
+	tableName,  el->id,  el->cohort_id,  el->module,  el->result_table);
+sqlUpdate(conn, update->string);
+freeDyString(&update);
+}
+
+void analysesSaveToDbEscaped(struct sqlConnection *conn, struct analyses *el, char *tableName, int updateSize)
+/* Save analyses 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) but may be slower than analysesSaveToDb().
+ * For example automatically copies and converts: 
+ * "autosql's features include" --> "autosql\'s features include" 
+ * before inserting into database. */ 
+{
+struct dyString *update = newDyString(updateSize);
+char  *module, *result_table;
+module = sqlEscapeString(el->module);
+result_table = sqlEscapeString(el->result_table);
+
+dyStringPrintf(update, "insert into %s values ( %u,%u,'%s','%s')", 
+	tableName,  el->id,  el->cohort_id,  module,  result_table);
+sqlUpdate(conn, update->string);
+freeDyString(&update);
+freez(&module);
+freez(&result_table);
+}
+
+struct analyses *analysesCommaIn(char **pS, struct analyses *ret)
+/* Create a analyses out of a comma separated string. 
+ * This will fill in ret if non-null, otherwise will
+ * return a new analyses */
+{
+char *s = *pS;
+
+if (ret == NULL)
+    AllocVar(ret);
+ret->id = sqlUnsignedComma(&s);
+ret->cohort_id = sqlUnsignedComma(&s);
+ret->module = sqlStringComma(&s);
+ret->result_table = sqlStringComma(&s);
+*pS = s;
+return ret;
+}
+
+void analysesFree(struct analyses **pEl)
+/* Free a single dynamically allocated analyses such as created
+ * with analysesLoad(). */
+{
+struct analyses *el;
+
+if ((el = *pEl) == NULL) return;
+freeMem(el->module);
+freeMem(el->result_table);
+freez(pEl);
+}
+
+void analysesFreeList(struct analyses **pList)
+/* Free a list of dynamically allocated analyses's */
+{
+struct analyses *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    analysesFree(&el);
+    }
+*pList = NULL;
+}
+
+void analysesOutput(struct analyses *el, FILE *f, char sep, char lastSep) 
+/* Print out analyses.  Separate fields with sep. Follow last field with lastSep. */
+{
+fprintf(f, "%u", el->id);
+fputc(sep,f);
+fprintf(f, "%u", el->cohort_id);
+fputc(sep,f);
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->module);
+if (sep == ',') fputc('"',f);
+fputc(sep,f);
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->result_table);
+if (sep == ',') fputc('"',f);
+fputc(lastSep,f);
+}
+
+void analysisParamsStaticLoad(char **row, struct analysisParams *ret)
+/* Load a row from analysisParams table into ret.  The contents of ret will
+ * be replaced at the next call to this function. */
+{
+
+ret->analysis_id = sqlUnsigned(row[0]);
+ret->key = row[1];
+ret->val = row[2];
+}
+
+struct analysisParams *analysisParamsLoad(char **row)
+/* Load a analysisParams from row fetched with select * from analysisParams
+ * from database.  Dispose of this with analysisParamsFree(). */
+{
+struct analysisParams *ret;
+
+AllocVar(ret);
+ret->analysis_id = sqlUnsigned(row[0]);
+ret->key = cloneString(row[1]);
+ret->val = cloneString(row[2]);
+return ret;
+}
+
+struct analysisParams *analysisParamsLoadAll(char *fileName) 
+/* Load all analysisParams from a whitespace-separated file.
+ * Dispose of this with analysisParamsFreeList(). */
+{
+struct analysisParams *list = NULL, *el;
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+char *row[3];
+
+while (lineFileRow(lf, row))
+    {
+    el = analysisParamsLoad(row);
+    slAddHead(&list, el);
+    }
+lineFileClose(&lf);
+slReverse(&list);
+return list;
+}
+
+struct analysisParams *analysisParamsLoadAllByChar(char *fileName, char chopper) 
+/* Load all analysisParams from a chopper separated file.
+ * Dispose of this with analysisParamsFreeList(). */
+{
+struct analysisParams *list = NULL, *el;
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+char *row[3];
+
+while (lineFileNextCharRow(lf, chopper, row, ArraySize(row)))
+    {
+    el = analysisParamsLoad(row);
+    slAddHead(&list, el);
+    }
+lineFileClose(&lf);
+slReverse(&list);
+return list;
+}
+
+struct analysisParams *analysisParamsLoadByQuery(struct sqlConnection *conn, char *query)
+/* Load all analysisParams 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 analysisParamsFreeList(). */
+{
+struct analysisParams *list = NULL, *el;
+struct sqlResult *sr;
+char **row;
+
+sr = sqlGetResult(conn, query);
+while ((row = sqlNextRow(sr)) != NULL)
+    {
+    el = analysisParamsLoad(row);
+    slAddHead(&list, el);
+    }
+slReverse(&list);
+sqlFreeResult(&sr);
+return list;
+}
+
+void analysisParamsSaveToDb(struct sqlConnection *conn, struct analysisParams *el, char *tableName, int updateSize)
+/* Save analysisParams 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. Arrays of native types are
+ * converted to comma separated strings and loaded as such, User defined types are
+ * inserted as NULL. Note that strings must be escaped to allow insertion into the database.
+ * For example "autosql's features include" --> "autosql\'s features include" 
+ * If worried about this use analysisParamsSaveToDbEscaped() */
+{
+struct dyString *update = newDyString(updateSize);
+dyStringPrintf(update, "insert into %s values ( %u,'%s','%s')", 
+	tableName,  el->analysis_id,  el->key,  el->val);
+sqlUpdate(conn, update->string);
+freeDyString(&update);
+}
+
+void analysisParamsSaveToDbEscaped(struct sqlConnection *conn, struct analysisParams *el, char *tableName, int updateSize)
+/* Save analysisParams 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) but may be slower than analysisParamsSaveToDb().
+ * For example automatically copies and converts: 
+ * "autosql's features include" --> "autosql\'s features include" 
+ * before inserting into database. */ 
+{
+struct dyString *update = newDyString(updateSize);
+char  *key, *val;
+key = sqlEscapeString(el->key);
+val = sqlEscapeString(el->val);
+
+dyStringPrintf(update, "insert into %s values ( %u,'%s','%s')", 
+	tableName,  el->analysis_id,  key,  val);
+sqlUpdate(conn, update->string);
+freeDyString(&update);
+freez(&key);
+freez(&val);
+}
+
+struct analysisParams *analysisParamsCommaIn(char **pS, struct analysisParams *ret)
+/* Create a analysisParams out of a comma separated string. 
+ * This will fill in ret if non-null, otherwise will
+ * return a new analysisParams */
+{
+char *s = *pS;
+
+if (ret == NULL)
+    AllocVar(ret);
+ret->analysis_id = sqlUnsignedComma(&s);
+ret->key = sqlStringComma(&s);
+ret->val = sqlStringComma(&s);
+*pS = s;
+return ret;
+}
+
+void analysisParamsFree(struct analysisParams **pEl)
+/* Free a single dynamically allocated analysisParams such as created
+ * with analysisParamsLoad(). */
+{
+struct analysisParams *el;
+
+if ((el = *pEl) == NULL) return;
+freeMem(el->key);
+freeMem(el->val);
+freez(pEl);
+}
+
+void analysisParamsFreeList(struct analysisParams **pList)
+/* Free a list of dynamically allocated analysisParams's */
+{
+struct analysisParams *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    analysisParamsFree(&el);
+    }
+*pList = NULL;
+}
+
+void analysisParamsOutput(struct analysisParams *el, FILE *f, char sep, char lastSep) 
+/* Print out analysisParams.  Separate fields with sep. Follow last field with lastSep. */
+{
+fprintf(f, "%u", el->analysis_id);
+fputc(sep,f);
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->key);
+if (sep == ',') fputc('"',f);
+fputc(sep,f);
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->val);
+if (sep == ',') fputc('"',f);
+fputc(lastSep,f);
+}
+
 void analysisFeaturesStaticLoad(char **row, struct analysisFeatures *ret)
 /* Load a row from analysisFeatures table into ret.  The contents of ret will
  * be replaced at the next call to this function. */
 {
 
-ret->feature_id = sqlUnsigned(row[0]);
+ret->id = sqlUnsigned(row[0]);
 ret->feature_name = row[1];
 }
 
 struct analysisFeatures *analysisFeaturesLoad(char **row)
@@ -2506,9 +3184,9 @@
 {
 struct analysisFeatures *ret;
 
 AllocVar(ret);
-ret->feature_id = sqlUnsigned(row[0]);
+ret->id = sqlUnsigned(row[0]);
 ret->feature_name = cloneString(row[1]);
 return ret;
 }
 
@@ -2580,9 +3258,9 @@
  * If worried about this use analysisFeaturesSaveToDbEscaped() */
 {
 struct dyString *update = newDyString(updateSize);
 dyStringPrintf(update, "insert into %s values ( %u,'%s')", 
-	tableName,  el->feature_id,  el->feature_name);
+	tableName,  el->id,  el->feature_name);
 sqlUpdate(conn, update->string);
 freeDyString(&update);
 }
 
@@ -2599,9 +3277,9 @@
 char  *feature_name;
 feature_name = sqlEscapeString(el->feature_name);
 
 dyStringPrintf(update, "insert into %s values ( %u,'%s')", 
-	tableName,  el->feature_id,  feature_name);
+	tableName,  el->id,  feature_name);
 sqlUpdate(conn, update->string);
 freeDyString(&update);
 freez(&feature_name);
 }
@@ -2614,9 +3292,9 @@
 char *s = *pS;
 
 if (ret == NULL)
     AllocVar(ret);
-ret->feature_id = sqlUnsignedComma(&s);
+ret->id = sqlUnsignedComma(&s);
 ret->feature_name = sqlStringComma(&s);
 *pS = s;
 return ret;
 }
@@ -2647,9 +3325,9 @@
 
 void analysisFeaturesOutput(struct analysisFeatures *el, FILE *f, char sep, char lastSep) 
 /* Print out analysisFeatures.  Separate fields with sep. Follow last field with lastSep. */
 {
-fprintf(f, "%u", el->feature_id);
+fprintf(f, "%u", el->id);
 fputc(sep,f);
 if (sep == ',') fputc('"',f);
 fprintf(f, "%s", el->feature_name);
 if (sep == ',') fputc('"',f);