/* rqlEval - evaluate tree returned by rqlParse given a record and function to lookup fields * in the record. . */ #include "common.h" #include "linefile.h" #include "hash.h" #include "dystring.h" #include "localmem.h" #include "tokenizer.h" #include "sqlNum.h" #include "rql.h" static struct rqlEval rqlLocalEval(struct rqlParse *p, void *record, RqlEvalLookup lookup, struct lm *lm); /* Evaluate self on parse tree, allocating memory if needed from lm. */ struct rqlEval rqlEvalCoerceToBoolean(struct rqlEval r) /* Return TRUE if it's a nonempty string or a non-zero number. */ { switch (r.type) { case rqlTypeBoolean: break; /* It's already done. */ case rqlTypeString: r.val.b = (r.val.s != NULL && r.val.s[0] != 0); break; case rqlTypeInt: r.val.b = (r.val.i != 0); break; case rqlTypeDouble: r.val.b = (r.val.x != 0.0); break; default: internalErr(); r.val.b = FALSE; break; } r.type = rqlTypeBoolean; return r; } static struct rqlEval rqlEvalEq(struct rqlParse *p, void *record, RqlEvalLookup lookup, struct lm *lm) /* Return true if two children are equal regardless of children type * (which are just gauranteed to be the same). */ { struct rqlParse *lp = p->children; struct rqlParse *rp = lp->next; struct rqlEval lv = rqlLocalEval(lp, record, lookup, lm); struct rqlEval rv = rqlLocalEval(rp, record, lookup, lm); struct rqlEval res; res.type = rqlTypeBoolean; assert(lv.type == rv.type); switch (lv.type) { case rqlTypeBoolean: res.val.b = (lv.val.b == rv.val.b); break; case rqlTypeString: res.val.b = sameString(lv.val.s, rv.val.s); break; case rqlTypeInt: res.val.b = (lv.val.i == rv.val.i); break; case rqlTypeDouble: res.val.b = (lv.val.x == rv.val.x); break; default: internalErr(); res.val.b = FALSE; break; } return res; } static struct rqlEval rqlEvalLt(struct rqlParse *p, void *record, RqlEvalLookup lookup, struct lm *lm) /* Return true if r < l . */ { struct rqlParse *lp = p->children; struct rqlParse *rp = lp->next; struct rqlEval lv = rqlLocalEval(lp, record, lookup, lm); struct rqlEval rv = rqlLocalEval(rp, record, lookup, lm); struct rqlEval res; res.type = rqlTypeBoolean; switch (lv.type) { case rqlTypeBoolean: res.val.b = (lv.val.b < rv.val.b); break; case rqlTypeString: res.val.b = strcmp(lv.val.s, rv.val.s) < 0; break; case rqlTypeInt: res.val.b = (lv.val.i < rv.val.i); break; case rqlTypeDouble: res.val.b = (lv.val.x < rv.val.x); break; default: internalErr(); res.val.b = FALSE; break; } return res; } static struct rqlEval rqlEvalGt(struct rqlParse *p, void *record, RqlEvalLookup lookup, struct lm *lm) /* Return true if r > l . */ { struct rqlParse *lp = p->children; struct rqlParse *rp = lp->next; struct rqlEval lv = rqlLocalEval(lp, record, lookup, lm); struct rqlEval rv = rqlLocalEval(rp, record, lookup, lm); struct rqlEval res; res.type = rqlTypeBoolean; switch (lv.type) { case rqlTypeBoolean: res.val.b = (lv.val.b > rv.val.b); break; case rqlTypeString: res.val.b = strcmp(lv.val.s, rv.val.s) > 0; break; case rqlTypeInt: res.val.b = (lv.val.i > rv.val.i); break; case rqlTypeDouble: res.val.b = (lv.val.x > rv.val.x); break; default: internalErr(); res.val.b = FALSE; break; } return res; } static struct rqlEval rqlEvalLike(struct rqlParse *p, void *record, RqlEvalLookup lookup, struct lm *lm) /* Return true if r like l . */ { struct rqlParse *lp = p->children; struct rqlParse *rp = lp->next; struct rqlEval lv = rqlLocalEval(lp, record, lookup, lm); struct rqlEval rv = rqlLocalEval(rp, record, lookup, lm); 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; } static struct rqlEval rqlEvalArrayIx(struct rqlParse *p, void *record, RqlEvalLookup lookup, struct lm *lm) /* Handle parse tree generated by an indexed array. */ { struct rqlParse *array = p->children; struct rqlParse *index = array->next; struct rqlEval arrayVal = rqlLocalEval(array, record, lookup, lm); struct rqlEval indexVal = rqlLocalEval(index, record, lookup, lm); struct rqlEval res; res.type = rqlTypeString; res.val.s = emptyForNull(lmCloneSomeWord(lm, arrayVal.val.s, indexVal.val.i)); return res; } static struct rqlEval rqlLocalEval(struct rqlParse *p, void *record, RqlEvalLookup lookup, struct lm *lm) /* Evaluate self on parse tree, allocating memory if needed from lm. */ { struct rqlEval res; switch (p->op) { case rqlOpLiteral: res.val = p->val; res.type = p->type; break; case rqlOpSymbol: res.type = rqlTypeString; char *s = lookup(record, p->val.s); if (s == NULL) res.val.s = ""; else res.val.s = s; break; case rqlOpEq: res = rqlEvalEq(p, record, lookup, lm); break; case rqlOpNe: res = rqlEvalEq(p, record, lookup, lm); res.val.b = !res.val.b; break; /* Inequalities. */ case rqlOpLt: res = rqlEvalLt(p, record, lookup, lm); break; case rqlOpGt: res = rqlEvalGt(p, record, lookup, lm); break; case rqlOpLe: res = rqlEvalGt(p, record, lookup, lm); res.val.b = !res.val.b; break; case rqlOpGe: res = rqlEvalLt(p, record, lookup, lm); res.val.b = !res.val.b; break; case rqlOpLike: res = rqlEvalLike(p,record, lookup, lm); break; /* Logical ops. */ case rqlOpAnd: { res.type = rqlTypeBoolean; res.val.b = TRUE; struct rqlParse *c; for (c = p->children; c != NULL; c= c->next) { struct rqlEval e = rqlLocalEval(c, record, lookup, lm); if (!e.val.b) { res.val.b = FALSE; break; } } break; } case rqlOpOr: { res.type = rqlTypeBoolean; res.val.b = FALSE; struct rqlParse *c; for (c = p->children; c != NULL; c= c->next) { struct rqlEval e = rqlLocalEval(c, record, lookup, lm); if (e.val.b) { res.val.b = TRUE; break; } } break; } case rqlOpNot: res = rqlLocalEval(p->children, record, lookup, lm); res.val.b = !res.val.b; break; /* Type casts. */ case rqlOpStringToBoolean: res = rqlLocalEval(p->children, record, lookup, lm); res.type = rqlTypeBoolean; res.val.b = (res.val.s[0] != 0); break; case rqlOpIntToBoolean: res = rqlLocalEval(p->children, record, lookup, lm); res.type = rqlTypeBoolean; res.val.b = (res.val.i != 0); break; case rqlOpDoubleToBoolean: res = rqlLocalEval(p->children, record, lookup, lm); res.type = rqlTypeBoolean; res.val.b = (res.val.x != 0.0); break; case rqlOpStringToInt: res = rqlLocalEval(p->children, record, lookup, lm); res.type = rqlTypeInt; res.val.i = atoi(res.val.s); break; case rqlOpDoubleToInt: res = rqlLocalEval(p->children, record, lookup, lm); res.type = rqlTypeInt; res.val.i = res.val.x; break; case rqlOpStringToDouble: res = rqlLocalEval(p->children, record, lookup, lm); res.type = rqlTypeDouble; res.val.x = atof(res.val.s); break; case rqlOpBooleanToInt: res = rqlLocalEval(p->children, record, lookup, lm); res.type = rqlTypeInt; res.val.i = res.val.b; break; case rqlOpBooleanToDouble: res = rqlLocalEval(p->children, record, lookup, lm); res.type = rqlTypeDouble; res.val.x = res.val.b; break; case rqlOpIntToDouble: res = rqlLocalEval(p->children, record, lookup, lm); res.type = rqlTypeDouble; res.val.x = res.val.b; break; /* Arithmetical negation. */ case rqlOpUnaryMinusInt: res = rqlLocalEval(p->children, record, lookup, lm); res.val.i = -res.val.i; break; case rqlOpUnaryMinusDouble: res = rqlLocalEval(p->children, record, lookup, lm); res.val.x = -res.val.x; break; case rqlOpArrayIx: res = rqlEvalArrayIx(p, record, lookup, lm); break; default: errAbort("Unknown op %s\n", rqlOpToString(p->op)); res.type = rqlTypeInt; // Keep compiler from complaining. res.val.i = 0; // Keep compiler from complaining. break; } return res; } struct rqlEval rqlEvalOnRecord(struct rqlParse *p, void *record, RqlEvalLookup lookup, struct lm *lm) /* Evaluate parse tree on record, using lm for memory for string operations. */ { return rqlLocalEval(p, record, lookup, lm); }