src/hg/lib/metaTbl.c 1.8

1.8 2010/03/31 23:34:18 tdreszer
Tightening screws. Don't allow shared metaTbl update except from protected file.
Index: src/hg/lib/metaTbl.c
===================================================================
RCS file: /projects/compbio/cvsroot/kent/src/hg/lib/metaTbl.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -b -B -U 4 -r1.7 -r1.8
--- src/hg/lib/metaTbl.c	30 Mar 2010 23:34:49 -0000	1.7
+++ src/hg/lib/metaTbl.c	31 Mar 2010 23:34:18 -0000	1.8
@@ -212,8 +212,10 @@
 
 /* -------------------------------- End autoSql Generated Code -------------------------------- */
 
 #include "ra.h"
+#include "hgConfig.h"
+#include "obscure.h"
 
 // ------- (static) convert from autoSql -------
 static void metaVarFree(struct metaVar **metaVarPtr)
 // Frees a single metaVar struct
@@ -225,9 +227,9 @@
 
 static void metaLeafObjFree(struct metaLeafObj **leafObjPtr)
 // Frees a single metaVar struct
 {
-    freeMem((*leafObjPtr)->objName);
+    freeMem((*leafObjPtr)->obj);
     freez(leafObjPtr);
 }
 
 static void metaLimbValFree(struct metaLimbVal **limbValPtr)
@@ -254,16 +256,16 @@
 struct metaVar *metaVar;
 struct metaTbl *thisRow;
 while((thisRow = slPopHead(metaTblPtr)) != NULL)
     {
-    if (metaObj == NULL || differentString(thisRow->objName,metaObj->objName) )
+    if (metaObj == NULL || differentString(thisRow->objName,metaObj->obj) )
         {
         // Finish last object before starting next!
         if(metaObj!= NULL)
             slReverse(&(metaObjs->vars));
         // Start new object
         AllocVar(metaObj);
-        metaObj->objName = thisRow->objName;
+        metaObj->obj     = thisRow->objName;
         metaObj->objType = metaObjTypeStringToEnum(thisRow->objType);
         freeMem(thisRow->objType);
         if ( buildHashes )
             metaObj->varHash = hashNew(0);
@@ -348,13 +350,13 @@
         freeMem(thisRow->val);  // Already got this from prev row
 
     // End with leaf
     AllocVar(leafObj);
-    leafObj->objName = thisRow->objName;
+    leafObj->obj     = thisRow->objName;
     leafObj->objType = metaObjTypeStringToEnum(thisRow->objType);
     freeMem(thisRow->objType);
     if ( buildHashes )
-        hashAddUnique(limbVal->objHash, leafObj->objName, leafObj); // Pointer to struct to resolve type!
+        hashAddUnique(limbVal->objHash, leafObj->obj, leafObj); // Pointer to struct to resolve type!
     slAddHead(&(limbVal->objs),leafObj);
 
     freeMem(thisRow);
     }
@@ -376,9 +378,9 @@
 /* Compare to sort on label. */
 {
 const struct metaObj *a = *((struct metaObj **)va);
 const struct metaObj *b = *((struct metaObj **)vb);
-return strcasecmp(a->objName, b->objName);
+return strcasecmp(a->obj, b->obj);
 }
 
 int metaVarCmp(const void *va, const void *vb)
 /* Compare to sort on label. */
@@ -431,9 +433,9 @@
     default:       return "unknown";
     }
 }
 
-// ------ Loading files and parsing lines ------
+// ------ Parsing lines ------
 struct metaObj *metadataLineParse(char *line)
 /* Parses a single formatted metadata line into metaObj for updates or queries. */
 {
 int thisWord = 0;
@@ -455,10 +457,10 @@
     AllocVar(metaObj);
     thisWord++;
     if(strchr(words[thisWord], '=') == NULL)
         {
-        metaObj->objName = cloneString(words[thisWord++]);
-        verbose(3, "metadataLineParse() objName=%s\n",metaObj->objName);
+        metaObj->obj = cloneString(words[thisWord++]);
+        verbose(3, "metadataLineParse() obj=%s\n",metaObj->obj);
         if(sameWord(words[thisWord],"delete"))
             {
             metaObj->deleteThis = TRUE;
             thisWord++;
@@ -473,9 +475,9 @@
                     //return NULL;
                     }
                 thisWord++;
                 }
-        if(thisWord < count && sameWord(words[thisWord],"delete"))  // Could be objName delete... or objName objType delete
+        if(thisWord < count && sameWord(words[thisWord],"delete"))  // Could be obj delete... or obj objType delete
             {
             metaObj->deleteThis = TRUE;
             thisWord++;
             }
@@ -511,9 +513,9 @@
         }
     freeMem(words);
 
     // Special for old style ENCODE metadata
