Skip to content

Commit 49e1400

Browse files
committed
MDEV-26427 MariaDB Server SEGV on INSERT .. SELECT
1. For INSERT..SELECT statements: don't include table/view the data is inserted into in the list of leaf tables 2. Remove duplicated and dead code related to table_count
1 parent 02e85ae commit 49e1400

File tree

8 files changed

+264
-59
lines changed

8 files changed

+264
-59
lines changed

mysql-test/main/insert_select.result

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -883,4 +883,74 @@ INSERT INTO t1 SELECT a*2 FROM t1 ORDER BY a;
883883
Warnings:
884884
Warning 1264 Out of range value for column 'a' at row 4
885885
DROP TABLE t1;
886+
CREATE TABLE t1 (a INT, b INT);
887+
INSERT INTO t1 (a) SELECT SUM(1);
888+
INSERT INTO t1 (a, b) SELECT AVG(2), MIN(3);
889+
INSERT INTO t1 (b) SELECT AVG('x') OVER ();
890+
ERROR 22007: Truncated incorrect DOUBLE value: 'x'
891+
INSERT INTO t1 SELECT MIN(7) OVER (), MAX(8) OVER();
892+
SELECT * FROM t1;
893+
a b
894+
1 NULL
895+
2 3
896+
7 8
897+
PREPARE stmt FROM 'INSERT INTO t1 (a) SELECT AVG(?)';
898+
EXECUTE stmt USING 9;
899+
EXECUTE stmt USING 10;
900+
PREPARE stmt FROM 'INSERT INTO t1 SELECT MIN(?), MAX(?)';
901+
EXECUTE stmt USING 11, 12;
902+
EXECUTE stmt USING 13, 14;
903+
DEALLOCATE PREPARE stmt;
904+
SELECT * FROM t1;
905+
a b
906+
1 NULL
907+
2 3
908+
7 8
909+
9 NULL
910+
10 NULL
911+
11 12
912+
13 14
913+
CREATE PROCEDURE p1(param_a INT, param_b INT)
914+
BEGIN
915+
INSERT INTO t1 SELECT MIN(param_a) OVER (), MAX(param_b);
916+
END//
917+
CALL p1(21, 22);
918+
CALL p1(23, 24);
919+
SELECT * FROM t1;
920+
a b
921+
1 NULL
922+
2 3
923+
7 8
924+
9 NULL
925+
10 NULL
926+
11 12
927+
13 14
928+
21 22
929+
23 24
930+
CREATE TABLE t2 (
931+
a DECIMAL UNIQUE CHECK (CASE 0 * 27302337.000000 WHEN 34 THEN
932+
+ 'x' LIKE 'x' OR a NOT IN (-1 / TRUE ^ 2) ELSE 7105743.000000 END));
933+
INSERT INTO t2 VALUES (90),( -1),(31152443.000000),(-32768),(NULL),(NULL);
934+
INSERT INTO t2 SELECT AVG('x') OVER (
935+
PARTITION BY ((NOT AVG(76698761.000000))) IS NOT NULL);
936+
ERROR 22007: Truncated incorrect DOUBLE value: 'x'
937+
INSERT IGNORE INTO t2 () VALUES (0),('x'),(3751286.000000),
938+
('x'),((a = 'x' AND 0 AND 0));
939+
Warnings:
940+
Warning 1366 Incorrect decimal value: 'x' for column `test`.`t2`.`a` at row 2
941+
Warning 1062 Duplicate entry '0' for key 'a'
942+
Warning 1366 Incorrect decimal value: 'x' for column `test`.`t2`.`a` at row 4
943+
Warning 1062 Duplicate entry '0' for key 'a'
944+
Warning 1062 Duplicate entry '0' for key 'a'
945+
INSERT INTO t2 VALUES (127);
946+
INSERT INTO t2 SELECT -2147483648 END FROM t2 AS TEXT JOIN t2 JOIN t2 TABLES;
947+
ERROR 23000: Duplicate entry '-2147483648' for key 'a'
948+
ALTER TABLE t2 ADD (
949+
b INT UNIQUE CHECK ((a = 'x' AND ((-(+(BINARY 49730460.000000)))) = 'x'
950+
BETWEEN 'x' AND 'x')));
951+
ERROR 22007: Truncated incorrect DECIMAL value: 'x'
952+
UPDATE t2 SET a = -128 WHERE a IS NULL ORDER BY 78 IN ('x','x'),a;
953+
ERROR 23000: Duplicate entry '-128' for key 'a'
954+
DROP TABLE t1, t2;
955+
DROP PROCEDURE p1;
886956
# End of 10.2 test

mysql-test/main/insert_select.test

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,4 +459,58 @@ INSERT INTO t1 SELECT a*2 FROM t1 ORDER BY a;
459459

460460
DROP TABLE t1;
461461

462+
#
463+
# MDEV-26427 MariaDB Server SEGV on INSERT .. SELECT
464+
#
465+
CREATE TABLE t1 (a INT, b INT);
466+
INSERT INTO t1 (a) SELECT SUM(1);
467+
INSERT INTO t1 (a, b) SELECT AVG(2), MIN(3);
468+
469+
--error ER_TRUNCATED_WRONG_VALUE
470+
INSERT INTO t1 (b) SELECT AVG('x') OVER ();
471+
INSERT INTO t1 SELECT MIN(7) OVER (), MAX(8) OVER();
472+
SELECT * FROM t1;
473+
474+
PREPARE stmt FROM 'INSERT INTO t1 (a) SELECT AVG(?)';
475+
EXECUTE stmt USING 9;
476+
EXECUTE stmt USING 10;
477+
478+
PREPARE stmt FROM 'INSERT INTO t1 SELECT MIN(?), MAX(?)';
479+
EXECUTE stmt USING 11, 12;
480+
EXECUTE stmt USING 13, 14;
481+
DEALLOCATE PREPARE stmt;
482+
SELECT * FROM t1;
483+
484+
DELIMITER //;
485+
CREATE PROCEDURE p1(param_a INT, param_b INT)
486+
BEGIN
487+
INSERT INTO t1 SELECT MIN(param_a) OVER (), MAX(param_b);
488+
END//
489+
DELIMITER ;//
490+
CALL p1(21, 22);
491+
CALL p1(23, 24);
492+
SELECT * FROM t1;
493+
494+
CREATE TABLE t2 (
495+
a DECIMAL UNIQUE CHECK (CASE 0 * 27302337.000000 WHEN 34 THEN
496+
+ 'x' LIKE 'x' OR a NOT IN (-1 / TRUE ^ 2) ELSE 7105743.000000 END));
497+
INSERT INTO t2 VALUES (90),( -1),(31152443.000000),(-32768),(NULL),(NULL);
498+
--error ER_TRUNCATED_WRONG_VALUE
499+
INSERT INTO t2 SELECT AVG('x') OVER (
500+
PARTITION BY ((NOT AVG(76698761.000000))) IS NOT NULL);
501+
INSERT IGNORE INTO t2 () VALUES (0),('x'),(3751286.000000),
502+
('x'),((a = 'x' AND 0 AND 0));
503+
INSERT INTO t2 VALUES (127);
504+
--error ER_DUP_ENTRY
505+
INSERT INTO t2 SELECT -2147483648 END FROM t2 AS TEXT JOIN t2 JOIN t2 TABLES;
506+
--error ER_TRUNCATED_WRONG_VALUE
507+
ALTER TABLE t2 ADD (
508+
b INT UNIQUE CHECK ((a = 'x' AND ((-(+(BINARY 49730460.000000)))) = 'x'
509+
BETWEEN 'x' AND 'x')));
510+
--error ER_DUP_ENTRY
511+
UPDATE t2 SET a = -128 WHERE a IS NULL ORDER BY 78 IN ('x','x'),a;
512+
513+
DROP TABLE t1, t2;
514+
DROP PROCEDURE p1;
515+
462516
--echo # End of 10.2 test

mysql-test/main/view.result

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1502,6 +1502,8 @@ execute stmt1 using @a;
15021502
set @a= 301;
15031503
execute stmt1 using @a;
15041504
deallocate prepare stmt1;
1505+
insert into v3(a) select sum(302);
1506+
insert into v3(a) select sum(303) over ();
15051507
select * from v3;
15061508
a b
15071509
100 0
@@ -1520,6 +1522,14 @@ a b
15201522
301 10
15211523
301 1000
15221524
301 2000
1525+
302 0
1526+
302 10
1527+
302 1000
1528+
302 2000
1529+
303 0
1530+
303 10
1531+
303 1000
1532+
303 2000
15231533
drop view v3;
15241534
drop tables t1,t2;
15251535
create table t1(f1 int);

mysql-test/main/view.test

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1334,6 +1334,8 @@ execute stmt1 using @a;
13341334
set @a= 301;
13351335
execute stmt1 using @a;
13361336
deallocate prepare stmt1;
1337+
insert into v3(a) select sum(302);
1338+
insert into v3(a) select sum(303) over ();
13371339
--sorted_result
13381340
select * from v3;
13391341

sql/sql_base.cc

Lines changed: 127 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -7577,46 +7577,118 @@ bool setup_fields(THD *thd, Ref_ptr_array ref_pointer_array,
75777577
DBUG_RETURN(MY_TEST(thd->is_error()));
75787578
}
75797579

7580+
/*
7581+
make list of leaves for a single TABLE_LIST
7582+
7583+
SYNOPSIS
7584+
make_leaves_for_single_table()
7585+
thd Thread handler
7586+
leaves List of leaf tables to be filled
7587+
table TABLE_LIST object to process
7588+
full_table_list Whether to include tables from mergeable derived table/view
7589+
*/
7590+
void make_leaves_for_single_table(THD *thd, List<TABLE_LIST> &leaves,
7591+
TABLE_LIST *table, bool& full_table_list,
7592+
TABLE_LIST *boundary)
7593+
{
7594+
if (table == boundary)
7595+
full_table_list= !full_table_list;
7596+
if (full_table_list && table->is_merged_derived())
7597+
{
7598+
SELECT_LEX *select_lex= table->get_single_select();
7599+
/*
7600+
It's safe to use select_lex->leaf_tables because all derived
7601+
tables/views were already prepared and has their leaf_tables
7602+
set properly.
7603+
*/
7604+
make_leaves_list(thd, leaves, select_lex->get_table_list(),
7605+
full_table_list, boundary);
7606+
}
7607+
else
7608+
{
7609+
leaves.push_back(table, thd->mem_root);
7610+
}
7611+
}
7612+
75807613

75817614
/*
75827615
make list of leaves of join table tree
75837616
75847617
SYNOPSIS
75857618
make_leaves_list()
7586-
list pointer to pointer on list first element
7587-
tables table list
7588-
full_table_list whether to include tables from mergeable derived table/view.
7589-
we need them for checks for INSERT/UPDATE statements only.
7590-
7591-
RETURN pointer on pointer to next_leaf of last element
7619+
leaves List of leaf tables to be filled
7620+
tables Table list
7621+
full_table_list Whether to include tables from mergeable derived table/view.
7622+
We need them for checks for INSERT/UPDATE statements only.
75927623
*/
75937624

