Skip to content

Commit ffe532f

Browse files
committed
Bug#18064775 Assertion failed: fields.elements == values.elements
Bug#11745889 Traditional: INSERT accepts invalid date from default value A recent bugfix (16820562) gave column count zero a special meaning, but failed to give an error for the case of zero column names but more than zero column values. The fix is to check explicitly for this case. The interface for check_insert_fields() has been extended with a bool value_count_known, to make it easy to remove it when the "known" property is no longer needed (all values are actually "known", but the code path is clumsy). The bugfix also re-introduced bug 11745889, which was fixed by bug 16078943, alas it did not contain a test for this particular case. The fix for this bug is to treat INSERT statements with no column names and no column values specified as if a partial (but empty) column list has been specified. This way, the write_set for the table is not populated and the columns will be picked for validation of default values.
1 parent abc4931 commit ffe532f

File tree

3 files changed

+87
-11
lines changed

3 files changed

+87
-11
lines changed

mysql-test/r/insert.result

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,3 +596,26 @@ Warning 1287 '@@max_insert_delayed_threads' is deprecated and will be removed in
596596
SET GLOBAL max_delayed_threads = DEFAULT;
597597
Warnings:
598598
Warning 1287 '@@max_delayed_threads' is deprecated and will be removed in a future release.
599+
#
600+
# Bug#18064775 Assertion failed: fields.elements == values.elements
601+
#
602+
CREATE TABLE t1(a INTEGER);
603+
INSERT INTO t1(a) values();
604+
ERROR 21S01: Column count doesn't match value count at row 1
605+
DROP TABLE t1;
606+
#
607+
# Bug#11745889 Traditional: INSERT accepts invalid date from default val
608+
#
609+
SET sql_mode='';
610+
CREATE TABLE default_date(a DATE NOT NULL DEFAULT '0000-00-00');
611+
INSERT INTO default_date VALUES();
612+
SET sql_mode='traditional';
613+
INSERT INTO default_date VALUES();
614+
ERROR 22007: Incorrect date value: '0000-00-00' for column 'a' at row 1
615+
INSERT INTO default_date VALUES('0000-00-00');
616+
ERROR 22007: Incorrect date value: '0000-00-00' for column 'a' at row 1
617+
SELECT * FROM default_date;
618+
a
619+
0000-00-00
620+
DROP TABLE default_date;
621+
SET sql_mode=default;

mysql-test/t/insert.test

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,3 +431,36 @@ SET GLOBAL delayed_insert_timeout = DEFAULT;
431431
SET GLOBAL delayed_queue_size = DEFAULT;
432432
SET GLOBAL max_insert_delayed_threads = DEFAULT;
433433
SET GLOBAL max_delayed_threads = DEFAULT;
434+
435+
--echo #
436+
--echo # Bug#18064775 Assertion failed: fields.elements == values.elements
437+
--echo #
438+
439+
CREATE TABLE t1(a INTEGER);
440+
--error ER_WRONG_VALUE_COUNT_ON_ROW
441+
INSERT INTO t1(a) values();
442+
DROP TABLE t1;
443+
444+
--echo #
445+
--echo # Bug#11745889 Traditional: INSERT accepts invalid date from default val
446+
--echo #
447+
448+
SET sql_mode='';
449+
450+
CREATE TABLE default_date(a DATE NOT NULL DEFAULT '0000-00-00');
451+
452+
INSERT INTO default_date VALUES();
453+
454+
SET sql_mode='traditional';
455+
456+
--error ER_TRUNCATED_WRONG_VALUE
457+
INSERT INTO default_date VALUES();
458+
459+
--error ER_TRUNCATED_WRONG_VALUE
460+
INSERT INTO default_date VALUES('0000-00-00');
461+
462+
SELECT * FROM default_date;
463+
464+
DROP TABLE default_date;
465+
466+
SET sql_mode=default;

