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\r\n\t') = 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 ;

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM