~mysql/mysql-server/mysql-6.0

« back to all changes in this revision

Viewing changes to innobase/row/row0mysql.c

  • Committer: monty at mysql
  • Date: 2001-02-17 12:19:19 UTC
  • mto: (554.1.1)
  • mto: This revision was merged to the branch mainline in revision 556.
  • Revision ID: sp1r-monty@donna.mysql.com-20010217121919-07904
Added Innobase to source distribution

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/******************************************************
 
2
Interface between Innobase row operations and MySQL.
 
3
Contains also create table and other data dictionary operations.
 
4
 
 
5
(c) 2000 Innobase Oy
 
6
 
 
7
Created 9/17/2000 Heikki Tuuri
 
8
*******************************************************/
 
9
 
 
10
#include "row0mysql.h"
 
11
 
 
12
#ifdef UNIV_NONINL
 
13
#include "row0mysql.ic"
 
14
#endif
 
15
 
 
16
#include "row0ins.h"
 
17
#include "row0sel.h"
 
18
#include "row0upd.h"
 
19
#include "row0row.h"
 
20
#include "que0que.h"
 
21
#include "pars0pars.h"
 
22
#include "dict0dict.h"
 
23
#include "dict0crea.h"
 
24
#include "trx0roll.h"
 
25
#include "trx0purge.h"
 
26
#include "lock0lock.h"
 
27
 
 
28
/***********************************************************************
 
29
Reads a MySQL format variable-length field (like VARCHAR) length and
 
30
returns pointer to the field data. */
 
31
 
 
32
byte*
 
33
row_mysql_read_var_ref_noninline(
 
34
/*=============================*/
 
35
                        /* out: field + 2 */
 
36
        ulint*  len,    /* out: variable-length field length */
 
37
        byte*   field)  /* in: field */
 
38
{
 
39
        return(row_mysql_read_var_ref(len, field));
 
40
}
 
41
 
 
42
/***********************************************************************
 
43
Stores a reference to a BLOB in the MySQL format. */
 
44
 
 
45
void
 
46
row_mysql_store_blob_ref(
 
47
/*=====================*/
 
48
        byte*   dest,           /* in: where to store */
 
49
        ulint   col_len,        /* in: dest buffer size: determines into
 
50
                                how many bytes the BLOB length is stored,
 
51
                                this may vary from 1 to 4 bytes */
 
52
        byte*   data,           /* in: BLOB data */
 
53
        ulint   len)            /* in: BLOB length */
 
54
{
 
55
        /* In dest there are 1 - 4 bytes reserved for the BLOB length,
 
56
        and after that 8 bytes reserved for the pointer to the data.
 
57
        In 32-bit architectures we only use the first 4 bytes of the pointer
 
58
        slot. */
 
59
 
 
60
        mach_write_to_n_little_endian(dest, col_len - 8, len);
 
61
 
 
62
        ut_memcpy(dest + col_len - 8, (byte*)&data, sizeof(byte*));     
 
63
}
 
64
 
 
65
/***********************************************************************
 
66
Reads a reference to a BLOB in the MySQL format. */
 
67
 
 
68
byte*
 
69
row_mysql_read_blob_ref(
 
70
/*====================*/
 
71
                                /* out: pointer to BLOB data */
 
72
        ulint*  len,            /* out: BLOB length */
 
73
        byte*   ref,            /* in: BLOB reference in the MySQL format */
 
74
        ulint   col_len)        /* in: BLOB reference length (not BLOB
 
75
                                length) */
 
76
{
 
77
        byte*   data;
 
78
 
 
79
        *len = mach_read_from_n_little_endian(ref, col_len - 8);
 
80
 
 
81
        ut_memcpy((byte*)&data, ref + col_len - 8, sizeof(byte*));
 
82
 
 
83
        return(data);
 
84
}
 
85
 
 
86
/******************************************************************
 
87
Convert a row in the MySQL format to a row in the Innobase format. */
 
88
static
 
89
void
 
90
row_mysql_convert_row_to_innobase(
 
91
/*==============================*/
 
92
        dtuple_t*       row,            /* in/out: Innobase row where the
 
93
                                        field type information is already
 
94
                                        copied there, or will be copied
 
95
                                        later */
 
96
        byte*           buf,            /* in/out: buffer to use in converting
 
97
                                        data in columns; this must be at least
 
98
                                        the size of mysql_rec! */
 
99
        row_prebuilt_t* prebuilt,       /* in: prebuilt struct where template
 
100
                                        must be of type ROW_MYSQL_WHOLE_ROW */
 
101
        byte*           mysql_rec)      /* in: row in the MySQL format;
 
102
                                        NOTE: do not discard as long as
 
103
                                        row is used, as row may contain
 
104
                                        pointers to this record! */
 
105
{
 
106
        mysql_row_templ_t*      templ;  
 
107
        dfield_t*               dfield;
 
108
        ulint                   i;
 
109
        
 
110
        ut_ad(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW);
 
111
        ut_ad(prebuilt->mysql_template);
 
112
 
 
113
        for (i = 0; i < prebuilt->n_template; i++) {
 
114
 
 
115
                templ = prebuilt->mysql_template + i;
 
116
                dfield = dtuple_get_nth_field(row, i);
 
117
 
 
118
                if (templ->mysql_null_bit_mask != 0) {
 
119
                        /* Column may be SQL NULL */
 
120
 
 
121
                        if (mysql_rec[templ->mysql_null_byte_offset] &
 
122
                                        (byte) (templ->mysql_null_bit_mask)) {
 
123
 
 
124
                                /* It is SQL NULL */
 
125
 
 
126
                                dfield_set_data(dfield, NULL, UNIV_SQL_NULL);
 
127
 
 
128
                                goto next_column;
 
129
                        }
 
130
                }                       
 
131
                
 
132
                row_mysql_store_col_in_innobase_format(dfield,
 
133
                                        prebuilt->ins_upd_rec_buff
 
134
                                                + templ->mysql_col_offset,
 
135
                                        mysql_rec + templ->mysql_col_offset,
 
136
                                        templ->mysql_col_len,
 
137
                                        templ->type, templ->is_unsigned);
 
138
next_column:
 
139
                ;
 
140
        } 
 
141
}
 