sql/sql_insert.cc

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -96,15 +96,23 @@ static bool check_view_single_update(List<Item> &fields, TABLE_LIST *view,
9696
@param table_list The table for insert.
9797
@param fields The insert fields.
9898
@param value_count Number of values supplied
99-
= 0: INSERT ... SELECT, delay field count check
99+
@param value_count_known if false, delay field count check
100+
@todo: Eliminate this when preparation is properly phased
100101
@param check_unique If duplicate values should be rejected.
101102
@param[out] insert_table_ref resolved reference to base table
102103
103104
@return false if success, true if error
105+
106+
@todo check_insert_fields() should be refactored as follows:
107+
- Remove the argument value_count_known and all predicates involving it.
108+
- Rearrange the call to check_insert_fields() from
109+
mysql_prepare_insert() so that the value_count is known also when
110+
processing a prepared statement.
104111
*/
105112

106113
static bool check_insert_fields(THD *thd, TABLE_LIST *table_list,
107114
List<Item> &fields, uint value_count,
115+
bool value_count_known,
108116
bool check_unique,
109117
TABLE_LIST **insert_table_ref)
110118
{
@@ -114,15 +122,18 @@ static bool check_insert_fields(THD *thd, TABLE_LIST *table_list,
114122

115123
DBUG_ASSERT(table_list->updatable);
116124

117-
if (fields.elements == 0)
125+
if (fields.elements == 0 && value_count_known && value_count > 0)
118126
{
119-
// No field list supplied, use field list of table being updated.
120-
127+
/*
128+
No field list supplied, but a value list has been supplied.
129+
Use field list of table being updated.
130+
*/
121131
DBUG_ASSERT(table); // This branch is not reached with a view:
122132

123133
*insert_table_ref= table_list;
124134

125-
if (value_count > 0 && value_count != table->s->fields)
135+
// Values for all fields in table are needed
136+
if (value_count != table->s->fields)
126137
{
127138
my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), 1L);
128139
return true;
@@ -147,7 +158,7 @@ static bool check_insert_fields(THD *thd, TABLE_LIST *table_list,
147158
Name_resolution_context_state ctx_state;
148159
int res;
149160

150-
if (value_count > 0 && fields.elements != value_count)
161+
if (value_count_known && fields.elements != value_count)
151162
{
152163
my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), 1L);
153164
return true;
@@ -1173,8 +1184,10 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
11731184
table_list->next_local= NULL;
11741185
context->resolve_in_table_list_only(table_list);
11751186

1176-
res= check_insert_fields(thd, context->table_list, fields, values->elements,
1177-
!insert_into_view, insert_table_ref);
1187+
if (!res)
1188+
res= check_insert_fields(thd, context->table_list, fields,
1189+
values->elements, true,
1190+
!insert_into_view, insert_table_ref);
11781191
table_map map= 0;
11791192
if (!res)
11801193
map= (*insert_table_ref)->table->map;
@@ -1218,7 +1231,14 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
12181231
thd->dup_field= NULL;
12191232
context->resolve_in_table_list_only(table_list);
12201233

1221-
res= check_insert_fields(thd, context->table_list, fields, 0,
1234+
/*
1235+
When processing a prepared INSERT ... SELECT statement,
1236+
mysql_prepare_insert() is called from
1237+
mysql_insert_select_prepare_tester(), when the values list (aka the
1238+
SELECT list from the SELECT) is not resolved yet, so pass "false"
1239+
for value_count_known.
1240+
*/
1241+
res= check_insert_fields(thd, context->table_list, fields, 0, false,
12221242
!insert_into_view, insert_table_ref);
12231243
table_map map= 0;
12241244
if (!res)
@@ -1811,8 +1831,8 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
18111831

18121832
/* Errors during check_insert_fields() should not be ignored. */
18131833
lex->current_select()->no_error= FALSE;
1814-
res= check_insert_fields(thd, table_list, *fields, values.elements,
1815-
!insert_into_view, &insert_table_ref);
1834+
res= check_insert_fields(thd, table_list, *fields, values.elements, true,
1835+
!insert_into_view, &insert_table_ref);
18161836
if (!res)
18171837
res= setup_fields(thd, Ref_ptr_array(), values, MARK_COLUMNS_READ, 0, 0);
18181838

0 commit comments

Comments
 (0)