Search code examples
mysqlstored-proceduresmysql-error-1064

Debuggin mySQL syntax error in stored procedure


I am redirecting this file into mysql promt to add a stored procedure:

DROP PROCEDURE IF EXISTS make_transaction;

DELIMITER //

CREATE PROCEDURE make_transaction(IN v_quote_id INT, IN v_your_id INT)
BEGIN

    DECLARE v_is_seller BOOLEAN;
    DECLARE v_option_type BOOLEAN;
    DECLARE v_trader_id INT;
    DECLARE v_premium DOUBLE(18, 4);
    DECLARE v_offer_expires DATETIME;
    DECLARE v_instrument_id INT;

    DECLARE v_pretend_now DATETIME;

    DECLARE v_buyer_id INT;
    DECLARE v_seller_id INT;

    DECLARE v_buyer_total_balance DOUBLE(18, 4);

    SELECT
        instrument_id,
        trader_type,
        option_type,
        trader_id,
        premium,
        offer_expires
    INTO
        v_instrument_id,
        v_is_seller,
        v_option_type,
        v_trader_id,
        v_premium,
        v_offer_expires
    FROM
        option_quotes
    WHERE
        quote_id = v_quote_id;

    IF v_is_seller THEN
        SET v_seller_id = v_trader_id;
        SET v_buyer_id = v_your_id;
    ELSE
        SET v_buyer_id = v_trader_id;
        SET v_seller_id = v_your_id;
    END IF;


    -- Last STOCK_TRADE time is assumed to be the current time
    SELECT DATE_TIME
    INTO v_pretend_now
    FROM STOCK_TRADE
    WHERE INSTRUMENT_ID=v_instrument_id
    ORDER BY DATE_TIME DESC
    LIMIT 1;


    SELECT total_balance
    INTO v_buyer_total_balance
    FROM traders
    WHERE trader_id=v_buyer_id;


    IF offer_expires <= v_pretend_now THEN
        SELECT 'That offer has expired';
    ELSE IF v_buyer_total_balance < v_premium THEN
        SELECT 'You do not have enough money to transact on this offering';
    ELSE
        INSERT INTO option_transactions
        (
            transaction_time,
            quote_id,
            buyer_id,
            seller_id,
            buyer_gain,
            seller_gain
        )
        VALUES
        (
            v_pretend_now,
            v_quote_id,
            v_buyer_id,
            v_seller_id,
            NULL, -- line 85
            NULL
        );
    END IF;
END //

DELIMITER ;

The error I am receiving trying to enter the stored procedure into db:

ERROR 1064 (42000) at line 5: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 85

The option_transactions table looks like this:

+------------------+--------------+------+-----+---------+-------+
| Field            | Type         | Null | Key | Default | Extra |
+------------------+--------------+------+-----+---------+-------+
| quote_id         | int(11)      | NO   | MUL | NULL    |       |
| buyer_id         | int(11)      | NO   | MUL | NULL    |       |
| seller_id        | int(11)      | NO   | MUL | NULL    |       |
| transaction_time | datetime     | NO   |     | NULL    |       |
| buyer_gain       | double(18,4) | YES  |     | NULL    |       |
| seller_gain      | double(18,4) | YES  |     | NULL    |       |
+------------------+--------------+------+-----+---------+-------+

I am new at mySQL, but the insert into command near line 85 appears correct in syntax to me, I am not sure where the problem is. How may I fix this?

(mysql server version 5.5.42)


Solution

  • Line 85 is not in the middle of your INSERT statement, it's at the end of the CREATE PROCEDURE statement. If I paste your code into vim and :se nu to show line numbers, and then I delete the initial lines before CREATE PROCEDURE, the last line is line 85:

    84     END IF;
    85 END //
    86
    87 DELIMITER ;
    

    So the line numbers in the error start counting from the first line of the statement, not the first line of the SQL script file.

    Then I went looking and found an imbalanced blocks:

    IF offer_expires <= v_pretend_now THEN
    ELSE IF v_buyer_total_balance < v_premium THEN
    ELSE
    END IF;
    

    You used a nested IF/THEN/ELSE/END IF inside an ELSE. So you actually have two IF statements, but only one END IF.

    To fix this, you have two options:

    1. Make it one IF statement with an ELSIF:

      IF offer_expires <= v_pretend_now THEN
      ELSEIF v_buyer_total_balance < v_premium THEN
      ELSE
      END IF;
      

      See https://dev.mysql.com/doc/refman/5.7/en/if.html for docs on the syntax of IF/THEN/ELSIF/ELSE/END IF.

    2. Finish both IF statements:

      IF offer_expires <= v_pretend_now THEN
      ELSE
          IF v_buyer_total_balance < v_premium THEN
          ELSE
          END IF;
      END IF;