142
 
 
143
/********************************************************************
 
144
Handles user errors and lock waits detected by the database engine. */
 
145
 
 
146
ibool
 
147
row_mysql_handle_errors(
 
148
/*====================*/
 
149
                                /* out: TRUE if it was a lock wait and
 
150
                                we should continue running the query thread */
 
151
        ulint*          new_err,/* out: possible new error encountered in
 
152
                                rollback, or the old error which was
 
153
                                during the function entry */
 
154
        trx_t*          trx,    /* in: transaction */
 
155
        que_thr_t*      thr,    /* in: query thread */
 
156
        trx_savept_t*   savept) /* in: savepoint */
 
157
{
 
158
        ibool   timeout_expired;
 
159
        ulint   err;
 
160
 
 
161
handle_new_error:
 
162
        err = trx->error_state;
 
163
        
 
164
        ut_a(err != DB_SUCCESS);
 
165
        
 
166
        trx->error_state = DB_SUCCESS;
 
167
 
 
168
        if (err == DB_DUPLICATE_KEY) {
 
169
                if (savept) {
 
170
                        /* Roll back the latest, possibly incomplete
 
171
                        insertion or update */
 
172
 
 
173
                        trx_general_rollback_for_mysql(trx, TRUE, savept);
 
174
                }                       
 
175
        } else if (err == DB_TOO_BIG_RECORD) {
 
176
                if (savept) {
 
177
                        /* Roll back the latest, possibly incomplete
 
178
                        insertion or update */
 
179
 
 
180
                        trx_general_rollback_for_mysql(trx, TRUE, savept);
 
181
                }                       
 
182
        } else if (err == DB_LOCK_WAIT) {
 
183
 
 
184
                timeout_expired = srv_suspend_mysql_thread(thr);
 
185
 
 
186
                if (timeout_expired) {
 
187
                        trx->error_state = DB_DEADLOCK;
 
188
 
 
189
                        que_thr_stop_for_mysql(thr);
 
190
 
 
191
                        goto handle_new_error;
 
192
                }
 
193
 
 
194
                *new_err = err;
 
195
 
 
196
                return(TRUE);
 
197
 
 
198
        } else if (err == DB_DEADLOCK) {
 
199
 
 
200
                /* Roll back the whole transaction */
 
201
 
 
202
                trx_general_rollback_for_mysql(trx, FALSE, NULL);
 
203
 
 
204
        } else if (err == DB_OUT_OF_FILE_SPACE) {
 
205
 
 
206
                /* Roll back the whole transaction */
 
207
 
 
208
                trx_general_rollback_for_mysql(trx, FALSE, NULL);
 
209
        } else if (err == DB_MUST_GET_MORE_FILE_SPACE) {
 
210
 
 
211
                ut_a(0); /* TODO: print something to MySQL error log */
 
212
        } else {
 
213
                ut_a(0);
 
214
        }               
 
215
 
 
216
        if (trx->error_state != DB_SUCCESS) {
 
217
                *new_err = trx->error_state;
 
218
        } else {
 
219
                *new_err = err;
 
220
        }
 
221
        
 
222
        trx->error_state = DB_SUCCESS;
 
223
 
 
224
        return(FALSE);
 
225
}
 
226
 
 
227
/************************************************************************
 
228
Create a prebuilt struct for a MySQL table handle. */
 
229
 
 
230
row_prebuilt_t*
 
231
row_create_prebuilt(
 
232
/*================*/
 
233
                                /* out, own: a prebuilt struct */
 
234
        dict_table_t*   table)  /* in: Innobase table handle */
 
235
{
 
236
        row_prebuilt_t* prebuilt;
 
237
        mem_heap_t*     heap;
 
238
        dict_index_t*   clust_index;
 
239
        dtuple_t*       ref;
 
240
        ulint           ref_len;
 
241
        ulint           i;
 
242
        
 
243
        heap = mem_heap_create(128);
 
244
 
 
245
        prebuilt = mem_heap_alloc(heap, sizeof(row_prebuilt_t));
 
246
 
 
247
        prebuilt->table = table;
 
248
 
 
249
        prebuilt->trx = NULL;
 
250
 
 
251
        prebuilt->sql_stat_start = TRUE;
 
252
 
 
253
        prebuilt->index = NULL;
 
254
        prebuilt->n_template = 0;
 
255
        prebuilt->mysql_template = NULL;
 
256
 
 
257
        prebuilt->heap = heap;
 
258
        prebuilt->ins_node = NULL;
 
259
 
 
260
        prebuilt->ins_upd_rec_buff = NULL;
 
261
        
 
262
        prebuilt->upd_node = NULL;
 
263
        prebuilt->ins_graph = NULL;
 
264
        prebuilt->upd_graph = NULL;
 
265
 
 
266
        prebuilt->pcur = btr_pcur_create_for_mysql();
 
267
        prebuilt->clust_pcur = btr_pcur_create_for_mysql();
 
268
 
 
269
        prebuilt->select_lock_type = LOCK_NONE;
 
270
 
 
271
        prebuilt->sel_graph = NULL;
 
272
 
 
273
        prebuilt->search_tuple = dtuple_create(heap,
 
274
                                                dict_table_get_n_cols(table));
 
275
        
 
276
        clust_index = dict_table_get_first_index(table);
 
277
 
 
278
        ref_len = dict_index_get_n_unique(clust_index);
 
279
 
 
280
        ref = dtuple_create(heap, ref_len);
 
281
 
 
282
        dict_index_copy_types(ref, clust_index, ref_len);
 
283
 
 
284
        prebuilt->clust_ref = ref;
 
285
 
 
286
        for (i = 0; i < MYSQL_FETCH_CACHE_SIZE; i++) {
 
287
                prebuilt->fetch_cache[i] = NULL;
 
288
        }
 
289
 
 
290
        prebuilt->n_fetch_cached = 0;
 
291
 
 
292
        prebuilt->blob_heap = NULL;
 
293
 
 
294
        prebuilt->old_vers_heap = NULL;
 
295
        
 
296
        return(prebuilt);
 
297
}
 
