[MDEV-21161] Stored aggregate function wrong result in correlated subquery Created: 2019-11-27  Updated: 2023-11-28

Status: Confirmed
Project: MariaDB Server
Component/s: None
Affects Version/s: 10.3.12, 10.3, 10.4, 10.5, 10.6, 10.7, 10.8, 10.9, 10.10
Fix Version/s: 10.4, 10.5, 10.6

Type: Bug Priority: Major
Reporter: Daniele Antonini Assignee: Sergei Petrunia
Resolution: Unresolved Votes: 1
Labels: None
Environment:

Used docker image "mariadb:10.3.12-bionic"



 Description   

/*

CREATE TABLE marks(stud_id INT, grade_count INT);
INSERT INTO marks VALUES (1,6), (2,4), (3,7), (4,5), (5,8), (5,9);
SELECT * FROM marks;

/* I get:

  • 1 6
  • 2 4
  • 3 7
  • 4 5
  • 5 8
  • 5 9
  • Now create the following aggregate function:
    */

DELIMITER //
DROP FUNCTION IF EXISTS aggregate_count //
CREATE AGGREGATE FUNCTION IF NOT EXISTS aggregate_count(x INT) RETURNS INT
BEGIN
DECLARE count_students INT DEFAULT 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND
RETURN count_students;
LOOP
FETCH GROUP NEXT ROW;
IF x THEN
SET count_students = count_students+1;
END IF;
END LOOP;
END //
DELIMITER ;

/* I can use aggregation in my queries as the following: */
select stud_id, aggregate_count(stud_id)
from marks
group by stud_id;
/*

  • as expected I get:
    *
  • 1 1
  • 2 1
  • 3 1
  • 4 1
  • 5 2
    */

/* but when used in a correlated subquery I have wrong result:*/
select t.stud_id, (
select aggregate_count(stud_id)
from marks
where stud_id = t.stud_id
) c
from (
select 1 as stud_id
union select 6
union select 5
) t;

/*

  • I get:
  • 1 1
  • 6 1 <---- wrong
  • 5 2
  • the correct value should be 0.
  • I debug a bit the aggregation function:
    */
    CREATE TABLE debug(msg TEXT);
    DELIMITER //
    DROP FUNCTION IF EXISTS aggregate_count //
    CREATE AGGREGATE FUNCTION IF NOT EXISTS aggregate_count(x INT) RETURNS INT
    BEGIN
    DECLARE count_students INT DEFAULT 0;
    DECLARE CONTINUE HANDLER FOR NOT FOUND
    RETURN count_students;
    LOOP
    FETCH GROUP NEXT ROW;
    IF x THEN
    SET count_students = count_students+1;
    END IF;
    insert into `debug`(msg) VALUES (concat('value: ', ifnull(x, 'null'), " -> count_students: ", count_students));
    END LOOP;
    END //
    DELIMITER ;

select t.stud_id, (
select aggregate_count(stud_id)
from marks
where stud_id = t.stud_id
) c
from (
select 1 as stud_id
union select 6
union select 5
) t;

select * from debug;

/*

  • value: 1 -> count_students: 1
  • value: null -> count_students: 0
  • value: 5 -> count_students: 1
  • value: 5 -> count_students: 2
  • Function seems to be invoked and return the correct value, but query return a wrong value.
    */


 Comments   
Comment by Alice Sherepa [ 2022-12-01 ]

Thank you! I repeated on 10.3-10.10:

CREATE TABLE marks(stud_id INT, grade_count INT);
INSERT INTO marks VALUES (1,6), (2,4), (3,7), (4,5), (5,8), (5,9);
 
DELIMITER //;
CREATE AGGREGATE FUNCTION aggregate_count(x INT) RETURNS INT
BEGIN
DECLARE count_students INT DEFAULT 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND
RETURN count_students;
LOOP
FETCH GROUP NEXT ROW;
IF x THEN
SET count_students = count_students+1;
END IF;
END LOOP;
END //
DELIMITER ;//
 
SELECT t.stud_id, (SELECT aggregate_count(stud_id) FROM marks WHERE stud_id = t.stud_id) c
FROM (SELECT 5 AS stud_id UNION SELECT 6) t;
 
SELECT t.stud_id, (SELECT aggregate_count(stud_id) FROM marks WHERE stud_id = t.stud_id) c
FROM (SELECT 6 AS stud_id UNION SELECT 5) t;

SELECT t.stud_id, (SELECT aggregate_count(stud_id) FROM marks WHERE stud_id = t.stud_id) c
FROM (SELECT 5 AS stud_id UNION SELECT 6) t;
stud_id	c
5	2
6	2
SELECT t.stud_id, (SELECT aggregate_count(stud_id) FROM marks WHERE stud_id = t.stud_id) c
FROM (SELECT 6 AS stud_id UNION SELECT 5) t;
stud_id	c
6	NULL
5	2

Comment by Daniele Antonini [ 2022-12-01 ]

Glad to be helpful

Generated at Thu Feb 08 09:05:02 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.