3435a322a06574dc5fa426795597faf62aedcfa1
galt
  Thu Jun 13 16:08:13 2013 -0700
extending sqlCheckIdentifiersList to support just one literal '.' since it is used by hgTables/bedList.c::bedSqlFieldsExceptForChrom()
diff --git src/hg/lib/jksql.c src/hg/lib/jksql.c
index 7ac9f5f..9f29626 100644
--- src/hg/lib/jksql.c
+++ src/hg/lib/jksql.c
@@ -2836,129 +2836,160 @@
 
 static void sqlCheckAllowAlphaChars(char allowed[256])
 /* Allow all chars by setting to 0 */
 {
 sqlCheckAllowUpperChars(allowed);
 sqlCheckAllowLowerChars(allowed);
 }
 
 static void sqlCheckAllowAlphaNumChars(char allowed[256])
 /* Allow all chars by setting to 0 */
 {
 sqlCheckAllowAlphaChars(allowed);
 sqlCheckAllowDigitChars(allowed);
 }
 
-
 /* Currently used 10 times in the code via define sqlChkIl. */
 char *sqlCheckIdentifiersList(char *identifiers)
-/* Check that only valid identifier characters are used in a comma-separated list */
+/* Check that only valid identifier characters are used in a comma-separated list
+ * '.' is allowed also since some code uses it in place of an actual field name.
+ * See hgTables/bedList.c::bedSqlFieldsExceptForChrom(). */
 {
 static boolean init = FALSE;
 static char allowed[256];
 if (!init)
     {
     sqlCheckDisallowAllChars(allowed);
     sqlCheckAllowAlphaNumChars(allowed);
     sqlCheckAllowChar('.', allowed);
     sqlCheckAllowChar('_', allowed);
     // sqlTableExists looks like a single table check, but apparently it has become abused
     // to support multiple tables e.g. sqlTableExists 
     sqlCheckAllowChar(' ', allowed);
     sqlCheckAllowChar(',', allowed);
+    sqlCheckAllowChar('\'', allowed); // single quote allowed for special case fieldname is '.'
     // NOTE it is important for security that no other characters be allowed here
     init = TRUE;
     }
 if (!sqlCheckAllowedChars(identifiers, allowed))
     {
     sqlCheckError("Illegal character found in identifier list %s", identifiers);
     return identifiers;
     }
 // Unfortunately, just checking that the characters are legal is far from enough to ensure safety.
 // the comma is required. Currently aliases and tick quotes are not supported.
 int len = strlen(identifiers);
 char c = 0;
 int i = 0;
 boolean needText = TRUE;
 boolean spaceOk = FALSE;
+boolean textDone = FALSE;
 // Currently identifiers list must start with an identifier, no leading spaces or comma allowed.
 // Currently the comma must immediately follow the identifier
 // Currently zero or one spaces may follow the comma
 // List should end with an identifier. No trailing comma or space allowed.
 // NOTE it is important for security that commas separate values.
 // We do not want to support multiple words separated by spaces.
 while (i < len)
     {
     c = identifiers[i];
     if (c == ' ')
 	{
 	if (!spaceOk)
 	    {
 	    sqlCheckError("Invalid Identifiers List [%s] unexpected space character", identifiers);
 	    return identifiers;
 	    }
 	spaceOk = FALSE;
 	}
     else if (c == ',')
 	{
 	if (needText)
 	    {
 	    sqlCheckError("Invalid Identifiers List [%s] unexpected comma character", identifiers);
 	    return identifiers;
 	    }
 	spaceOk = TRUE;
 	needText = TRUE;
+	textDone = FALSE;
 	}
     else // other chars are part of the identifier
 	{
+	if (textDone)
+	    {
+	    sqlCheckError("Invalid Identifiers List [%s] expected comma", identifiers);
+	    return identifiers;
+	    }
 	needText = FALSE;
 	spaceOk = FALSE;
+	if (c == '\'') // check for '.' exception allowed
+	    {
+	    if (i+strlen("'.'") > len)
+		{
+		sqlCheckError("Invalid Identifiers List [%s] quoted-literal not supported", identifiers);
+		return identifiers;
+		}
+	    if (identifiers[i+1] != '.') // next char must be a period
+		{
+		sqlCheckError("Invalid Identifiers List [%s] quoted-literal not supported", identifiers);
+		return identifiers;
+		}
+	    if (identifiers[i+2] != '\'') // next char must be a single-quote
+		{
+		sqlCheckError("Invalid Identifiers List [%s] quoted-literal not supported", identifiers);
+		return identifiers;
+		}
+	    i += 2;
+	    textDone = TRUE;
+	    }
 	}
     
     ++i;	    
     }
 if (needText || spaceOk)
     {
     sqlCheckError("Invalid Identifiers List [%s] unexpected trailing comma or space character", identifiers);
     return identifiers;
     }
 
 return identifiers;
 }
 
+
 char *sqlCheckIdentifier(char *identifier)
 /* Check that only valid identifier characters are used */
 {
 static boolean init = FALSE;
 static char allowed[256];
 if (!init)
     {
     sqlCheckDisallowAllChars(allowed);
     sqlCheckAllowAlphaNumChars(allowed);
     sqlCheckAllowChar('.', allowed);
     sqlCheckAllowChar('_', allowed);
     // NOTE it is important for security that no other characters be allowed here
     init = TRUE;
     }
 if (!sqlCheckAllowedChars(identifier, allowed))
     {
     sqlCheckError("Illegal character found in identifier %s", identifier);
     }
 return identifier;
 }
 
 
+
 /* --------------------------- */
 
 int sqlEscapeAllStrings(char *buffer, char *s, int bufSize, char escPunc)
 /* Escape all strings demarked by escPunc char. *
  * Returns final size not including terminating 0. 
  * User needs to pre-allocate enough space that mysql_escape will never run out of space.
  * This function should be efficient on statements with many strings to be escaped. */
 {
 char *sOrig = s;
 int sz = 0;
 int remainder = bufSize;
 boolean done = FALSE;
 while (1)
     {
     char *start = strchr(s, escPunc);