298
 
 
299
/************************************************************************
 
300
Free a prebuilt struct for a MySQL table handle. */
 
301
 
 
302
void
 
303
row_prebuilt_free(
 
304
/*==============*/
 
305
        row_prebuilt_t* prebuilt)       /* in, own: prebuilt struct */
 
306
{
 
307
        ulint   i;
 
308
 
 
309
        btr_pcur_free_for_mysql(prebuilt->pcur);
 
310
        btr_pcur_free_for_mysql(prebuilt->clust_pcur);
 
311
 
 
312
        if (prebuilt->mysql_template) {
 
313
                mem_free(prebuilt->mysql_template);
 
314
        }
 
315
 
 
316
        if (prebuilt->ins_graph) {
 
317
                que_graph_free_recursive(prebuilt->ins_graph);
 
318
        }
 
319
 
 
320
        if (prebuilt->sel_graph) {
 
321
                que_graph_free_recursive(prebuilt->sel_graph);
 
322
        }
 
323
        
 
324
        if (prebuilt->upd_graph) {
 
325
                que_graph_free_recursive(prebuilt->upd_graph);
 
326
        }
 
327
        
 
328
        if (prebuilt->blob_heap) {
 
329
                mem_heap_free(prebuilt->blob_heap);
 
330
        }
 
331
 
 
332
        if (prebuilt->old_vers_heap) {
 
333
                mem_heap_free(prebuilt->old_vers_heap);
 
334
        }
 
335
        
 
336
        for (i = 0; i < MYSQL_FETCH_CACHE_SIZE; i++) {
 
337
                if (prebuilt->fetch_cache[i] != NULL) {
 
338
                        mem_free(prebuilt->fetch_cache[i]);
 
339
                }
 
340
        }
 
341
 
 
342
        mem_heap_free(prebuilt->heap);
 
343
}
 
344
 
 
345
/*************************************************************************
 
346
Updates the transaction pointers in query graphs stored in the prebuilt
 
347
struct. */
 
348
 
 
349
void
 
350
row_update_prebuilt_trx(
 
351
/*====================*/
 
352
                                        /* out: prebuilt dtuple */
 
353
        row_prebuilt_t* prebuilt,       /* in: prebuilt struct in MySQL
 
354
                                        handle */
 
355
        trx_t*          trx)            /* in: transaction handle */
 
356
{       
 
357
        prebuilt->trx = trx;
 
358
 
 
359
        if (prebuilt->ins_graph) {
 
360
                prebuilt->ins_graph->trx = trx;
 
361
        }
 
362
 
 
363
        if (prebuilt->upd_graph) {
 
364
                prebuilt->upd_graph->trx = trx;
 
365
        }
 
366
 
 
367
        if (prebuilt->sel_graph) {
 
368
                prebuilt->sel_graph->trx = trx;
 
369
        }       
 
370
}
 
371
 
 
372
/*************************************************************************
 
373
Gets pointer to a prebuilt dtuple used in insertions. If the insert graph
 
374
has not yet been built in the prebuilt struct, then this function first
 
375
builds it. */
 
376
static
 
377
dtuple_t*
 
378
row_get_prebuilt_insert_row(
 
379
/*========================*/
 
380
                                        /* out: prebuilt dtuple */
 
381
        row_prebuilt_t* prebuilt)       /* in: prebuilt struct in MySQL
 
382
                                        handle */
 
383
{
 
384
        ins_node_t*     node;
 
385
        dtuple_t*       row;
 
386
        dict_table_t*   table   = prebuilt->table;
 
387
 
 
388
        ut_ad(prebuilt && table && prebuilt->trx);
 
389
        
 
390
        if (prebuilt->ins_node == NULL) {
 
391
 
 
392
                /* Not called before for this handle: create an insert node
 
393
                and query graph to the prebuilt struct */
 
394
 
 
395
                node = ins_node_create(INS_DIRECT, table, prebuilt->heap);
 
396
                
 
397
                prebuilt->ins_node = node;
 
398
 
 
399
                if (prebuilt->ins_upd_rec_buff == NULL) {
 
400
                        prebuilt->ins_upd_rec_buff = mem_heap_alloc(
 
401
                                                prebuilt->heap,
 
402
                                                prebuilt->mysql_row_len);
 
403
                }
 
404
                
 
405
                row = dtuple_create(prebuilt->heap,
 
406
                                        dict_table_get_n_cols(table));
 
407
 
 
408
                dict_table_copy_types(row, table);
 
409
 
 
410
                ins_node_set_new_row(node, row);
 
411
 
 
412
                prebuilt->ins_graph =
 
413
                        que_node_get_parent(
 
414
                                pars_complete_graph_for_exec(node,
 
415
                                                        prebuilt->trx,
 
416
                                                        prebuilt->heap));
 
417
                prebuilt->ins_graph->state = QUE_FORK_ACTIVE;
 
418
        }
 
419
 
 
420
        return(prebuilt->ins_node->row);        
 
421
}
 