7594-
void make_leaves_list(THD *thd, List<TABLE_LIST> &list, TABLE_LIST *tables,
7625+
void make_leaves_list(THD *thd, List<TABLE_LIST> &leaves, TABLE_LIST *tables,
75957626
bool full_table_list, TABLE_LIST *boundary)
75967627

75977628
{
75987629
for (TABLE_LIST *table= tables; table; table= table->next_local)
75997630
{
7600-
if (table == boundary)
7601-
full_table_list= !full_table_list;
7602-
if (full_table_list && table->is_merged_derived())
7603-
{
7604-
SELECT_LEX *select_lex= table->get_single_select();
7605-
/*
7606-
It's safe to use select_lex->leaf_tables because all derived
7607-
tables/views were already prepared and has their leaf_tables
7608-
set properly.
7609-
*/
7610-
make_leaves_list(thd, list, select_lex->get_table_list(),
7611-
full_table_list, boundary);
7612-
}
7613-
else
7614-
{
7615-
list.push_back(table, thd->mem_root);
7616-
}
7631+
make_leaves_for_single_table(thd, leaves, table, full_table_list,
7632+
boundary);
7633+
}
7634+
}
7635+
7636+
7637+
/*
7638+
Setup the map and other attributes for a single TABLE_LIST object
7639+
7640+
SYNOPSIS
7641+
setup_table_attributes()
7642+
thd Thread handler
7643+
table_list TABLE_LIST object to process
7644+
first_select_table First table participating in SELECT for INSERT..SELECT
7645+
statements, NULL for other cases
7646+
tablenr Serial number of the table in the SQL statement
7647+
7648+
RETURN
7649+
false Success
7650+
true Failure
7651+
*/
7652+
bool setup_table_attributes(THD *thd, TABLE_LIST *table_list,
7653+
TABLE_LIST *first_select_table,
7654+
uint &tablenr)
7655+
{
7656+
TABLE *table= table_list->table;
7657+
if (table)
7658+
table->pos_in_table_list= table_list;
7659+
if (first_select_table && table_list->top_table() == first_select_table)
7660+
{
7661+
/* new counting for SELECT of INSERT ... SELECT command */
7662+
first_select_table= 0;
7663+
thd->lex->select_lex.insert_tables= tablenr;
7664+
tablenr= 0;
7665+
}
7666+
if (table_list->jtbm_subselect)
7667+
{
7668+
table_list->jtbm_table_no= tablenr;
7669+
}
7670+
else if (table)
7671+
{
7672+
table->pos_in_table_list= table_list;
7673+
setup_table_map(table, table_list, tablenr);
7674+
7675+
if (table_list->process_index_hints(table))
7676+
return true;
7677+
}
7678+
tablenr++;
7679+
/*
7680+
We test the max tables here as we setup_table_map() should not be called
7681+
with tablenr >= 64
7682+
*/
7683+
if (tablenr > MAX_TABLES)
7684+
{
7685+
my_error(ER_TOO_MANY_TABLES, MYF(0), static_cast<int>(MAX_TABLES));
7686+
return true;
76177687
}
7688+
return false;
76187689
}
76197690

7691+
76207692
/*
76217693
prepare tables
76227694
@@ -7673,7 +7745,14 @@ bool setup_tables(THD *thd, Name_resolution_context *context,
76737745
leaves.empty();
76747746
if (select_lex->prep_leaf_list_state != SELECT_LEX::SAVED)
76757747
{
7676-
make_leaves_list(thd, leaves, tables, full_table_list, first_select_table);
7748+
/*
7749+
For INSERT ... SELECT statements we must not include the first table
7750+
(where the data is being inserted into) in the list of leaves
7751+
*/
7752+
TABLE_LIST *tables_for_leaves=
7753+
select_insert ? first_select_table : tables;
7754+
make_leaves_list(thd, leaves, tables_for_leaves, full_table_list,
7755+
first_select_table);
76777756
select_lex->prep_leaf_list_state= SELECT_LEX::READY;
76787757
select_lex->leaf_tables_exec.empty();
76797758
}
@@ -7684,37 +7763,34 @@ bool setup_tables(THD *thd, Name_resolution_context *context,
76847763
leaves.push_back(table_list, thd->mem_root);
76857764
}
76867765

7766+
List_iterator<TABLE_LIST> ti(leaves);
76877767
while ((table_list= ti++))
76887768
{
7689-
TABLE *table= table_list->table;
7690-
if (table)
7691-
table->pos_in_table_list= table_list;
7692-
if (first_select_table &&
7693-
table_list->top_table() == first_select_table)
7694-
{
7695-
/* new counting for SELECT of INSERT ... SELECT command */
7696-
first_select_table= 0;
7697-
thd->lex->select_lex.insert_tables= tablenr;
7698-
tablenr= 0;
7699-
}
7700-
if(table_list->jtbm_subselect)
7701-
{
7702-
table_list->jtbm_table_no= tablenr;
7703-
}
7704-
else if (table)
7705-
{
7706-
table->pos_in_table_list= table_list;
7707-
setup_table_map(table, table_list, tablenr);
7769+
if (setup_table_attributes(thd, table_list, first_select_table, tablenr))
7770+
DBUG_RETURN(1);
7771+
}
77087772

7709-
if (table_list->process_index_hints(table))
7773+
if (select_insert)
7774+
{
7775+
/*
7776+
The table/view in which the data is inserted must not be included into
7777+
the leaf_tables list. But we need this table/view to setup attributes
7778+
for it. So build a temporary list of leaves and setup attributes for
7779+
the tables included
7780+
*/
7781+
List<TABLE_LIST> leaves;
7782+
TABLE_LIST *table= tables;
7783+
7784+
make_leaves_for_single_table(thd, leaves, table, full_table_list,
7785+
first_select_table);
7786+
7787+
List_iterator<TABLE_LIST> ti(leaves);
7788+
while ((table_list= ti++))
7789+
{
7790+
if (setup_table_attributes(thd, table_list, first_select_table,
7791+
tablenr))
77107792
DBUG_RETURN(1);
77117793
}
7712-
tablenr++;
7713-
}
7714-
if (tablenr > MAX_TABLES)
7715-
{
7716-
my_error(ER_TOO_MANY_TABLES,MYF(0), static_cast<int>(MAX_TABLES));
7717-
DBUG_RETURN(1);
77187794
}
77197795
}
77207796
else

0 commit comments

Comments
 (0)