Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions client/mysql.cc
Original file line number Diff line number Diff line change
Expand Up @@ -914,6 +914,7 @@ static COMMANDS commands[] = {
{ "ADDTIME", 0, 0, 0, ""},
{ "AES_ENCRYPT", 0, 0, 0, ""},
{ "AES_DECRYPT", 0, 0, 0, ""},
{ "ANY_VALUE", 0, 0, 0, ""},
{ "AREA", 0, 0, 0, ""},
{ "ASIN", 0, 0, 0, ""},
{ "ASBINARY", 0, 0, 0, ""},
Expand Down
170 changes: 170 additions & 0 deletions mysql-test/main/any_value.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
#
# MDEV-10426: ANY_VALUE function
#
CREATE TABLE t0 (a INT, b INT);
CREATE TABLE t1 (a INT, b INT);
CREATE TABLE t2 (a INT, b INT);
CREATE TABLE t3 (c INT, d INT);
CREATE TABLE t4 (x INT, y INT, z INT);
CREATE TABLE t5 (x INT, y INT, INDEX idx (y, x));
CREATE TABLE t6 (x INT, y CHAR(1), z INT);
INSERT INTO t0 VALUES (NULL,10),(NULL,10),(NULL,20),(NULL,20),(NULL,30);
INSERT INTO t1 VALUES (NULL,NULL),(NULL,NULL),(NULL,NULL);
INSERT INTO t2 VALUES (1,10),(2,10),(NULL,20),(3,20),(NULL,30),(4,40);
INSERT INTO t3 VALUES (1,100),(2,200),(3,300);
INSERT INTO t4 VALUES (1,10,10),(2,10,10),(3,20,20),(4,20,20),(5,30,30);
INSERT INTO t5 VALUES (1,10),(2,10),(3,20),(4,20),(5,30);
INSERT INTO t6 VALUES (1,'a',1),(1,'a',2),(1,'b',3),(1,'b',4),(2,'a',5),(2,'a',6),(2,'b',7);
SET @save_sql_mode=@@sql_mode;
SET SQL_MODE='';
SELECT ANY_VALUE(b) FROM t2;
ANY_VALUE(b)
10
SELECT b, a FROM t2 GROUP BY b;
b a
10 1
20 NULL
30 NULL
40 4
SELECT b, ANY_VALUE(a) FROM t2 GROUP BY b;
b ANY_VALUE(a)
10 1
20 NULL
30 NULL
40 4
SET SQL_MODE=ONLY_FULL_GROUP_BY;
SELECT ANY_VALUE(b) FROM t0;
ANY_VALUE(b)
10
SELECT ANY_VALUE(b) FROM t2;
ANY_VALUE(b)
10
SELECT COUNT(*), ANY_VALUE(b) FROM t2;
COUNT(*) ANY_VALUE(b)
6 10
SELECT c FROM t3 WHERE ANY_VALUE(d) = 200;
ERROR HY000: Invalid use of group function
SELECT ANY_VALUE(b) FROM t0 GROUP BY b;
ANY_VALUE(b)
10
20
30
SELECT ANY_VALUE(a), b FROM t2 GROUP BY b;
ANY_VALUE(a) b
1 10
NULL 20
NULL 30
4 40
SELECT ANY_VALUE(b) FROM t2 GROUP BY b;
ANY_VALUE(b)
10
20
30
40
SELECT b, ANY_VALUE(a + 100) FROM t2 GROUP BY b;
b ANY_VALUE(a + 100)
10 101
20 NULL
30 NULL
40 104
SELECT b, ANY_VALUE(a * 2 + b) FROM t2 GROUP BY b;
b ANY_VALUE(a * 2 + b)
10 12
20 NULL
30 NULL
40 48
SELECT y, ANY_VALUE(x + z) FROM t4 GROUP BY y;
y ANY_VALUE(x + z)
10 11
20 23
30 35
SELECT ANY_VALUE(a) FROM t0;
ANY_VALUE(a)
NULL
SELECT b, ANY_VALUE(a) FROM t0 GROUP BY b;
b ANY_VALUE(a)
10 NULL
20 NULL
30 NULL
SELECT COUNT(*), ANY_VALUE(a) FROM t0;
COUNT(*) ANY_VALUE(a)
5 NULL
SELECT b, COUNT(*), ANY_VALUE(a) FROM t0 GROUP BY b;
b COUNT(*) ANY_VALUE(a)
10 2 NULL
20 2 NULL
30 1 NULL
SELECT ANY_VALUE(a), ANY_VALUE(b) FROM t1;
ANY_VALUE(a) ANY_VALUE(b)
NULL NULL
SELECT COUNT(*), ANY_VALUE(a) FROM t1;
COUNT(*) ANY_VALUE(a)
3 NULL
SELECT a, ANY_VALUE(b) FROM t1 GROUP BY a;
a ANY_VALUE(b)
NULL NULL
SELECT y, ANY_VALUE(x) FROM t5 GROUP BY y;
y ANY_VALUE(x)
10 1
20 3
30 5
EXPLAIN SELECT y, ANY_VALUE(x) FROM t5 GROUP BY y;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t5 index NULL idx 10 NULL 5 Using index
SELECT b, (SELECT SUM(t3.d) + SUM(t2.a) FROM t3) AS sub FROM t2 GROUP BY b;
b sub
10 603
20 603
30 NULL
40 604
SELECT b, (SELECT SUM(t3.d) + ANY_VALUE(t2.a) FROM t3) AS sub FROM t2 GROUP BY b;
b sub
10 601
20 NULL
30 NULL
40 604
SELECT y, ANY_VALUE(z) FROM t4 GROUP BY y HAVING ANY_VALUE(z) = 20;
y ANY_VALUE(z)
20 20
SELECT x, y, ANY_VALUE(z) FROM t6 GROUP BY x, y WITH ROLLUP;
x y ANY_VALUE(z)
1 a 1
1 b 3
1 NULL 1
2 a 5
2 b 7
2 NULL 5
NULL NULL 1
SELECT x, y, ANY_VALUE(x) OVER (PARTITION BY y) AS w FROM t4 ORDER BY x;
x y w
1 10 1
2 10 1
3 20 3
4 20 3
5 30 5
SELECT x, y, ANY_VALUE(x) OVER () AS w FROM t4 ORDER BY x;
x y w
1 10 1
2 10 1
3 20 1
4 20 1
5 30 1
SELECT x, y, ANY_VALUE(z) OVER (PARTITION BY y ORDER BY x) AS w FROM t4 ORDER BY x;
x y w
1 10 10
2 10 10
3 20 20
4 20 20
5 30 30
DROP TABLE t0,t1,t2,t3,t4,t5,t6;
CREATE TABLE t (a CHAR CHARACTER SET latin2);
INSERT INTO t VALUES ('a'),('b');
SELECT charset(ANY_VALUE(a)), collation(ANY_VALUE(a)) FROM t;
charset(ANY_VALUE(a)) collation(ANY_VALUE(a))
latin2 latin2_general_ci
SELECT coercibility(ANY_VALUE(a)), coercibility(ANY_VALUE('x')) FROM t;
coercibility(ANY_VALUE(a)) coercibility(ANY_VALUE('x'))
2 6
DROP TABLE t;
SET sql_mode=@save_sql_mode;
# End of 13.1 tests.
115 changes: 115 additions & 0 deletions mysql-test/main/any_value.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
--echo #
--echo # MDEV-10426: ANY_VALUE function
--echo #

CREATE TABLE t0 (a INT, b INT);
Comment thread
jaeheonshim marked this conversation as resolved.
CREATE TABLE t1 (a INT, b INT);
CREATE TABLE t2 (a INT, b INT);
CREATE TABLE t3 (c INT, d INT);
CREATE TABLE t4 (x INT, y INT, z INT);
CREATE TABLE t5 (x INT, y INT, INDEX idx (y, x));
CREATE TABLE t6 (x INT, y CHAR(1), z INT);
INSERT INTO t0 VALUES (NULL,10),(NULL,10),(NULL,20),(NULL,20),(NULL,30);
INSERT INTO t1 VALUES (NULL,NULL),(NULL,NULL),(NULL,NULL);
INSERT INTO t2 VALUES (1,10),(2,10),(NULL,20),(3,20),(NULL,30),(4,40);
INSERT INTO t3 VALUES (1,100),(2,200),(3,300);
INSERT INTO t4 VALUES (1,10,10),(2,10,10),(3,20,20),(4,20,20),(5,30,30);
INSERT INTO t5 VALUES (1,10),(2,10),(3,20),(4,20),(5,30);
INSERT INTO t6 VALUES (1,'a',1),(1,'a',2),(1,'b',3),(1,'b',4),(2,'a',5),(2,'a',6),(2,'b',7);

SET @save_sql_mode=@@sql_mode;
SET SQL_MODE='';

SELECT ANY_VALUE(b) FROM t2;

SELECT b, a FROM t2 GROUP BY b;
SELECT b, ANY_VALUE(a) FROM t2 GROUP BY b;

SET SQL_MODE=ONLY_FULL_GROUP_BY;

#
# Without GROUP BY
#

SELECT ANY_VALUE(b) FROM t0;
SELECT ANY_VALUE(b) FROM t2;

# Mixing real aggregate function
SELECT COUNT(*), ANY_VALUE(b) FROM t2;

# In WHERE
--error ER_INVALID_GROUP_FUNC_USE
SELECT c FROM t3 WHERE ANY_VALUE(d) = 200;

#
# With GROUP BY
#

SELECT ANY_VALUE(b) FROM t0 GROUP BY b;

# Regular use in SELECT-list
SELECT ANY_VALUE(a), b FROM t2 GROUP BY b;
SELECT ANY_VALUE(b) FROM t2 GROUP BY b;

# Expression inside ANY_VALUE
SELECT b, ANY_VALUE(a + 100) FROM t2 GROUP BY b;
SELECT b, ANY_VALUE(a * 2 + b) FROM t2 GROUP BY b;
SELECT y, ANY_VALUE(x + z) FROM t4 GROUP BY y;

#
# NULL handling
#

SELECT ANY_VALUE(a) FROM t0;
SELECT b, ANY_VALUE(a) FROM t0 GROUP BY b;

SELECT COUNT(*), ANY_VALUE(a) FROM t0;
SELECT b, COUNT(*), ANY_VALUE(a) FROM t0 GROUP BY b;

SELECT ANY_VALUE(a), ANY_VALUE(b) FROM t1;
SELECT COUNT(*), ANY_VALUE(a) FROM t1;

SELECT a, ANY_VALUE(b) FROM t1 GROUP BY a;

# Table with index on GROUP BY column
SELECT y, ANY_VALUE(x) FROM t5 GROUP BY y;
EXPLAIN SELECT y, ANY_VALUE(x) FROM t5 GROUP BY y;

# Correlated subquery
SELECT b, (SELECT SUM(t3.d) + SUM(t2.a) FROM t3) AS sub FROM t2 GROUP BY b;

SELECT b, (SELECT SUM(t3.d) + ANY_VALUE(t2.a) FROM t3) AS sub FROM t2 GROUP BY b;

# In HAVING
SELECT y, ANY_VALUE(z) FROM t4 GROUP BY y HAVING ANY_VALUE(z) = 20;

# Rollup
SELECT x, y, ANY_VALUE(z) FROM t6 GROUP BY x, y WITH ROLLUP;

#
# As a window function
#

SELECT x, y, ANY_VALUE(x) OVER (PARTITION BY y) AS w FROM t4 ORDER BY x;
SELECT x, y, ANY_VALUE(x) OVER () AS w FROM t4 ORDER BY x;
SELECT x, y, ANY_VALUE(z) OVER (PARTITION BY y ORDER BY x) AS w FROM t4 ORDER BY x;

DROP TABLE t0,t1,t2,t3,t4,t5,t6;

#
# Charset/Collation/Coercibility Tests
#

CREATE TABLE t (a CHAR CHARACTER SET latin2);
INSERT INTO t VALUES ('a'),('b');

# Charset/Collation preserved

SELECT charset(ANY_VALUE(a)), collation(ANY_VALUE(a)) FROM t;
SELECT coercibility(ANY_VALUE(a)), coercibility(ANY_VALUE('x')) FROM t;

DROP TABLE t;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This all seems fine so far.
Bonus points, consider this

create table t1 (a int, b int, index(a));
insert into t1 values (1, 1), (1, 2), (2, 3);
select a, any_value(b) from t1 group by a;

does the row t1(a,b) = (1,2) need to read by the engine/handler?
Is it?
There is already similar code in the server (see loosescan here)
https://mariadb.com/docs/server/ha-and-performance/optimization-and-tuning/query-optimizer/minmax-optimization
Note: i don't actually expect you to implement this, but do write up something.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, as you've added a token to the parser, you've changed the 'digest hashes' in a perfschema test. You'll need to record/update those too.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also also, there is a single line in a commit with whitespace before a newline, remove that whitespace.
Add some tests without ONLY_FULL_GROUP_BY sql_mode, and demonstrate how to use it as a window function.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the digest hashes, fixed whitespace, and added the additional test cases. I will report back with short circuit possibilities for any_value


SET sql_mode=@save_sql_mode;

--echo # End of 13.1 tests.
50 changes: 49 additions & 1 deletion mysql-test/main/group_by.result
Original file line number Diff line number Diff line change
Expand Up @@ -1047,7 +1047,10 @@ m
3
SELECT (SELECT SUM(t1_outer.a) FROM t1 AS t1_inner LIMIT 1)
FROM t1 AS t1_outer GROUP BY t1_outer.b;
ERROR 42000: 'test.t1_outer.a' isn't in GROUP BY
(SELECT SUM(t1_outer.a) FROM t1 AS t1_inner LIMIT 1)
3
7
11
SELECT 1 FROM t1 as t1_outer
WHERE (SELECT t1_outer.b FROM t1 AS t1_inner GROUP BY t1_inner.b LIMIT 1);
1
Expand Down Expand Up @@ -3154,3 +3157,48 @@ we BPYFY BPYFY
we c c
DROP TABLE t1, t2;
# End of 11.8 tests
#
# MDEV-39932: Assert correct ONLY_FULL_GROUP_BY behavior with outer refs in correlated subqueries
#
SET @save_sql_mode=@@sql_mode;
SET SQL_MODE = 'ONLY_FULL_GROUP_BY';
CREATE TABLE t1 (a INT PRIMARY KEY, b INT);
INSERT INTO t1 VALUES (1,1),(2,1),(3,2),(4,2),(5,3),(6,3);
SELECT (SELECT SUM(t1_inner.a) + t1_outer.a FROM t1 AS t1_inner LIMIT 1) AS c1
FROM t1 AS t1_outer GROUP BY t1_outer.b;
ERROR 42000: 'test.t1_outer.a' isn't in GROUP BY
SELECT (SELECT SUM(t1_outer.b) + t1_outer.a FROM t1 AS t1_inner LIMIT 1) AS c1
FROM t1 AS t1_outer GROUP BY t1_outer.b;
ERROR 42000: 'test.t1_outer.a' isn't in GROUP BY
SELECT (SELECT SUM(t1_inner.a + t1_outer.a) FROM t1 AS t1_inner LIMIT 1) AS c1
FROM t1 AS t1_outer GROUP BY t1_outer.b;
ERROR 42000: 'test.t1_outer.a' isn't in GROUP BY
SELECT (SELECT SUM(t1_outer.a) + t1_outer.b FROM t1 AS t1_inner LIMIT 1) AS c1
FROM t1 AS t1_outer GROUP BY t1_outer.b;
c1
4
9
14
SELECT (SELECT SUM(t1_inner.a) FROM t1 AS t1_inner WHERE t1_inner.a = t1_outer.a LIMIT 1) AS c1
FROM t1 AS t1_outer GROUP BY t1_outer.b;
ERROR 42000: 'test.t1_outer.a' isn't in GROUP BY
SELECT (SELECT t1_inner.a FROM t1 AS t1_inner WHERE t1_outer.a > 5 LIMIT 1) AS c1
FROM t1 AS t1_outer GROUP BY t1_outer.b;
ERROR 42000: 'test.t1_outer.a' isn't in GROUP BY
SELECT (SELECT t1_inner.a FROM t1 AS t1_inner WHERE SUM(t1_outer.a) > 5 LIMIT 1) AS c1
FROM t1 AS t1_outer GROUP BY t1_outer.b;
c1
NULL
1
1
SELECT (SELECT t1_inner.a FROM t1 AS t1_inner GROUP BY t1_inner.a HAVING t1_inner.a + SUM(t1_outer.a) > 5 LIMIT 1) AS c1
FROM t1 AS t1_outer GROUP BY t1_outer.b;
c1
3
1
1
DROP TABLE t1;
SET sql_mode=@save_sql_mode;
#
# End of 10.11 tests
#
Loading