422
 
 
423
/*************************************************************************
 
424
Updates the table modification counter and calculates new estimates
 
425
for table and index statistics if necessary. */
 
426
UNIV_INLINE
 
427
void
 
428
row_update_statistics_if_needed(
 
429
/*============================*/
 
430
        row_prebuilt_t* prebuilt)       /* in: prebuilt struct */
 
431
{
 
432
        ulint   counter;
 
433
        ulint   old_counter;
 
434
        
 
435
        counter = prebuilt->table->stat_modif_counter;
 
436
 
 
437
        counter += prebuilt->mysql_row_len;
 
438
        prebuilt->table->stat_modif_counter = counter;
 
439
 
 
440
        old_counter = prebuilt->table->stat_last_estimate_counter;
 
441
 
 
442
        if (counter - old_counter >= DICT_STAT_CALCULATE_INTERVAL
 
443
            || counter - old_counter >=
 
444
                (UNIV_PAGE_SIZE
 
445
                        * prebuilt->table->stat_clustered_index_size / 2)) {
 
446
 
 
447
                dict_update_statistics(prebuilt->table);
 
448
        }       
 
449
}
 
450
 
 
451
/*************************************************************************
 
452
Does an insert for MySQL. */
 
453
 
 
454
int
 
455
row_insert_for_mysql(
 
456
/*=================*/
 
457
                                        /* out: error code or DB_SUCCESS */
 
458
        byte*           mysql_rec,      /* in: row in the MySQL format */
 
459
        row_prebuilt_t* prebuilt)       /* in: prebuilt struct in MySQL
 
460
                                        handle */
 
461
{
 
462
        trx_savept_t    savept;
 
463
        que_thr_t*      thr;
 
464
        ulint           err;
 
465
        ibool           was_lock_wait;
 
466
        trx_t*          trx             = prebuilt->trx;
 
467
        ins_node_t*     node            = prebuilt->ins_node;
 
468
        
 
469
        ut_ad(trx);
 
470
        ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
 
471
        
 
472
        if (node == NULL) {
 
473
                row_get_prebuilt_insert_row(prebuilt);
 
474
                node = prebuilt->ins_node;
 
475
        }
 
476
 
 
477
        row_mysql_convert_row_to_innobase(node->row,
 
478
                                                prebuilt->ins_upd_rec_buff,
 
479
                                                prebuilt, mysql_rec);
 
480
        savept = trx_savept_take(trx);
 
481
        
 
482
        thr = que_fork_get_first_thr(prebuilt->ins_graph);
 
483
 
 
484
        if (prebuilt->sql_stat_start) {
 
485
                node->state = INS_NODE_SET_IX_LOCK;
 
486
                prebuilt->sql_stat_start = FALSE;
 
487
        } else {
 
488
                node->state = INS_NODE_ALLOC_ROW_ID;
 
489
        }
 
490
        
 
491
        que_thr_move_to_run_state_for_mysql(thr, trx);
 
492
 
 
493
run_again:
 
494
        thr->run_node = node;
 
495
        thr->prev_node = node;
 
496
 
 
497
        row_ins_step(thr);
 
498
        
 
499
        err = trx->error_state;
 
500
 
 
501
        if (err != DB_SUCCESS) {
 
502
                que_thr_stop_for_mysql(thr);
 
503
 
 
504
                was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
 
505
                                                                &savept);
 
506
                if (was_lock_wait) {
 
507
                        goto run_again;
 
508
                }
 
509
 
 
510
                return(err);
 
511
        }
 
512
 
 
513
        que_thr_stop_for_mysql_no_error(thr, trx);
 
514
        
 
515
        prebuilt->table->stat_n_rows++;
 
516
 
 
517
        if (prebuilt->table->stat_n_rows == 0) {
 
518
                /* Avoid wrap-over */
 
519
                prebuilt->table->stat_n_rows--;
 
520
        }       
 
521
 
 
522
        row_update_statistics_if_needed(prebuilt);
 
523
 
 
524
        return((int) err);
 
525
}
 
526
 
 
527
/*************************************************************************
 
528
Builds a dummy query graph used in selects. */
 
529
 
 
530
void
 
531
row_prebuild_sel_graph(
 
532
/*===================*/
 
533
        row_prebuilt_t* prebuilt)       /* in: prebuilt struct in MySQL
 
534
                                        handle */
 
535
{
 
536
        sel_node_t*     node;
 
537
 
 
538
        ut_ad(prebuilt && prebuilt->trx);
 
539
        
 
540
        if (prebuilt->sel_graph == NULL) {
 
541
 
 
542
                node = sel_node_create(prebuilt->heap);
 
543
                                
 
544
                prebuilt->sel_graph =
 
545
                        que_node_get_parent(
 
546
                                pars_complete_graph_for_exec(node,
 
547
                                                        prebuilt->trx,
 
548
                                                        prebuilt->heap));
 
549
 
 
550
                prebuilt->sel_graph->state = QUE_FORK_ACTIVE;
 
551
        }
 
552
}
 
