zoukankan      html  css  js  c++  java
  • MySql执行动态表达式函数

    执行动态的字符串表达式

    1.支持加(+)、减(-)、乘(*)、除(/)、与(&&)、或(||)、非(!)、等于(=)、不等于(!= <>)、大于(>)、大于等于(>=)、小于(<)、小于等于(<=)

    2.非的优先级高于其他运算符,其他运算符优先级相同,可以通过括号来控制运算的先后顺序

    3.除运算符、括号、空格外,只能包含数字和小数点

    /*二目运算*/
    DROP FUNCTION compute;
    DELIMITER $$
    CREATE FUNCTION compute(v1 DOUBLE, o CHAR(2), v2 DOUBLE) RETURNS DOUBLE
    BEGIN
        IF(o = '+')
        THEN
            RETURN v1 + v2;
        ELSEIF(o = '-')
        THEN
            RETURN v1 - v2;
        ELSEIF(o = '*')
        THEN
            RETURN v1 * v2;
        ELSEIF(o = '/')
        THEN
            RETURN v1 / v2;
        ELSEIF(o = '=')
        THEN
            RETURN v1 = v2;
        ELSEIF(o = '!=')
        THEN
            RETURN v1 != v2;
        ELSEIF(o = '&&')
        THEN
            RETURN v1 AND v2;
        ELSEIF(o = '||')
        THEN
            RETURN v1 OR v2;
        ELSEIF(o = '>')
        THEN
            RETURN v1 > v2;
        ELSEIF(o = '>=')
        THEN
            RETURN v1 >= v2;
        ELSEIF(o = '<')
        THEN
            RETURN v1 < v2;
        ELSEIF(o = '<=')
        THEN
            RETURN v1 <= v2;
        ELSE
            RETURN 0;
        END IF;
    END;
    $$
    DELIMITER ;
    
    
    
    /*执行表达式*/
    DROP FUNCTION eval;
    DELIMITER $$
    CREATE FUNCTION eval(express VARCHAR(2000)) RETURNS DOUBLE
    BEGIN
        DECLARE hasValue TINYINT;
        DECLARE r DOUBLE;/*结果*/
        DECLARE l INT;
        DECLARE i INT;
        DECLARE lt INT;/*临时*/
        DECLARE it INT;/*临时*/
        DECLARE c CHAR;/*当前字符*/
        DECLARE t CHAR;/*双字操作符前一个字符*/
        DECLARE tt VARCHAR(200); /*临时*/
        DECLARE o VARCHAR(20); /*操作符*/
        DECLARE v VARCHAR(20); /**/
        DECLARE v1 DOUBLE;/*结果*/
        DECLARE v2 DOUBLE;/*结果*/
    
        DECLARE stack VARCHAR(4000); /*堆栈*/
        /*DECLARE _log VARCHAR(2000);*/ /*临时*/
        
        DECLARE fc INT;/*搜索括号计数*/
        DECLARE fi INT;/*搜索括号指针*/
        SET r = 0;
        SET hasValue = 0;
    
        SET l = LENGTH(express);
        SET i = 1;
        SET t = '';
        SET v = '';
        SET o = '';
        set stack = '';
        /*set _log = '';*/
    
        _loop : LOOP
            IF(i > l)
            THEN
                SET c = '';
            ELSE
                SET tt = SUBSTRING(express, i, 1);
                SET c = if(tt = ' ', 'S', tt);
            END IF;
            /*set _log = concat(_log, ',char:[', c,',', v,']');*/
            IF(c = '')
            THEN /*表达式结束*/
                IF(v != '')
                THEN
                    SET v2 = v;
                    set v = '';
                    IF (o != '')
                    THEN
                        IF (hasValue = 0)
                        THEN
                            IF (o = '-')
                            THEN
                                SET r = -v2;
                            ELSE
                                /*无前操作数*/
                                /*set _log = concat(_log, ',no v1');*/
                                set r = NULL;
                                set i = l + 1;
                            END IF;
                            SET hasValue = 1;
                        ELSE
                            SET r = compute(r, o, v2);
                        END IF;
                    ELSEIF (hasValue = 0)
                    THEN
                        SET r = v2;
                        SET hasValue = 1;
                    ELSE
                        /*无操作符*/
                        set r = NULL;
                        set i = l + 1;
                    END IF;
                ELSEIF (o != '' OR t = '!' OR t = '<' OR t = '' OR t = '&' OR t = '|')
                THEN
                    /*无后操作数或操作符不全*/
                    /*set _log = concat(_log, ',error operator');*/
                    set r = NULL;
                    set i = l + 1;
                END IF;
            ELSEIF (c = ')')
            THEN
                /*未匹配的右括号*/
                set r = NULL;
                set i = l + 1;
            ELSE        
                IF (v != '' AND LOCATE(c,'0123456789.') = 0)
                THEN
                    /*set _log = concat(_log, ',charEnd:[', v,']');*/
                    /*数字结束*/
                    SET v2 = v;
                    set v = '';
                    IF (o != '')
                    THEN
                        IF (hasValue = 0)
                        THEN
                            IF (o = '-')
                            THEN
                                SET r = -v2;
                            ELSE
                                /*无前操作数*/
                                /*set _log = concat(_log, ',no v1');*/
                                set r = NULL;
                                set i = l + 1;
                            END IF;
                            SET hasValue = 1;
                        ELSE
                            SET r = compute(r, o, v2);
                        END IF;
                        SET o = '';
                    ELSEIF (hasValue = 0)
                    THEN
                        SET r = v2;
                        SET hasValue = 1;
                    ELSE
                        /*无操作符*/
                        /*set _log = concat(_log, ',no operator');*/
                        set r = NULL;
                        set i = l + 1;
                    END IF;
                END IF;
    
                if(i <= l)
                then                
                    IF (t = '!' AND c != '=' OR t = '<' AND c != '>' AND c != '=' OR t = '>' AND c != '=') /*非、大于、小于*/
                    THEN
                        
                        /*set _log = concat(_log, ',check !><');*/
                        if(o != '' and t != '!')
                        then
                            /*多余的操作数*/
                            /*set _log = concat(_log, ',otiose operator[',o,']');*/
                            set r = NULL;
                            set i = l + 1;
                        else
                            /*搜索下一个表达式或者值*/
                            SET fc = 0;
                            SET fi = i;
                            SET tt = '';
                            SET v = '';
                            WHILE (fi <= l AND (tt = '' OR fc > 0))
                            DO
                                SET c = SUBSTRING(express,fi, 1);
                                IF (c = '(')
                                THEN
                                    SET tt = '(';
                                    SET fc = fc + 1;
                                ELSEIF (c = ')')
                                THEN
                                    SET fc = fc - 1;
                                ELSEIF (tt = '' AND LOCATE(c, '0123456789.'))
                                THEN
                                    SET tt = '0';
                                    SET fc = 1;
                                ELSEIF (tt = '0' AND LOCATE(c, '0123456789.') = 0)
                                THEN
                                    SET fc = 0;
                                    SET fi = fi - 1;
                                END IF;
                                SET fi = fi + 1;
                            END WHILE;
    
                            IF (fc = 0 OR tt = '0')
                            THEN
                                /*当前状态入栈,并初始化变量*/
                                set stack = concat(stack ,'$',hasValue,',',ifnull(r, ''),',',o,',',t,',',l,',',fi);
                                /*set _log = concat(_log, ',not:',substring(express, i, fi - i), ',push:[',hasValue,',',ifnull(r, ''),',',o,',',t,',',l,',',fi,']');*/
                                set i = i;
                                set l = fi - 1;
                                set hasValue = 0;
                                set r = 0;
                                set t = '';
                                SET o = '';
                                set v = '';
    
                                /*开始新的循环*/
                                ITERATE _loop;
                            ELSE
                                /*没有找到操作数*/
                                /*set _log = concat(_log, ',no value');*/
                                set r = NULL;
                                set i = l + 1;
                            END IF;
                        END if;
                    ELSEIF (c = '(')
                    THEN
                        /*寻找匹配的)*/
                        SET fc = 1;
                        SET i = i + 1;
                        SET fi = i;
                        WHILE (fi <= l AND fc > 0)
                        DO
                            SET c = SUBSTRING(express,fi, 1);
                            IF (c = '(')
                            THEN
                                SET fc = fc + 1;
                            ELSEIF (c = ')')
                            THEN
                                SET fc = fc - 1;
                            END IF;
                            SET fi = fi + 1;
                        END WHILE;
    
                        IF (fc = 0)
                        THEN
                            
                            /*当前状态入栈,并初始化变量*/
                            set stack = concat(stack ,'$',hasValue,',',ifnull(r, ''),',',o,',','',',',l,',',fi);
                            /*set _log = concat(_log, ',sub:',substring(express, i, fi - 1 - i), ',push:[',hasValue,',',ifnull(r, ''),',',o,',',t,',',l,',',fi,']');*/
                            set i = i;
                            set l = fi - 2;
                            set hasValue = 0;
                            set r = 0;
                            set t = '';
                            SET o = '';
                            set v = '';
    
                            /*开始新的循环*/
                            ITERATE _loop;
                        ELSE /*没有找到匹配的右括号*/                        
                            /*set _log = concat(_log, ',no )');*/
                            set r = NULL;/*无操作符*/
                            set i = l + 1;
                        END IF;
                    ELSEIF (LOCATE(c, '0123456789.') > 0)
                    THEN
                        /*找到数字*/
                        IF (v = '')
                        THEN
                            /*set _log = concat(_log, ',char:',c);*/
                            SET v = c;
                        ELSE
                            /*set _log = concat(_log, ',concat:',c);*/
                            SET v = CONCAT(v, c);
                        END IF;
                    ELSEIF(LOCATE(c,'!<>|&=+-*/'))
                    THEN
                        SET tt = '';
                        IF (t = '!' AND c = '=')
                        THEN
                            SET tt = '!=';
                        ELSEIF (t = '<' AND c = '>')
                        THEN
                            SET tt = '!=';
                        ELSEIF (t = '|' AND c = '|')
                        THEN
                            SET tt = '||';
                        ELSEIF (t = '&' AND c = '&')
                        THEN
                            SET tt = '&&';
                        ELSEIF (t = '' AND c = '=')
                        THEN
                            SET tt = '=';
                        ELSEIF (t = '>' AND c = '=')
                        THEN
                            SET tt = '>=';
                        ELSEIF (t = '<' AND c = '=')
                        THEN
                            SET tt = '<=';
                        ELSEIF (t = '' AND c = '+')
                        THEN
                            SET tt = '+';
                        ELSEIF (t = '' AND c = '-')
                        THEN
                            SET tt = '-';
                        ELSEIF (t = '' AND c = '*')
                        THEN
                            SET tt = '*';
                        ELSEIF (t = '' AND c = '/')
                        THEN
                            SET tt = '/';
                        END IF;
    
                        IF (o != '' AND tt != '')
                        THEN
                            /*set _log = concat(_log, ',otiose operator');*/
                            set r = NULL; /*多个操作符*/
                            set i = l + 1;
                        ELSEIF (tt != '')
                        THEN
                            SET o = tt;
                            SET t = '';
                        ELSEIF (c = '!' OR c = '<' OR c = '>' OR c = '&' OR c = '|')
                        THEN
                            IF(t = '')
                            THEN
                                SET t = c;
                            ELSE
                                /*set _log = concat(_log, ',no operator');*/
                                set r = NULL; /*错误的操作符*/
                                set i = l + 1;
                            END IF;
                        END IF;
                    ELSEIF(LOCATE(c, ' S
    	') = 0)
                    THEN
                        /*set _log = concat(_log, ',error char');*/
                        set r = NULL; /*无效字符*/
                        set i = l + 1;
                    END IF;
                END IF;
            END IF;
    
            SET i = i + 1;
            if(i > l + 1)
            then
                if (stack != '') /*堆栈未空,返回上一层*/
                then
                    set l = 0;
                    repeat
                        set l = locate('$',stack, l + 1);
                        if(l != 0)
                        then
                            set i = l;
                        end if;
                    until l = 0 end repeat;
    
                    set tt = substring(stack, i + 1);
                    set stack = substring(stack, 1, i - 1);
                    /*set _log = concat(_log, ',pop:[', tt,'],stack:[',stack,']');*/
                    /*恢复上一层环境,并计算 concat('$',hasValue,',',v1,',',o,',',t,',',l,',',fi - 1);*/
                    set i = 1;
                    set it = 1;
                    set lt = 0;
                    repeat
                        set lt = locate(',',tt, lt + 1);
                        if(i = 1)
                        then
                            set hasValue = substring(tt, it, lt - it);
                        elseif(i = 2)
                        then
                            set v1 = substring(tt, it, lt - it);
                        elseif(i = 3)
                        then
                            set o = substring(tt, it, lt - it);
                        elseif(i = 4)
                        then
                            set t = substring(tt, it, lt - it);
                        elseif(i = 5)
                        then
                            set l = substring(tt, it, lt - it);
                        elseif(i = 6)
                        then
                            set i = substring(tt, it);
                        end if;
    
                        if(lt != 0)
                        then
                            set it = lt + 1;
                            set i = i + 1;
                        end if;
                    until lt = 0 end repeat;
    
                    /*set _log = concat(_log, ',parse:[',hasValue,',',v1,',',o,',',t,',',l,',',i,']');*/
    
                    if(t = '!')
                    then
                        set r = not r;
                    elseif(t != '')
                    then
                        set o = t;
                    end if;
                    set t = '';
    
                    IF (o != '')
                    THEN
                        IF (hasValue = 0)
                        THEN
                            IF (o = '-')
                            THEN
                                SET r = -r;
                            ELSE
                                SET r = NULL;
                            END IF;
                            SET hasValue = 1;
                        ELSE
                            SET r = compute(v1, o, r);
                        END IF;
                        SET o = '';
                    ELSEIF (hasValue = 0)
                    THEN
                        SET hasValue = 1;
                    ELSE
                        /*无操作符*/
                        set r = NULL;
                        set i = l + 1;
                    END IF;
                    /*set _log = concat(_log, ',r=', ifnull(r, 'null'));*/
                else
                    LEAVE _loop;
                end if;
            end if;
        END LOOP;
        
        /*set _log = concat('r=',ifnull(r, 'null'),_log);*/
            RETURN r;
    END;
    $$
    DELIMITER ;
  • 相关阅读:
    WPF TextBox 一些设置技巧
    Rust 初始配置
    Framework​Element.​Find​Name 根据名字查找控件
    C# SQLite 数据库操作
    MP3 信息读取
    C# event 事件学习
    Nginx 整合 Lua 实现动态生成缩略图
    Spring Cloud 入门 之 Config 篇(六)
    Spring Cloud 入门 之 Zuul 篇(五)
    Flyway 简单入门教程
  • 原文地址:https://www.cnblogs.com/freewing/p/5784154.html
Copyright © 2011-2022 走看看