summaryrefslogtreecommitdiff
path: root/sql/sql_trigger.cc
diff options
context:
space:
mode:
authorSergei Golubchik <serg@mariadb.org>2015-11-14 22:51:54 +0100
committerSergei Golubchik <serg@mariadb.org>2015-12-21 21:30:54 +0100
commit0686c34d22a5cbf93015012eaf77a4a977b63afb (patch)
tree3c95207d5e01a905f9e87820e6439fe6c6547653 /sql/sql_trigger.cc
parentad5db17e882fea36dcae6f6e61996b5f9bf28962 (diff)
downloadmariadb-git-0686c34d22a5cbf93015012eaf77a4a977b63afb.tar.gz
MDEV-8605 MariaDB not use DEFAULT value even when inserted NULL for NOT NULLABLE column
NOT NULL constraint must be checked *after* the BEFORE triggers. That is for INSERT and UPDATE statements even NOT NULL fields must be able to store a NULL temporarily at least while BEFORE INSERT/UPDATE triggers are running.
Diffstat (limited to 'sql/sql_trigger.cc')
-rw-r--r--sql/sql_trigger.cc88
1 files changed, 63 insertions, 25 deletions
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index bea19f1329c..272e1445273 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -1073,29 +1073,71 @@ Table_triggers_list::~Table_triggers_list()
@retval
True error
*/
-bool Table_triggers_list::prepare_record1_accessors(TABLE *table)
+bool Table_triggers_list::prepare_record_accessors(TABLE *table)
{
- Field **fld, **old_fld;
+ Field **fld, **trg_fld;
- if (!(record1_field= (Field **)alloc_root(&table->mem_root,
- (table->s->fields + 1) *
- sizeof(Field*))))
- return 1;
+ if ((bodies[TRG_EVENT_INSERT][TRG_ACTION_BEFORE] ||
+ bodies[TRG_EVENT_UPDATE][TRG_ACTION_BEFORE])
+ && (table->s->stored_fields != table->s->null_fields))
- for (fld= table->field, old_fld= record1_field; *fld; fld++, old_fld++)
{
- /*
- QQ: it is supposed that it is ok to use this function for field
- cloning...
- */
- if (!(*old_fld= (*fld)->make_new_field(&table->mem_root, table,
- table == (*fld)->table)))
+ int null_bytes= (table->s->stored_fields - table->s->null_fields + 7)/8;
+ if (!(extra_null_bitmap= (uchar*)alloc_root(&table->mem_root, null_bytes)))
return 1;
- (*old_fld)->move_field_offset((my_ptrdiff_t)(table->record[1] -
- table->record[0]));
+ if (!(record0_field= (Field **)alloc_root(&table->mem_root,
+ (table->s->fields + 1) *
+ sizeof(Field*))))
+ return 1;
+
+ uchar *null_ptr= extra_null_bitmap;
+ uchar null_bit= 1;
+ for (fld= table->field, trg_fld= record0_field; *fld; fld++, trg_fld++)
+ {
+ if (!(*fld)->null_ptr && !(*fld)->vcol_info)
+ {
+ Field *f;
+ if (!(f= *trg_fld= (*fld)->make_new_field(&table->mem_root, table,
+ table == (*fld)->table)))
+ return 1;
+
+ f->null_ptr= null_ptr;
+ f->null_bit= null_bit;
+ if (null_bit == 128)
+ null_ptr++, null_bit= 1;
+ else
+ null_bit*= 2;
+ }
+ else
+ *trg_fld= *fld;
+ }
+ *trg_fld= 0;
+ DBUG_ASSERT(null_ptr <= extra_null_bitmap + null_bytes);
+ bzero(extra_null_bitmap, null_bytes);
}
- *old_fld= 0;
+ else
+ record0_field= table->field;
+ if (bodies[TRG_EVENT_UPDATE][TRG_ACTION_BEFORE] ||
+ bodies[TRG_EVENT_UPDATE][TRG_ACTION_AFTER] ||
+ bodies[TRG_EVENT_DELETE][TRG_ACTION_BEFORE] ||
+ bodies[TRG_EVENT_DELETE][TRG_ACTION_AFTER])
+ {
+ if (!(record1_field= (Field **)alloc_root(&table->mem_root,
+ (table->s->fields + 1) *
+ sizeof(Field*))))
+ return 1;
+
+ for (fld= table->field, trg_fld= record1_field; *fld; fld++, trg_fld++)
+ {
+ if (!(*trg_fld= (*fld)->make_new_field(&table->mem_root, table,
+ table == (*fld)->table)))
+ return 1;
+ (*trg_fld)->move_field_offset((my_ptrdiff_t)(table->record[1] -
+ table->record[0]));
+ }
+ *trg_fld= 0;
+ }
return 0;
}
@@ -1320,13 +1362,6 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
table->triggers= triggers;
status_var_increment(thd->status_var.feature_trigger);
- /*
- TODO: This could be avoided if there is no triggers
- for UPDATE and DELETE.
- */
- if (!names_only && triggers->prepare_record1_accessors(table))
- DBUG_RETURN(1);
-
List_iterator_fast<ulonglong> itm(triggers->definition_modes_list);
List_iterator_fast<LEX_STRING> it_definer(triggers->definers_list);
List_iterator_fast<LEX_STRING> it_client_cs_name(triggers->client_cs_names);
@@ -1539,6 +1574,9 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
thd->spcont= save_spcont;
thd->variables.sql_mode= save_sql_mode;
+ if (!names_only && triggers->prepare_record_accessors(table))
+ DBUG_RETURN(1);
+
DBUG_RETURN(0);
err_with_lex_cleanup:
@@ -2107,13 +2145,13 @@ bool Table_triggers_list::process_triggers(THD *thd,
if (old_row_is_record1)
{
old_field= record1_field;
- new_field= trigger_table->field;
+ new_field= record0_field;
}
else
{
DBUG_ASSERT(event == TRG_EVENT_DELETE);
new_field= record1_field;
- old_field= trigger_table->field;
+ old_field= record0_field;
}
/*
This trigger must have been processed by the pre-locking