553
 
 
554
/*************************************************************************
 
555
Gets pointer to a prebuilt update vector used in updates. If the update
 
556
graph has not yet been built in the prebuilt struct, then this function
 
557
first builds it. */
 
558
 
 
559
upd_t*
 
560
row_get_prebuilt_update_vector(
 
561
/*===========================*/
 
562
                                        /* out: prebuilt update vector */
 
563
        row_prebuilt_t* prebuilt)       /* in: prebuilt struct in MySQL
 
564
                                        handle */
 
565
{
 
566
        dict_table_t*   table   = prebuilt->table;
 
567
        upd_node_t*     node;
 
568
 
 
569
        ut_ad(prebuilt && table && prebuilt->trx);
 
570
        
 
571
        if (prebuilt->upd_node == NULL) {
 
572
 
 
573
                /* Not called before for this handle: create an update node
 
574
                and query graph to the prebuilt struct */
 
575
 
 
576
                node = upd_node_create(prebuilt->heap);
 
577
                
 
578
                prebuilt->upd_node = node;
 
579
 
 
580
                node->in_mysql_interface = TRUE;
 
581
                node->is_delete = FALSE;
 
582
                node->searched_update = FALSE;
 
583
                node->select_will_do_update = FALSE;
 
584
                node->select = NULL;
 
585
                node->pcur = btr_pcur_create_for_mysql();
 
586
                node->table = table;
 
587
 
 
588
                node->update = upd_create(dict_table_get_n_cols(table),
 
589
                                                        prebuilt->heap);
 
590
                UT_LIST_INIT(node->columns);
 
591
                node->has_clust_rec_x_lock = TRUE;
 
592
                node->cmpl_info = 0;
 
593
 
 
594
                node->table_sym = NULL;
 
595
                node->col_assign_list = NULL;
 
596
                
 
597
                prebuilt->upd_graph =
 
598
                        que_node_get_parent(
 
599
                                pars_complete_graph_for_exec(node,
 
600
                                                        prebuilt->trx,
 
601
                                                        prebuilt->heap));
 
602
                prebuilt->upd_graph->state = QUE_FORK_ACTIVE;
 
603
        }
 
604
 
 
605
        return(prebuilt->upd_node->update);
 
606
}
 
607
 
 
608
/*************************************************************************
 
609
Does an update or delete of a row for MySQL. */
 
610
 
 
611
int
 
612
row_update_for_mysql(
 
613
/*=================*/
 
614
                                        /* out: error code or DB_SUCCESS */
 
615
        byte*           mysql_rec,      /* in: the row to be updated, in
 
616
                                        the MySQL format */
 
617
        row_prebuilt_t* prebuilt)       /* in: prebuilt struct in MySQL
 
618
                                        handle */
 
619
{
 
620
        trx_savept_t    savept;
 
621
        ulint           err;
 
622
        que_thr_t*      thr;
 
623
        ibool           was_lock_wait;
 
624
        dict_index_t*   clust_index; 
 
625
        ulint           ref_len;
 
626
        upd_node_t*     node;
 
627
        dict_table_t*   table           = prebuilt->table;
 
628
        trx_t*          trx             = prebuilt->trx;
 
629
        mem_heap_t*     heap;
 
630
        dtuple_t*       search_tuple;
 
631
        dtuple_t*       row_tuple;
 
632
        mtr_t           mtr;
 
633
        
 
634
        ut_ad(prebuilt && trx);
 
635
        ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
 
636
 
 
637
        node = prebuilt->upd_node;
 
638
 
 
639
        clust_index = dict_table_get_first_index(table);
 
640
 
 
641
        if (prebuilt->in_update_remember_pos) {
 
642
                if (prebuilt->index == clust_index) {
 
643
                        btr_pcur_copy_stored_position(node->pcur,
 
644
                                                        prebuilt->pcur);
 
645
                } else {
 
646
                        btr_pcur_copy_stored_position(node->pcur,
 
647
                                                        prebuilt->clust_pcur);
 
648
                }
 
649
                
 
650
                ut_ad(node->pcur->rel_pos == BTR_PCUR_ON);
 
651
 
 
652
                goto skip_cursor_search;
 
653
        }       
 
654
 
 
655
        /* We have to search for the correct cursor position */
 
656
 
 
657
        ref_len = dict_index_get_n_unique(clust_index);
 
658
 
 
659
        heap = mem_heap_create(450);
 
660
 
 
661
        row_tuple = dtuple_create(heap, dict_table_get_n_cols(table));
 
662
        dict_table_copy_types(row_tuple, table);
 
663
 
 
664
        if (prebuilt->ins_upd_rec_buff == NULL) {
 
665
                prebuilt->ins_upd_rec_buff = mem_heap_alloc(prebuilt->heap,
 
666
                                                prebuilt->mysql_row_len);
 
667
        }
 
668
                
 
669
        row_mysql_convert_row_to_innobase(row_tuple,
 
670
                                                prebuilt->ins_upd_rec_buff,
 
671
                                                prebuilt, mysql_rec);
 
672
 
 
673
        search_tuple = dtuple_create(heap, ref_len);
 
674
 
 
675
        row_build_row_ref_from_row(search_tuple, table, row_tuple);
 
676
 
 
677
        mtr_start(&mtr);
 
678
        
 
679
        btr_pcur_open_with_no_init(clust_index, search_tuple, PAGE_CUR_LE,
 
680
                                        BTR_SEARCH_LEAF, node->pcur, 0, &mtr);  
 
681
 
 
682
        btr_pcur_store_position(node->pcur, &mtr);
 
683
        
 
684
        mtr_commit(&mtr);
 
685
 
 
686
        mem_heap_free(heap);
 
687
 
 
688
skip_cursor_search:
 
689
        savept = trx_savept_take(trx);
 
690
        
 
691
        thr = que_fork_get_first_thr(prebuilt->upd_graph);
 
692
 
 
693
        node->state = UPD_NODE_UPDATE_CLUSTERED;
 
694
 
 
695
        ut_ad(!prebuilt->sql_stat_start);
 
696
 
 
697
        que_thr_move_to_run_state_for_mysql(thr, trx);
 
698
run_again:
 
699
        thr->run_node = node;
 
700
        thr->prev_node = node;
 
701
 
 
702
        row_upd_step(thr);
 
703
 
 
704
        err = trx->error_state;
 
705
 
 
706
        if (err != DB_SUCCESS) {
 
707
                que_thr_stop_for_mysql(thr);
 
708
                
 
709
                if (err == DB_RECORD_NOT_FOUND) {
 
710
                        trx->error_state = DB_SUCCESS;
 
711
 
 
712
                        return((int) err);
 
713
                }
 
714
        
 
715
                was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
 
716
                                                                &savept);
 
717
                if (was_lock_wait) {
 
718
                        goto run_again;
 
719
                }
 
720
 
 
721
                return(err);
 
722
        }
 
