var_t * exp_eval_operation(exp_t *exp, var_t *mailspec) { var_t *left = NULL, *right = NULL, *copy; exp_operation_t *eo = exp->ex_data; var_t *result = NULL; var_type_t type; /* * Variable assigment */ if (eo->eo_operator == '=') { return exp_assign(eo->eo_operand[0], eo->eo_operand[1], mailspec); } /* * isset operator */ if (eo->eo_operator == IS_SET) { return exp_isset(mailspec, eo->eo_operand[0]); } /* * Do not load unneccessary symbols in boolean operations */ if (eo->eo_operator == AND || eo->eo_operator == OR) { result = exp_bool(mailspec, eo->eo_operator, eo->eo_operand[0], eo->eo_operand[1]); goto exit; } /* * Load left operand */ left = exp_eval(eo->eo_operand[0], mailspec); /* * ! operator */ if (eo->eo_operator == '!') { return exp_not(left); } /* * Hack: IS_NULL operator */ if (eo->eo_operator == IS_NULL) { result = exp_is_null(left); goto exit; } /* * Evaluate right operand */ if (eo->eo_operand[1]) { right = exp_eval(eo->eo_operand[1], mailspec); } switch(eo->eo_operator) { // Comparator case '<': case '>': case LE: case GE: case EQ: case NE: result = exp_compare(eo->eo_operator, left, right); goto exit; // Regex case '~': case NR: result = exp_eval_regex(eo->eo_operator, left, right); goto exit; // In case IN: result = exp_eval_in(left, right); goto exit; // Address prefix operator case '/': if (left == NULL || right == NULL) { break; } if (!(left->v_type == VT_ADDR && right->v_type == VT_INT)) { break; } result = exp_addr_prefix(left, right); goto exit; default: break; } // Math operators need left and right to be set if (left == NULL || right == NULL) { result = EXP_EMPTY; goto exit; } // Make sure we work with the same types if (left->v_type != right->v_type) { /* * The biggest type has precedence (see exp.h) * STRING > FLOAT > INT */ type = VAR_MAX_TYPE(left, right); if (type == left->v_type) { copy = var_cast_copy(type, right); } else { copy = var_cast_copy(type, left); } if (copy == NULL) { log_error("exp_eval_operation: var_cast_copy " "failed"); goto exit; } if (type == left->v_type) { exp_free(right); right = copy; right->v_flags |= VF_EXP_FREE; } else { exp_free(left); left = copy; left->v_flags |= VF_EXP_FREE; } } switch (left->v_type) { case VT_INT: result = exp_math_int(eo->eo_operator, left, right); break; case VT_FLOAT: result = exp_math_float(eo->eo_operator, left, right); break; case VT_STRING: result = exp_math_string(eo->eo_operator, left, right); break; default: log_error("exp_eval_operation: bad type"); goto exit; } exit: if (left) { exp_free(left); } if (right) { exp_free(right); } return result; }
sql_exp * exp_copy( sql_allocator *sa, sql_exp * e) { sql_exp *l, *r, *r2, *ne = NULL; switch(e->type){ case e_column: ne = exp_column(sa, e->l, e->r, exp_subtype(e), e->card, has_nil(e), is_intern(e)); ne->flag = e->flag; break; case e_cmp: if (e->flag == cmp_or) { list *l = exps_copy(sa, e->l); list *r = exps_copy(sa, e->r); if (l && r) ne = exp_or(sa, l,r); } else if (e->flag == cmp_in || e->flag == cmp_notin || get_cmp(e) == cmp_filter) { sql_exp *l = exp_copy(sa, e->l); list *r = exps_copy(sa, e->r); if (l && r) { if (get_cmp(e) == cmp_filter) ne = exp_filter(sa, l, r, e->f, is_anti(e)); else ne = exp_in(sa, l, r, e->flag); } } else { l = exp_copy(sa, e->l); r = exp_copy(sa, e->r); if (e->f) { r2 = exp_copy(sa, e->f); if (l && r && r2) ne = exp_compare2(sa, l, r, r2, e->flag); } else if (l && r) { ne = exp_compare(sa, l, r, e->flag); } } break; case e_convert: l = exp_copy(sa, e->l); if (l) ne = exp_convert(sa, l, exp_fromtype(e), exp_totype(e)); break; case e_aggr: case e_func: { list *l = e->l, *nl = NULL; if (!l) { return e; } else { nl = exps_copy(sa, l); if (!nl) return NULL; } if (e->type == e_func) ne = exp_op(sa, nl, e->f); else ne = exp_aggr(sa, nl, e->f, need_distinct(e), need_no_nil(e), e->card, has_nil(e)); break; } case e_atom: if (e->l) ne = exp_atom(sa, e->l); else if (!e->r) ne = exp_atom_ref(sa, e->flag, &e->tpe); else ne = exp_param(sa, e->r, &e->tpe, e->flag); break; case e_psm: if (e->flag == PSM_SET) ne = exp_set(sa, e->name, exp_copy(sa, e->l), GET_PSM_LEVEL(e->flag)); break; } if (ne && e->p) ne->p = prop_copy(sa, e->p); if (e->name) exp_setname(sa, ne, exp_find_rel_name(e), exp_name(e)); return ne; }