-    if(metaObj->objName == NULL)
+    if(metaObj->obj == NULL)
         {
         char * tableName = NULL;
         char * fileName = NULL;
         for(metaVar  = metaObj->vars;
@@ -529,60 +531,34 @@
             {
             verbose(3, "tableName:%s\n",tableName);
             if(fileName == NULL || startsWithWordByDelimiter(tableName,'.',fileName))
                 {
-                metaObj->objName = cloneString(tableName);
+                metaObj->obj     = cloneString(tableName);
                 metaObj->objType = otTable;
                 }
             }
         else if(fileName != NULL)
             {
             verbose(3, "fileName:%s\n",fileName);
             // NOTE: that the file object is the root of the name, so that file.fastq.gz = file.fastq
-            metaObj->objName = cloneFirstWordByDelimiter(fileName,'.');
+            metaObj->obj     = cloneFirstWordByDelimiter(fileName,'.');
             metaObj->objType = otFile;
             }
         }
 
-if(metaObj->objName == NULL)
+if(metaObj->obj == NULL)
     {
-    errAbort("No objName found. This is not properly formatted metadata:\n\t%s\n",line);
+    errAbort("No obj found. This is not properly formatted metadata:\n\t%s\n",line);
     //metaObjsFree(&metaObj);
     //return NULL;
     }
 if(metaObj->objType == otUnknown) // NOTE: defaulting to table
     {
     metaObj->objType = otTable;
     }
     slReverse(&(metaObj->vars));
-    verbose(3, "metadataLineParse() objName=%s(%s) %s(%s)=%s\n",
-    metaObj->objName, metaObjTypeEnumToString(metaObj->objType),metaObj->vars->var,metaVarTypeEnumToString(metaObj->vars->varType),metaObj->vars->val);
-return metaObj;
-}
-
-struct metaObj *metaObjCreate(char *obj,char *type,char *var, char *varType,char *val)
-/* Creates a singular metaObj query object based on obj and all other optional params. */
-{
-struct metaObj *metaObj = NULL;
-
-    if(obj == NULL)
-        errAbort("Need obj to create metaObj query object.\n");
-
-    AllocVar(metaObj);
-    metaObj->objName = cloneString(obj);
-    metaObj->objType = (type==NULL?otUnknown:metaObjTypeStringToEnum(type));
-
-    if(var != NULL)
-        {
-        struct metaVar * metaVar;
-        AllocVar(metaVar);
-
-        metaVar->var     = cloneString(var);
-        metaVar->varType = (varType==NULL?vtUnknown:metaVarTypeStringToEnum(varType));
-        if(val != NULL)
-            metaVar->val     = cloneString(val);
-        metaObj->vars = metaVar; // Only one
-        }
+    verbose(3, "metadataLineParse() obj=%s(%s) %s(%s)=%s\n",
+    metaObj->obj, metaObjTypeEnumToString(metaObj->objType),metaObj->vars->var,metaVarTypeEnumToString(metaObj->vars->varType),metaObj->vars->val);
 return metaObj;
 }
 
 struct metaByVar *metaByVarsLineParse(char *line)
@@ -600,9 +576,9 @@
     char **words = needMem(sizeof(char *) * count);
     count = chopByWhiteRespectDoubleQuotes(cloneLine,words,count);
 
     verbose(3, "metaByVarsLineParse() word count:%d\n\t%s\n",count,line);
-    // Get objName and figure out if this is a delete line
+    // Get obj and figure out if this is a delete line
     varHash = hashNew(0);
 
     // All words are expected to be var=val pairs!
     for(thisWord=0;thisWord<count;thisWord++)
@@ -641,8 +617,9 @@
         slCount(metaByVars->vals),metaByVars->var,metaByVars->vals->val);
 return metaByVars;
 }
 
+// ------ Loading from args, hashes and tdb ------
 struct metaByVar*metaByVarCreate(char *var, char *varType,char *val)
 /* Creates a singular var=val pair struct for metadata queries. */
 {
 struct metaByVar *metaByVar = NULL;
@@ -665,34 +642,32 @@
 
 return metaByVar;
 }
 