723
 
 
724
        que_thr_stop_for_mysql_no_error(thr, trx);
 
725
 
 
726
        if (prebuilt->upd_node->is_delete) {
 
727
                if (prebuilt->table->stat_n_rows > 0) {
 
728
                        prebuilt->table->stat_n_rows--;
 
729
                }
 
730
        }       
 
731
 
 
732
        row_update_statistics_if_needed(prebuilt);
 
733
 
 
734
        return((int) err);
 
735
}
 
736
 
 
737
/*************************************************************************
 
738
Checks if a table is such that we automatically created a clustered
 
739
index on it (on row id). */
 
740
 
 
741
ibool
 
742
row_table_got_default_clust_index(
 
743
/*==============================*/
 
744
        dict_table_t*   table)
 
745
{
 
746
        dict_index_t*   clust_index;
 
747
 
 
748
        clust_index = dict_table_get_first_index(table);
 
749
 
 
750
        if (dtype_get_mtype(dict_index_get_nth_type(clust_index, 0))
 
751
                                                                == DATA_SYS) {
 
752
                return(TRUE);
 
753
        }
 
754
 
 
755
        return(FALSE);
 
756
}
 
757
 
 
758
/*************************************************************************
 
759
Does a table creation operation for MySQL. */
 
760
 
 
761
int
 
762
row_create_table_for_mysql(
 
763
/*=======================*/
 
764
                                /* out: error code or DB_SUCCESS */
 
765
        dict_table_t*   table,  /* in: table definition */
 
766
        trx_t*          trx)    /* in: transaction handle */
 
767
{
 
768
        tab_node_t*     node;
 
769
        mem_heap_t*     heap;
 
770
        que_thr_t*      thr;
 
771
        ulint           err;
 
772
 
 
773
        ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
 
774
        
 
775
        /* Serialize data dictionary operations with dictionary mutex:
 
776
        no deadlocks can occur then in these operations */
 
777
 
 
778
        mutex_enter(&(dict_sys->mutex));
 
779
 
 
780
        heap = mem_heap_create(512);
 
781
 
 
782
        trx->dict_operation = TRUE;
 
783
        
 
784
        node = tab_create_graph_create(table, heap);
 
785
 
 
786
        thr = pars_complete_graph_for_exec(node, trx, heap);
 
787
 
 
788
        ut_a(thr == que_fork_start_command(que_node_get_parent(thr),
 
789
                                                SESS_COMM_EXECUTE, 0));
 
790
        que_run_threads(thr);
 
791
 
 
792
        err = trx->error_state;
 
793
 
 
794
        if (err != DB_SUCCESS) {
 
795
                /* We have special error handling here */
 
796
                ut_a(err == DB_OUT_OF_FILE_SPACE);
 
797
                trx->error_state = DB_SUCCESS;
 
798
                
 
799
                trx_general_rollback_for_mysql(trx, FALSE, NULL);
 
800
 
 
801
                row_drop_table_for_mysql(table->name, trx, TRUE);
 
802
 
 
803
                trx->error_state = DB_SUCCESS;
 
804
        }
 
805
 
 
806
        mutex_exit(&(dict_sys->mutex));
 
807
        que_graph_free((que_t*) que_node_get_parent(thr));
 
808
        
 
809
        return((int) err);
 
810
}
 
811
 
 
812
/*************************************************************************
 
813
Does an index creation operation for MySQL. TODO: currently failure
 
814
to create an index results in dropping the whole table! This is no problem
 
815
currently as all indexes must be created at the same time as the table. */
 
816
 
 
817
int
 
818
row_create_index_for_mysql(
 
819
/*=======================*/
 
820
                                        /* out: error number or DB_SUCCESS */
 
821
        dict_index_t*   index,          /* in: index defintion */
 
822
        trx_t*          trx)            /* in: transaction handle */
 
