src/utils/raSqlQuery/raSqlQuery.c 1.6

1.6 2009/11/20 04:57:14 kent
Allowing like in where spec.
Index: src/utils/raSqlQuery/raSqlQuery.c
===================================================================
RCS file: /projects/compbio/cvsroot/kent/src/utils/raSqlQuery/raSqlQuery.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -b -B -U 4 -r1.5 -r1.6
--- src/utils/raSqlQuery/raSqlQuery.c	20 Nov 2009 04:39:16 -0000	1.5
+++ src/utils/raSqlQuery/raSqlQuery.c	20 Nov 2009 04:57:14 -0000	1.6
@@ -87,8 +87,9 @@
     rqlParseGt,  /* Greater than comparison. */
     rqlParseLt,  /* Less than comparison. */
     rqlParseGe,  /* Greater than or equals comparison. */
     rqlParseLe,  /* Less than or equals comparison. */
+    rqlParseLike, /* SQL wildcard compare. */
 
     rqlParseAnd,     /* An and */
     rqlParseOr,      /* An or */
     };
@@ -134,8 +135,10 @@
     case rqlParseGe:
         return "rqlParseGe";
     case rqlParseLe:
         return "rqlParseLe";
+    case rqlParseLike:
+	return "rqlParseLike";
 
     default:
 	return "rqlParseUnknown";
     }
@@ -414,8 +417,9 @@
 {
 struct rqlParse *l = rqlParseUnaryMinus(tkz);
 struct rqlParse *p = l;
 char *tok = tokenizerNext(tkz);
+boolean forceString = FALSE;
 if (tok != NULL)
     {
     enum rqlParseOp op = rqlParseUnknown;
     if (sameString(tok, "="))
@@ -440,8 +444,13 @@
 	    op = rqlParseGe;
 	else
 	    op = rqlParseLe;
 	}
+    else if (sameString(tok, "like"))
+        {
+	forceString = TRUE;
+	op = rqlParseLike;
+	}
     else
         {
 	tokenizerReuse(tkz);
 	return p;
@@ -451,11 +460,22 @@
     p->op = op;
     p->type = rqlTypeBoolean;
 
     /* Now force children to be the same type, inserting casts if need be. */
+    if (forceString)
+	{
+	if (l->type != rqlTypeString || r->type != rqlTypeString)
+	    {
+	    errAbort("Expecting string type around comparison line %d of %s",
+	    	tkz->lf->lineIx, tkz->lf->fileName);
+	    }
+	}
+    else
+	{
     enum rqlType childType = commonTypeForBop(l->type, r->type);
     l = rqlParseCoerce(l, childType);
     r = rqlParseCoerce(r, childType);
+	}
 
     /* Now hang children onto node. */
     p->children = l;
     l->next = r;
@@ -660,8 +680,23 @@
     }
 return res;
 }
 
+struct rqlEval rqlEvalLike(struct rqlParse *p, struct raRecord *ra)
+/* Return true if r like l . */
+{
+struct rqlParse *lp = p->children;
+struct rqlParse *rp = lp->next;
+struct rqlEval lv = rqlEvalOnRecord(lp, ra);
+struct rqlEval rv = rqlEvalOnRecord(rp, ra);
+struct rqlEval res;
+res.type = rqlTypeBoolean;
+assert(rv.type == rqlTypeString);
+assert(rv.type == lv.type);
+res.val.b = sqlMatchLike(rv.val.s, lv.val.s);
+return res;
+}
+
 struct rqlEval rqlEvalOnRecord(struct rqlParse *p, struct raRecord *ra)
 /* Evaluate self on ra. */
 {
 struct rqlEval res;
@@ -701,8 +736,11 @@
     case rqlParseGe:
         res = rqlEvalLt(p, ra);
 	res.val.b = !res.val.b;
 	break;
+    case rqlParseLike:
+        res = rqlEvalLike(p,ra);
+	break;
 
     /* Type casts. */
     case rqlParseStringToBoolean:
 	res = rqlEvalOnRecord(p->children, ra);