-struct metaObj *metaObjsLoadFromFormattedFile(char *fileName)
-// Load all metaObjs from a file containing metadata formatted lines
+struct metaObj *metaObjCreate(char *obj,char *type,char *var, char *varType,char *val)
+/* Creates a singular metaObj query object based on obj and all other optional params. */
 {
-struct metaObj *metaObjs = NULL;
-struct lineFile *lf = lineFileOpen(fileName, TRUE);
-char *line;
+struct metaObj *metaObj = NULL;
 
-while (lineFileNext(lf, &line,NULL))
-    {
-    if(startsWithWord("metaObject",line))
-        {
-        // This is the RA style file!!
-        lineFileClose(&lf);
-        return metaObjsLoadFromRAFile(fileName);
-        }
-    struct metaObj *metaObj = metadataLineParse(line);
-    if(metaObj == NULL)
+    if(obj == NULL)
+        errAbort("Need obj to create metaObj query object.\n");
+
+    AllocVar(metaObj);
+    metaObj->obj     = cloneString(obj);
+    metaObj->objType = (type==NULL?otUnknown:metaObjTypeStringToEnum(type));
+
+    if(var != NULL)
         {
-        metaObjsFree(&metaObjs);
-        return NULL;
-        }
-    slAddHead(&metaObjs,metaObj);
+        struct metaVar * metaVar;
+        AllocVar(metaVar);
+
+        metaVar->var     = cloneString(var);
+        metaVar->varType = (varType==NULL?vtUnknown:metaVarTypeStringToEnum(varType));
+        if(val != NULL)
+            metaVar->val     = cloneString(val);
+        metaObj->vars = metaVar; // Only one
     }
-    lineFileClose(&lf);
-    slReverse(&metaObjs);  // Go ahead and keep this in file order
-    return metaObjs;
+return metaObj;
 }
 
 struct metaObj *metaObjsLoadFromHashes(struct hash *objsHash)
 // Load all metaObjs from a file containing metadata formatted lines
@@ -704,11 +679,12 @@
 while((objEl = hashNext(&objCookie)) != NULL)
     {
     struct metaObj *metaObj;
     AllocVar(metaObj);
-    metaObj->objName = cloneString(objEl->name);
-    struct hash *varHash = objEl->val;
-    struct hashCookie varCookie = hashFirst(varHash);
+    metaObj->obj     = cloneString(objEl->name);
+    metaObj->varHash = hashNew(0);
+    struct hash *hashedVars = objEl->val;
+    struct hashCookie varCookie = hashFirst(hashedVars);
     struct hashEl* varEl = NULL;
     while((varEl = hashNext(&varCookie)) != NULL)
         {
         if(sameString(varEl->name,"metaObject"))
@@ -721,8 +697,9 @@
             AllocVar(metaVar);
             metaVar->var     = cloneString(varEl->name);
             metaVar->varType = vtTxt;                    // FIXME: binary?
             metaVar->val     = cloneString(varEl->val);
+            hashAdd(metaObj->varHash, metaVar->var, metaVar); // pointer to struct to resolve type
             slAddHead(&(metaObj->vars),metaVar);
             }
 
         }
@@ -732,9 +709,86 @@
     slSort(&metaObjs,&metaObjCmp); // Should be in determined order
     return metaObjs;
 }
 