823
{
 
824
        ind_node_t*     node;
 
825
        mem_heap_t*     heap;
 
826
        que_thr_t*      thr;
 
827
        ulint           err;
 
828
        
 
829
        ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
 
830
        
 
831
        /* Serialize data dictionary operations with dictionary mutex:
 
832
        no deadlocks can occur then in these operations */
 
833
 
 
834
        mutex_enter(&(dict_sys->mutex));
 
835
 
 
836
        heap = mem_heap_create(512);
 
837
 
 
838
        trx->dict_operation = TRUE;
 
839
 
 
840
        node = ind_create_graph_create(index, heap);
 
841
 
 
842
        thr = pars_complete_graph_for_exec(node, trx, heap);
 
843
 
 
844
        ut_a(thr == que_fork_start_command(que_node_get_parent(thr),
 
845
                                                SESS_COMM_EXECUTE, 0));
 
846
        que_run_threads(thr);
 
847
 
 
848
        err = trx->error_state;
 
849
 
 
850
        if (err != DB_SUCCESS) {
 
851
                /* We have special error handling here */
 
852
                ut_a(err == DB_OUT_OF_FILE_SPACE);
 
853
                
 
854
                trx->error_state = DB_SUCCESS;
 
855
 
 
856
                trx_general_rollback_for_mysql(trx, FALSE, NULL);
 
857
 
 
858
                row_drop_table_for_mysql(index->table_name, trx, TRUE);
 
859
 
 
860
                trx->error_state = DB_SUCCESS;
 
861
        }
 
862
 
 
863
        mutex_exit(&(dict_sys->mutex));
 
864
 
 
865
        que_graph_free((que_t*) que_node_get_parent(thr));
 
866
        
 
867
        return((int) err);
 
868
}
 
869
 
 
870
/*************************************************************************
 
871
Drops a table for MySQL. */
 
872
 
 
873
int
 
874
row_drop_table_for_mysql(
 
875
/*=====================*/
 
876
                                /* out: error code or DB_SUCCESS */
 
877
        char*   name,           /* in: table name */
 
878
        trx_t*  trx,            /* in: transaction handle */
 
879
        ibool   has_dict_mutex) /* in: TRUE if the caller already owns the
 
880
                                dictionary system mutex */
 
881
{
 
882
        dict_table_t*   table;
 
883
        que_thr_t*      thr;
 
884
        que_t*          graph;
 
885
        ulint           err;
 
886
        char*           str1;
 
887
        char*           str2;
 
888
        ulint           len;
 
889
        char            buf[10000];
 
890
retry:
 
891
        ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
 
892
        ut_a(name != NULL);
 
893
        
 
894
        /* We use the private SQL parser of Innobase to generate the
 
895
        query graphs needed in deleting the dictionary data from system
 
896
        tables in Innobase. Deleting a row from SYS_INDEXES table also
 
897
        frees the file segments of the B-tree associated with the index. */
 
898
 
 
899
        str1 =
 
900
        "PROCEDURE DROP_TABLE_PROC () IS\n"
 
901
        "table_id CHAR;\n"
 
902
        "index_id CHAR;\n"
 
903
        "found INT;\n"
 
904
        "BEGIN\n"
 
905
        "SELECT ID INTO table_id\n"
 
906
        "FROM SYS_TABLES\n"
 
907
        "WHERE NAME ='";
 
908
 
 
909
        str2 = 
 
910
        "';\n"
 
911
        "IF (SQL % NOTFOUND) THEN\n"
 
912
        "       COMMIT WORK;\n"
 
913
        "       RETURN;\n"
 
914
        "END IF;\n"
 
915
        "found := 1;\n"
 
916
        "WHILE found = 1 LOOP\n"
 
917
        "       SELECT ID INTO index_id\n"
 
918
        "       FROM SYS_INDEXES\n"
 
919
        "       WHERE TABLE_ID = table_id;\n"   
 
920
        "       IF (SQL % NOTFOUND) THEN\n"
 
921
        "               found := 0;\n"
 
922
        "       ELSE"
 
923
        "               DELETE FROM SYS_FIELDS WHERE INDEX_ID = index_id;\n"
 
924
        "               DELETE FROM SYS_INDEXES WHERE ID = index_id;\n"
 
925
        "       END IF;\n"
 
926
        "END LOOP;\n"
 
927
        "DELETE FROM SYS_COLUMNS WHERE TABLE_ID = table_id;\n"
 
928
        "DELETE FROM SYS_TABLES WHERE ID = table_id;\n"
 
929
        "COMMIT WORK;\n"
 
930
        "END;\n";
 
931
 
 
932
        len = ut_strlen(str1);
 
933
 
 
934
        ut_memcpy(buf, str1, len);
 
935
        ut_memcpy(buf + len, name, ut_strlen(name));
 
936
 
 
937
        len += ut_strlen(name);
 
938
 
 
939
        ut_memcpy(buf + len, str2, ut_strlen(str2) + 1);
 
940
 
 
941
        /* Serialize data dictionary operations with dictionary mutex:
 
942
        no deadlocks can occur then in these operations */
 
943
 
 
944
        if (!has_dict_mutex) {
 
945
                mutex_enter(&(dict_sys->mutex));
 
946
        }
 
947
 
 
948
        graph = pars_sql(buf);
 
949
 
 
950
        ut_a(graph);
 
951
 
 
952
        graph->trx = trx;
 
953
        trx->graph = NULL;
 
954
 
 
955
        graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
 
956
 
 
957
        /* Prevent purge from running while we are dropping the table */
 
958
        rw_lock_s_lock(&(purge_sys->purge_is_running));
 
959
 
 
960
        table = dict_table_get_low(name);
 
961
 
 
962
        if (!table) {
 
963
                err = DB_TABLE_NOT_FOUND;
 
964
 
 
965
                goto funct_exit;
 
966
        }
 
967
 
 
968
        /* Check if there are any locks on the table: if yes, it cannot
 
969
        be dropped: we have to wait for the locks to be released  */
 
970
 
 
971
        if (lock_is_on_table(table)) {
 
972
 
 
973
                err = DB_TABLE_IS_BEING_USED;
 
974
 
 
975
                goto funct_exit;
 
976
        }               
 
977
 
 
978
        /* TODO: check that MySQL prevents users from accessing the table
 
979
        after this function row_drop_table_for_mysql has been called:
 
980
        otherwise anyone with an open handle to the table could, for example,
 
981
        come to read the table! */
 
982
 
 
983
        trx->dict_operation = TRUE;
 
984
        trx->table_id = table->id;
 
985
 
 
986
        ut_a(thr = que_fork_start_command(graph, SESS_COMM_EXECUTE, 0));
 
987
 
 
988
        que_run_threads(thr);
 
989
 
 
990
        err = trx->error_state;
 
991
 
 
992
        if (err != DB_SUCCESS) {
 
993
                ut_a(err == DB_OUT_OF_FILE_SPACE);
 
994
 
 
995
                err = DB_MUST_GET_MORE_FILE_SPACE;
 
996
                
 
997
                row_mysql_handle_errors(&err, trx, thr, NULL);
 
998
 
 
999
                ut_a(0);
 
1000
        } else {
 
1001
                dict_table_remove_from_cache(table);
 
1002
        }
 
1003
funct_exit:     
 
1004
        rw_lock_s_unlock(&(purge_sys->purge_is_running));
 
1005
 
 
1006
        if (!has_dict_mutex) {
 
1007
                mutex_exit(&(dict_sys->mutex));
 
1008
        }
 
1009
 
 
1010
        que_graph_free(graph);
 
1011
        
 
1012
        if (err == DB_TABLE_IS_BEING_USED) {
 
1013
                os_thread_sleep(200000);
 
1014
 
 
1015
                goto retry;
 
1016
        }
 
1017
 
 
1018
        return((int) err);
 
1019
}
 
