1
by brian
clean slate |
1 |
/* Copyright (C) 2000-2006 MySQL AB
|
2 |
||
3 |
This program is free software; you can redistribute it and/or modify
|
|
4 |
it under the terms of the GNU General Public License as published by
|
|
5 |
the Free Software Foundation; version 2 of the License.
|
|
6 |
||
7 |
This program is distributed in the hope that it will be useful,
|
|
8 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
9 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
10 |
GNU General Public License for more details.
|
|
11 |
||
12 |
You should have received a copy of the GNU General Public License
|
|
13 |
along with this program; if not, write to the Free Software
|
|
14 |
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
|
15 |
||
16 |
||
17 |
/*
|
|
18 |
Single table and multi table updates of tables.
|
|
19 |
Multi-table updates were introduced by Sinisa & Monty
|
|
20 |
*/
|
|
21 |
||
22 |
#include "mysql_priv.h" |
|
23 |
#include "sql_select.h" |
|
202.3.6
by Monty Taylor
First pass at gettexizing the error messages. |
24 |
#include <drizzled/drizzled_error_messages.h> |
1
by brian
clean slate |
25 |
|
26 |
/* Return 0 if row hasn't changed */
|
|
27 |
||
28 |
bool compare_record(TABLE *table) |
|
29 |
{
|
|
30 |
if (table->s->blob_fields + table->s->varchar_fields == 0) |
|
31 |
return cmp_record(table,record[1]); |
|
32 |
/* Compare null bits */
|
|
33 |
if (memcmp(table->null_flags, |
|
34 |
table->null_flags+table->s->rec_buff_length, |
|
35 |
table->s->null_bytes)) |
|
56
by brian
Next pass of true/false update. |
36 |
return true; // Diff in NULL value |
1
by brian
clean slate |
37 |
/* Compare updated fields */
|
38 |
for (Field **ptr= table->field ; *ptr ; ptr++) |
|
39 |
{
|
|
40 |
if (bitmap_is_set(table->write_set, (*ptr)->field_index) && |
|
41 |
(*ptr)->cmp_binary_offset(table->s->rec_buff_length)) |
|
56
by brian
Next pass of true/false update. |
42 |
return true; |
1
by brian
clean slate |
43 |
}
|
56
by brian
Next pass of true/false update. |
44 |
return false; |
1
by brian
clean slate |
45 |
}
|
46 |
||
47 |
||
48 |
/*
|
|
49 |
check that all fields are real fields
|
|
50 |
||
51 |
SYNOPSIS
|
|
52 |
check_fields()
|
|
53 |
thd thread handler
|
|
54 |
items Items for check
|
|
55 |
||
56 |
RETURN
|
|
56
by brian
Next pass of true/false update. |
57 |
true Items can't be used in UPDATE
|
58 |
false Items are OK
|
|
1
by brian
clean slate |
59 |
*/
|
60 |
||
61 |
static bool check_fields(THD *thd, List<Item> &items) |
|
62 |
{
|
|
63 |
List_iterator<Item> it(items); |
|
64 |
Item *item; |
|
65 |
Item_field *field; |
|
66 |
||
67 |
while ((item= it++)) |
|
68 |
{
|
|
69 |
if (!(field= item->filed_for_view_update())) |
|
70 |
{
|
|
71 |
/* item has name, because it comes from VIEW SELECT list */
|
|
72 |
my_error(ER_NONUPDATEABLE_COLUMN, MYF(0), item->name); |
|
56
by brian
Next pass of true/false update. |
73 |
return true; |
1
by brian
clean slate |
74 |
}
|
75 |
/*
|
|
76 |
we make temporary copy of Item_field, to avoid influence of changing
|
|
77 |
result_field on Item_ref which refer on this field
|
|
78 |
*/
|
|
79 |
thd->change_item_tree(it.ref(), new Item_field(thd, field)); |
|
80 |
}
|
|
56
by brian
Next pass of true/false update. |
81 |
return false; |
1
by brian
clean slate |
82 |
}
|
83 |
||
84 |
||
85 |
/**
|
|
86 |
Re-read record if more columns are needed for error message.
|
|
87 |
||
88 |
If we got a duplicate key error, we want to write an error
|
|
89 |
message containing the value of the duplicate key. If we do not have
|
|
90 |
all fields of the key value in record[0], we need to re-read the
|
|
91 |
record with a proper read_set.
|
|
92 |
||
93 |
@param[in] error error number
|
|
94 |
@param[in] table table
|
|
95 |
*/
|
|
96 |
||
97 |
static void prepare_record_for_error_message(int error, TABLE *table) |
|
98 |
{
|
|
99 |
Field **field_p; |
|
100 |
Field *field; |
|
101 |
uint keynr; |
|
102 |
MY_BITMAP unique_map; /* Fields in offended unique. */ |
|
103 |
my_bitmap_map unique_map_buf[bitmap_buffer_size(MAX_FIELDS)]; |
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
104 |
|
1
by brian
clean slate |
105 |
/*
|
106 |
Only duplicate key errors print the key value.
|
|
107 |
If storage engine does always read all columns, we have the value alraedy.
|
|
108 |
*/
|
|
109 |
if ((error != HA_ERR_FOUND_DUPP_KEY) || |
|
110 |
!(table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ)) |
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
111 |
return; |
1
by brian
clean slate |
112 |
|
113 |
/*
|
|
114 |
Get the number of the offended index.
|
|
115 |
We will see MAX_KEY if the engine cannot determine the affected index.
|
|
116 |
*/
|
|
117 |
if ((keynr= table->file->get_dup_key(error)) >= MAX_KEY) |
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
118 |
return; |
1
by brian
clean slate |
119 |
|
120 |
/* Create unique_map with all fields used by that index. */
|
|
56
by brian
Next pass of true/false update. |
121 |
bitmap_init(&unique_map, unique_map_buf, table->s->fields, false); |
1
by brian
clean slate |
122 |
table->mark_columns_used_by_index_no_reset(keynr, &unique_map); |
123 |
||
124 |
/* Subtract read_set and write_set. */
|
|
125 |
bitmap_subtract(&unique_map, table->read_set); |
|
126 |
bitmap_subtract(&unique_map, table->write_set); |
|
127 |
||
128 |
/*
|
|
129 |
If the unique index uses columns that are neither in read_set
|
|
130 |
nor in write_set, we must re-read the record.
|
|
131 |
Otherwise no need to do anything.
|
|
132 |
*/
|
|
133 |
if (bitmap_is_clear_all(&unique_map)) |
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
134 |
return; |
1
by brian
clean slate |
135 |
|
136 |
/* Get identifier of last read record into table->file->ref. */
|
|
137 |
table->file->position(table->record[0]); |
|
138 |
/* Add all fields used by unique index to read_set. */
|
|
139 |
bitmap_union(table->read_set, &unique_map); |
|
140 |
/* Tell the engine about the new set. */
|
|
141 |
table->file->column_bitmaps_signal(); |
|
142 |
/* Read record that is identified by table->file->ref. */
|
|
143 |
(void) table->file->rnd_pos(table->record[1], table->file->ref); |
|
144 |
/* Copy the newly read columns into the new record. */
|
|
145 |
for (field_p= table->field; (field= *field_p); field_p++) |
|
146 |
if (bitmap_is_set(&unique_map, field->field_index)) |
|
147 |
field->copy_from_tmp(table->s->rec_buff_length); |
|
148 |
||
51.2.2
by Patrick Galbraith
Removed DBUGs from |
149 |
return; |
1
by brian
clean slate |
150 |
}
|
151 |
||
152 |
||
153 |
/*
|
|
154 |
Process usual UPDATE
|
|
155 |
||
156 |
SYNOPSIS
|
|
157 |
mysql_update()
|
|
158 |
thd thread handler
|
|
159 |
fields fields for update
|
|
160 |
values values of fields for update
|
|
161 |
conds WHERE clause expression
|
|
162 |
order_num number of elemen in ORDER BY clause
|
|
163 |
order ORDER BY clause list
|
|
164 |
limit limit clause
|
|
165 |
handle_duplicates how to handle duplicates
|
|
166 |
||
167 |
RETURN
|
|
168 |
0 - OK
|
|
169 |
2 - privilege check and openning table passed, but we need to convert to
|
|
170 |
multi-update because of view substitution
|
|
171 |
1 - error
|
|
172 |
*/
|
|
173 |
||
174 |
int mysql_update(THD *thd, |
|
175 |
TABLE_LIST *table_list, |
|
176 |
List<Item> &fields, |
|
77.1.45
by Monty Taylor
Warning fixes. |
177 |
List<Item> &values, |
1
by brian
clean slate |
178 |
COND *conds, |
179 |
uint order_num, ORDER *order, |
|
77.1.45
by Monty Taylor
Warning fixes. |
180 |
ha_rows limit, |
212.1.3
by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)). |
181 |
enum enum_duplicates handle_duplicates __attribute__((unused)), |
77.1.45
by Monty Taylor
Warning fixes. |
182 |
bool ignore) |
1
by brian
clean slate |
183 |
{
|
184 |
bool using_limit= limit != HA_POS_ERROR; |
|
185 |
bool safe_update= test(thd->options & OPTION_SAFE_UPDATES); |
|
186 |
bool used_key_is_modified, transactional_table, will_batch; |
|
187 |
bool can_compare_record; |
|
188 |
int error, loc_error; |
|
189 |
uint used_index= MAX_KEY, dup_key_found; |
|
56
by brian
Next pass of true/false update. |
190 |
bool need_sort= true; |
1
by brian
clean slate |
191 |
uint table_count= 0; |
192 |
ha_rows updated, found; |
|
193 |
key_map old_covering_keys; |
|
194 |
TABLE *table; |
|
195 |
SQL_SELECT *select; |
|
196 |
READ_RECORD info; |
|
197 |
SELECT_LEX *select_lex= &thd->lex->select_lex; |
|
198 |
bool need_reopen; |
|
151
by Brian Aker
Ulonglong to uint64_t |
199 |
uint64_t id; |
1
by brian
clean slate |
200 |
List<Item> all_fields; |
201 |
THD::killed_state killed_status= THD::NOT_KILLED; |
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
202 |
|
1
by brian
clean slate |
203 |
for ( ; ; ) |
204 |
{
|
|
205 |
if (open_tables(thd, &table_list, &table_count, 0)) |
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
206 |
return(1); |
1
by brian
clean slate |
207 |
|
208 |
if (!lock_tables(thd, table_list, table_count, &need_reopen)) |
|
209 |
break; |
|
210 |
if (!need_reopen) |
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
211 |
return(1); |
1
by brian
clean slate |
212 |
close_tables_for_reopen(thd, &table_list); |
213 |
}
|
|
214 |
||
215 |
if (mysql_handle_derived(thd->lex, &mysql_derived_prepare) || |
|
216 |
(thd->fill_derived_tables() && |
|
217 |
mysql_handle_derived(thd->lex, &mysql_derived_filling))) |
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
218 |
return(1); |
1
by brian
clean slate |
219 |
|
220 |
MYSQL_UPDATE_START(); |
|
221 |
thd_proc_info(thd, "init"); |
|
222 |
table= table_list->table; |
|
223 |
||
224 |
/* Calculate "table->covering_keys" based on the WHERE */
|
|
225 |
table->covering_keys= table->s->keys_in_use; |
|
226 |
table->quick_keys.clear_all(); |
|
227 |
||
228 |
if (mysql_prepare_update(thd, table_list, &conds, order_num, order)) |
|
229 |
goto abort; |
|
230 |
||
231 |
old_covering_keys= table->covering_keys; // Keys used in WHERE |
|
232 |
/* Check the fields we are going to modify */
|
|
233 |
if (setup_fields_with_no_wrap(thd, 0, fields, MARK_COLUMNS_WRITE, 0, 0)) |
|
234 |
goto abort; /* purecov: inspected */ |
|
235 |
if (table->timestamp_field) |
|
236 |
{
|
|
237 |
// Don't set timestamp column if this is modified
|
|
238 |
if (bitmap_is_set(table->write_set, |
|
239 |
table->timestamp_field->field_index)) |
|
240 |
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET; |
|
241 |
else
|
|
242 |
{
|
|
243 |
if (table->timestamp_field_type == TIMESTAMP_AUTO_SET_ON_UPDATE || |
|
244 |
table->timestamp_field_type == TIMESTAMP_AUTO_SET_ON_BOTH) |
|
245 |
bitmap_set_bit(table->write_set, |
|
246 |
table->timestamp_field->field_index); |
|
247 |
}
|
|
248 |
}
|
|
249 |
||
250 |
if (setup_fields(thd, 0, values, MARK_COLUMNS_READ, 0, 0)) |
|
251 |
{
|
|
252 |
free_underlaid_joins(thd, select_lex); |
|
253 |
goto abort; /* purecov: inspected */ |
|
254 |
}
|
|
255 |
||
256 |
if (select_lex->inner_refs_list.elements && |
|
257 |
fix_inner_refs(thd, all_fields, select_lex, select_lex->ref_pointer_array)) |
|
258 |
{
|
|
259 |
MYSQL_UPDATE_END(); |
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
260 |
return(-1); |
1
by brian
clean slate |
261 |
}
|
262 |
||
263 |
if (conds) |
|
264 |
{
|
|
265 |
Item::cond_result cond_value; |
|
266 |
conds= remove_eq_conds(thd, conds, &cond_value); |
|
267 |
if (cond_value == Item::COND_FALSE) |
|
268 |
limit= 0; // Impossible WHERE |
|
269 |
}
|
|
270 |
||
271 |
/*
|
|
272 |
If a timestamp field settable on UPDATE is present then to avoid wrong
|
|
273 |
update force the table handler to retrieve write-only fields to be able
|
|
274 |
to compare records and detect data change.
|
|
275 |
*/
|
|
276 |
if (table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ && |
|
277 |
table->timestamp_field && |
|
278 |
(table->timestamp_field_type == TIMESTAMP_AUTO_SET_ON_UPDATE || |
|
279 |
table->timestamp_field_type == TIMESTAMP_AUTO_SET_ON_BOTH)) |
|
280 |
bitmap_union(table->read_set, table->write_set); |
|
281 |
// Don't count on usage of 'only index' when calculating which key to use
|
|
282 |
table->covering_keys.clear_all(); |
|
283 |
||
284 |
/* Update the table->file->stats.records number */
|
|
285 |
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); |
|
286 |
||
287 |
select= make_select(table, 0, 0, conds, 0, &error); |
|
288 |
if (error || !limit || |
|
289 |
(select && select->check_quick(thd, safe_update, limit))) |
|
290 |
{
|
|
291 |
delete select; |
|
292 |
free_underlaid_joins(thd, select_lex); |
|
293 |
if (error) |
|
294 |
goto abort; // Error in where |
|
295 |
MYSQL_UPDATE_END(); |
|
296 |
my_ok(thd); // No matching records |
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
297 |
return(0); |
1
by brian
clean slate |
298 |
}
|
299 |
if (!select && limit != HA_POS_ERROR) |
|
300 |
{
|
|
301 |
if ((used_index= get_index_for_order(table, order, limit)) != MAX_KEY) |
|
56
by brian
Next pass of true/false update. |
302 |
need_sort= false; |
1
by brian
clean slate |
303 |
}
|
304 |
/* If running in safe sql mode, don't allow updates without keys */
|
|
305 |
if (table->quick_keys.is_clear_all()) |
|
306 |
{
|
|
307 |
thd->server_status|=SERVER_QUERY_NO_INDEX_USED; |
|
308 |
if (safe_update && !using_limit) |
|
309 |
{
|
|
310 |
my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE, |
|
311 |
ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0)); |
|
312 |
goto err; |
|
313 |
}
|
|
314 |
}
|
|
315 |
||
316 |
table->mark_columns_needed_for_update(); |
|
317 |
||
318 |
/* Check if we are modifying a key that we are used to search with */
|
|
319 |
||
320 |
if (select && select->quick) |
|
321 |
{
|
|
322 |
used_index= select->quick->index; |
|
323 |
used_key_is_modified= (!select->quick->unique_key_range() && |
|
324 |
select->quick->is_keys_used(table->write_set)); |
|
325 |
}
|
|
326 |
else
|
|
327 |
{
|
|
328 |
used_key_is_modified= 0; |
|
329 |
if (used_index == MAX_KEY) // no index for sort order |
|
330 |
used_index= table->file->key_used_on_scan; |
|
331 |
if (used_index != MAX_KEY) |
|
332 |
used_key_is_modified= is_key_used(table, used_index, table->write_set); |
|
333 |
}
|
|
334 |
||
335 |
||
336 |
if (used_key_is_modified || order) |
|
337 |
{
|
|
338 |
/*
|
|
339 |
We can't update table directly; We must first search after all
|
|
340 |
matching rows before updating the table!
|
|
341 |
*/
|
|
342 |
if (used_index < MAX_KEY && old_covering_keys.is_set(used_index)) |
|
343 |
{
|
|
344 |
table->key_read=1; |
|
345 |
table->mark_columns_used_by_index(used_index); |
|
346 |
}
|
|
347 |
else
|
|
348 |
{
|
|
349 |
table->use_all_columns(); |
|
350 |
}
|
|
351 |
||
352 |
/* note: We avoid sorting avoid if we sort on the used index */
|
|
353 |
if (order && (need_sort || used_key_is_modified)) |
|
354 |
{
|
|
355 |
/*
|
|
356 |
Doing an ORDER BY; Let filesort find and sort the rows we are going
|
|
357 |
to update
|
|
358 |
NOTE: filesort will call table->prepare_for_position()
|
|
359 |
*/
|
|
360 |
uint length= 0; |
|
361 |
SORT_FIELD *sortorder; |
|
362 |
ha_rows examined_rows; |
|
363 |
||
364 |
table->sort.io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE), |
|
365 |
MYF(MY_FAE | MY_ZEROFILL)); |
|
366 |
if (!(sortorder=make_unireg_sortorder(order, &length, NULL)) || |
|
367 |
(table->sort.found_records= filesort(thd, table, sortorder, length, |
|
368 |
select, limit, 1, |
|
369 |
&examined_rows)) |
|
370 |
== HA_POS_ERROR) |
|
371 |
{
|
|
372 |
goto err; |
|
373 |
}
|
|
374 |
/*
|
|
375 |
Filesort has already found and selected the rows we want to update,
|
|
376 |
so we don't need the where clause
|
|
377 |
*/
|
|
378 |
delete select; |
|
379 |
select= 0; |
|
380 |
}
|
|
381 |
else
|
|
382 |
{
|
|
383 |
/*
|
|
384 |
We are doing a search on a key that is updated. In this case
|
|
385 |
we go trough the matching rows, save a pointer to them and
|
|
386 |
update these in a separate loop based on the pointer.
|
|
387 |
*/
|
|
388 |
||
389 |
IO_CACHE tempfile; |
|
390 |
if (open_cached_file(&tempfile, mysql_tmpdir,TEMP_PREFIX, |
|
391 |
DISK_BUFFER_SIZE, MYF(MY_WME))) |
|
392 |
goto err; |
|
393 |
||
394 |
/* If quick select is used, initialize it before retrieving rows. */
|
|
395 |
if (select && select->quick && select->quick->reset()) |
|
396 |
goto err; |
|
397 |
table->file->try_semi_consistent_read(1); |
|
398 |
||
399 |
/*
|
|
400 |
When we get here, we have one of the following options:
|
|
401 |
A. used_index == MAX_KEY
|
|
402 |
This means we should use full table scan, and start it with
|
|
403 |
init_read_record call
|
|
404 |
B. used_index != MAX_KEY
|
|
405 |
B.1 quick select is used, start the scan with init_read_record
|
|
406 |
B.2 quick select is not used, this is full index scan (with LIMIT)
|
|
407 |
Full index scan must be started with init_read_record_idx
|
|
408 |
*/
|
|
409 |
||
410 |
if (used_index == MAX_KEY || (select && select->quick)) |
|
411 |
init_read_record(&info,thd,table,select,0,1); |
|
412 |
else
|
|
413 |
init_read_record_idx(&info, thd, table, 1, used_index); |
|
414 |
||
415 |
thd_proc_info(thd, "Searching rows for update"); |
|
416 |
ha_rows tmp_limit= limit; |
|
417 |
||
418 |
while (!(error=info.read_record(&info)) && !thd->killed) |
|
419 |
{
|
|
420 |
if (!(select && select->skip_record())) |
|
421 |
{
|
|
422 |
if (table->file->was_semi_consistent_read()) |
|
423 |
continue; /* repeat the read of the same row if it still exists */ |
|
424 |
||
425 |
table->file->position(table->record[0]); |
|
426 |
if (my_b_write(&tempfile,table->file->ref, |
|
427 |
table->file->ref_length)) |
|
428 |
{
|
|
429 |
error=1; /* purecov: inspected */ |
|
430 |
break; /* purecov: inspected */ |
|
431 |
}
|
|
432 |
if (!--limit && using_limit) |
|
433 |
{
|
|
434 |
error= -1; |
|
435 |
break; |
|
436 |
}
|
|
437 |
}
|
|
438 |
else
|
|
439 |
table->file->unlock_row(); |
|
440 |
}
|
|
441 |
if (thd->killed && !error) |
|
442 |
error= 1; // Aborted |
|
443 |
limit= tmp_limit; |
|
444 |
table->file->try_semi_consistent_read(0); |
|
445 |
end_read_record(&info); |
|
446 |
||
447 |
/* Change select to use tempfile */
|
|
448 |
if (select) |
|
449 |
{
|
|
450 |
delete select->quick; |
|
451 |
if (select->free_cond) |
|
452 |
delete select->cond; |
|
453 |
select->quick=0; |
|
454 |
select->cond=0; |
|
455 |
}
|
|
456 |
else
|
|
457 |
{
|
|
458 |
select= new SQL_SELECT; |
|
459 |
select->head=table; |
|
460 |
}
|
|
461 |
if (reinit_io_cache(&tempfile,READ_CACHE,0L,0,0)) |
|
462 |
error=1; /* purecov: inspected */ |
|
463 |
select->file=tempfile; // Read row ptrs from this file |
|
464 |
if (error >= 0) |
|
465 |
goto err; |
|
466 |
}
|
|
467 |
if (table->key_read) |
|
468 |
table->restore_column_maps_after_mark_index(); |
|
469 |
}
|
|
470 |
||
471 |
if (ignore) |
|
472 |
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); |
|
473 |
||
474 |
if (select && select->quick && select->quick->reset()) |
|
475 |
goto err; |
|
476 |
table->file->try_semi_consistent_read(1); |
|
477 |
init_read_record(&info,thd,table,select,0,1); |
|
478 |
||
479 |
updated= found= 0; |
|
480 |
/* Generate an error when trying to set a NOT NULL field to NULL. */
|
|
481 |
thd->count_cuted_fields= ignore ? CHECK_FIELD_WARN |
|
482 |
: CHECK_FIELD_ERROR_FOR_NULL; |
|
483 |
thd->cuted_fields=0L; |
|
484 |
thd_proc_info(thd, "Updating"); |
|
485 |
||
486 |
transactional_table= table->file->has_transactions(); |
|
487 |
thd->abort_on_warning= test(!ignore && |
|
488 |
(thd->variables.sql_mode & |
|
489 |
(MODE_STRICT_TRANS_TABLES | |
|
490 |
MODE_STRICT_ALL_TABLES))); |
|
491 |
will_batch= !table->file->start_bulk_update(); |
|
492 |
||
493 |
/*
|
|
494 |
Assure that we can use position()
|
|
495 |
if we need to create an error message.
|
|
496 |
*/
|
|
497 |
if (table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ) |
|
498 |
table->prepare_for_position(); |
|
499 |
||
500 |
/*
|
|
501 |
We can use compare_record() to optimize away updates if
|
|
502 |
the table handler is returning all columns OR if
|
|
503 |
if all updated columns are read
|
|
504 |
*/
|
|
505 |
can_compare_record= (!(table->file->ha_table_flags() & |
|
506 |
HA_PARTIAL_COLUMN_READ) || |
|
507 |
bitmap_is_subset(table->write_set, table->read_set)); |
|
508 |
||
509 |
while (!(error=info.read_record(&info)) && !thd->killed) |
|
510 |
{
|
|
511 |
if (!(select && select->skip_record())) |
|
512 |
{
|
|
513 |
if (table->file->was_semi_consistent_read()) |
|
514 |
continue; /* repeat the read of the same row if it still exists */ |
|
515 |
||
516 |
store_record(table,record[1]); |
|
517 |
if (fill_record(thd, fields, values, 0)) |
|
518 |
break; /* purecov: inspected */ |
|
519 |
||
520 |
found++; |
|
521 |
||
522 |
if (!can_compare_record || compare_record(table)) |
|
523 |
{
|
|
524 |
if (will_batch) |
|
525 |
{
|
|
526 |
/*
|
|
527 |
Typically a batched handler can execute the batched jobs when:
|
|
528 |
1) When specifically told to do so
|
|
529 |
2) When it is not a good idea to batch anymore
|
|
530 |
3) When it is necessary to send batch for other reasons
|
|
531 |
(One such reason is when READ's must be performed)
|
|
532 |
||
533 |
1) is covered by exec_bulk_update calls.
|
|
534 |
2) and 3) is handled by the bulk_update_row method.
|
|
535 |
|
|
536 |
bulk_update_row can execute the updates including the one
|
|
537 |
defined in the bulk_update_row or not including the row
|
|
538 |
in the call. This is up to the handler implementation and can
|
|
539 |
vary from call to call.
|
|
540 |
||
541 |
The dup_key_found reports the number of duplicate keys found
|
|
542 |
in those updates actually executed. It only reports those if
|
|
543 |
the extra call with HA_EXTRA_IGNORE_DUP_KEY have been issued.
|
|
544 |
If this hasn't been issued it returns an error code and can
|
|
545 |
ignore this number. Thus any handler that implements batching
|
|
546 |
for UPDATE IGNORE must also handle this extra call properly.
|
|
547 |
||
548 |
If a duplicate key is found on the record included in this
|
|
549 |
call then it should be included in the count of dup_key_found
|
|
550 |
and error should be set to 0 (only if these errors are ignored).
|
|
551 |
*/
|
|
552 |
error= table->file->ha_bulk_update_row(table->record[1], |
|
553 |
table->record[0], |
|
554 |
&dup_key_found); |
|
555 |
limit+= dup_key_found; |
|
556 |
updated-= dup_key_found; |
|
557 |
}
|
|
558 |
else
|
|
559 |
{
|
|
560 |
/* Non-batched update */
|
|
561 |
error= table->file->ha_update_row(table->record[1], |
|
562 |
table->record[0]); |
|
563 |
}
|
|
564 |
if (!error || error == HA_ERR_RECORD_IS_THE_SAME) |
|
565 |
{
|
|
566 |
if (error != HA_ERR_RECORD_IS_THE_SAME) |
|
567 |
updated++; |
|
568 |
else
|
|
569 |
error= 0; |
|
570 |
}
|
|
571 |
else if (!ignore || |
|
572 |
table->file->is_fatal_error(error, HA_CHECK_DUP_KEY)) |
|
573 |
{
|
|
574 |
/*
|
|
575 |
If (ignore && error is ignorable) we don't have to
|
|
576 |
do anything; otherwise...
|
|
577 |
*/
|
|
578 |
myf flags= 0; |
|
579 |
||
580 |
if (table->file->is_fatal_error(error, HA_CHECK_DUP_KEY)) |
|
581 |
flags|= ME_FATALERROR; /* Other handler errors are fatal */ |
|
582 |
||
583 |
prepare_record_for_error_message(error, table); |
|
584 |
table->file->print_error(error,MYF(flags)); |
|
585 |
error= 1; |
|
586 |
break; |
|
587 |
}
|
|
588 |
}
|
|
589 |
||
590 |
if (!--limit && using_limit) |
|
591 |
{
|
|
592 |
/*
|
|
593 |
We have reached end-of-file in most common situations where no
|
|
594 |
batching has occurred and if batching was supposed to occur but
|
|
595 |
no updates were made and finally when the batch execution was
|
|
596 |
performed without error and without finding any duplicate keys.
|
|
597 |
If the batched updates were performed with errors we need to
|
|
598 |
check and if no error but duplicate key's found we need to
|
|
599 |
continue since those are not counted for in limit.
|
|
600 |
*/
|
|
601 |
if (will_batch && |
|
602 |
((error= table->file->exec_bulk_update(&dup_key_found)) || |
|
603 |
dup_key_found)) |
|
604 |
{
|
|
605 |
if (error) |
|
606 |
{
|
|
607 |
/* purecov: begin inspected */
|
|
608 |
/*
|
|
609 |
The handler should not report error of duplicate keys if they
|
|
610 |
are ignored. This is a requirement on batching handlers.
|
|
611 |
*/
|
|
612 |
prepare_record_for_error_message(error, table); |
|
613 |
table->file->print_error(error,MYF(0)); |
|
614 |
error= 1; |
|
615 |
break; |
|
616 |
/* purecov: end */
|
|
617 |
}
|
|
618 |
/*
|
|
619 |
Either an error was found and we are ignoring errors or there
|
|
620 |
were duplicate keys found. In both cases we need to correct
|
|
621 |
the counters and continue the loop.
|
|
622 |
*/
|
|
623 |
limit= dup_key_found; //limit is 0 when we get here so need to + |
|
624 |
updated-= dup_key_found; |
|
625 |
}
|
|
626 |
else
|
|
627 |
{
|
|
628 |
error= -1; // Simulate end of file |
|
629 |
break; |
|
630 |
}
|
|
631 |
}
|
|
632 |
}
|
|
633 |
else
|
|
634 |
table->file->unlock_row(); |
|
635 |
thd->row_count++; |
|
636 |
}
|
|
637 |
dup_key_found= 0; |
|
638 |
/*
|
|
639 |
Caching the killed status to pass as the arg to query event constuctor;
|
|
640 |
The cached value can not change whereas the killed status can
|
|
641 |
(externally) since this point and change of the latter won't affect
|
|
642 |
binlogging.
|
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
643 |
It's assumed that if an error was set in combination with an effective
|
1
by brian
clean slate |
644 |
killed status then the error is due to killing.
|
645 |
*/
|
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
646 |
killed_status= thd->killed; // get the status of the volatile |
1
by brian
clean slate |
647 |
// simulated killing after the loop must be ineffective for binlogging
|
648 |
error= (killed_status == THD::NOT_KILLED)? error : 1; |
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
649 |
|
1
by brian
clean slate |
650 |
if (error && |
651 |
will_batch && |
|
652 |
(loc_error= table->file->exec_bulk_update(&dup_key_found))) |
|
653 |
/*
|
|
654 |
An error has occurred when a batched update was performed and returned
|
|
655 |
an error indication. It cannot be an allowed duplicate key error since
|
|
656 |
we require the batching handler to treat this as a normal behavior.
|
|
657 |
||
658 |
Otherwise we simply remove the number of duplicate keys records found
|
|
659 |
in the batched update.
|
|
660 |
*/
|
|
661 |
{
|
|
662 |
/* purecov: begin inspected */
|
|
663 |
prepare_record_for_error_message(loc_error, table); |
|
664 |
table->file->print_error(loc_error,MYF(ME_FATALERROR)); |
|
665 |
error= 1; |
|
666 |
/* purecov: end */
|
|
667 |
}
|
|
668 |
else
|
|
669 |
updated-= dup_key_found; |
|
670 |
if (will_batch) |
|
671 |
table->file->end_bulk_update(); |
|
672 |
table->file->try_semi_consistent_read(0); |
|
673 |
||
674 |
if (!transactional_table && updated > 0) |
|
56
by brian
Next pass of true/false update. |
675 |
thd->transaction.stmt.modified_non_trans_table= true; |
1
by brian
clean slate |
676 |
|
677 |
end_read_record(&info); |
|
678 |
delete select; |
|
679 |
thd_proc_info(thd, "end"); |
|
680 |
VOID(table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY)); |
|
681 |
||
682 |
/*
|
|
683 |
error < 0 means really no error at all: we processed all rows until the
|
|
684 |
last one without error. error > 0 means an error (e.g. unique key
|
|
685 |
violation and no IGNORE or REPLACE). error == 0 is also an error (if
|
|
686 |
preparing the record or invoking before triggers fails). See
|
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
687 |
ha_autocommit_or_rollback(error>=0) and return(error>=0) below.
|
1
by brian
clean slate |
688 |
Sometimes we want to binlog even if we updated no rows, in case user used
|
689 |
it to be sure master and slave are in same state.
|
|
690 |
*/
|
|
691 |
if ((error < 0) || thd->transaction.stmt.modified_non_trans_table) |
|
692 |
{
|
|
693 |
if (mysql_bin_log.is_open()) |
|
694 |
{
|
|
695 |
if (error < 0) |
|
696 |
thd->clear_error(); |
|
697 |
if (thd->binlog_query(THD::ROW_QUERY_TYPE, |
|
698 |
thd->query, thd->query_length, |
|
56
by brian
Next pass of true/false update. |
699 |
transactional_table, false, killed_status) && |
1
by brian
clean slate |
700 |
transactional_table) |
701 |
{
|
|
702 |
error=1; // Rollback update |
|
703 |
}
|
|
704 |
}
|
|
705 |
if (thd->transaction.stmt.modified_non_trans_table) |
|
56
by brian
Next pass of true/false update. |
706 |
thd->transaction.all.modified_non_trans_table= true; |
1
by brian
clean slate |
707 |
}
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
708 |
assert(transactional_table || !updated || thd->transaction.stmt.modified_non_trans_table); |
1
by brian
clean slate |
709 |
free_underlaid_joins(thd, select_lex); |
710 |
||
711 |
/* If LAST_INSERT_ID(X) was used, report X */
|
|
712 |
id= thd->arg_of_last_insert_id_function ? |
|
713 |
thd->first_successful_insert_id_in_prev_stmt : 0; |
|
714 |
||
715 |
MYSQL_UPDATE_END(); |
|
716 |
if (error < 0) |
|
717 |
{
|
|
718 |
char buff[STRING_BUFFER_USUAL_SIZE]; |
|
719 |
sprintf(buff, ER(ER_UPDATE_INFO), (ulong) found, (ulong) updated, |
|
720 |
(ulong) thd->cuted_fields); |
|
721 |
thd->row_count_func= |
|
722 |
(thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated; |
|
723 |
my_ok(thd, (ulong) thd->row_count_func, id, buff); |
|
724 |
}
|
|
725 |
thd->count_cuted_fields= CHECK_FIELD_IGNORE; /* calc cuted fields */ |
|
726 |
thd->abort_on_warning= 0; |
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
727 |
return((error >= 0 || thd->is_error()) ? 1 : 0); |
1
by brian
clean slate |
728 |
|
729 |
err: |
|
730 |
delete select; |
|
731 |
free_underlaid_joins(thd, select_lex); |
|
732 |
if (table->key_read) |
|
733 |
{
|
|
734 |
table->key_read=0; |
|
735 |
table->file->extra(HA_EXTRA_NO_KEYREAD); |
|
736 |
}
|
|
737 |
thd->abort_on_warning= 0; |
|
738 |
||
739 |
abort: |
|
740 |
MYSQL_UPDATE_END(); |
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
741 |
return(1); |
1
by brian
clean slate |
742 |
}
|
743 |
||
744 |
/*
|
|
745 |
Prepare items in UPDATE statement
|
|
746 |
||
747 |
SYNOPSIS
|
|
748 |
mysql_prepare_update()
|
|
749 |
thd - thread handler
|
|
750 |
table_list - global/local table list
|
|
751 |
conds - conditions
|
|
752 |
order_num - number of ORDER BY list entries
|
|
753 |
order - ORDER BY clause list
|
|
754 |
||
755 |
RETURN VALUE
|
|
56
by brian
Next pass of true/false update. |
756 |
false OK
|
757 |
true error
|
|
1
by brian
clean slate |
758 |
*/
|
759 |
bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list, |
|
760 |
Item **conds, uint order_num, ORDER *order) |
|
761 |
{
|
|
762 |
List<Item> all_fields; |
|
763 |
SELECT_LEX *select_lex= &thd->lex->select_lex; |
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
764 |
|
1
by brian
clean slate |
765 |
/*
|
766 |
Statement-based replication of UPDATE ... LIMIT is not safe as order of
|
|
767 |
rows is not defined, so in mixed mode we go to row-based.
|
|
768 |
||
769 |
Note that we may consider a statement as safe if ORDER BY primary_key
|
|
770 |
is present. However it may confuse users to see very similiar statements
|
|
771 |
replicated differently.
|
|
772 |
*/
|
|
773 |
if (thd->lex->current_select->select_limit) |
|
774 |
{
|
|
775 |
thd->lex->set_stmt_unsafe(); |
|
776 |
thd->set_current_stmt_binlog_row_based_if_mixed(); |
|
777 |
}
|
|
778 |
||
779 |
thd->lex->allow_sum_func= 0; |
|
780 |
||
781 |
if (setup_tables_and_check_access(thd, &select_lex->context, |
|
782 |
&select_lex->top_join_list, |
|
783 |
table_list, |
|
784 |
&select_lex->leaf_tables, |
|
785 |
false) || |
|
786 |
setup_conds(thd, table_list, select_lex->leaf_tables, conds) || |
|
787 |
select_lex->setup_ref_array(thd, order_num) || |
|
788 |
setup_order(thd, select_lex->ref_pointer_array, |
|
789 |
table_list, all_fields, all_fields, order)) |
|
51.1.8
by Jay Pipes
Resolving conflicts for a few files regarding FALSE=>false |
790 |
return(true); |
1
by brian
clean slate |
791 |
|
792 |
/* Check that we are not using table that we are updating in a sub select */
|
|
793 |
{
|
|
794 |
TABLE_LIST *duplicate; |
|
795 |
if ((duplicate= unique_table(thd, table_list, table_list->next_global, 0))) |
|
796 |
{
|
|
797 |
update_non_unique_table_error(table_list, "UPDATE", duplicate); |
|
798 |
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name); |
|
51.1.8
by Jay Pipes
Resolving conflicts for a few files regarding FALSE=>false |
799 |
return(true); |
1
by brian
clean slate |
800 |
}
|
801 |
}
|
|
177.1.1
by brian
Removed dead code around prep. |
802 |
|
51.1.8
by Jay Pipes
Resolving conflicts for a few files regarding FALSE=>false |
803 |
return(false); |
1
by brian
clean slate |
804 |
}
|
805 |
||
806 |
||
807 |
/***************************************************************************
|
|
808 |
Update multiple tables from join
|
|
809 |
***************************************************************************/
|
|
810 |
||
811 |
/*
|
|
812 |
Get table map for list of Item_field
|
|
813 |
*/
|
|
814 |
||
815 |
static table_map get_table_map(List<Item> *items) |
|
816 |
{
|
|
817 |
List_iterator_fast<Item> item_it(*items); |
|
818 |
Item_field *item; |
|
819 |
table_map map= 0; |
|
820 |
||
821 |
while ((item= (Item_field *) item_it++)) |
|
822 |
map|= item->used_tables(); |
|
823 |
return map; |
|
824 |
}
|
|
825 |
||
826 |
||
827 |
/*
|
|
828 |
make update specific preparation and checks after opening tables
|
|
829 |
||
830 |
SYNOPSIS
|
|
831 |
mysql_multi_update_prepare()
|
|
832 |
thd thread handler
|
|
833 |
||
834 |
RETURN
|
|
56
by brian
Next pass of true/false update. |
835 |
false OK
|
836 |
true Error
|
|
1
by brian
clean slate |
837 |
*/
|
838 |
||
839 |
int mysql_multi_update_prepare(THD *thd) |
|
840 |
{
|
|
841 |
LEX *lex= thd->lex; |
|
842 |
TABLE_LIST *table_list= lex->query_tables; |
|
843 |
TABLE_LIST *tl, *leaves; |
|
844 |
List<Item> *fields= &lex->select_lex.item_list; |
|
845 |
table_map tables_for_update; |
|
846 |
bool update_view= 0; |
|
847 |
/*
|
|
848 |
if this multi-update was converted from usual update, here is table
|
|
849 |
counter else junk will be assigned here, but then replaced with real
|
|
850 |
count in open_tables()
|
|
851 |
*/
|
|
852 |
uint table_count= lex->table_count; |
|
853 |
const bool using_lock_tables= thd->locked_tables != 0; |
|
854 |
bool original_multiupdate= (thd->lex->sql_command == SQLCOM_UPDATE_MULTI); |
|
56
by brian
Next pass of true/false update. |
855 |
bool need_reopen= false; |
51.2.2
by Patrick Galbraith
Removed DBUGs from |
856 |
|
1
by brian
clean slate |
857 |
|
858 |
/* following need for prepared statements, to run next time multi-update */
|
|
859 |
thd->lex->sql_command= SQLCOM_UPDATE_MULTI; |
|
860 |
||
861 |
reopen_tables: |
|
862 |
||
863 |
/* open tables and create derived ones, but do not lock and fill them */
|
|
864 |
if (((original_multiupdate || need_reopen) && |
|
865 |
open_tables(thd, &table_list, &table_count, 0)) || |
|
866 |
mysql_handle_derived(lex, &mysql_derived_prepare)) |
|
51.1.8
by Jay Pipes
Resolving conflicts for a few files regarding FALSE=>false |
867 |
return(true); |
1
by brian
clean slate |
868 |
/*
|
869 |
setup_tables() need for VIEWs. JOIN::prepare() will call setup_tables()
|
|
870 |
second time, but this call will do nothing (there are check for second
|
|
871 |
call in setup_tables()).
|
|
872 |
*/
|
|
873 |
||
874 |
if (setup_tables_and_check_access(thd, &lex->select_lex.context, |
|
875 |
&lex->select_lex.top_join_list, |
|
876 |
table_list, |
|
877 |
&lex->select_lex.leaf_tables, false)) |
|
51.1.8
by Jay Pipes
Resolving conflicts for a few files regarding FALSE=>false |
878 |
return(true); |
1
by brian
clean slate |
879 |
|
880 |
if (setup_fields_with_no_wrap(thd, 0, *fields, MARK_COLUMNS_WRITE, 0, 0)) |
|
51.1.8
by Jay Pipes
Resolving conflicts for a few files regarding FALSE=>false |
881 |
return(true); |
1
by brian
clean slate |
882 |
|
883 |
if (update_view && check_fields(thd, *fields)) |
|
884 |
{
|
|
51.1.8
by Jay Pipes
Resolving conflicts for a few files regarding FALSE=>false |
885 |
return(true); |
1
by brian
clean slate |
886 |
}
|
887 |
||
888 |
tables_for_update= get_table_map(fields); |
|
889 |
||
890 |
/*
|
|
891 |
Setup timestamp handling and locking mode
|
|
892 |
*/
|
|
893 |
leaves= lex->select_lex.leaf_tables; |
|
894 |
for (tl= leaves; tl; tl= tl->next_leaf) |
|
895 |
{
|
|
896 |
TABLE *table= tl->table; |
|
897 |
/* Only set timestamp column if this is not modified */
|
|
898 |
if (table->timestamp_field && |
|
899 |
bitmap_is_set(table->write_set, |
|
900 |
table->timestamp_field->field_index)) |
|
901 |
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET; |
|
902 |
||
903 |
/* if table will be updated then check that it is unique */
|
|
904 |
if (table->map & tables_for_update) |
|
905 |
{
|
|
906 |
table->mark_columns_needed_for_update(); |
|
907 |
/*
|
|
908 |
If table will be updated we should not downgrade lock for it and
|
|
909 |
leave it as is.
|
|
910 |
*/
|
|
911 |
}
|
|
912 |
else
|
|
913 |
{
|
|
914 |
/*
|
|
915 |
If we are using the binary log, we need TL_READ_NO_INSERT to get
|
|
916 |
correct order of statements. Otherwise, we use a TL_READ lock to
|
|
917 |
improve performance.
|
|
918 |
*/
|
|
919 |
tl->lock_type= using_update_log ? TL_READ_NO_INSERT : TL_READ; |
|
920 |
tl->updating= 0; |
|
921 |
/* Update TABLE::lock_type accordingly. */
|
|
922 |
if (!tl->placeholder() && !using_lock_tables) |
|
923 |
tl->table->reginfo.lock_type= tl->lock_type; |
|
924 |
}
|
|
925 |
}
|
|
926 |
||
927 |
/* now lock and fill tables */
|
|
928 |
if (lock_tables(thd, table_list, table_count, &need_reopen)) |
|
929 |
{
|
|
930 |
if (!need_reopen) |
|
51.1.8
by Jay Pipes
Resolving conflicts for a few files regarding FALSE=>false |
931 |
return(true); |
1
by brian
clean slate |
932 |
|
933 |
/*
|
|
934 |
We have to reopen tables since some of them were altered or dropped
|
|
935 |
during lock_tables() or something was done with their triggers.
|
|
936 |
Let us do some cleanups to be able do setup_table() and setup_fields()
|
|
937 |
once again.
|
|
938 |
*/
|
|
939 |
List_iterator_fast<Item> it(*fields); |
|
940 |
Item *item; |
|
941 |
while ((item= it++)) |
|
942 |
item->cleanup(); |
|
943 |
||
944 |
/* We have to cleanup translation tables of views. */
|
|
945 |
for (TABLE_LIST *tbl= table_list; tbl; tbl= tbl->next_global) |
|
946 |
tbl->cleanup_items(); |
|
947 |
||
948 |
close_tables_for_reopen(thd, &table_list); |
|
949 |
goto reopen_tables; |
|
950 |
}
|
|
951 |
||
952 |
/*
|
|
953 |
Check that we are not using table that we are updating, but we should
|
|
954 |
skip all tables of UPDATE SELECT itself
|
|
955 |
*/
|
|
56
by brian
Next pass of true/false update. |
956 |
lex->select_lex.exclude_from_table_unique_test= true; |
1
by brian
clean slate |
957 |
/* We only need SELECT privilege for columns in the values list */
|
958 |
for (tl= leaves; tl; tl= tl->next_leaf) |
|
959 |
{
|
|
960 |
if (tl->lock_type != TL_READ && |
|
961 |
tl->lock_type != TL_READ_NO_INSERT) |
|
962 |
{
|
|
963 |
TABLE_LIST *duplicate; |
|
964 |
if ((duplicate= unique_table(thd, tl, table_list, 0))) |
|
965 |
{
|
|
966 |
update_non_unique_table_error(table_list, "UPDATE", duplicate); |
|
51.1.8
by Jay Pipes
Resolving conflicts for a few files regarding FALSE=>false |
967 |
return(true); |
1
by brian
clean slate |
968 |
}
|
969 |
}
|
|
970 |
}
|
|
971 |
/*
|
|
56
by brian
Next pass of true/false update. |
972 |
Set exclude_from_table_unique_test value back to false. It is needed for
|
1
by brian
clean slate |
973 |
further check in multi_update::prepare whether to use record cache.
|
974 |
*/
|
|
56
by brian
Next pass of true/false update. |
975 |
lex->select_lex.exclude_from_table_unique_test= false; |
1
by brian
clean slate |
976 |
|
977 |
if (thd->fill_derived_tables() && |
|
978 |
mysql_handle_derived(lex, &mysql_derived_filling)) |
|
51.1.8
by Jay Pipes
Resolving conflicts for a few files regarding FALSE=>false |
979 |
return(true); |
1
by brian
clean slate |
980 |
|
51.1.8
by Jay Pipes
Resolving conflicts for a few files regarding FALSE=>false |
981 |
return (false); |
1
by brian
clean slate |
982 |
}
|
983 |
||
984 |
||
985 |
/*
|
|
986 |
Setup multi-update handling and call SELECT to do the join
|
|
987 |
*/
|
|
988 |
||
989 |
bool mysql_multi_update(THD *thd, |
|
990 |
TABLE_LIST *table_list, |
|
991 |
List<Item> *fields, |
|
992 |
List<Item> *values, |
|
993 |
COND *conds, |
|
151
by Brian Aker
Ulonglong to uint64_t |
994 |
uint64_t options, |
1
by brian
clean slate |
995 |
enum enum_duplicates handle_duplicates, bool ignore, |
996 |
SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex) |
|
997 |
{
|
|
998 |
multi_update *result; |
|
999 |
bool res; |
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
1000 |
|
1
by brian
clean slate |
1001 |
if (!(result= new multi_update(table_list, |
1002 |
thd->lex->select_lex.leaf_tables, |
|
1003 |
fields, values, |
|
1004 |
handle_duplicates, ignore))) |
|
51.1.8
by Jay Pipes
Resolving conflicts for a few files regarding FALSE=>false |
1005 |
return(true); |
1
by brian
clean slate |
1006 |
|
1007 |
thd->abort_on_warning= test(thd->variables.sql_mode & |
|
1008 |
(MODE_STRICT_TRANS_TABLES | |
|
1009 |
MODE_STRICT_ALL_TABLES)); |
|
1010 |
||
1011 |
List<Item> total_list; |
|
1012 |
res= mysql_select(thd, &select_lex->ref_pointer_array, |
|
1013 |
table_list, select_lex->with_wild, |
|
1014 |
total_list, |
|
1015 |
conds, 0, (ORDER *) NULL, (ORDER *)NULL, (Item *) NULL, |
|
1016 |
(ORDER *)NULL, |
|
1017 |
options | SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK | |
|
1018 |
OPTION_SETUP_TABLES_DONE, |
|
1019 |
result, unit, select_lex); |
|
1020 |
res|= thd->is_error(); |
|
1021 |
if (unlikely(res)) |
|
1022 |
{
|
|
1023 |
/* If we had a another error reported earlier then this will be ignored */
|
|
1024 |
result->send_error(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR)); |
|
1025 |
result->abort(); |
|
1026 |
}
|
|
1027 |
delete result; |
|
1028 |
thd->abort_on_warning= 0; |
|
51.1.8
by Jay Pipes
Resolving conflicts for a few files regarding FALSE=>false |
1029 |
return(false); |
1
by brian
clean slate |
1030 |
}
|
1031 |
||
1032 |
||
1033 |
multi_update::multi_update(TABLE_LIST *table_list, |
|
1034 |
TABLE_LIST *leaves_list, |
|
1035 |
List<Item> *field_list, List<Item> *value_list, |
|
1036 |
enum enum_duplicates handle_duplicates_arg, |
|
1037 |
bool ignore_arg) |
|
1038 |
:all_tables(table_list), leaves(leaves_list), update_tables(0), |
|
1039 |
tmp_tables(0), updated(0), found(0), fields(field_list), |
|
1040 |
values(value_list), table_count(0), copy_field(0), |
|
1041 |
handle_duplicates(handle_duplicates_arg), do_update(1), trans_safe(1), |
|
1042 |
transactional_tables(0), ignore(ignore_arg), error_handled(0) |
|
1043 |
{}
|
|
1044 |
||
1045 |
||
1046 |
/*
|
|
1047 |
Connect fields with tables and create list of tables that are updated
|
|
1048 |
*/
|
|
1049 |
||
212.1.3
by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)). |
1050 |
int multi_update::prepare(List<Item> ¬_used_values __attribute__((unused)), |
1051 |
SELECT_LEX_UNIT *lex_unit __attribute__((unused))) |
|
1
by brian
clean slate |
1052 |
{
|
1053 |
TABLE_LIST *table_ref; |
|
1054 |
SQL_LIST update; |
|
1055 |
table_map tables_to_update; |
|
1056 |
Item_field *item; |
|
1057 |
List_iterator_fast<Item> field_it(*fields); |
|
1058 |
List_iterator_fast<Item> value_it(*values); |
|
1059 |
uint i, max_fields; |
|
1060 |
uint leaf_table_count= 0; |
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
1061 |
|
1
by brian
clean slate |
1062 |
thd->count_cuted_fields= CHECK_FIELD_WARN; |
1063 |
thd->cuted_fields=0L; |
|
1064 |
thd_proc_info(thd, "updating main table"); |
|
1065 |
||
1066 |
tables_to_update= get_table_map(fields); |
|
1067 |
||
1068 |
if (!tables_to_update) |
|
1069 |
{
|
|
1070 |
my_message(ER_NO_TABLES_USED, ER(ER_NO_TABLES_USED), MYF(0)); |
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
1071 |
return(1); |
1
by brian
clean slate |
1072 |
}
|
1073 |
||
1074 |
/*
|
|
1075 |
We have to check values after setup_tables to get covering_keys right in
|
|
1076 |
reference tables
|
|
1077 |
*/
|
|
1078 |
||
1079 |
if (setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0)) |
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
1080 |
return(1); |
1
by brian
clean slate |
1081 |
|
1082 |
/*
|
|
1083 |
Save tables beeing updated in update_tables
|
|
1084 |
update_table->shared is position for table
|
|
1085 |
Don't use key read on tables that are updated
|
|
1086 |
*/
|
|
1087 |
||
1088 |
update.empty(); |
|
1089 |
for (table_ref= leaves; table_ref; table_ref= table_ref->next_leaf) |
|
1090 |
{
|
|
1091 |
/* TODO: add support of view of join support */
|
|
1092 |
TABLE *table=table_ref->table; |
|
1093 |
leaf_table_count++; |
|
1094 |
if (tables_to_update & table->map) |
|
1095 |
{
|
|
1096 |
TABLE_LIST *tl= (TABLE_LIST*) thd->memdup((char*) table_ref, |
|
1097 |
sizeof(*tl)); |
|
1098 |
if (!tl) |
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
1099 |
return(1); |
1
by brian
clean slate |
1100 |
update.link_in_list((uchar*) tl, (uchar**) &tl->next_local); |
1101 |
tl->shared= table_count++; |
|
1102 |
table->no_keyread=1; |
|
1103 |
table->covering_keys.clear_all(); |
|
1104 |
table->pos_in_table_list= tl; |
|
1105 |
}
|
|
1106 |
}
|
|
1107 |
||
1108 |
||
1109 |
table_count= update.elements; |
|
1110 |
update_tables= (TABLE_LIST*) update.first; |
|
1111 |
||
1112 |
tmp_tables = (TABLE**) thd->calloc(sizeof(TABLE *) * table_count); |
|
1113 |
tmp_table_param = (TMP_TABLE_PARAM*) thd->calloc(sizeof(TMP_TABLE_PARAM) * |
|
1114 |
table_count); |
|
1115 |
fields_for_table= (List_item **) thd->alloc(sizeof(List_item *) * |
|
1116 |
table_count); |
|
1117 |
values_for_table= (List_item **) thd->alloc(sizeof(List_item *) * |
|
1118 |
table_count); |
|
1119 |
if (thd->is_fatal_error) |
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
1120 |
return(1); |
1
by brian
clean slate |
1121 |
for (i=0 ; i < table_count ; i++) |
1122 |
{
|
|
1123 |
fields_for_table[i]= new List_item; |
|
1124 |
values_for_table[i]= new List_item; |
|
1125 |
}
|
|
1126 |
if (thd->is_fatal_error) |
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
1127 |
return(1); |
1
by brian
clean slate |
1128 |
|
1129 |
/* Split fields into fields_for_table[] and values_by_table[] */
|
|
1130 |
||
1131 |
while ((item= (Item_field *) field_it++)) |
|
1132 |
{
|
|
1133 |
Item *value= value_it++; |
|
1134 |
uint offset= item->field->table->pos_in_table_list->shared; |
|
1135 |
fields_for_table[offset]->push_back(item); |
|
1136 |
values_for_table[offset]->push_back(value); |
|
1137 |
}
|
|
1138 |
if (thd->is_fatal_error) |
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
1139 |
return(1); |
1
by brian
clean slate |
1140 |
|
1141 |
/* Allocate copy fields */
|
|
1142 |
max_fields=0; |
|
1143 |
for (i=0 ; i < table_count ; i++) |
|
1144 |
set_if_bigger(max_fields, fields_for_table[i]->elements + leaf_table_count); |
|
1145 |
copy_field= new Copy_field[max_fields]; |
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
1146 |
return(thd->is_fatal_error != 0); |
1
by brian
clean slate |
1147 |
}
|
1148 |
||
1149 |
||
1150 |
/*
|
|
1151 |
Check if table is safe to update on fly
|
|
1152 |
||
1153 |
SYNOPSIS
|
|
1154 |
safe_update_on_fly()
|
|
1155 |
thd Thread handler
|
|
1156 |
join_tab How table is used in join
|
|
1157 |
all_tables List of tables
|
|
1158 |
||
1159 |
NOTES
|
|
1160 |
We can update the first table in join on the fly if we know that
|
|
1161 |
a row in this table will never be read twice. This is true under
|
|
1162 |
the following conditions:
|
|
1163 |
||
1164 |
- We are doing a table scan and the data is in a separate file (MyISAM) or
|
|
1165 |
if we don't update a clustered key.
|
|
1166 |
||
1167 |
- We are doing a range scan and we don't update the scan key or
|
|
1168 |
the primary key for a clustered table handler.
|
|
1169 |
||
1170 |
- Table is not joined to itself.
|
|
1171 |
||
1172 |
This function gets information about fields to be updated from
|
|
1173 |
the TABLE::write_set bitmap.
|
|
1174 |
||
1175 |
WARNING
|
|
1176 |
This code is a bit dependent of how make_join_readinfo() works.
|
|
1177 |
||
1178 |
RETURN
|
|
1179 |
0 Not safe to update
|
|
1180 |
1 Safe to update
|
|
1181 |
*/
|
|
1182 |
||
1183 |
static bool safe_update_on_fly(THD *thd, JOIN_TAB *join_tab, |
|
1184 |
TABLE_LIST *table_ref, TABLE_LIST *all_tables) |
|
1185 |
{
|
|
1186 |
TABLE *table= join_tab->table; |
|
1187 |
if (unique_table(thd, table_ref, all_tables, 0)) |
|
1188 |
return 0; |
|
1189 |
switch (join_tab->type) { |
|
1190 |
case JT_SYSTEM: |
|
1191 |
case JT_CONST: |
|
1192 |
case JT_EQ_REF: |
|
56
by brian
Next pass of true/false update. |
1193 |
return true; // At most one matching row |
1
by brian
clean slate |
1194 |
case JT_REF: |
1195 |
case JT_REF_OR_NULL: |
|
1196 |
return !is_key_used(table, join_tab->ref.key, table->write_set); |
|
1197 |
case JT_ALL: |
|
1198 |
/* If range search on index */
|
|
1199 |
if (join_tab->quick) |
|
1200 |
return !join_tab->quick->is_keys_used(table->write_set); |
|
1201 |
/* If scanning in clustered key */
|
|
1202 |
if ((table->file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) && |
|
1203 |
table->s->primary_key < MAX_KEY) |
|
1204 |
return !is_key_used(table, table->s->primary_key, table->write_set); |
|
56
by brian
Next pass of true/false update. |
1205 |
return true; |
1
by brian
clean slate |
1206 |
default: |
1207 |
break; // Avoid compler warning |
|
1208 |
}
|
|
56
by brian
Next pass of true/false update. |
1209 |
return false; |
1
by brian
clean slate |
1210 |
|
1211 |
}
|
|
1212 |
||
1213 |
||
1214 |
/*
|
|
1215 |
Initialize table for multi table
|
|
1216 |
||
1217 |
IMPLEMENTATION
|
|
1218 |
- Update first table in join on the fly, if possible
|
|
1219 |
- Create temporary tables to store changed values for all other tables
|
|
1220 |
that are updated (and main_table if the above doesn't hold).
|
|
1221 |
*/
|
|
1222 |
||
1223 |
bool
|
|
1224 |
multi_update::initialize_tables(JOIN *join) |
|
1225 |
{
|
|
1226 |
TABLE_LIST *table_ref; |
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
1227 |
|
1
by brian
clean slate |
1228 |
if ((thd->options & OPTION_SAFE_UPDATES) && error_if_full_join(join)) |
51.2.2
by Patrick Galbraith
Removed DBUGs from |
1229 |
return(1); |
1
by brian
clean slate |
1230 |
main_table=join->join_tab->table; |
1231 |
table_to_update= 0; |
|
1232 |
||
1233 |
/* Any update has at least one pair (field, value) */
|
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
1234 |
assert(fields->elements); |
1
by brian
clean slate |
1235 |
|
1236 |
/* Create a temporary table for keys to all tables, except main table */
|
|
1237 |
for (table_ref= update_tables; table_ref; table_ref= table_ref->next_local) |
|
1238 |
{
|
|
1239 |
TABLE *table=table_ref->table; |
|
1240 |
uint cnt= table_ref->shared; |
|
1241 |
List<Item> temp_fields; |
|
1242 |
ORDER group; |
|
1243 |
TMP_TABLE_PARAM *tmp_param; |
|
1244 |
||
1245 |
table->mark_columns_needed_for_update(); |
|
1246 |
if (ignore) |
|
1247 |
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); |
|
1248 |
if (table == main_table) // First table in join |
|
1249 |
{
|
|
1250 |
if (safe_update_on_fly(thd, join->join_tab, table_ref, all_tables)) |
|
1251 |
{
|
|
1252 |
table_to_update= main_table; // Update table on the fly |
|
1253 |
continue; |
|
1254 |
}
|
|
1255 |
}
|
|
1256 |
table->prepare_for_position(); |
|
1257 |
||
1258 |
tmp_param= tmp_table_param+cnt; |
|
1259 |
||
1260 |
/*
|
|
1261 |
Create a temporary table to store all fields that are changed for this
|
|
1262 |
table. The first field in the temporary table is a pointer to the
|
|
1263 |
original row so that we can find and update it. For the updatable
|
|
1264 |
VIEW a few following fields are rowids of tables used in the CHECK
|
|
1265 |
OPTION condition.
|
|
1266 |
*/
|
|
1267 |
||
1268 |
List_iterator_fast<TABLE> tbl_it(unupdated_check_opt_tables); |
|
1269 |
TABLE *tbl= table; |
|
1270 |
do
|
|
1271 |
{
|
|
1272 |
Field_string *field= new Field_string(tbl->file->ref_length, 0, |
|
1273 |
tbl->alias, &my_charset_bin); |
|
241
by Brian Aker
First pass of CHAR removal. |
1274 |
#ifdef OLD
|
1275 |
Field_varstring *field= new Field_varstring(tbl->file->ref_length, 0, |
|
1276 |
tbl->alias, tbl->s, &my_charset_bin); |
|
1277 |
#endif
|
|
1
by brian
clean slate |
1278 |
if (!field) |
51.2.2
by Patrick Galbraith
Removed DBUGs from |
1279 |
return(1); |
1
by brian
clean slate |
1280 |
field->init(tbl); |
1281 |
/*
|
|
1282 |
The field will be converted to varstring when creating tmp table if
|
|
1283 |
table to be updated was created by mysql 4.1. Deny this.
|
|
1284 |
*/
|
|
1285 |
Item_field *ifield= new Item_field((Field *) field); |
|
1286 |
if (!ifield) |
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
1287 |
return(1); |
1
by brian
clean slate |
1288 |
ifield->maybe_null= 0; |
1289 |
if (temp_fields.push_back(ifield)) |
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
1290 |
return(1); |
1
by brian
clean slate |
1291 |
} while ((tbl= tbl_it++)); |
1292 |
||
1293 |
temp_fields.concat(fields_for_table[cnt]); |
|
1294 |
||
1295 |
/* Make an unique key over the first field to avoid duplicated updates */
|
|
212.6.6
by Mats Kindahl
Removing redundant use of casts in drizzled/ for memcmp(), memcpy(), memset(), and memmove(). |
1296 |
memset(&group, 0, sizeof(group)); |
1
by brian
clean slate |
1297 |
group.asc= 1; |
1298 |
group.item= (Item**) temp_fields.head_ref(); |
|
1299 |
||
1300 |
tmp_param->quick_group=1; |
|
1301 |
tmp_param->field_count=temp_fields.elements; |
|
1302 |
tmp_param->group_parts=1; |
|
1303 |
tmp_param->group_length= table->file->ref_length; |
|
1304 |
if (!(tmp_tables[cnt]=create_tmp_table(thd, |
|
1305 |
tmp_param, |
|
1306 |
temp_fields, |
|
1307 |
(ORDER*) &group, 0, 0, |
|
1308 |
TMP_TABLE_ALL_COLUMNS, |
|
1309 |
HA_POS_ERROR, |
|
1310 |
(char *) ""))) |
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
1311 |
return(1); |
1
by brian
clean slate |
1312 |
tmp_tables[cnt]->file->extra(HA_EXTRA_WRITE_CACHE); |
1313 |
}
|
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
1314 |
return(0); |
1
by brian
clean slate |
1315 |
}
|
1316 |
||
1317 |
||
1318 |
multi_update::~multi_update() |
|
1319 |
{
|
|
1320 |
TABLE_LIST *table; |
|
1321 |
for (table= update_tables ; table; table= table->next_local) |
|
1322 |
{
|
|
1323 |
table->table->no_keyread= table->table->no_cache= 0; |
|
1324 |
if (ignore) |
|
1325 |
table->table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); |
|
1326 |
}
|
|
1327 |
||
1328 |
if (tmp_tables) |
|
1329 |
{
|
|
1330 |
for (uint cnt = 0; cnt < table_count; cnt++) |
|
1331 |
{
|
|
1332 |
if (tmp_tables[cnt]) |
|
1333 |
{
|
|
1334 |
free_tmp_table(thd, tmp_tables[cnt]); |
|
1335 |
tmp_table_param[cnt].cleanup(); |
|
1336 |
}
|
|
1337 |
}
|
|
1338 |
}
|
|
1339 |
if (copy_field) |
|
1340 |
delete [] copy_field; |
|
1341 |
thd->count_cuted_fields= CHECK_FIELD_IGNORE; // Restore this setting |
|
77.1.45
by Monty Taylor
Warning fixes. |
1342 |
assert(trans_safe || !updated || |
1
by brian
clean slate |
1343 |
thd->transaction.all.modified_non_trans_table); |
1344 |
}
|
|
1345 |
||
1346 |
||
212.1.3
by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)). |
1347 |
bool multi_update::send_data(List<Item> ¬_used_values __attribute__((unused))) |
1
by brian
clean slate |
1348 |
{
|
1349 |
TABLE_LIST *cur_table; |
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
1350 |
|
1
by brian
clean slate |
1351 |
for (cur_table= update_tables; cur_table; cur_table= cur_table->next_local) |
1352 |
{
|
|
1353 |
TABLE *table= cur_table->table; |
|
1354 |
uint offset= cur_table->shared; |
|
1355 |
/*
|
|
1356 |
Check if we are using outer join and we didn't find the row
|
|
1357 |
or if we have already updated this row in the previous call to this
|
|
1358 |
function.
|
|
1359 |
||
1360 |
The same row may be presented here several times in a join of type
|
|
1361 |
UPDATE t1 FROM t1,t2 SET t1.a=t2.a
|
|
1362 |
||
1363 |
In this case we will do the update for the first found row combination.
|
|
1364 |
The join algorithm guarantees that we will not find the a row in
|
|
1365 |
t1 several times.
|
|
1366 |
*/
|
|
1367 |
if (table->status & (STATUS_NULL_ROW | STATUS_UPDATED)) |
|
1368 |
continue; |
|
1369 |
||
1370 |
/*
|
|
1371 |
We can use compare_record() to optimize away updates if
|
|
1372 |
the table handler is returning all columns OR if
|
|
1373 |
if all updated columns are read
|
|
1374 |
*/
|
|
1375 |
if (table == table_to_update) |
|
1376 |
{
|
|
1377 |
bool can_compare_record; |
|
1378 |
can_compare_record= (!(table->file->ha_table_flags() & |
|
1379 |
HA_PARTIAL_COLUMN_READ) || |
|
1380 |
bitmap_is_subset(table->write_set, |
|
1381 |
table->read_set)); |
|
1382 |
table->status|= STATUS_UPDATED; |
|
1383 |
store_record(table,record[1]); |
|
1384 |
if (fill_record(thd, *fields_for_table[offset], |
|
1385 |
*values_for_table[offset], 0)) |
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
1386 |
return(1); |
1
by brian
clean slate |
1387 |
|
1388 |
found++; |
|
1389 |
if (!can_compare_record || compare_record(table)) |
|
1390 |
{
|
|
1391 |
int error; |
|
1392 |
if (!updated++) |
|
1393 |
{
|
|
1394 |
/*
|
|
1395 |
Inform the main table that we are going to update the table even
|
|
1396 |
while we may be scanning it. This will flush the read cache
|
|
1397 |
if it's used.
|
|
1398 |
*/
|
|
1399 |
main_table->file->extra(HA_EXTRA_PREPARE_FOR_UPDATE); |
|
1400 |
}
|
|
1401 |
if ((error=table->file->ha_update_row(table->record[1], |
|
1402 |
table->record[0])) && |
|
1403 |
error != HA_ERR_RECORD_IS_THE_SAME) |
|
1404 |
{
|
|
1405 |
updated--; |
|
1406 |
if (!ignore || |
|
1407 |
table->file->is_fatal_error(error, HA_CHECK_DUP_KEY)) |
|
1408 |
{
|
|
1409 |
/*
|
|
1410 |
If (ignore && error == is ignorable) we don't have to
|
|
1411 |
do anything; otherwise...
|
|
1412 |
*/
|
|
1413 |
myf flags= 0; |
|
1414 |
||
1415 |
if (table->file->is_fatal_error(error, HA_CHECK_DUP_KEY)) |
|
1416 |
flags|= ME_FATALERROR; /* Other handler errors are fatal */ |
|
1417 |
||
1418 |
prepare_record_for_error_message(error, table); |
|
1419 |
table->file->print_error(error,MYF(flags)); |
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
1420 |
return(1); |
1
by brian
clean slate |
1421 |
}
|
1422 |
}
|
|
1423 |
else
|
|
1424 |
{
|
|
1425 |
if (error == HA_ERR_RECORD_IS_THE_SAME) |
|
1426 |
{
|
|
1427 |
error= 0; |
|
1428 |
updated--; |
|
1429 |
}
|
|
1430 |
/* non-transactional or transactional table got modified */
|
|
1431 |
/* either multi_update class' flag is raised in its branch */
|
|
1432 |
if (table->file->has_transactions()) |
|
1433 |
transactional_tables= 1; |
|
1434 |
else
|
|
1435 |
{
|
|
1436 |
trans_safe= 0; |
|
56
by brian
Next pass of true/false update. |
1437 |
thd->transaction.stmt.modified_non_trans_table= true; |
1
by brian
clean slate |
1438 |
}
|
1439 |
}
|
|
1440 |
}
|
|
1441 |
}
|
|
1442 |
else
|
|
1443 |
{
|
|
1444 |
int error; |
|
1445 |
TABLE *tmp_table= tmp_tables[offset]; |
|
1446 |
/*
|
|
1447 |
For updatable VIEW store rowid of the updated table and
|
|
1448 |
rowids of tables used in the CHECK OPTION condition.
|
|
1449 |
*/
|
|
1450 |
uint field_num= 0; |
|
1451 |
List_iterator_fast<TABLE> tbl_it(unupdated_check_opt_tables); |
|
1452 |
TABLE *tbl= table; |
|
1453 |
do
|
|
1454 |
{
|
|
1455 |
tbl->file->position(tbl->record[0]); |
|
212.6.6
by Mats Kindahl
Removing redundant use of casts in drizzled/ for memcmp(), memcpy(), memset(), and memmove(). |
1456 |
memcpy(tmp_table->field[field_num]->ptr, |
1457 |
tbl->file->ref, tbl->file->ref_length); |
|
1
by brian
clean slate |
1458 |
field_num++; |
1459 |
} while ((tbl= tbl_it++)); |
|
1460 |
||
1461 |
/* Store regular updated fields in the row. */
|
|
1462 |
fill_record(thd, |
|
1463 |
tmp_table->field + 1 + unupdated_check_opt_tables.elements, |
|
1464 |
*values_for_table[offset], 1); |
|
1465 |
||
1466 |
/* Write row, ignoring duplicated updates to a row */
|
|
1467 |
error= tmp_table->file->ha_write_row(tmp_table->record[0]); |
|
1468 |
if (error != HA_ERR_FOUND_DUPP_KEY && error != HA_ERR_FOUND_DUPP_UNIQUE) |
|
1469 |
{
|
|
1470 |
if (error && |
|
1471 |
create_myisam_from_heap(thd, tmp_table, |
|
1472 |
tmp_table_param[offset].start_recinfo, |
|
1473 |
&tmp_table_param[offset].recinfo, |
|
1474 |
error, 1)) |
|
1475 |
{
|
|
1476 |
do_update=0; |
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
1477 |
return(1); // Not a table_is_full error |
1
by brian
clean slate |
1478 |
}
|
1479 |
found++; |
|
1480 |
}
|
|
1481 |
}
|
|
1482 |
}
|
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
1483 |
return(0); |
1
by brian
clean slate |
1484 |
}
|
1485 |
||
1486 |
||
1487 |
void multi_update::send_error(uint errcode,const char *err) |
|
1488 |
{
|
|
1489 |
/* First send error what ever it is ... */
|
|
1490 |
my_error(errcode, MYF(0), err); |
|
1491 |
}
|
|
1492 |
||
1493 |
||
1494 |
void multi_update::abort() |
|
1495 |
{
|
|
1496 |
/* the error was handled or nothing deleted and no side effects return */
|
|
1497 |
if (error_handled || |
|
1498 |
(!thd->transaction.stmt.modified_non_trans_table && !updated)) |
|
1499 |
return; |
|
1500 |
/*
|
|
1501 |
If all tables that has been updated are trans safe then just do rollback.
|
|
1502 |
If not attempt to do remaining updates.
|
|
1503 |
*/
|
|
1504 |
||
1505 |
if (! trans_safe) |
|
1506 |
{
|
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
1507 |
assert(thd->transaction.stmt.modified_non_trans_table); |
1
by brian
clean slate |
1508 |
if (do_update && table_count > 1) |
1509 |
{
|
|
1510 |
/* Add warning here */
|
|
1511 |
/*
|
|
1512 |
todo/fixme: do_update() is never called with the arg 1.
|
|
1513 |
should it change the signature to become argless?
|
|
1514 |
*/
|
|
1515 |
VOID(do_updates()); |
|
1516 |
}
|
|
1517 |
}
|
|
1518 |
if (thd->transaction.stmt.modified_non_trans_table) |
|
1519 |
{
|
|
1520 |
/*
|
|
1521 |
The query has to binlog because there's a modified non-transactional table
|
|
1522 |
either from the query's list or via a stored routine: bug#13270,23333
|
|
1523 |
*/
|
|
1524 |
if (mysql_bin_log.is_open()) |
|
1525 |
{
|
|
1526 |
/*
|
|
1527 |
THD::killed status might not have been set ON at time of an error
|
|
1528 |
got caught and if happens later the killed error is written
|
|
1529 |
into repl event.
|
|
1530 |
*/
|
|
1531 |
thd->binlog_query(THD::ROW_QUERY_TYPE, |
|
1532 |
thd->query, thd->query_length, |
|
56
by brian
Next pass of true/false update. |
1533 |
transactional_tables, false); |
1
by brian
clean slate |
1534 |
}
|
56
by brian
Next pass of true/false update. |
1535 |
thd->transaction.all.modified_non_trans_table= true; |
1
by brian
clean slate |
1536 |
}
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
1537 |
assert(trans_safe || !updated || thd->transaction.stmt.modified_non_trans_table); |
1
by brian
clean slate |
1538 |
}
|
1539 |
||
1540 |
||
1541 |
int multi_update::do_updates() |
|
1542 |
{
|
|
1543 |
TABLE_LIST *cur_table; |
|
1544 |
int local_error= 0; |
|
1545 |
ha_rows org_updated; |
|
1546 |
TABLE *table, *tmp_table; |
|
1547 |
List_iterator_fast<TABLE> check_opt_it(unupdated_check_opt_tables); |
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
1548 |
|
1
by brian
clean slate |
1549 |
do_update= 0; // Don't retry this function |
1550 |
if (!found) |
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
1551 |
return(0); |
1
by brian
clean slate |
1552 |
for (cur_table= update_tables; cur_table; cur_table= cur_table->next_local) |
1553 |
{
|
|
1554 |
bool can_compare_record; |
|
1555 |
uint offset= cur_table->shared; |
|
1556 |
||
1557 |
table = cur_table->table; |
|
1558 |
if (table == table_to_update) |
|
1559 |
continue; // Already updated |
|
1560 |
org_updated= updated; |
|
1561 |
tmp_table= tmp_tables[cur_table->shared]; |
|
1562 |
tmp_table->file->extra(HA_EXTRA_CACHE); // Change to read cache |
|
1563 |
(void) table->file->ha_rnd_init(0); |
|
1564 |
table->file->extra(HA_EXTRA_NO_CACHE); |
|
1565 |
||
1566 |
check_opt_it.rewind(); |
|
1567 |
while(TABLE *tbl= check_opt_it++) |
|
1568 |
{
|
|
1569 |
if (tbl->file->ha_rnd_init(1)) |
|
1570 |
goto err; |
|
1571 |
tbl->file->extra(HA_EXTRA_CACHE); |
|
1572 |
}
|
|
1573 |
||
1574 |
/*
|
|
1575 |
Setup copy functions to copy fields from temporary table
|
|
1576 |
*/
|
|
1577 |
List_iterator_fast<Item> field_it(*fields_for_table[offset]); |
|
1578 |
Field **field= tmp_table->field + |
|
1579 |
1 + unupdated_check_opt_tables.elements; // Skip row pointers |
|
1580 |
Copy_field *copy_field_ptr= copy_field, *copy_field_end; |
|
1581 |
for ( ; *field ; field++) |
|
1582 |
{
|
|
1583 |
Item_field *item= (Item_field* ) field_it++; |
|
1584 |
(copy_field_ptr++)->set(item->field, *field, 0); |
|
1585 |
}
|
|
1586 |
copy_field_end=copy_field_ptr; |
|
1587 |
||
1588 |
if ((local_error = tmp_table->file->ha_rnd_init(1))) |
|
1589 |
goto err; |
|
1590 |
||
1591 |
can_compare_record= (!(table->file->ha_table_flags() & |
|
1592 |
HA_PARTIAL_COLUMN_READ) || |
|
1593 |
bitmap_is_subset(table->write_set, |
|
1594 |
table->read_set)); |
|
1595 |
||
1596 |
for (;;) |
|
1597 |
{
|
|
1598 |
if (thd->killed && trans_safe) |
|
1599 |
goto err; |
|
1600 |
if ((local_error=tmp_table->file->rnd_next(tmp_table->record[0]))) |
|
1601 |
{
|
|
1602 |
if (local_error == HA_ERR_END_OF_FILE) |
|
1603 |
break; |
|
1604 |
if (local_error == HA_ERR_RECORD_DELETED) |
|
1605 |
continue; // May happen on dup key |
|
1606 |
goto err; |
|
1607 |
}
|
|
1608 |
||
1609 |
/* call rnd_pos() using rowids from temporary table */
|
|
1610 |
check_opt_it.rewind(); |
|
1611 |
TABLE *tbl= table; |
|
1612 |
uint field_num= 0; |
|
1613 |
do
|
|
1614 |
{
|
|
1615 |
if((local_error= |
|
1616 |
tbl->file->rnd_pos(tbl->record[0], |
|
1617 |
(uchar *) tmp_table->field[field_num]->ptr))) |
|
1618 |
goto err; |
|
1619 |
field_num++; |
|
1620 |
} while((tbl= check_opt_it++)); |
|
1621 |
||
1622 |
table->status|= STATUS_UPDATED; |
|
1623 |
store_record(table,record[1]); |
|
1624 |
||
1625 |
/* Copy data from temporary table to current table */
|
|
1626 |
for (copy_field_ptr=copy_field; |
|
1627 |
copy_field_ptr != copy_field_end; |
|
1628 |
copy_field_ptr++) |
|
1629 |
(*copy_field_ptr->do_copy)(copy_field_ptr); |
|
1630 |
||
1631 |
if (!can_compare_record || compare_record(table)) |
|
1632 |
{
|
|
1633 |
if ((local_error=table->file->ha_update_row(table->record[1], |
|
1634 |
table->record[0])) && |
|
1635 |
local_error != HA_ERR_RECORD_IS_THE_SAME) |
|
1636 |
{
|
|
1637 |
if (!ignore || |
|
1638 |
table->file->is_fatal_error(local_error, HA_CHECK_DUP_KEY)) |
|
1639 |
goto err; |
|
1640 |
}
|
|
1641 |
if (local_error != HA_ERR_RECORD_IS_THE_SAME) |
|
1642 |
updated++; |
|
1643 |
else
|
|
1644 |
local_error= 0; |
|
1645 |
}
|
|
1646 |
}
|
|
1647 |
||
1648 |
if (updated != org_updated) |
|
1649 |
{
|
|
1650 |
if (table->file->has_transactions()) |
|
1651 |
transactional_tables= 1; |
|
1652 |
else
|
|
1653 |
{
|
|
1654 |
trans_safe= 0; // Can't do safe rollback |
|
56
by brian
Next pass of true/false update. |
1655 |
thd->transaction.stmt.modified_non_trans_table= true; |
1
by brian
clean slate |
1656 |
}
|
1657 |
}
|
|
1658 |
(void) table->file->ha_rnd_end(); |
|
1659 |
(void) tmp_table->file->ha_rnd_end(); |
|
1660 |
check_opt_it.rewind(); |
|
1661 |
while (TABLE *tbl= check_opt_it++) |
|
1662 |
tbl->file->ha_rnd_end(); |
|
1663 |
||
1664 |
}
|
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
1665 |
return(0); |
1
by brian
clean slate |
1666 |
|
1667 |
err: |
|
1668 |
{
|
|
1669 |
prepare_record_for_error_message(local_error, table); |
|
1670 |
table->file->print_error(local_error,MYF(ME_FATALERROR)); |
|
1671 |
}
|
|
1672 |
||
1673 |
(void) table->file->ha_rnd_end(); |
|
1674 |
(void) tmp_table->file->ha_rnd_end(); |
|
1675 |
check_opt_it.rewind(); |
|
1676 |
while (TABLE *tbl= check_opt_it++) |
|
1677 |
tbl->file->ha_rnd_end(); |
|
1678 |
||
1679 |
if (updated != org_updated) |
|
1680 |
{
|
|
1681 |
if (table->file->has_transactions()) |
|
1682 |
transactional_tables= 1; |
|
1683 |
else
|
|
1684 |
{
|
|
1685 |
trans_safe= 0; |
|
56
by brian
Next pass of true/false update. |
1686 |
thd->transaction.stmt.modified_non_trans_table= true; |
1
by brian
clean slate |
1687 |
}
|
1688 |
}
|
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
1689 |
return(1); |
1
by brian
clean slate |
1690 |
}
|
1691 |
||
1692 |
||
1693 |
/* out: 1 if error, 0 if success */
|
|
1694 |
||
1695 |
bool multi_update::send_eof() |
|
1696 |
{
|
|
1697 |
char buff[STRING_BUFFER_USUAL_SIZE]; |
|
151
by Brian Aker
Ulonglong to uint64_t |
1698 |
uint64_t id; |
1
by brian
clean slate |
1699 |
THD::killed_state killed_status= THD::NOT_KILLED; |
51.2.2
by Patrick Galbraith
Removed DBUGs from |
1700 |
|
1
by brian
clean slate |
1701 |
thd_proc_info(thd, "updating reference tables"); |
1702 |
||
1703 |
/*
|
|
1704 |
Does updates for the last n - 1 tables, returns 0 if ok;
|
|
1705 |
error takes into account killed status gained in do_updates()
|
|
1706 |
*/
|
|
1707 |
int local_error = (table_count) ? do_updates() : 0; |
|
1708 |
/*
|
|
1709 |
if local_error is not set ON until after do_updates() then
|
|
1710 |
later carried out killing should not affect binlogging.
|
|
1711 |
*/
|
|
1712 |
killed_status= (local_error == 0)? THD::NOT_KILLED : thd->killed; |
|
1713 |
thd_proc_info(thd, "end"); |
|
1714 |
||
1715 |
/*
|
|
1716 |
Write the SQL statement to the binlog if we updated
|
|
1717 |
rows and we succeeded or if we updated some non
|
|
1718 |
transactional tables.
|
|
1719 |
|
|
1720 |
The query has to binlog because there's a modified non-transactional table
|
|
1721 |
either from the query's list or via a stored routine: bug#13270,23333
|
|
1722 |
*/
|
|
1723 |
||
51.2.2
by Patrick Galbraith
Removed DBUGs from |
1724 |
assert(trans_safe || !updated || |
1
by brian
clean slate |
1725 |
thd->transaction.stmt.modified_non_trans_table); |
1726 |
if (local_error == 0 || thd->transaction.stmt.modified_non_trans_table) |
|
1727 |
{
|
|
1728 |
if (mysql_bin_log.is_open()) |
|
1729 |
{
|
|
1730 |
if (local_error == 0) |
|
1731 |
thd->clear_error(); |
|
1732 |
if (thd->binlog_query(THD::ROW_QUERY_TYPE, |
|
1733 |
thd->query, thd->query_length, |
|
56
by brian
Next pass of true/false update. |
1734 |
transactional_tables, false, killed_status) && |
1
by brian
clean slate |
1735 |
trans_safe) |
1736 |
{
|
|
51.2.2
by Patrick Galbraith
Removed DBUGs from |
1737 |
local_error= 1; // Rollback update |
1
by brian
clean slate |
1738 |
}
|
1739 |
}
|
|
1740 |
if (thd->transaction.stmt.modified_non_trans_table) |
|
56
by brian
Next pass of true/false update. |
1741 |
thd->transaction.all.modified_non_trans_table= true; |
1
by brian
clean slate |
1742 |
}
|
1743 |
if (local_error != 0) |
|
56
by brian
Next pass of true/false update. |
1744 |
error_handled= true; // to force early leave from ::send_error() |
1
by brian
clean slate |
1745 |
|
1746 |
if (local_error > 0) // if the above log write did not fail ... |
|
1747 |
{
|
|
1748 |
/* Safety: If we haven't got an error before (can happen in do_updates) */
|
|
1749 |
my_message(ER_UNKNOWN_ERROR, "An error occured in multi-table update", |
|
1750 |
MYF(0)); |
|
51.1.8
by Jay Pipes
Resolving conflicts for a few files regarding FALSE=>false |
1751 |
return(true); |
1
by brian
clean slate |
1752 |
}
|
1753 |
||
1754 |
id= thd->arg_of_last_insert_id_function ? |
|
1755 |
thd->first_successful_insert_id_in_prev_stmt : 0; |
|
1756 |
sprintf(buff, ER(ER_UPDATE_INFO), (ulong) found, (ulong) updated, |
|
1757 |
(ulong) thd->cuted_fields); |
|
1758 |
thd->row_count_func= |
|
1759 |
(thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated; |
|
1760 |
::my_ok(thd, (ulong) thd->row_count_func, id, buff); |
|
51.1.8
by Jay Pipes
Resolving conflicts for a few files regarding FALSE=>false |
1761 |
return(false); |
1
by brian
clean slate |
1762 |
}
|