-struct metaObj *metaObjsLoadFromRAFile(char *fileName)
+static struct metaObj *metadataForTableFromTdb(struct trackDb *tdb)
+// Returns the metadata for a table from a tdb setting.
+{
+metadata_t *metadata = metadataSettingGet(tdb);
+// convert to a metaObj
+struct metaObj *metaObj = NULL;
+AllocVar(metaObj);
+metaObj->obj     = tdb->tableName;
+metaObj->objType = otTable;
+metaObj->varHash = hashNew(0);
+
+int ix =0;
+for(;ix<metadata->count;ix++)
+    {
+    struct metaVar *metaVar = NULL;
+    AllocVar(metaVar);
+    metaVar->var     = metadata->tags[ix];
+    metaVar->varType = vtTxt;
+    metaVar->val     = metadata->values[ix];
+    hashAdd(metaObj->varHash, metaVar->var, metaVar); // pointer to struct to resolve type
+    slAddHead(&(metaObj->vars),metaVar);
+    }
+slSort(&(metaObj->vars),&metaVarCmp); // Should be in determined order
+metadataFree(&metadata);
+return metaObj;
+}
+
+struct metaObj *metadataForTable(char *db,struct trackDb *tdb,char *table)
+// Returns the metadata for a table.  Either tdb or table must be provided
+{
+struct sqlConnection *conn = sqlConnect(db);
+char *metaTbl = metaTblName(conn,TRUE);  // Look for sandbox name first
+struct metaObj *metaObj = NULL;
+if(tdb != NULL && tdb->tableName != NULL)
+    table = tdb->tableName;
+if(metaTbl != NULL)
+    metaObj = metaObjQueryByObj(conn,metaTbl,table,NULL);
+sqlDisconnect(&conn);
+
+if(metaObj == NULL && tdb != NULL)
+    return metadataForTableFromTdb(tdb);
+
+return metaObj;
+}
+
+// ------ Loading from files ------
+struct metaObj *metaObjsLoadFromFormattedFile(char *fileName,boolean *validated)
+// Load all metaObjs from a file containing metadata formatted lines
+{
+struct metaObj *metaObjs = NULL;
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+char *line;
+
+while (lineFileNext(lf, &line,NULL))
+    {
+    if(startsWithWord("metaObject",line))
+        {
+        // This is the RA style file!!
+        lineFileClose(&lf);
+        return metaObjsLoadFromRAFile(fileName,validated);
+        }
+    struct metaObj *metaObj = metadataLineParse(line);
+    if(metaObj == NULL)
+        {
+        metaObjsFree(&metaObjs);
+        return NULL;
+        }
+    slAddHead(&metaObjs,metaObj);
+    }
+    lineFileClose(&lf);
+    slReverse(&metaObjs);  // Go ahead and keep this in file order
+    if(validated)
+        *validated = FALSE;
+    return metaObjs;
+}
+
+#define METATBL_MAGIC_PREFIX "# MAGIC: "
+struct metaObj *metaObjsLoadFromRAFile(char *fileName,boolean *validated)
 // Load all metaObjs from a file containing RA formatted 'metaObjects'
 {
 struct hash *mdHash = raReadAll(fileName, "metaObject");
 if(mdHash == NULL)
@@ -743,11 +797,126 @@
     return NULL;
     }
 struct metaObj *metaObjs = metaObjsLoadFromHashes(mdHash);
 hashFree(&mdHash);
+
+// Try to validate file
+if(validated)
+    {
+    *validated = FALSE;
+    struct lineFile *lf = lineFileOpen(fileName, TRUE);
+    char *line = lineFileSkipToLineStartingWith(lf,METATBL_MAGIC_PREFIX,1000000);
+    if(line != NULL)
+        {
+        int fileMagic = atoi(line+strlen(METATBL_MAGIC_PREFIX));
+        int objsMagic = metaObjCRC(metaObjs);
+        verbose(3,"Objects magic: %d  Files magic: %d (%s)\n",objsMagic,fileMagic,line+strlen(METATBL_MAGIC_PREFIX));
+        *validated = (fileMagic == objsMagic);
+        }
+    else
+        verbose(3,"Can't find magic number on this file.\n");
+    }
 return metaObjs;
 }
 