1020
 
 
1021
/*************************************************************************
 
1022
Renames a table for MySQL. */
 
1023
 
 
1024
int
 
1025
row_rename_table_for_mysql(
 
1026
/*=======================*/
 
1027
                                /* out: error code or DB_SUCCESS */
 
1028
        char*   old_name,       /* in: old table name */
 
1029
        char*   new_name,       /* in: new table name */
 
1030
        trx_t*  trx)            /* in: transaction handle */
 
1031
{
 
1032
        dict_table_t*   table;
 
1033
        que_thr_t*      thr;
 
1034
        que_t*          graph;
 
1035
        ulint           err;
 
1036
        char*           str1;
 
1037
        char*           str2;
 
1038
        char*           str3;
 
1039
        ulint           len;
 
1040
        char            buf[10000];
 
1041
 
 
1042
        ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
 
1043
        ut_a(old_name != NULL);
 
1044
        ut_a(new_name != NULL);
 
1045
 
 
1046
        str1 =
 
1047
        "PROCEDURE RENAME_TABLE_PROC () IS\n"
 
1048
        "BEGIN\n"
 
1049
        "UPDATE SYS_TABLES SET NAME ='";
 
1050
 
 
1051
        str2 = 
 
1052
        "' WHERE NAME = '";
 
1053
 
 
1054
        str3 =
 
1055
        "';\n"
 
1056
        "COMMIT WORK;\n"
 
1057
        "END;\n";
 
1058
 
 
1059
        len = ut_strlen(str1);
 
1060
 
 
1061
        ut_memcpy(buf, str1, len);
 
1062
 
 
1063
        ut_memcpy(buf + len, new_name, ut_strlen(new_name));
 
1064
 
 
1065
        len += ut_strlen(new_name);
 
1066
 
 
1067
        ut_memcpy(buf + len, str2, ut_strlen(str2));
 
1068
 
 
1069
        len += ut_strlen(str2);
 
1070
 
 
1071
        ut_memcpy(buf + len, old_name, ut_strlen(old_name));
 
1072
 
 
1073
        len += ut_strlen(old_name);
 
1074
 
 
1075
        ut_memcpy(buf + len, str3, ut_strlen(str3) + 1);
 
1076
        
 
1077
        /* Serialize data dictionary operations with dictionary mutex:
 
1078
        no deadlocks can occur then in these operations */
 
1079
 
 
1080
        mutex_enter(&(dict_sys->mutex));
 
1081
 
 
1082
        table = dict_table_get_low(old_name);
 
1083
 
 
1084
        graph = pars_sql(buf);
 
1085
 
 
1086
        ut_a(graph);
 
1087
 
 
1088
        graph->trx = trx;
 
1089
        trx->graph = NULL;
 
1090
 
 
1091
        graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
 
1092
 
 
1093
        if (!table) {
 
1094
                err = DB_TABLE_NOT_FOUND;
 
1095
 
 
1096
                goto funct_exit;
 
1097
        }
 
1098
 
 
1099
        ut_a(thr = que_fork_start_command(graph, SESS_COMM_EXECUTE, 0));
 
1100
 
 
1101
        que_run_threads(thr);
 
1102
 
 
1103
        err = trx->error_state;
 
1104
 
 
1105
        if (err != DB_SUCCESS) {
 
1106
                row_mysql_handle_errors(&err, trx, thr, NULL);
 
1107
        } else {
 
1108
                ut_a(dict_table_rename_in_cache(table, new_name));
 
1109
        }
 
1110
funct_exit:     
 
1111
        mutex_exit(&(dict_sys->mutex));
 
1112
 
 
1113
        que_graph_free(graph);
 
1114
        
 
1115
        return((int) err);
 
1116
}