MySQL/MariaDB plugin does not seem to notice error signals

I’m no expert on this database… I really dislike it, but it’s not my choice… so I’m definitely no expert. I’m trying to throw an exception inside a function, but Xojo is ignoring it. I use a line like:

SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'This is an error.';

And in Xojo will use

db.ExecuteSQL("SELECT function_name();")

And I don’t get a DatabaseException from Xojo. The Xojo code continues, but the database function (correctly) does not complete.

Do I need to raise the exception some other way for Xojo to react?

@Thom_McGrath,

I will confirm, but this is either the database library ignoring signal raised inside functions or an issue with certain versions of MariaDb.

I think what you are attempting is the ‘correct’ modern way using ‘signal’.

DELIMITER //

CREATE FUNCTION GetUserAge(birth_date DATE)
RETURNS INT
DETERMINISTIC
BEGIN
    -- Check if the birth date is in the future
    IF birth_date > CURDATE() THEN
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'Invalid date: Birth date cannot be in the future.';
    END IF;

    RETURN TIMESTAMPDIFF(YEAR, birth_date, CURDATE());
END //

DELIMITER ;

However, If that is not working as expected for you from within Xojo, there is a universal fallback to force a deliberate native database error, which you should be able to catch in Xojo:

DELIMITER //

CREATE FUNCTION DivideNumbers(numerator DECIMAL(10,2), denominator DECIMAL(10,2))
RETURNS DECIMAL(10,2)
DETERMINISTIC
BEGIN
    -- If denominator is zero, force an error to stop execution
    IF denominator = 0 THEN
        -- This will fail immediately and return a native MariaDB error
        TRUNCATE TABLE `ERROR: Cannot divide by zero`;
    END IF;

    RETURN numerator / denominator;
END //

DELIMITER ;

Maybe use something less dramatic than truncate table though…

Then, without trying to sound patronising (you are a far better dev than I am)…

Try
  ' try and run your function
Catch e As DatabaseException
  ' do something with e
End Try

Note in the second case, you still get to set custom error message text.

I hope that helps.

Kind regards, Andrew

Yeah you’ve got exactly the right idea. Catching the error with a try block is precisely what I want to do. But Xojo isn’t firing an exception, so there is nothing to catch.

The workaround I’ve had to use is a useless return value in the executed function. If I get the expected value, I know it worked. If I get null, it must have failed. I can’t get the message, but it’s at least something.

@Thom_McGrath, I tried a few variations inside Functions in MariaDb. All techniques throw errors correctly in Navicat Premium Lite (database client), but are ignored as DatabaseExceptions in Xojo.

So I suggest you convert your Functions (that return a value or values) to Stored Procedures (that return a value or values).

From my example this morning.

DELIMITER //

CREATE PROCEDURE CalculateDiscountProc(
    IN price DECIMAL(10,2), 
    IN discount_pct INT,
    OUT final_price DECIMAL(10,2) -- This parameter returns the value
)
BEGIN
    -- Standard, clean error signaling (No workarounds needed!)
    IF discount_pct > 100 THEN
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'ERROR: Discount percent cannot exceed 100%';
    END IF;

    -- Perform the calculation and assign it to the OUT variable
    SET final_price = price - (price * (discount_pct / 100));
END //

DELIMITER ;

I can’t remember why, but at some stage, I began favouring stored procedures because they reported errors correctly.

Try
  db.ExecuteSQL("CALL CalculateDiscountProc(" + tfAmount.Text + "," + tfDiscount.Text + ",@result)")
  Var rs AS RowSet = db.SelectSQL("SELECT @result")
  TextArea1.Text = rs.ColumnAt(0).StringValue
Catch e As DatabaseException
  TextArea1.Text = e.Message
End Try

You can see the error being caught in the debugger.

Screenshot 2026-09-30 at 4.31.26 pm

At least now you can catch errors as DatabaseExceptions, with roughly the same workflow as Functions.

I hope that helps.

Kind regards, Andrew

Thank you, this is very helpful!

Maybe it works with stored functions instead of stored procs?

So you could do something more direct as:

DELIMITER //

CREATE FUNCTION CalculateDiscountFunc(
    price DECIMAL(10,2), 
    discount_pct INT
)
RETURNS DECIMAL(10,2)
DETERMINISTIC
BEGIN
    -- Standard error signaling works the same way in functions
    IF discount_pct > 100 THEN
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'ERROR: Discount percent cannot exceed 100%';
    END IF;

    -- Perform the calculation and return the value directly
    RETURN price - (price * (discount_pct / 100));
END //

DELIMITER ;

And simpler to use as:

Try

  Var calcParms As String = tfAmount.String + " , " + tfDiscount.String
  Var sql As String = "SELECT CalculateDiscountProc(" + calcParms + ") As result;")

  Var rs AS RowSet = db.SelectSQL(sql)

  TextArea1.Text = rs.ColumnAt(0).StringValue

Catch e As DatabaseException

  TextArea1.Text = e.Message

End Try

And yes, I use Functions to return some special columns I do calculate