852fd481e68ca3d3feaf29e1da20e1b49304f9ce
angie
  Fri Mar 14 10:03:48 2014 -0700
Fixing problem with hgVai code not recognizing a genePred whoseasObject was derived from sql field info.  Unfortunately, when a sql
field's type is longblob, we don't know whether its autoSql definition
was a list (like exonStarts[exonCount]) or just an lstring.  To play
it safe, we call it an lstring which works fine for feeding data
through the annoGrator system.  However, when comparing a sql-derived
asObj with lstring to the real autoSql-derived asObj, asCompareObjs
will see different types for the same field and return false.  So
for the purposes of recognizing a genePred, we need to simply compare
column names.

diff --git src/lib/asParse.c src/lib/asParse.c
index 867bd79..4371616 100644
--- src/lib/asParse.c
+++ src/lib/asParse.c
@@ -77,57 +77,76 @@
 struct dyString *type = dyStringNew(32);
 if ((lt->type == t_enum) || (lt->type == t_set))
     sqlSymDef(col, type);
 else if (col->isList || col->isArray)
     dyStringPrintf(type, "longblob");
 else if (lt->type == t_char)
     dyStringPrintf(type, "char(%d)", col->fixedSize ? col->fixedSize : 1);
 else
     dyStringPrintf(type, "%s", lt->sqlName);
 return type;
 }
 
 char *asTypeNameFromSqlType(char *sqlType)
 /* Return the autoSql type name (not enum) for the given SQL type, or NULL.
  * Don't attempt to free result. */
+// Unfortunately, when sqlType is longblob, we don't know whether it's a list
+// of some type or an lstring.  :(
 {
 if (sqlType == NULL)
     return NULL;
-// We need to strip '(...)' strings from all types except 'varchar' which must be 'varchar(255)'
-int len = strlen(sqlType) + 8;
-char buf[len];
+// For comparison with asTypes[*], we need to strip '(...)' strings from all types
+// except 'varchar' which must be 'varchar(255)'.  For 'char', we need to remember
+// what was in the '(...)' so we can add back the '[...]' after type comparison.
+boolean isArray = FALSE;
+int arraySize = 0;
+static char buf[1024];
 if (startsWith("varchar", sqlType))
-    safecpy(buf, len, "varchar(255)");
+    safecpy(buf, sizeof(buf), "varchar(255)");
 else
     {
-    safecpy(buf, len, sqlType);
+    safecpy(buf, sizeof(buf), sqlType);
     char *leftParen = strstr(buf, " (");
     if (leftParen == NULL)
 	leftParen = strchr(buf, '(');
     if (leftParen != NULL)
 	{
+	isArray = startsWith("char", sqlType);
 	char *rightParen = strrchr(leftParen, ')');
 	if (rightParen != NULL)
 	    {
+	    *rightParen = '\0';
+	    arraySize = atoi(leftParen+1);
 	    strcpy(leftParen, rightParen+1);
 	    }
+	else
+	    errAbort("asTypeNameFromSqlType: mismatched ( in sql type def'%s'", sqlType);
 	}
     }
 int i;
 for (i = 0;  i < ArraySize(asTypes);  i++)
     if (sameString(buf, asTypes[i].sqlName))
+	{
+	if (isArray)
+	    {
+	    int typeLen = strlen(buf);
+	    safef(buf+typeLen, sizeof(buf)-typeLen, "[%d]", arraySize);
+	    return buf;
+	    }
+	else
 	    return asTypes[i].name;
+	}
 return NULL;
 }
 
 static struct asColumn *mustFindColumn(struct asObject *table, char *colName)
 /* Return column or die. */
 {
 struct asColumn *col;
 
 for (col = table->columnList; col != NULL; col = col->next)
     {
     if (sameWord(col->name, colName))
 	return col;
     }
 errAbort("Couldn't find column %s", colName);
 return NULL;
@@ -611,15 +630,32 @@
     if (!differencesFound && checkCount < numColumnsToCheck)
 	errAbort("Unexpected error in asCompareObjLists: asked to compare %d columns in %s and %s, but only found %d in one or both asObjects."
 	    , numColumnsToCheck, name1, name2, checkCount);
     }
 if (differencesFound)
     {
     if (abortOnDifference)
     	errAbort("asObjects differ.");
     else
     	verbose(verboseLevel,"asObjects differ. Matching field count=%d\n", checkCount);
     }
 if (retNumColumnsSame)
     *retNumColumnsSame = checkCount;
 return (!differencesFound);
 }
+
+boolean asColumnNamesMatchFirstN(struct asObject *as1, struct asObject *as2, int n)
+/* Compare only the column names of as1 and as2, not types because if an asObj has been
+ * created from sql type info, longblobs are cast to lstrings but in the proper autoSql
+ * might be lists instead (e.g. longblob in sql, uint exonStarts[exonCount] in autoSql. */
+{
+struct asColumn *col1 = as1->columnList, *col2 = as2->columnList;
+int checkCount = 0;
+for (col1 = as1->columnList, col2 = as2->columnList;
+     col1 != NULL && col2 != NULL && checkCount < n;
+     col1 = col1->next, col2 = col2->next, ++checkCount)
+    {
+    if (!sameOk(col1->name, col2->name))
+	return FALSE;
+    }
+return TRUE;
+}