+// ------ Table name and creation ------
+#define METATBL_SPEC_LOCATION "/cluster/bin/sqlCreate/metaTbl.sql"
+
+void metaTblReCreate(struct sqlConnection *conn,char *tblName,boolean testOnly)
+// Creates ore Recreates the named metaTbl.
+{
+if(sqlTableExists(conn,tblName))
+    verbose(2, "Table '%s' already exists.  It will be recreated.\n",tblName);
+
+char *sql = NULL;
+readInGulp(METATBL_SPEC_LOCATION, &sql, NULL);
+char *pos = strchr(sql, ';');
+if ( pos != NULL)
+    *pos = 0;
+char *oldSql = cloneString(sql);
+pos = stringIn("CREATE TABLE ", oldSql);
+if (pos == NULL)
+    errAbort("Can't find CREATE TABLE in %s\n", METATBL_SPEC_LOCATION);
+nextWord(&pos);
+nextWord(&pos);
+char *oldName = nextWord(&pos);
+if(differentWord(oldName, tblName))
+    {
+    char *saveSql = cloneString(sql);
+    freeMem(sql);
+    sql = replaceChars(saveSql, oldName, tblName);
+    freeMem(saveSql);
+    }
+freeMem(oldSql);
+verbose(2, "Requesting table creation:\n\t%s;\n", sql);
+if(!testOnly)
+    sqlRemakeTable(conn,tblName, sql);
+freeMem(sql);
+}
+
+char*metaTblName(struct sqlConnection *conn,boolean mySandBox)
+// returns the metaTbl name or NULL if conn supplied but the table doesn't exist
+{
+char *tblName = NULL;
+char *root = NULL;
+char *sand = NULL;
+char *name = cfgOption("db.metaTbl");
+if(name == NULL)
+    {
+    name = cfgOption("db.trackDb");
+    if(name == NULL)
+        root = cloneString(METATBL_DEFAULT_NAME);
+    }
+
+// Divide name into root and sand
+if(root == NULL)
+    {
+    char delimit = '_';
+    if((sand = strchr(name,delimit)) == NULL)
+        {
+        delimit = '-';
+        if((sand = strchr(name,delimit)) == NULL)
+            root = cloneString(name);  // No sandBox portion
+        }
+
+    if(root == NULL)  // There should be a sandbox portion
+        {
+        root = cloneNextWordByDelimiter(&name,delimit);
+        if(mySandBox && *name != 0)
+            sand = name;
+        }
+    }
+
+// Since db.trackDb was used, make sure to swap it
+if(sameWord("trackDb",root))
+    {
+    freeMem(root);
+    root = cloneString(METATBL_DEFAULT_NAME);
+    }
+
+if(!mySandBox || sand == NULL)
+    tblName = root;
+else
+    {
+    int size = strlen(root) + strlen(sand) + 2;
+    tblName = needMem(size);
+    safef(tblName,size,"%s_%s",root,sand);
+    }
+
+// Test for table
+if(conn != NULL && !sqlTableExists(conn,tblName))
+    {
+    if(sand == NULL || sameWord(tblName,root)) // Then try the root
+        return NULL;
+    freeMem(tblName);
+    tblName = root;
+    if(!sqlTableExists(conn,tblName))
+        return NULL;
+    }
+
+return tblName;
+}
+
 // -------------- Updating the DB --------------
 int metaObjsSetToDb(struct sqlConnection *conn,char *tableName,struct metaObj *metaObjs,boolean replace,boolean testOnly)
 // Adds or updates metadata obj/var pairs into the named table.  Returns total rows affected
 {
@@ -755,28 +924,28 @@
 struct metaObj *metaObj;
 struct metaVar *metaVar;
 int count = 0;
 
-    if(tableName == NULL)
+if(tableName == NULL)
         tableName = METATBL_DEFAULT_NAME;
 
-    if(!sqlTableExists(conn,tableName))
-        errAbort("metaObjsSetToDb attempting to update non-existent table.\n");
+if(!sqlTableExists(conn,tableName))
+    errAbort("metaObjsSetToDb attempting to update non-existent table named '%s'.\n",tableName);
 
 for(metaObj = metaObjs;metaObj != NULL; metaObj = metaObj->next)
     {
     // Handle delete requests first
     if(metaObj->deleteThis)
         {
         if(metaObj->vars == NULL) // deletes all
             {
-            safef(query, sizeof(query),"%s where objName = '%s'",tableName,metaObj->objName);
+            safef(query, sizeof(query),"%s where objName = '%s'",tableName,metaObj->obj);
             int delCnt = sqlRowCount(conn,query);
 
             if(delCnt>0)
                 {
                 safef(query, sizeof(query),
-                    "delete from %s where objName = '%s'",tableName,metaObj->objName);
+                    "delete from %s where objName = '%s'",tableName,metaObj->obj);
                 verbose(2, "Requesting delete of %d rows:\n\t%s;\n",delCnt, query);
                 if(!testOnly)
                     sqlUpdate(conn, query);
                 count += delCnt;
@@ -787,14 +956,14 @@
             for(metaVar = metaObj->vars;metaVar != NULL; metaVar = metaVar->next)
                 {
                 safef(query, sizeof(query),
                     "select objName from %s where objName = '%s' and var = '%s'",
-                    tableName,metaObj->objName,metaVar->var);
+                    tableName,metaObj->obj,metaVar->var);
                 if(sqlExists(conn,query))
                     {
                     safef(query, sizeof(query),
                         "delete from %s where objName = '%s' and var = '%s'",
-                        tableName,metaObj->objName,metaVar->var);
+                        tableName,metaObj->obj,metaVar->var);
                     verbose(2, "Requesting delete of 1 row:\n\t%s;\n",query);
                     if(!testOnly)
                         sqlUpdate(conn, query);
                     count++;
@@ -804,15 +973,15 @@
         continue;  // Done with this metaObj
         }
     else if (replace)  // If replace then clear out deadwood before inserting new vars
         {
-        safef(query, sizeof(query),"%s where objName = '%s'",tableName,metaObj->objName);
+        safef(query, sizeof(query),"%s where objName = '%s'",tableName,metaObj->obj);
         int delCnt = sqlRowCount(conn,query);
 
         if(delCnt>0)
             {
             safef(query, sizeof(query),
-                "delete from %s where objName = '%s'",tableName,metaObj->objName);
+                "delete from %s where objName = '%s'",tableName,metaObj->obj);
             verbose(2, "Requesting replacement of %d rows:\n\t%s;\n",delCnt, query);
             if(!testOnly)
                 sqlUpdate(conn, query);
             count += delCnt;
@@ -824,9 +993,9 @@
         {
         // Be sure to check for var existence first, then update
         if (!replace)
             {
-            struct metaObj *objExists = metaObjQueryByObj(conn,tableName,metaObj->objName,metaVar->var);
+            struct metaObj *objExists = metaObjQueryByObj(conn,tableName,metaObj->obj,metaVar->var);
             if(objExists)
                 {
                 if(differentString(metaVar->val,objExists->vars->val)
                 || metaVar->varType != objExists->vars->varType)
@@ -834,9 +1003,9 @@
                     safef(query, sizeof(query),
                         "update %s set varType = '%s', val = '%s' where objName = '%s' and var = '%s'",
                             tableName,
                             metaVarTypeEnumToString(metaVar->varType),sqlEscapeString(metaVar->val), // FIXME: binary val?
-                            metaObj->objName,metaVar->var);
+                            metaObj->obj,metaVar->var);
                     verbose(2, "Requesting update of 1 row:\n\t%s;\n",query);
                     if(!testOnly)
                         sqlUpdate(conn, query);
                     count++;
@@ -847,10 +1016,10 @@
             }
         // Finally ready to insert new vars
         safef(query, sizeof(query),
             "insert into %s values ( '%s','%s','%s','%s','%s')",
-                tableName,metaObj->objName,metaObjTypeEnumToString(metaObj->objType),
-                          metaVar->var,    metaVarTypeEnumToString(metaVar->varType),
+                tableName,metaObj->obj,metaObjTypeEnumToString(metaObj->objType),
+                          metaVar->var,metaVarTypeEnumToString(metaVar->varType),
                           sqlEscapeString(metaVar->val)); // FIXME: binary val?
         verbose(2, "Requesting insert of one row:\n\t%s;\n",query);
         if(!testOnly)
             sqlUpdate(conn, query);
@@ -864,9 +1033,9 @@
 struct metaObj *metaObjQuery(struct sqlConnection *conn,char *table,struct metaObj *metaObj)
 // Query the metadata table by obj and optional vars and vals in metaObj struct.  If metaObj is NULL query all.
 // Returns new metaObj struct fully populated and sorted in obj,var order.
 {
-//  select obj,var,val where (var= [and val=]) or ([var= and] val=) order by obj,var
+//  select objName,var,val where (var= [and val=]) or ([var= and] val=) order by objName,var
     boolean buildHash = TRUE;
 
     if(table == NULL)
         table = METATBL_DEFAULT_NAME;
@@ -875,11 +1044,11 @@
         return NULL;
 
     struct dyString *dy = newDyString(4096);
     dyStringPrintf(dy, "select objName,objType,var,varType,val from %s", table);
-    if(metaObj != NULL && metaObj->objName != NULL)
+    if(metaObj != NULL && metaObj->obj != NULL)
         {
-        dyStringPrintf(dy, " where objName = '%s'", metaObj->objName);
+        dyStringPrintf(dy, " where objName = '%s'", metaObj->obj);
 
         struct metaVar *metaVar;
         for(metaVar=metaObj->vars;metaVar!=NULL;metaVar=metaVar->next)
             {
@@ -909,15 +1078,15 @@
         metaObjCount(metaObjs,TRUE),metaObjCount(metaObjs,FALSE));
     return metaObjs;
 }
 
-struct metaObj *metaObjQueryByObj(struct sqlConnection *conn,char *table,char *objName,char *varName)
+struct metaObj *metaObjQueryByObj(struct sqlConnection *conn,char *table,char *obj,char *var)
 // Query a single metadata object and optional var from a table (default metaTbl).
 {
-if(objName == NULL)
+if(obj == NULL)
     return metaObjQuery(conn,table,NULL);
 
-struct metaObj *queryObj  = metaObjCreate(objName,NULL,varName,NULL,NULL);
+struct metaObj *queryObj  = metaObjCreate(obj,NULL,var,NULL,NULL);
 struct metaObj *resultObj = metaObjQuery(conn,table,queryObj);
 metaObjsFree(&queryObj);
 return resultObj;
 }
@@ -925,9 +1094,9 @@
 struct metaByVar *metaByVarsQuery(struct sqlConnection *conn,char *table,struct metaByVar *metaByVars)
 // Query the metadata table by one or more var=val pairs to find the distinct set of objs that satisfy ANY conditions.
 // Returns new metaByVar struct fully populated and sorted in var,val,obj order.
 {
-//  select var,val,obj where (var= [and val in (val1,val2)]) or (var= [and val in (val1,val2)]) order by var,val,obj
+//  select objName,var,val where (var= [and val in (val1,val2)]) or (var= [and val in (val1,val2)]) order by var,val,objName
 
     if(table == NULL)
         table = METATBL_DEFAULT_NAME;
     if(!sqlTableExists(conn,table))
@@ -962,14 +1131,14 @@
     verbose(3, "Requesting query:\n\t%s;\n",dyStringContents(dy));
 
     struct metaTbl *metaTbl = metaTblLoadByQuery(conn, dyStringCannibalize(&dy));
     verbose(3, "rows (vars) returned: %d\n",slCount(metaTbl));
-    struct metaByVar *metaVars = metaByVarsLoadFromMemory(&metaTbl,TRUE);
+    struct metaByVar *metaByVarsFromMem = metaByVarsLoadFromMemory(&metaTbl,TRUE);
     verbose(3, "Returned %d vars(s) with %d val(s) with %d object(s).\n",
-        metaByVarCount(metaVars,TRUE ,FALSE),
-        metaByVarCount(metaVars,FALSE,TRUE ),
-        metaByVarCount(metaVars,FALSE,FALSE));
-    return metaVars;
+        metaByVarCount(metaByVarsFromMem,TRUE ,FALSE),
+        metaByVarCount(metaByVarsFromMem,FALSE,TRUE ),
+        metaByVarCount(metaByVarsFromMem,FALSE,FALSE));
+    return metaByVarsFromMem;
 }
 
 struct metaByVar *metaByVarQueryByVar(struct sqlConnection *conn,char *table,char *varName,char *val)
 // Query a single metadata variable and optional val from a table (default metaTbl) for searching val->obj.
@@ -986,9 +1155,9 @@
 struct metaObj *metaObjsQueryByVars(struct sqlConnection *conn,char *table,struct metaByVar *metaByVars)
 // Query the metadata table by one or more var=val pairs to find the distinct set of objs that satisfy ALL conditions.
 // Returns new metaObj struct fully populated and sorted in obj,var order.
 {
-//  select var,val,obj where (var= [and val in (val1,val2)]) or (var= [and val in (val1,val2)]) order by var,val,obj
+//  select objName,var,val where (var= [and val in (val1,val2)]) or (var= [and val in (val1,val2)]) order by objName,var
 
     if(table == NULL)
         table = METATBL_DEFAULT_NAME;
     if(!sqlTableExists(conn,table))
@@ -1055,12 +1224,12 @@
 // TODO: Expand for mutilple var types; strip quotes from vals on ra style
 struct metaObj *metaObj = NULL;
 for(metaObj=metaObjs;metaObj!=NULL;metaObj=metaObj->next)
     {
-    if(metaObj->objName == NULL)
+    if(metaObj->obj == NULL)
         continue;
 
-    printf("%s %s",(raStyle?"metaObject":"metadata"),metaObj->objName);
+    printf("%s %s",(raStyle?"metaObject":"metadata"),metaObj->obj);
     if(metaObj->deleteThis)
         printf(" delete");
     else
         {
@@ -1089,8 +1258,10 @@
             }
         }
     printf("%s",(raStyle?"\n\n":"\n"));
     }
+if(raStyle) // NOTE: currently only supporting validation of RA files
+    printf("%s%d\n",METATBL_MAGIC_PREFIX,metaObjCRC(metaObjs));
 }
 
 void metaByVarPrint(struct metaByVar *metaByVars,boolean raStyle)
 // prints var=val pairs and objs that go with them single lines or ra style
@@ -1133,12 +1304,12 @@
 
         struct metaLeafObj *leafObj = NULL;
         for(leafObj=limbVal->objs;leafObj!=NULL;leafObj=leafObj->next)
             {
-            if(leafObj->objName == NULL)
+            if(leafObj->obj == NULL)
                 continue;
 
-            printf("%s%s",(raStyle?"\n        ":" "),leafObj->objName);
+            printf("%s%s",(raStyle?"\n        ":" "),leafObj->obj);
             }
         printf("\n");
         }
     }
@@ -1151,9 +1322,9 @@
 int count = 0;
 struct metaObj *metaObj = NULL;
 for(metaObj=metaObjs;metaObj!=NULL;metaObj=metaObj->next)
     {
-    if(metaObj->objName == NULL)
+    if(metaObj->obj == NULL)
         continue;
     if(objs)
         count++;
     else
@@ -1194,9 +1365,9 @@
                 {
                 struct metaLeafObj *leafObj = NULL;
                 for(leafObj=limbVal->objs;leafObj!=NULL;leafObj=leafObj->next)
                     {
-                    if(leafObj->objName != NULL)
+                    if(leafObj->obj != NULL)
                         count++;
                     }
                 }
             }
@@ -1205,41 +1376,88 @@
 return count;
 }
 
 // ----------------- Utilities -----------------
+
+char *metadataFindValue(struct metaObj *metaObj, char *var)
+// Finds the val associated with the var or retruns NULL
+{
+if (metaObj == NULL)
+    return NULL;
+
+struct metaVar *metaVar = NULL;
+if(metaObj->varHash != NULL)
+    metaVar = hashFindVal(metaObj->varHash,var);
+else
+    {
+    for(metaVar=metaObj->vars;metaVar!=NULL;metaVar=metaVar->next)
+        {
+        if(sameOk(var,metaVar->var))
+            break;
+        }
+    }
+if(metaVar == NULL)
+    return NULL;
+
+return metaVar->val;
+}
+
 boolean metaObjContains(struct metaObj *metaObj, char *var, char *val)
 // Returns TRUE if object contains var, val or both
 {
-if (metaObj != NULL)
+if (metaObj == NULL)
+    return FALSE;
+
+if(var != NULL)
     {
-    struct metaVar *metaVar;
-    for(metaVar=metaObj->vars;metaVar!=NULL;metaVar=metaVar->next)
+    char *foundVal = metadataFindValue(metaObj,var);
+    if(foundVal == NULL)
+        return FALSE;
+    if(val == NULL)
+        return TRUE;
+    return sameOk(foundVal,val);
+    }
+struct metaVar *metaVar = NULL;
+for(metaVar=metaObj->vars;metaVar!=NULL;metaVar=metaVar->next)
         {
         if(differentStringNullOk(var,metaVar->var) != 0)
             continue;
         if(differentStringNullOk(val,metaVar->val) != 0)
             continue;
         return TRUE;
         }
-    }
+
 return FALSE;
 }
 
 boolean metaByVarContains(struct metaByVar *metaByVar, char *val, char *obj)
 // Returns TRUE if var contains val, obj or both
 {
 if (metaByVar != NULL)
     {
-    struct metaLimbVal *limbVal;
+    struct metaLimbVal *limbVal = NULL;
+    struct metaLeafObj *leafObj = NULL;
+    if(metaByVar->valHash != NULL && val != NULL)
+        {
+        limbVal = hashFindVal(metaByVar->valHash,val);
+        if(limbVal == NULL || limbVal->val == NULL)
+            return FALSE;
+        if(limbVal->objHash != NULL && obj != NULL)
+            {
+            leafObj = hashFindVal(limbVal->objHash,obj);
+            if(leafObj == NULL)
+                return FALSE;
+            return sameOk(leafObj->obj,obj);
+            }
+        }
     for(limbVal=metaByVar->vals;limbVal!=NULL;limbVal=limbVal->next)
         {
         if(differentStringNullOk(val,limbVal->val) != 0)
             continue;
 
-        struct metaLeafObj *leafObj;
         for(leafObj=limbVal->objs;leafObj!=NULL;leafObj=leafObj->next)
             {
-            if(differentStringNullOk(obj,leafObj->objName) != 0)
+            if(differentStringNullOk(obj,leafObj->obj) != 0)
                 continue;
             return TRUE;
             }
         }
@@ -1365,8 +1583,31 @@
         }
     }
 }
 
+int metaObjCRC(struct metaObj *metaObjs)
+// returns a summ of all individual CRC values of all metObj strings
+{
+int crc = 0;
+struct metaObj *metaObj = NULL;
+for(metaObj=metaObjs;metaObj!=NULL;metaObj=metaObj->next)
+    {
+    if(metaObj->obj != NULL)
+        crc += hashCrc(metaObj->obj);
+
+    struct metaVar *metaVar = NULL;
+    for(metaVar=metaObj->vars;metaVar!=NULL;metaVar=metaVar->next)
+        {
+        if(metaVar->var != NULL)
+            crc += hashCrc(metaVar->var);
+        if(metaVar->varType == vtTxt && metaVar->val != NULL)
+            crc += hashCrc(metaVar->val);
+        }
+    }
+
+return crc;
+}
+
 // --------------- Free at last ----------------
 void metaObjsFree(struct metaObj **metaObjsPtr)
 // Frees one or more metadata objects and any contained metaVars.  Will free any hashes as well.
 {
@@ -1385,9 +1626,9 @@
         while((metaVar = slPopHead(&(metaObj->vars))) != NULL)
             metaVarFree(&metaVar);
 
         // The rest of root
-        freeMem(metaObj->objName);
+        freeMem(metaObj->obj);
         freeMem(metaObj);
         }
     freez(metaObjsPtr);
     }