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 |
#ifdef USE_PRAGMA_IMPLEMENTATION
|
|
18 |
#pragma implementation // gcc: Class implementation |
|
19 |
#endif
|
|
20 |
||
21 |
#define MYSQL_SERVER 1
|
|
22 |
#include "mysql_priv.h" |
|
23 |
#include <mysql/plugin.h> |
|
24 |
#include <m_ctype.h> |
|
25 |
#include <my_bit.h> |
|
26 |
#include <myisampack.h> |
|
27 |
#include "ha_myisam.h" |
|
28 |
#include <stdarg.h> |
|
29 |
#include "myisamdef.h" |
|
30 |
||
31 |
ulong myisam_recover_options= HA_RECOVER_NONE; |
|
32 |
||
33 |
/* bits in myisam_recover_options */
|
|
34 |
const char *myisam_recover_names[] = |
|
35 |
{ "DEFAULT", "BACKUP", "FORCE", "QUICK", NullS}; |
|
36 |
TYPELIB myisam_recover_typelib= {array_elements(myisam_recover_names)-1,"", |
|
37 |
myisam_recover_names, NULL}; |
|
38 |
||
39 |
const char *myisam_stats_method_names[] = {"nulls_unequal", "nulls_equal", |
|
40 |
"nulls_ignored", NullS}; |
|
41 |
TYPELIB myisam_stats_method_typelib= { |
|
42 |
array_elements(myisam_stats_method_names) - 1, "", |
|
43 |
myisam_stats_method_names, NULL}; |
|
44 |
||
45 |
||
46 |
/*****************************************************************************
|
|
47 |
** MyISAM tables
|
|
48 |
*****************************************************************************/
|
|
49 |
||
50 |
static handler *myisam_create_handler(handlerton *hton, |
|
51 |
TABLE_SHARE *table, |
|
52 |
MEM_ROOT *mem_root) |
|
53 |
{
|
|
54 |
return new (mem_root) ha_myisam(hton, table); |
|
55 |
}
|
|
56 |
||
57 |
// collect errors printed by mi_check routines
|
|
58 |
||
59 |
static void mi_check_print_msg(MI_CHECK *param, const char* msg_type, |
|
60 |
const char *fmt, va_list args) |
|
61 |
{
|
|
62 |
THD* thd = (THD*)param->thd; |
|
63 |
Protocol *protocol= thd->protocol; |
|
64 |
uint length, msg_length; |
|
65 |
char msgbuf[MI_MAX_MSG_BUF]; |
|
66 |
char name[NAME_LEN*2+2]; |
|
67 |
||
77.1.18
by Monty Taylor
Removed my_vsnprintf and my_snprintf. |
68 |
msg_length= vsnprintf(msgbuf, sizeof(msgbuf), fmt, args); |
1
by brian
clean slate |
69 |
msgbuf[sizeof(msgbuf) - 1] = 0; // healthy paranoia |
70 |
||
71 |
DBUG_PRINT(msg_type,("message: %s",msgbuf)); |
|
72 |
||
73 |
if (!thd->vio_ok()) |
|
74 |
{
|
|
75 |
sql_print_error(msgbuf); |
|
76 |
return; |
|
77 |
}
|
|
78 |
||
79 |
if (param->testflag & (T_CREATE_MISSING_KEYS | T_SAFE_REPAIR | |
|
80 |
T_AUTO_REPAIR)) |
|
81 |
{
|
|
82 |
my_message(ER_NOT_KEYFILE,msgbuf,MYF(MY_WME)); |
|
83 |
return; |
|
84 |
}
|
|
85 |
length=(uint) (strxmov(name, param->db_name,".",param->table_name,NullS) - |
|
86 |
name); |
|
87 |
/*
|
|
88 |
TODO: switch from protocol to push_warning here. The main reason we didn't
|
|
89 |
it yet is parallel repair. Due to following trace:
|
|
90 |
mi_check_print_msg/push_warning/sql_alloc/my_pthread_getspecific_ptr.
|
|
91 |
||
92 |
Also we likely need to lock mutex here (in both cases with protocol and
|
|
93 |
push_warning).
|
|
94 |
*/
|
|
95 |
protocol->prepare_for_resend(); |
|
96 |
protocol->store(name, length, system_charset_info); |
|
97 |
protocol->store(param->op_name, system_charset_info); |
|
98 |
protocol->store(msg_type, system_charset_info); |
|
99 |
protocol->store(msgbuf, msg_length, system_charset_info); |
|
100 |
if (protocol->write()) |
|
101 |
sql_print_error("Failed on my_net_write, writing to stderr instead: %s\n", |
|
102 |
msgbuf); |
|
103 |
return; |
|
104 |
}
|
|
105 |
||
106 |
||
107 |
/*
|
|
108 |
Convert TABLE object to MyISAM key and column definition
|
|
109 |
||
110 |
SYNOPSIS
|
|
111 |
table2myisam()
|
|
112 |
table_arg in TABLE object.
|
|
113 |
keydef_out out MyISAM key definition.
|
|
114 |
recinfo_out out MyISAM column definition.
|
|
115 |
records_out out Number of fields.
|
|
116 |
||
117 |
DESCRIPTION
|
|
118 |
This function will allocate and initialize MyISAM key and column
|
|
119 |
definition for further use in mi_create or for a check for underlying
|
|
120 |
table conformance in merge engine.
|
|
121 |
||
122 |
The caller needs to free *recinfo_out after use. Since *recinfo_out
|
|
123 |
and *keydef_out are allocated with a my_multi_malloc, *keydef_out
|
|
124 |
is freed automatically when *recinfo_out is freed.
|
|
125 |
||
126 |
RETURN VALUE
|
|
127 |
0 OK
|
|
128 |
!0 error code
|
|
129 |
*/
|
|
130 |
||
131 |
int table2myisam(TABLE *table_arg, MI_KEYDEF **keydef_out, |
|
132 |
MI_COLUMNDEF **recinfo_out, uint *records_out) |
|
133 |
{
|
|
134 |
uint i, j, recpos, minpos, fieldpos, temp_length, length; |
|
135 |
enum ha_base_keytype type= HA_KEYTYPE_BINARY; |
|
136 |
uchar *record; |
|
137 |
KEY *pos; |
|
138 |
MI_KEYDEF *keydef; |
|
139 |
MI_COLUMNDEF *recinfo, *recinfo_pos; |
|
140 |
HA_KEYSEG *keyseg; |
|
141 |
TABLE_SHARE *share= table_arg->s; |
|
142 |
uint options= share->db_options_in_use; |
|
143 |
DBUG_ENTER("table2myisam"); |
|
144 |
if (!(my_multi_malloc(MYF(MY_WME), |
|
145 |
recinfo_out, (share->fields * 2 + 2) * sizeof(MI_COLUMNDEF), |
|
146 |
keydef_out, share->keys * sizeof(MI_KEYDEF), |
|
147 |
&keyseg, |
|
148 |
(share->key_parts + share->keys) * sizeof(HA_KEYSEG), |
|
149 |
NullS))) |
|
150 |
DBUG_RETURN(HA_ERR_OUT_OF_MEM); /* purecov: inspected */ |
|
151 |
keydef= *keydef_out; |
|
152 |
recinfo= *recinfo_out; |
|
153 |
pos= table_arg->key_info; |
|
154 |
for (i= 0; i < share->keys; i++, pos++) |
|
155 |
{
|
|
74
by Brian Aker
More removal of FT from MyISAM |
156 |
keydef[i].flag= ((uint16) pos->flags & (HA_NOSAME | HA_FULLTEXT )); |
157 |
keydef[i].key_alg= pos->algorithm == HA_KEY_ALG_UNDEF ? (HA_KEY_ALG_BTREE) : pos->algorithm; |
|
1
by brian
clean slate |
158 |
keydef[i].block_length= pos->block_size; |
159 |
keydef[i].seg= keyseg; |
|
160 |
keydef[i].keysegs= pos->key_parts; |
|
161 |
for (j= 0; j < pos->key_parts; j++) |
|
162 |
{
|
|
163 |
Field *field= pos->key_part[j].field; |
|
164 |
type= field->key_type(); |
|
165 |
keydef[i].seg[j].flag= pos->key_part[j].key_part_flag; |
|
166 |
||
167 |
if (options & HA_OPTION_PACK_KEYS || |
|
168 |
(pos->flags & (HA_PACK_KEY | HA_BINARY_PACK_KEY | |
|
169 |
HA_SPACE_PACK_USED))) |
|
170 |
{
|
|
171 |
if (pos->key_part[j].length > 8 && |
|
172 |
(type == HA_KEYTYPE_TEXT || |
|
173 |
type == HA_KEYTYPE_NUM || |
|
174 |
(type == HA_KEYTYPE_BINARY && !field->zero_pack()))) |
|
175 |
{
|
|
176 |
/* No blobs here */
|
|
177 |
if (j == 0) |
|
178 |
keydef[i].flag|= HA_PACK_KEY; |
|
179 |
if (!(field->flags & ZEROFILL_FLAG) && |
|
180 |
(field->type() == MYSQL_TYPE_STRING || |
|
181 |
field->type() == MYSQL_TYPE_VAR_STRING || |
|
182 |
((int) (pos->key_part[j].length - field->decimals())) >= 4)) |
|
183 |
keydef[i].seg[j].flag|= HA_SPACE_PACK; |
|
184 |
}
|
|
185 |
else if (j == 0 && (!(pos->flags & HA_NOSAME) || pos->key_length > 16)) |
|
186 |
keydef[i].flag|= HA_BINARY_PACK_KEY; |
|
187 |
}
|
|
188 |
keydef[i].seg[j].type= (int) type; |
|
189 |
keydef[i].seg[j].start= pos->key_part[j].offset; |
|
190 |
keydef[i].seg[j].length= pos->key_part[j].length; |
|
191 |
keydef[i].seg[j].bit_start= keydef[i].seg[j].bit_end= |
|
192 |
keydef[i].seg[j].bit_length= 0; |
|
193 |
keydef[i].seg[j].bit_pos= 0; |
|
194 |
keydef[i].seg[j].language= field->charset()->number; |
|
195 |
||
196 |
if (field->null_ptr) |
|
197 |
{
|
|
198 |
keydef[i].seg[j].null_bit= field->null_bit; |
|
199 |
keydef[i].seg[j].null_pos= (uint) (field->null_ptr- |
|
200 |
(uchar*) table_arg->record[0]); |
|
201 |
}
|
|
202 |
else
|
|
203 |
{
|
|
204 |
keydef[i].seg[j].null_bit= 0; |
|
205 |
keydef[i].seg[j].null_pos= 0; |
|
206 |
}
|
|
62
by Brian Aker
First pass of removing BIT_TYPE |
207 |
if (field->type() == MYSQL_TYPE_BLOB) |
1
by brian
clean slate |
208 |
{
|
209 |
keydef[i].seg[j].flag|= HA_BLOB_PART; |
|
210 |
/* save number of bytes used to pack length */
|
|
211 |
keydef[i].seg[j].bit_start= (uint) (field->pack_length() - |
|
212 |
share->blob_ptr_size); |
|
213 |
}
|
|
214 |
}
|
|
215 |
keyseg+= pos->key_parts; |
|
216 |
}
|
|
217 |
if (table_arg->found_next_number_field) |
|
218 |
keydef[share->next_number_index].flag|= HA_AUTO_KEY; |
|
219 |
record= table_arg->record[0]; |
|
220 |
recpos= 0; |
|
221 |
recinfo_pos= recinfo; |
|
222 |
while (recpos < (uint) share->reclength) |
|
223 |
{
|
|
224 |
Field **field, *found= 0; |
|
225 |
minpos= share->reclength; |
|
226 |
length= 0; |
|
227 |
||
228 |
for (field= table_arg->field; *field; field++) |
|
229 |
{
|
|
230 |
if ((fieldpos= (*field)->offset(record)) >= recpos && |
|
231 |
fieldpos <= minpos) |
|
232 |
{
|
|
233 |
/* skip null fields */
|
|
234 |
if (!(temp_length= (*field)->pack_length_in_rec())) |
|
235 |
continue; /* Skip null-fields */ |
|
236 |
if (! found || fieldpos < minpos || |
|
237 |
(fieldpos == minpos && temp_length < length)) |
|
238 |
{
|
|
239 |
minpos= fieldpos; |
|
240 |
found= *field; |
|
241 |
length= temp_length; |
|
242 |
}
|
|
243 |
}
|
|
244 |
}
|
|
245 |
DBUG_PRINT("loop", ("found: 0x%lx recpos: %d minpos: %d length: %d", |
|
246 |
(long) found, recpos, minpos, length)); |
|
247 |
if (recpos != minpos) |
|
248 |
{ // Reserved space (Null bits?) |
|
249 |
bzero((char*) recinfo_pos, sizeof(*recinfo_pos)); |
|
250 |
recinfo_pos->type= (int) FIELD_NORMAL; |
|
251 |
recinfo_pos++->length= (uint16) (minpos - recpos); |
|
252 |
}
|
|
253 |
if (!found) |
|
254 |
break; |
|
255 |
||
256 |
if (found->flags & BLOB_FLAG) |
|
257 |
recinfo_pos->type= (int) FIELD_BLOB; |
|
258 |
else if (found->type() == MYSQL_TYPE_VARCHAR) |
|
259 |
recinfo_pos->type= FIELD_VARCHAR; |
|
260 |
else if (!(options & HA_OPTION_PACK_RECORD)) |
|
261 |
recinfo_pos->type= (int) FIELD_NORMAL; |
|
262 |
else if (found->zero_pack()) |
|
263 |
recinfo_pos->type= (int) FIELD_SKIP_ZERO; |
|
264 |
else
|
|
265 |
recinfo_pos->type= (int) ((length <= 3 || |
|
266 |
(found->flags & ZEROFILL_FLAG)) ? |
|
267 |
FIELD_NORMAL : |
|
268 |
found->type() == MYSQL_TYPE_STRING || |
|
269 |
found->type() == MYSQL_TYPE_VAR_STRING ? |
|
270 |
FIELD_SKIP_ENDSPACE : |
|
271 |
FIELD_SKIP_PRESPACE); |
|
272 |
if (found->null_ptr) |
|
273 |
{
|
|
274 |
recinfo_pos->null_bit= found->null_bit; |
|
275 |
recinfo_pos->null_pos= (uint) (found->null_ptr - |
|
276 |
(uchar*) table_arg->record[0]); |
|
277 |
}
|
|
278 |
else
|
|
279 |
{
|
|
280 |
recinfo_pos->null_bit= 0; |
|
281 |
recinfo_pos->null_pos= 0; |
|
282 |
}
|
|
283 |
(recinfo_pos++)->length= (uint16) length; |
|
284 |
recpos= minpos + length; |
|
285 |
DBUG_PRINT("loop", ("length: %d type: %d", |
|
286 |
recinfo_pos[-1].length,recinfo_pos[-1].type)); |
|
287 |
}
|
|
288 |
*records_out= (uint) (recinfo_pos - recinfo); |
|
289 |
DBUG_RETURN(0); |
|
290 |
}
|
|
291 |
||
292 |
||
293 |
/*
|
|
294 |
Check for underlying table conformance
|
|
295 |
||
296 |
SYNOPSIS
|
|
297 |
check_definition()
|
|
298 |
t1_keyinfo in First table key definition
|
|
299 |
t1_recinfo in First table record definition
|
|
300 |
t1_keys in Number of keys in first table
|
|
301 |
t1_recs in Number of records in first table
|
|
302 |
t2_keyinfo in Second table key definition
|
|
303 |
t2_recinfo in Second table record definition
|
|
304 |
t2_keys in Number of keys in second table
|
|
305 |
t2_recs in Number of records in second table
|
|
306 |
strict in Strict check switch
|
|
307 |
||
308 |
DESCRIPTION
|
|
309 |
This function compares two MyISAM definitions. By intention it was done
|
|
310 |
to compare merge table definition against underlying table definition.
|
|
311 |
It may also be used to compare dot-frm and MYI definitions of MyISAM
|
|
312 |
table as well to compare different MyISAM table definitions.
|
|
313 |
||
314 |
For merge table it is not required that number of keys in merge table
|
|
315 |
must exactly match number of keys in underlying table. When calling this
|
|
316 |
function for underlying table conformance check, 'strict' flag must be
|
|
317 |
set to false, and converted merge definition must be passed as t1_*.
|
|
318 |
||
319 |
Otherwise 'strict' flag must be set to 1 and it is not required to pass
|
|
320 |
converted dot-frm definition as t1_*.
|
|
321 |
||
322 |
RETURN VALUE
|
|
323 |
0 - Equal definitions.
|
|
324 |
1 - Different definitions.
|
|
325 |
||
326 |
TODO
|
|
327 |
- compare FULLTEXT keys;
|
|
328 |
- compare SPATIAL keys;
|
|
329 |
- compare FIELD_SKIP_ZERO which is converted to FIELD_NORMAL correctly
|
|
330 |
(should be corretly detected in table2myisam).
|
|
331 |
*/
|
|
332 |
||
333 |
int check_definition(MI_KEYDEF *t1_keyinfo, MI_COLUMNDEF *t1_recinfo, |
|
334 |
uint t1_keys, uint t1_recs, |
|
335 |
MI_KEYDEF *t2_keyinfo, MI_COLUMNDEF *t2_recinfo, |
|
336 |
uint t2_keys, uint t2_recs, bool strict) |
|
337 |
{
|
|
338 |
uint i, j; |
|
339 |
DBUG_ENTER("check_definition"); |
|
340 |
if ((strict ? t1_keys != t2_keys : t1_keys > t2_keys)) |
|
341 |
{
|
|
342 |
DBUG_PRINT("error", ("Number of keys differs: t1_keys=%u, t2_keys=%u", |
|
343 |
t1_keys, t2_keys)); |
|
344 |
DBUG_RETURN(1); |
|
345 |
}
|
|
346 |
if (t1_recs != t2_recs) |
|
347 |
{
|
|
348 |
DBUG_PRINT("error", ("Number of recs differs: t1_recs=%u, t2_recs=%u", |
|
349 |
t1_recs, t2_recs)); |
|
350 |
DBUG_RETURN(1); |
|
351 |
}
|
|
352 |
for (i= 0; i < t1_keys; i++) |
|
353 |
{
|
|
354 |
HA_KEYSEG *t1_keysegs= t1_keyinfo[i].seg; |
|
355 |
HA_KEYSEG *t2_keysegs= t2_keyinfo[i].seg; |
|
356 |
if (t1_keyinfo[i].flag & HA_FULLTEXT && t2_keyinfo[i].flag & HA_FULLTEXT) |
|
357 |
continue; |
|
358 |
else if (t1_keyinfo[i].flag & HA_FULLTEXT || |
|
359 |
t2_keyinfo[i].flag & HA_FULLTEXT) |
|
360 |
{
|
|
361 |
DBUG_PRINT("error", ("Key %d has different definition", i)); |
|
362 |
DBUG_PRINT("error", ("t1_fulltext= %d, t2_fulltext=%d", |
|
363 |
test(t1_keyinfo[i].flag & HA_FULLTEXT), |
|
364 |
test(t2_keyinfo[i].flag & HA_FULLTEXT))); |
|
365 |
DBUG_RETURN(1); |
|
366 |
}
|
|
367 |
if (t1_keyinfo[i].flag & HA_SPATIAL && t2_keyinfo[i].flag & HA_SPATIAL) |
|
368 |
continue; |
|
369 |
else if (t1_keyinfo[i].flag & HA_SPATIAL || |
|
370 |
t2_keyinfo[i].flag & HA_SPATIAL) |
|
371 |
{
|
|
372 |
DBUG_PRINT("error", ("Key %d has different definition", i)); |
|
373 |
DBUG_PRINT("error", ("t1_spatial= %d, t2_spatial=%d", |
|
374 |
test(t1_keyinfo[i].flag & HA_SPATIAL), |
|
375 |
test(t2_keyinfo[i].flag & HA_SPATIAL))); |
|
376 |
DBUG_RETURN(1); |
|
377 |
}
|
|
378 |
if (t1_keyinfo[i].keysegs != t2_keyinfo[i].keysegs || |
|
379 |
t1_keyinfo[i].key_alg != t2_keyinfo[i].key_alg) |
|
380 |
{
|
|
381 |
DBUG_PRINT("error", ("Key %d has different definition", i)); |
|
382 |
DBUG_PRINT("error", ("t1_keysegs=%d, t1_key_alg=%d", |
|
383 |
t1_keyinfo[i].keysegs, t1_keyinfo[i].key_alg)); |
|
384 |
DBUG_PRINT("error", ("t2_keysegs=%d, t2_key_alg=%d", |
|
385 |
t2_keyinfo[i].keysegs, t2_keyinfo[i].key_alg)); |
|
386 |
DBUG_RETURN(1); |
|
387 |
}
|
|
388 |
for (j= t1_keyinfo[i].keysegs; j--;) |
|
389 |
{
|
|
390 |
uint8 t1_keysegs_j__type= t1_keysegs[j].type; |
|
391 |
||
392 |
/*
|
|
393 |
Table migration from 4.1 to 5.1. In 5.1 a *TEXT key part is
|
|
394 |
always HA_KEYTYPE_VARTEXT2. In 4.1 we had only the equivalent of
|
|
395 |
HA_KEYTYPE_VARTEXT1. Since we treat both the same on MyISAM
|
|
396 |
level, we can ignore a mismatch between these types.
|
|
397 |
*/
|
|
398 |
if ((t1_keysegs[j].flag & HA_BLOB_PART) && |
|
399 |
(t2_keysegs[j].flag & HA_BLOB_PART)) |
|
400 |
{
|
|
401 |
if ((t1_keysegs_j__type == HA_KEYTYPE_VARTEXT2) && |
|
402 |
(t2_keysegs[j].type == HA_KEYTYPE_VARTEXT1)) |
|
403 |
t1_keysegs_j__type= HA_KEYTYPE_VARTEXT1; /* purecov: tested */ |
|
404 |
else if ((t1_keysegs_j__type == HA_KEYTYPE_VARBINARY2) && |
|
405 |
(t2_keysegs[j].type == HA_KEYTYPE_VARBINARY1)) |
|
406 |
t1_keysegs_j__type= HA_KEYTYPE_VARBINARY1; /* purecov: inspected */ |
|
407 |
}
|
|
408 |
||
409 |
if (t1_keysegs_j__type != t2_keysegs[j].type || |
|
410 |
t1_keysegs[j].language != t2_keysegs[j].language || |
|
411 |
t1_keysegs[j].null_bit != t2_keysegs[j].null_bit || |
|
412 |
t1_keysegs[j].length != t2_keysegs[j].length) |
|
413 |
{
|
|
414 |
DBUG_PRINT("error", ("Key segment %d (key %d) has different " |
|
415 |
"definition", j, i)); |
|
416 |
DBUG_PRINT("error", ("t1_type=%d, t1_language=%d, t1_null_bit=%d, " |
|
417 |
"t1_length=%d", |
|
418 |
t1_keysegs[j].type, t1_keysegs[j].language, |
|
419 |
t1_keysegs[j].null_bit, t1_keysegs[j].length)); |
|
420 |
DBUG_PRINT("error", ("t2_type=%d, t2_language=%d, t2_null_bit=%d, " |
|
421 |
"t2_length=%d", |
|
422 |
t2_keysegs[j].type, t2_keysegs[j].language, |
|
423 |
t2_keysegs[j].null_bit, t2_keysegs[j].length)); |
|
424 |
||
425 |
DBUG_RETURN(1); |
|
426 |
}
|
|
427 |
}
|
|
428 |
}
|
|
429 |
for (i= 0; i < t1_recs; i++) |
|
430 |
{
|
|
431 |
MI_COLUMNDEF *t1_rec= &t1_recinfo[i]; |
|
432 |
MI_COLUMNDEF *t2_rec= &t2_recinfo[i]; |
|
433 |
/*
|
|
434 |
FIELD_SKIP_ZERO can be changed to FIELD_NORMAL in mi_create,
|
|
435 |
see NOTE1 in mi_create.c
|
|
436 |
*/
|
|
437 |
if ((t1_rec->type != t2_rec->type && |
|
438 |
!(t1_rec->type == (int) FIELD_SKIP_ZERO && |
|
439 |
t1_rec->length == 1 && |
|
440 |
t2_rec->type == (int) FIELD_NORMAL)) || |
|
441 |
t1_rec->length != t2_rec->length || |
|
442 |
t1_rec->null_bit != t2_rec->null_bit) |
|
443 |
{
|
|
444 |
DBUG_PRINT("error", ("Field %d has different definition", i)); |
|
445 |
DBUG_PRINT("error", ("t1_type=%d, t1_length=%d, t1_null_bit=%d", |
|
446 |
t1_rec->type, t1_rec->length, t1_rec->null_bit)); |
|
447 |
DBUG_PRINT("error", ("t2_type=%d, t2_length=%d, t2_null_bit=%d", |
|
448 |
t2_rec->type, t2_rec->length, t2_rec->null_bit)); |
|
449 |
DBUG_RETURN(1); |
|
450 |
}
|
|
451 |
}
|
|
452 |
DBUG_RETURN(0); |
|
453 |
}
|
|
454 |
||
455 |
||
456 |
extern "C" { |
|
457 |
||
458 |
volatile int *killed_ptr(MI_CHECK *param) |
|
459 |
{
|
|
460 |
/* In theory Unsafe conversion, but should be ok for now */
|
|
461 |
return (int*) &(((THD *)(param->thd))->killed); |
|
462 |
}
|
|
463 |
||
464 |
void mi_check_print_error(MI_CHECK *param, const char *fmt,...) |
|
465 |
{
|
|
466 |
param->error_printed|=1; |
|
467 |
param->out_flag|= O_DATA_LOST; |
|
468 |
va_list args; |
|
469 |
va_start(args, fmt); |
|
470 |
mi_check_print_msg(param, "error", fmt, args); |
|
471 |
va_end(args); |
|
472 |
}
|
|
473 |
||
474 |
void mi_check_print_info(MI_CHECK *param, const char *fmt,...) |
|
475 |
{
|
|
476 |
va_list args; |
|
477 |
va_start(args, fmt); |
|
478 |
mi_check_print_msg(param, "info", fmt, args); |
|
479 |
va_end(args); |
|
480 |
}
|
|
481 |
||
482 |
void mi_check_print_warning(MI_CHECK *param, const char *fmt,...) |
|
483 |
{
|
|
484 |
param->warning_printed=1; |
|
485 |
param->out_flag|= O_DATA_LOST; |
|
486 |
va_list args; |
|
487 |
va_start(args, fmt); |
|
488 |
mi_check_print_msg(param, "warning", fmt, args); |
|
489 |
va_end(args); |
|
490 |
}
|
|
491 |
||
492 |
/**
|
|
493 |
Report list of threads (and queries) accessing a table, thread_id of a
|
|
494 |
thread that detected corruption, ource file name and line number where
|
|
495 |
this corruption was detected, optional extra information (string).
|
|
496 |
||
497 |
This function is intended to be used when table corruption is detected.
|
|
498 |
||
499 |
@param[in] file MI_INFO object.
|
|
500 |
@param[in] message Optional error message.
|
|
501 |
@param[in] sfile Name of source file.
|
|
502 |
@param[in] sline Line number in source file.
|
|
503 |
||
504 |
@return void
|
|
505 |
*/
|
|
506 |
||
507 |
void _mi_report_crashed(MI_INFO *file, const char *message, |
|
508 |
const char *sfile, uint sline) |
|
509 |
{
|
|
510 |
THD *cur_thd; |
|
511 |
LIST *element; |
|
512 |
char buf[1024]; |
|
513 |
pthread_mutex_lock(&file->s->intern_lock); |
|
514 |
if ((cur_thd= (THD*) file->in_use.data)) |
|
515 |
sql_print_error("Got an error from thread_id=%lu, %s:%d", cur_thd->thread_id, |
|
516 |
sfile, sline); |
|
517 |
else
|
|
518 |
sql_print_error("Got an error from unknown thread, %s:%d", sfile, sline); |
|
519 |
if (message) |
|
520 |
sql_print_error("%s", message); |
|
521 |
for (element= file->s->in_use; element; element= list_rest(element)) |
|
522 |
{
|
|
523 |
THD *thd= (THD*) element->data; |
|
524 |
sql_print_error("%s", thd ? thd_security_context(thd, buf, sizeof(buf), 0) |
|
525 |
: "Unknown thread accessing table"); |
|
526 |
}
|
|
527 |
pthread_mutex_unlock(&file->s->intern_lock); |
|
528 |
}
|
|
529 |
||
77.1.13
by Monty Taylor
Fixed wonky linkage thing. |
530 |
}
|
1
by brian
clean slate |
531 |
|
532 |
ha_myisam::ha_myisam(handlerton *hton, TABLE_SHARE *table_arg) |
|
533 |
:handler(hton, table_arg), file(0), |
|
534 |
int_table_flags(HA_NULL_IN_KEY | HA_CAN_FULLTEXT | HA_CAN_SQL_HANDLER | |
|
535 |
HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE | |
|
536 |
HA_DUPLICATE_POS | HA_CAN_INDEX_BLOBS | HA_AUTO_PART_KEY | |
|
537 |
HA_FILE_BASED | HA_CAN_GEOMETRY | HA_NO_TRANSACTIONS | |
|
538 |
HA_CAN_INSERT_DELAYED | HA_CAN_BIT_FIELD | HA_CAN_RTREEKEYS | |
|
539 |
HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT | |
|
540 |
HA_NEED_READ_RANGE_BUFFER | HA_MRR_CANT_SORT), |
|
541 |
can_enable_indexes(1) |
|
542 |
{}
|
|
543 |
||
544 |
handler *ha_myisam::clone(MEM_ROOT *mem_root) |
|
545 |
{
|
|
546 |
ha_myisam *new_handler= static_cast <ha_myisam *>(handler::clone(mem_root)); |
|
547 |
if (new_handler) |
|
548 |
new_handler->file->state= file->state; |
|
549 |
return new_handler; |
|
550 |
}
|
|
551 |
||
552 |
||
553 |
static const char *ha_myisam_exts[] = { |
|
554 |
".MYI", |
|
555 |
".MYD", |
|
556 |
NullS
|
|
557 |
};
|
|
558 |
||
559 |
const char **ha_myisam::bas_ext() const |
|
560 |
{
|
|
561 |
return ha_myisam_exts; |
|
562 |
}
|
|
563 |
||
564 |
||
77.1.9
by Monty Taylor
All of storage/ compiles clean now. |
565 |
const char *ha_myisam::index_type(uint key_number __attribute__((__unused__))) |
1
by brian
clean slate |
566 |
{
|
74
by Brian Aker
More removal of FT from MyISAM |
567 |
return "BTREE"; |
1
by brian
clean slate |
568 |
}
|
569 |
||
570 |
/* Name is here without an extension */
|
|
571 |
int ha_myisam::open(const char *name, int mode, uint test_if_locked) |
|
572 |
{
|
|
573 |
MI_KEYDEF *keyinfo; |
|
574 |
MI_COLUMNDEF *recinfo= 0; |
|
575 |
uint recs; |
|
576 |
uint i; |
|
577 |
||
578 |
/*
|
|
579 |
If the user wants to have memory mapped data files, add an
|
|
580 |
open_flag. Do not memory map temporary tables because they are
|
|
581 |
expected to be inserted and thus extended a lot. Memory mapping is
|
|
582 |
efficient for files that keep their size, but very inefficient for
|
|
583 |
growing files. Using an open_flag instead of calling mi_extra(...
|
|
584 |
HA_EXTRA_MMAP ...) after mi_open() has the advantage that the
|
|
585 |
mapping is not repeated for every open, but just done on the initial
|
|
586 |
open, when the MyISAM share is created. Everytime the server
|
|
587 |
requires to open a new instance of a table it calls this method. We
|
|
588 |
will always supply HA_OPEN_MMAP for a permanent table. However, the
|
|
589 |
MyISAM storage engine will ignore this flag if this is a secondary
|
|
590 |
open of a table that is in use by other threads already (if the
|
|
591 |
MyISAM share exists already).
|
|
592 |
*/
|
|
593 |
if (!(file=mi_open(name, mode, test_if_locked | HA_OPEN_FROM_SQL_LAYER))) |
|
594 |
return (my_errno ? my_errno : -1); |
|
595 |
if (!table->s->tmp_table) /* No need to perform a check for tmp table */ |
|
596 |
{
|
|
597 |
if ((my_errno= table2myisam(table, &keyinfo, &recinfo, &recs))) |
|
598 |
{
|
|
599 |
/* purecov: begin inspected */
|
|
600 |
DBUG_PRINT("error", ("Failed to convert TABLE object to MyISAM " |
|
601 |
"key and column definition")); |
|
602 |
goto err; |
|
603 |
/* purecov: end */
|
|
604 |
}
|
|
605 |
if (check_definition(keyinfo, recinfo, table->s->keys, recs, |
|
606 |
file->s->keyinfo, file->s->rec, |
|
607 |
file->s->base.keys, file->s->base.fields, true)) |
|
608 |
{
|
|
609 |
/* purecov: begin inspected */
|
|
610 |
my_errno= HA_ERR_CRASHED; |
|
611 |
goto err; |
|
612 |
/* purecov: end */
|
|
613 |
}
|
|
614 |
}
|
|
615 |
||
616 |
if (test_if_locked & (HA_OPEN_IGNORE_IF_LOCKED | HA_OPEN_TMP_TABLE)) |
|
617 |
VOID(mi_extra(file, HA_EXTRA_NO_WAIT_LOCK, 0)); |
|
618 |
||
619 |
info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST); |
|
620 |
if (!(test_if_locked & HA_OPEN_WAIT_IF_LOCKED)) |
|
621 |
VOID(mi_extra(file, HA_EXTRA_WAIT_LOCK, 0)); |
|
622 |
if (!table->s->db_record_offset) |
|
623 |
int_table_flags|=HA_REC_NOT_IN_SEQ; |
|
624 |
if (file->s->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD)) |
|
625 |
int_table_flags|=HA_HAS_CHECKSUM; |
|
626 |
||
627 |
keys_with_parts.clear_all(); |
|
628 |
for (i= 0; i < table->s->keys; i++) |
|
629 |
{
|
|
630 |
table->key_info[i].block_size= file->s->keyinfo[i].block_length; |
|
631 |
||
632 |
KEY_PART_INFO *kp= table->key_info[i].key_part; |
|
633 |
KEY_PART_INFO *kp_end= kp + table->key_info[i].key_parts; |
|
634 |
for (; kp != kp_end; kp++) |
|
635 |
{
|
|
636 |
if (!kp->field->part_of_key.is_set(i)) |
|
637 |
{
|
|
638 |
keys_with_parts.set_bit(i); |
|
639 |
break; |
|
640 |
}
|
|
641 |
}
|
|
642 |
}
|
|
643 |
my_errno= 0; |
|
644 |
goto end; |
|
645 |
err: |
|
646 |
this->close(); |
|
647 |
end: |
|
648 |
/*
|
|
649 |
Both recinfo and keydef are allocated by my_multi_malloc(), thus only
|
|
650 |
recinfo must be freed.
|
|
651 |
*/
|
|
652 |
if (recinfo) |
|
653 |
my_free((uchar*) recinfo, MYF(0)); |
|
654 |
return my_errno; |
|
655 |
}
|
|
656 |
||
657 |
int ha_myisam::close(void) |
|
658 |
{
|
|
659 |
MI_INFO *tmp=file; |
|
660 |
file=0; |
|
661 |
return mi_close(tmp); |
|
662 |
}
|
|
663 |
||
664 |
int ha_myisam::write_row(uchar *buf) |
|
665 |
{
|
|
666 |
ha_statistic_increment(&SSV::ha_write_count); |
|
667 |
||
668 |
/* If we have a timestamp column, update it to the current time */
|
|
669 |
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT) |
|
670 |
table->timestamp_field->set_time(); |
|
671 |
||
672 |
/*
|
|
673 |
If we have an auto_increment column and we are writing a changed row
|
|
674 |
or a new row, then update the auto_increment value in the record.
|
|
675 |
*/
|
|
676 |
if (table->next_number_field && buf == table->record[0]) |
|
677 |
{
|
|
678 |
int error; |
|
679 |
if ((error= update_auto_increment())) |
|
680 |
return error; |
|
681 |
}
|
|
682 |
return mi_write(file,buf); |
|
683 |
}
|
|
684 |
||
685 |
int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt) |
|
686 |
{
|
|
687 |
if (!file) return HA_ADMIN_INTERNAL_ERROR; |
|
688 |
int error; |
|
689 |
MI_CHECK param; |
|
690 |
MYISAM_SHARE* share = file->s; |
|
691 |
const char *old_proc_info=thd->proc_info; |
|
692 |
||
693 |
thd_proc_info(thd, "Checking table"); |
|
694 |
myisamchk_init(¶m); |
|
695 |
param.thd = thd; |
|
696 |
param.op_name = "check"; |
|
697 |
param.db_name= table->s->db.str; |
|
698 |
param.table_name= table->alias; |
|
699 |
param.testflag = check_opt->flags | T_CHECK | T_SILENT; |
|
700 |
param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method; |
|
701 |
||
702 |
if (!(table->db_stat & HA_READ_ONLY)) |
|
703 |
param.testflag|= T_STATISTICS; |
|
704 |
param.using_global_keycache = 1; |
|
705 |
||
706 |
if (!mi_is_crashed(file) && |
|
707 |
(((param.testflag & T_CHECK_ONLY_CHANGED) && |
|
708 |
!(share->state.changed & (STATE_CHANGED | STATE_CRASHED | |
|
709 |
STATE_CRASHED_ON_REPAIR)) && |
|
710 |
share->state.open_count == 0) || |
|
711 |
((param.testflag & T_FAST) && (share->state.open_count == |
|
712 |
(uint) (share->global_changed ? 1 : 0))))) |
|
713 |
return HA_ADMIN_ALREADY_DONE; |
|
714 |
||
715 |
error = chk_status(¶m, file); // Not fatal |
|
716 |
error = chk_size(¶m, file); |
|
717 |
if (!error) |
|
718 |
error |= chk_del(¶m, file, param.testflag); |
|
719 |
if (!error) |
|
720 |
error = chk_key(¶m, file); |
|
721 |
if (!error) |
|
722 |
{
|
|
723 |
if ((!(param.testflag & T_QUICK) && |
|
724 |
((share->options & |
|
725 |
(HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) || |
|
726 |
(param.testflag & (T_EXTEND | T_MEDIUM)))) || |
|
727 |
mi_is_crashed(file)) |
|
728 |
{
|
|
729 |
uint old_testflag=param.testflag; |
|
730 |
param.testflag|=T_MEDIUM; |
|
731 |
if (!(error= init_io_cache(¶m.read_cache, file->dfile, |
|
732 |
my_default_record_cache_size, READ_CACHE, |
|
733 |
share->pack.header_length, 1, MYF(MY_WME)))) |
|
734 |
{
|
|
735 |
error= chk_data_link(¶m, file, param.testflag & T_EXTEND); |
|
736 |
end_io_cache(&(param.read_cache)); |
|
737 |
}
|
|
738 |
param.testflag= old_testflag; |
|
739 |
}
|
|
740 |
}
|
|
741 |
if (!error) |
|
742 |
{
|
|
743 |
if ((share->state.changed & (STATE_CHANGED | |
|
744 |
STATE_CRASHED_ON_REPAIR | |
|
745 |
STATE_CRASHED | STATE_NOT_ANALYZED)) || |
|
746 |
(param.testflag & T_STATISTICS) || |
|
747 |
mi_is_crashed(file)) |
|
748 |
{
|
|
749 |
file->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED; |
|
750 |
pthread_mutex_lock(&share->intern_lock); |
|
751 |
share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED | |
|
752 |
STATE_CRASHED_ON_REPAIR); |
|
753 |
if (!(table->db_stat & HA_READ_ONLY)) |
|
754 |
error=update_state_info(¶m,file,UPDATE_TIME | UPDATE_OPEN_COUNT | |
|
755 |
UPDATE_STAT); |
|
756 |
pthread_mutex_unlock(&share->intern_lock); |
|
757 |
info(HA_STATUS_NO_LOCK | HA_STATUS_TIME | HA_STATUS_VARIABLE | |
|
758 |
HA_STATUS_CONST); |
|
759 |
}
|
|
760 |
}
|
|
761 |
else if (!mi_is_crashed(file) && !thd->killed) |
|
762 |
{
|
|
763 |
mi_mark_crashed(file); |
|
764 |
file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED; |
|
765 |
}
|
|
766 |
||
767 |
thd_proc_info(thd, old_proc_info); |
|
768 |
return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK; |
|
769 |
}
|
|
770 |
||
771 |
||
772 |
/*
|
|
773 |
analyze the key distribution in the table
|
|
774 |
As the table may be only locked for read, we have to take into account that
|
|
775 |
two threads may do an analyze at the same time!
|
|
776 |
*/
|
|
777 |
||
77.1.9
by Monty Taylor
All of storage/ compiles clean now. |
778 |
int ha_myisam::analyze(THD *thd, |
779 |
HA_CHECK_OPT* check_opt __attribute__((__unused__))) |
|
1
by brian
clean slate |
780 |
{
|
781 |
int error=0; |
|
782 |
MI_CHECK param; |
|
783 |
MYISAM_SHARE* share = file->s; |
|
784 |
||
785 |
myisamchk_init(¶m); |
|
786 |
param.thd = thd; |
|
787 |
param.op_name= "analyze"; |
|
788 |
param.db_name= table->s->db.str; |
|
789 |
param.table_name= table->alias; |
|
790 |
param.testflag= (T_FAST | T_CHECK | T_SILENT | T_STATISTICS | |
|
791 |
T_DONT_CHECK_CHECKSUM); |
|
792 |
param.using_global_keycache = 1; |
|
793 |
param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method; |
|
794 |
||
795 |
if (!(share->state.changed & STATE_NOT_ANALYZED)) |
|
796 |
return HA_ADMIN_ALREADY_DONE; |
|
797 |
||
798 |
error = chk_key(¶m, file); |
|
799 |
if (!error) |
|
800 |
{
|
|
801 |
pthread_mutex_lock(&share->intern_lock); |
|
802 |
error=update_state_info(¶m,file,UPDATE_STAT); |
|
803 |
pthread_mutex_unlock(&share->intern_lock); |
|
804 |
}
|
|
805 |
else if (!mi_is_crashed(file) && !thd->killed) |
|
806 |
mi_mark_crashed(file); |
|
807 |
return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK; |
|
808 |
}
|
|
809 |
||
810 |
||
811 |
int ha_myisam::repair(THD* thd, HA_CHECK_OPT *check_opt) |
|
812 |
{
|
|
813 |
int error; |
|
814 |
MI_CHECK param; |
|
815 |
ha_rows start_records; |
|
816 |
||
817 |
if (!file) return HA_ADMIN_INTERNAL_ERROR; |
|
818 |
||
819 |
myisamchk_init(¶m); |
|
820 |
param.thd = thd; |
|
821 |
param.op_name= "repair"; |
|
822 |
param.testflag= ((check_opt->flags & ~(T_EXTEND)) | |
|
823 |
T_SILENT | T_FORCE_CREATE | T_CALC_CHECKSUM | |
|
824 |
(check_opt->flags & T_EXTEND ? T_REP : T_REP_BY_SORT)); |
|
825 |
param.sort_buffer_length= check_opt->sort_buffer_size; |
|
826 |
start_records=file->state->records; |
|
827 |
while ((error=repair(thd,param,0)) && param.retry_repair) |
|
828 |
{
|
|
829 |
param.retry_repair=0; |
|
830 |
if (test_all_bits(param.testflag, |
|
831 |
(uint) (T_RETRY_WITHOUT_QUICK | T_QUICK))) |
|
832 |
{
|
|
833 |
param.testflag&= ~T_RETRY_WITHOUT_QUICK; |
|
834 |
sql_print_information("Retrying repair of: '%s' without quick", |
|
835 |
table->s->path.str); |
|
836 |
continue; |
|
837 |
}
|
|
838 |
param.testflag&= ~T_QUICK; |
|
839 |
if ((param.testflag & T_REP_BY_SORT)) |
|
840 |
{
|
|
841 |
param.testflag= (param.testflag & ~T_REP_BY_SORT) | T_REP; |
|
842 |
sql_print_information("Retrying repair of: '%s' with keycache", |
|
843 |
table->s->path.str); |
|
844 |
continue; |
|
845 |
}
|
|
846 |
break; |
|
847 |
}
|
|
848 |
if (!error && start_records != file->state->records && |
|
849 |
!(check_opt->flags & T_VERY_SILENT)) |
|
850 |
{
|
|
851 |
char llbuff[22],llbuff2[22]; |
|
852 |
sql_print_information("Found %s of %s rows when repairing '%s'", |
|
853 |
llstr(file->state->records, llbuff), |
|
854 |
llstr(start_records, llbuff2), |
|
855 |
table->s->path.str); |
|
856 |
}
|
|
857 |
return error; |
|
858 |
}
|
|
859 |
||
860 |
int ha_myisam::optimize(THD* thd, HA_CHECK_OPT *check_opt) |
|
861 |
{
|
|
862 |
int error; |
|
863 |
if (!file) return HA_ADMIN_INTERNAL_ERROR; |
|
864 |
MI_CHECK param; |
|
865 |
||
866 |
myisamchk_init(¶m); |
|
867 |
param.thd = thd; |
|
868 |
param.op_name= "optimize"; |
|
869 |
param.testflag= (check_opt->flags | T_SILENT | T_FORCE_CREATE | |
|
870 |
T_REP_BY_SORT | T_STATISTICS | T_SORT_INDEX); |
|
871 |
param.sort_buffer_length= check_opt->sort_buffer_size; |
|
872 |
if ((error= repair(thd,param,1)) && param.retry_repair) |
|
873 |
{
|
|
874 |
sql_print_warning("Warning: Optimize table got errno %d on %s.%s, retrying", |
|
875 |
my_errno, param.db_name, param.table_name); |
|
876 |
param.testflag&= ~T_REP_BY_SORT; |
|
877 |
error= repair(thd,param,1); |
|
878 |
}
|
|
879 |
return error; |
|
880 |
}
|
|
881 |
||
882 |
||
883 |
int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool do_optimize) |
|
884 |
{
|
|
885 |
int error=0; |
|
886 |
uint local_testflag=param.testflag; |
|
887 |
bool optimize_done= !do_optimize, statistics_done=0; |
|
888 |
const char *old_proc_info=thd->proc_info; |
|
889 |
char fixed_name[FN_REFLEN]; |
|
890 |
MYISAM_SHARE* share = file->s; |
|
891 |
ha_rows rows= file->state->records; |
|
892 |
DBUG_ENTER("ha_myisam::repair"); |
|
893 |
||
894 |
/*
|
|
895 |
Normally this method is entered with a properly opened table. If the
|
|
896 |
repair fails, it can be repeated with more elaborate options. Under
|
|
897 |
special circumstances it can happen that a repair fails so that it
|
|
898 |
closed the data file and cannot re-open it. In this case file->dfile
|
|
899 |
is set to -1. We must not try another repair without an open data
|
|
900 |
file. (Bug #25289)
|
|
901 |
*/
|
|
902 |
if (file->dfile == -1) |
|
903 |
{
|
|
904 |
sql_print_information("Retrying repair of: '%s' failed. " |
|
905 |
"Please try REPAIR EXTENDED or myisamchk", |
|
906 |
table->s->path.str); |
|
907 |
DBUG_RETURN(HA_ADMIN_FAILED); |
|
908 |
}
|
|
909 |
||
910 |
param.db_name= table->s->db.str; |
|
911 |
param.table_name= table->alias; |
|
912 |
param.tmpfile_createflag = O_RDWR | O_TRUNC; |
|
913 |
param.using_global_keycache = 1; |
|
914 |
param.thd= thd; |
|
915 |
param.tmpdir= &mysql_tmpdir_list; |
|
916 |
param.out_flag= 0; |
|
917 |
strmov(fixed_name,file->filename); |
|
918 |
||
919 |
// Don't lock tables if we have used LOCK TABLE
|
|
920 |
if (!thd->locked_tables && |
|
921 |
mi_lock_database(file, table->s->tmp_table ? F_EXTRA_LCK : F_WRLCK)) |
|
922 |
{
|
|
923 |
mi_check_print_error(¶m,ER(ER_CANT_LOCK),my_errno); |
|
924 |
DBUG_RETURN(HA_ADMIN_FAILED); |
|
925 |
}
|
|
926 |
||
927 |
if (!do_optimize || |
|
928 |
((file->state->del || share->state.split != file->state->records) && |
|
929 |
(!(param.testflag & T_QUICK) || |
|
930 |
!(share->state.changed & STATE_NOT_OPTIMIZED_KEYS)))) |
|
931 |
{
|
|
932 |
uint64_t key_map= ((local_testflag & T_CREATE_MISSING_KEYS) ? |
|
933 |
mi_get_mask_all_keys_active(share->base.keys) : |
|
934 |
share->state.key_map); |
|
935 |
uint testflag=param.testflag; |
|
936 |
if (mi_test_if_sort_rep(file,file->state->records,key_map,0) && |
|
937 |
(local_testflag & T_REP_BY_SORT)) |
|
938 |
{
|
|
939 |
local_testflag|= T_STATISTICS; |
|
940 |
param.testflag|= T_STATISTICS; // We get this for free |
|
941 |
statistics_done=1; |
|
942 |
if (thd->variables.myisam_repair_threads>1) |
|
943 |
{
|
|
944 |
char buf[40]; |
|
945 |
/* TODO: respect myisam_repair_threads variable */
|
|
77.1.18
by Monty Taylor
Removed my_vsnprintf and my_snprintf. |
946 |
snprintf(buf, 40, "Repair with %d threads", my_count_bits(key_map)); |
1
by brian
clean slate |
947 |
thd_proc_info(thd, buf); |
948 |
error = mi_repair_parallel(¶m, file, fixed_name, |
|
949 |
param.testflag & T_QUICK); |
|
950 |
thd_proc_info(thd, "Repair done"); // to reset proc_info, as |
|
951 |
// it was pointing to local buffer
|
|
952 |
}
|
|
953 |
else
|
|
954 |
{
|
|
955 |
thd_proc_info(thd, "Repair by sorting"); |
|
956 |
error = mi_repair_by_sort(¶m, file, fixed_name, |
|
957 |
param.testflag & T_QUICK); |
|
958 |
}
|
|
959 |
}
|
|
960 |
else
|
|
961 |
{
|
|
962 |
thd_proc_info(thd, "Repair with keycache"); |
|
963 |
param.testflag &= ~T_REP_BY_SORT; |
|
964 |
error= mi_repair(¶m, file, fixed_name, |
|
965 |
param.testflag & T_QUICK); |
|
966 |
}
|
|
967 |
param.testflag=testflag; |
|
968 |
optimize_done=1; |
|
969 |
}
|
|
970 |
if (!error) |
|
971 |
{
|
|
972 |
if ((local_testflag & T_SORT_INDEX) && |
|
973 |
(share->state.changed & STATE_NOT_SORTED_PAGES)) |
|
974 |
{
|
|
975 |
optimize_done=1; |
|
976 |
thd_proc_info(thd, "Sorting index"); |
|
977 |
error=mi_sort_index(¶m,file,fixed_name); |
|
978 |
}
|
|
979 |
if (!statistics_done && (local_testflag & T_STATISTICS)) |
|
980 |
{
|
|
981 |
if (share->state.changed & STATE_NOT_ANALYZED) |
|
982 |
{
|
|
983 |
optimize_done=1; |
|
984 |
thd_proc_info(thd, "Analyzing"); |
|
985 |
error = chk_key(¶m, file); |
|
986 |
}
|
|
987 |
else
|
|
988 |
local_testflag&= ~T_STATISTICS; // Don't update statistics |
|
989 |
}
|
|
990 |
}
|
|
991 |
thd_proc_info(thd, "Saving state"); |
|
992 |
if (!error) |
|
993 |
{
|
|
994 |
if ((share->state.changed & STATE_CHANGED) || mi_is_crashed(file)) |
|
995 |
{
|
|
996 |
share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED | |
|
997 |
STATE_CRASHED_ON_REPAIR); |
|
998 |
file->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED; |
|
999 |
}
|
|
1000 |
/*
|
|
1001 |
the following 'if', thought conceptually wrong,
|
|
1002 |
is a useful optimization nevertheless.
|
|
1003 |
*/
|
|
1004 |
if (file->state != &file->s->state.state) |
|
1005 |
file->s->state.state = *file->state; |
|
1006 |
if (file->s->base.auto_key) |
|
1007 |
update_auto_increment_key(¶m, file, 1); |
|
1008 |
if (optimize_done) |
|
1009 |
error = update_state_info(¶m, file, |
|
1010 |
UPDATE_TIME | UPDATE_OPEN_COUNT | |
|
1011 |
(local_testflag & |
|
1012 |
T_STATISTICS ? UPDATE_STAT : 0)); |
|
1013 |
info(HA_STATUS_NO_LOCK | HA_STATUS_TIME | HA_STATUS_VARIABLE | |
|
1014 |
HA_STATUS_CONST); |
|
1015 |
if (rows != file->state->records && ! (param.testflag & T_VERY_SILENT)) |
|
1016 |
{
|
|
1017 |
char llbuff[22],llbuff2[22]; |
|
1018 |
mi_check_print_warning(¶m,"Number of rows changed from %s to %s", |
|
1019 |
llstr(rows,llbuff), |
|
1020 |
llstr(file->state->records,llbuff2)); |
|
1021 |
}
|
|
1022 |
}
|
|
1023 |
else
|
|
1024 |
{
|
|
1025 |
mi_mark_crashed_on_repair(file); |
|
1026 |
file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED; |
|
1027 |
update_state_info(¶m, file, 0); |
|
1028 |
}
|
|
1029 |
thd_proc_info(thd, old_proc_info); |
|
1030 |
if (!thd->locked_tables) |
|
1031 |
mi_lock_database(file,F_UNLCK); |
|
1032 |
DBUG_RETURN(error ? HA_ADMIN_FAILED : |
|
1033 |
!optimize_done ? HA_ADMIN_ALREADY_DONE : HA_ADMIN_OK); |
|
1034 |
}
|
|
1035 |
||
1036 |
||
1037 |
/*
|
|
1038 |
Assign table indexes to a specific key cache.
|
|
1039 |
*/
|
|
1040 |
||
1041 |
int ha_myisam::assign_to_keycache(THD* thd, HA_CHECK_OPT *check_opt) |
|
1042 |
{
|
|
1043 |
KEY_CACHE *new_key_cache= check_opt->key_cache; |
|
1044 |
const char *errmsg= 0; |
|
1045 |
int error= HA_ADMIN_OK; |
|
1046 |
uint64_t map; |
|
1047 |
TABLE_LIST *table_list= table->pos_in_table_list; |
|
1048 |
DBUG_ENTER("ha_myisam::assign_to_keycache"); |
|
1049 |
||
1050 |
table->keys_in_use_for_query.clear_all(); |
|
1051 |
||
1052 |
if (table_list->process_index_hints(table)) |
|
1053 |
DBUG_RETURN(HA_ADMIN_FAILED); |
|
1054 |
map= ~(uint64_t) 0; |
|
1055 |
if (!table->keys_in_use_for_query.is_clear_all()) |
|
1056 |
/* use all keys if there's no list specified by the user through hints */
|
|
1057 |
map= table->keys_in_use_for_query.to_ulonglong(); |
|
1058 |
||
1059 |
if ((error= mi_assign_to_key_cache(file, map, new_key_cache))) |
|
1060 |
{
|
|
1061 |
char buf[STRING_BUFFER_USUAL_SIZE]; |
|
77.1.18
by Monty Taylor
Removed my_vsnprintf and my_snprintf. |
1062 |
snprintf(buf, sizeof(buf), |
1
by brian
clean slate |
1063 |
"Failed to flush to index file (errno: %d)", error); |
1064 |
errmsg= buf; |
|
1065 |
error= HA_ADMIN_CORRUPT; |
|
1066 |
}
|
|
1067 |
||
1068 |
if (error != HA_ADMIN_OK) |
|
1069 |
{
|
|
1070 |
/* Send error to user */
|
|
1071 |
MI_CHECK param; |
|
1072 |
myisamchk_init(¶m); |
|
1073 |
param.thd= thd; |
|
1074 |
param.op_name= "assign_to_keycache"; |
|
1075 |
param.db_name= table->s->db.str; |
|
1076 |
param.table_name= table->s->table_name.str; |
|
1077 |
param.testflag= 0; |
|
1078 |
mi_check_print_error(¶m, errmsg); |
|
1079 |
}
|
|
1080 |
DBUG_RETURN(error); |
|
1081 |
}
|
|
1082 |
||
1083 |
||
1084 |
/*
|
|
1085 |
Disable indexes, making it persistent if requested.
|
|
1086 |
||
1087 |
SYNOPSIS
|
|
1088 |
disable_indexes()
|
|
1089 |
mode mode of operation:
|
|
1090 |
HA_KEY_SWITCH_NONUNIQ disable all non-unique keys
|
|
1091 |
HA_KEY_SWITCH_ALL disable all keys
|
|
1092 |
HA_KEY_SWITCH_NONUNIQ_SAVE dis. non-uni. and make persistent
|
|
1093 |
HA_KEY_SWITCH_ALL_SAVE dis. all keys and make persistent
|
|
1094 |
||
1095 |
IMPLEMENTATION
|
|
1096 |
HA_KEY_SWITCH_NONUNIQ is not implemented.
|
|
1097 |
HA_KEY_SWITCH_ALL_SAVE is not implemented.
|
|
1098 |
||
1099 |
RETURN
|
|
1100 |
0 ok
|
|
1101 |
HA_ERR_WRONG_COMMAND mode not implemented.
|
|
1102 |
*/
|
|
1103 |
||
1104 |
int ha_myisam::disable_indexes(uint mode) |
|
1105 |
{
|
|
1106 |
int error; |
|
1107 |
||
1108 |
if (mode == HA_KEY_SWITCH_ALL) |
|
1109 |
{
|
|
1110 |
/* call a storage engine function to switch the key map */
|
|
1111 |
error= mi_disable_indexes(file); |
|
1112 |
}
|
|
1113 |
else if (mode == HA_KEY_SWITCH_NONUNIQ_SAVE) |
|
1114 |
{
|
|
1115 |
mi_extra(file, HA_EXTRA_NO_KEYS, 0); |
|
1116 |
info(HA_STATUS_CONST); // Read new key info |
|
1117 |
error= 0; |
|
1118 |
}
|
|
1119 |
else
|
|
1120 |
{
|
|
1121 |
/* mode not implemented */
|
|
1122 |
error= HA_ERR_WRONG_COMMAND; |
|
1123 |
}
|
|
1124 |
return error; |
|
1125 |
}
|
|
1126 |
||
1127 |
||
1128 |
/*
|
|
1129 |
Enable indexes, making it persistent if requested.
|
|
1130 |
||
1131 |
SYNOPSIS
|
|
1132 |
enable_indexes()
|
|
1133 |
mode mode of operation:
|
|
1134 |
HA_KEY_SWITCH_NONUNIQ enable all non-unique keys
|
|
1135 |
HA_KEY_SWITCH_ALL enable all keys
|
|
1136 |
HA_KEY_SWITCH_NONUNIQ_SAVE en. non-uni. and make persistent
|
|
1137 |
HA_KEY_SWITCH_ALL_SAVE en. all keys and make persistent
|
|
1138 |
||
1139 |
DESCRIPTION
|
|
1140 |
Enable indexes, which might have been disabled by disable_index() before.
|
|
1141 |
The modes without _SAVE work only if both data and indexes are empty,
|
|
1142 |
since the MyISAM repair would enable them persistently.
|
|
1143 |
To be sure in these cases, call handler::delete_all_rows() before.
|
|
1144 |
||
1145 |
IMPLEMENTATION
|
|
1146 |
HA_KEY_SWITCH_NONUNIQ is not implemented.
|
|
1147 |
HA_KEY_SWITCH_ALL_SAVE is not implemented.
|
|
1148 |
||
1149 |
RETURN
|
|
1150 |
0 ok
|
|
1151 |
!=0 Error, among others:
|
|
1152 |
HA_ERR_CRASHED data or index is non-empty. Delete all rows and retry.
|
|
1153 |
HA_ERR_WRONG_COMMAND mode not implemented.
|
|
1154 |
*/
|
|
1155 |
||
1156 |
int ha_myisam::enable_indexes(uint mode) |
|
1157 |
{
|
|
1158 |
int error; |
|
1159 |
||
1160 |
if (mi_is_all_keys_active(file->s->state.key_map, file->s->base.keys)) |
|
1161 |
{
|
|
1162 |
/* All indexes are enabled already. */
|
|
1163 |
return 0; |
|
1164 |
}
|
|
1165 |
||
1166 |
if (mode == HA_KEY_SWITCH_ALL) |
|
1167 |
{
|
|
1168 |
error= mi_enable_indexes(file); |
|
1169 |
/*
|
|
1170 |
Do not try to repair on error,
|
|
1171 |
as this could make the enabled state persistent,
|
|
1172 |
but mode==HA_KEY_SWITCH_ALL forbids it.
|
|
1173 |
*/
|
|
1174 |
}
|
|
1175 |
else if (mode == HA_KEY_SWITCH_NONUNIQ_SAVE) |
|
1176 |
{
|
|
1177 |
THD *thd=current_thd; |
|
1178 |
MI_CHECK param; |
|
1179 |
const char *save_proc_info=thd->proc_info; |
|
1180 |
thd_proc_info(thd, "Creating index"); |
|
1181 |
myisamchk_init(¶m); |
|
1182 |
param.op_name= "recreating_index"; |
|
1183 |
param.testflag= (T_SILENT | T_REP_BY_SORT | T_QUICK | |
|
1184 |
T_CREATE_MISSING_KEYS); |
|
1185 |
param.myf_rw&= ~MY_WAIT_IF_FULL; |
|
1186 |
param.sort_buffer_length= thd->variables.myisam_sort_buff_size; |
|
1187 |
param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method; |
|
1188 |
param.tmpdir=&mysql_tmpdir_list; |
|
1189 |
if ((error= (repair(thd,param,0) != HA_ADMIN_OK)) && param.retry_repair) |
|
1190 |
{
|
|
1191 |
sql_print_warning("Warning: Enabling keys got errno %d on %s.%s, retrying", |
|
1192 |
my_errno, param.db_name, param.table_name); |
|
1193 |
/* Repairing by sort failed. Now try standard repair method. */
|
|
1194 |
param.testflag&= ~(T_REP_BY_SORT | T_QUICK); |
|
1195 |
error= (repair(thd,param,0) != HA_ADMIN_OK); |
|
1196 |
/*
|
|
1197 |
If the standard repair succeeded, clear all error messages which
|
|
1198 |
might have been set by the first repair. They can still be seen
|
|
1199 |
with SHOW WARNINGS then.
|
|
1200 |
*/
|
|
1201 |
if (! error) |
|
1202 |
thd->clear_error(); |
|
1203 |
}
|
|
1204 |
info(HA_STATUS_CONST); |
|
1205 |
thd_proc_info(thd, save_proc_info); |
|
1206 |
}
|
|
1207 |
else
|
|
1208 |
{
|
|
1209 |
/* mode not implemented */
|
|
1210 |
error= HA_ERR_WRONG_COMMAND; |
|
1211 |
}
|
|
1212 |
return error; |
|
1213 |
}
|
|
1214 |
||
1215 |
||
1216 |
/*
|
|
1217 |
Test if indexes are disabled.
|
|
1218 |
||
1219 |
||
1220 |
SYNOPSIS
|
|
1221 |
indexes_are_disabled()
|
|
1222 |
no parameters
|
|
1223 |
||
1224 |
||
1225 |
RETURN
|
|
1226 |
0 indexes are not disabled
|
|
1227 |
1 all indexes are disabled
|
|
1228 |
[2 non-unique indexes are disabled - NOT YET IMPLEMENTED]
|
|
1229 |
*/
|
|
1230 |
||
1231 |
int ha_myisam::indexes_are_disabled(void) |
|
1232 |
{
|
|
1233 |
||
1234 |
return mi_indexes_are_disabled(file); |
|
1235 |
}
|
|
1236 |
||
1237 |
||
1238 |
/*
|
|
1239 |
prepare for a many-rows insert operation
|
|
1240 |
e.g. - disable indexes (if they can be recreated fast) or
|
|
1241 |
activate special bulk-insert optimizations
|
|
1242 |
||
1243 |
SYNOPSIS
|
|
1244 |
start_bulk_insert(rows)
|
|
1245 |
rows Rows to be inserted
|
|
1246 |
0 if we don't know
|
|
1247 |
||
1248 |
NOTICE
|
|
1249 |
Do not forget to call end_bulk_insert() later!
|
|
1250 |
*/
|
|
1251 |
||
1252 |
void ha_myisam::start_bulk_insert(ha_rows rows) |
|
1253 |
{
|
|
1254 |
DBUG_ENTER("ha_myisam::start_bulk_insert"); |
|
1255 |
THD *thd= current_thd; |
|
1256 |
ulong size= min(thd->variables.read_buff_size, |
|
1257 |
(ulong) (table->s->avg_row_length*rows)); |
|
1258 |
DBUG_PRINT("info",("start_bulk_insert: rows %lu size %lu", |
|
1259 |
(ulong) rows, size)); |
|
1260 |
||
1261 |
/* don't enable row cache if too few rows */
|
|
1262 |
if (! rows || (rows > MI_MIN_ROWS_TO_USE_WRITE_CACHE)) |
|
1263 |
mi_extra(file, HA_EXTRA_WRITE_CACHE, (void*) &size); |
|
1264 |
||
1265 |
can_enable_indexes= mi_is_all_keys_active(file->s->state.key_map, |
|
1266 |
file->s->base.keys); |
|
1267 |
||
1268 |
if (!(specialflag & SPECIAL_SAFE_MODE)) |
|
1269 |
{
|
|
1270 |
/*
|
|
1271 |
Only disable old index if the table was empty and we are inserting
|
|
1272 |
a lot of rows.
|
|
1273 |
We should not do this for only a few rows as this is slower and
|
|
1274 |
we don't want to update the key statistics based of only a few rows.
|
|
1275 |
*/
|
|
1276 |
if (file->state->records == 0 && can_enable_indexes && |
|
1277 |
(!rows || rows >= MI_MIN_ROWS_TO_DISABLE_INDEXES)) |
|
1278 |
mi_disable_non_unique_index(file,rows); |
|
1279 |
else
|
|
1280 |
if (!file->bulk_insert && |
|
1281 |
(!rows || rows >= MI_MIN_ROWS_TO_USE_BULK_INSERT)) |
|
1282 |
{
|
|
1283 |
mi_init_bulk_insert(file, thd->variables.bulk_insert_buff_size, rows); |
|
1284 |
}
|
|
1285 |
}
|
|
1286 |
DBUG_VOID_RETURN; |
|
1287 |
}
|
|
1288 |
||
1289 |
/*
|
|
1290 |
end special bulk-insert optimizations,
|
|
1291 |
which have been activated by start_bulk_insert().
|
|
1292 |
||
1293 |
SYNOPSIS
|
|
1294 |
end_bulk_insert()
|
|
1295 |
no arguments
|
|
1296 |
||
1297 |
RETURN
|
|
1298 |
0 OK
|
|
1299 |
!= 0 Error
|
|
1300 |
*/
|
|
1301 |
||
1302 |
int ha_myisam::end_bulk_insert() |
|
1303 |
{
|
|
1304 |
mi_end_bulk_insert(file); |
|
1305 |
int err=mi_extra(file, HA_EXTRA_NO_CACHE, 0); |
|
1306 |
return err ? err : can_enable_indexes ? |
|
1307 |
enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE) : 0; |
|
1308 |
}
|
|
1309 |
||
1310 |
||
1311 |
bool ha_myisam::check_and_repair(THD *thd) |
|
1312 |
{
|
|
1313 |
int error=0; |
|
1314 |
int marked_crashed; |
|
1315 |
char *old_query; |
|
1316 |
uint old_query_length; |
|
1317 |
HA_CHECK_OPT check_opt; |
|
1318 |
DBUG_ENTER("ha_myisam::check_and_repair"); |
|
1319 |
||
1320 |
check_opt.init(); |
|
1321 |
check_opt.flags= T_MEDIUM | T_AUTO_REPAIR; |
|
1322 |
// Don't use quick if deleted rows
|
|
1323 |
if (!file->state->del && (myisam_recover_options & HA_RECOVER_QUICK)) |
|
1324 |
check_opt.flags|=T_QUICK; |
|
1325 |
sql_print_warning("Checking table: '%s'",table->s->path.str); |
|
1326 |
||
1327 |
old_query= thd->query; |
|
1328 |
old_query_length= thd->query_length; |
|
1329 |
pthread_mutex_lock(&LOCK_thread_count); |
|
1330 |
thd->query= table->s->table_name.str; |
|
1331 |
thd->query_length= table->s->table_name.length; |
|
1332 |
pthread_mutex_unlock(&LOCK_thread_count); |
|
1333 |
||
1334 |
if ((marked_crashed= mi_is_crashed(file)) || check(thd, &check_opt)) |
|
1335 |
{
|
|
1336 |
sql_print_warning("Recovering table: '%s'",table->s->path.str); |
|
1337 |
check_opt.flags= |
|
1338 |
((myisam_recover_options & HA_RECOVER_BACKUP ? T_BACKUP_DATA : 0) | |
|
1339 |
(marked_crashed ? 0 : T_QUICK) | |
|
1340 |
(myisam_recover_options & HA_RECOVER_FORCE ? 0 : T_SAFE_REPAIR) | |
|
1341 |
T_AUTO_REPAIR); |
|
1342 |
if (repair(thd, &check_opt)) |
|
1343 |
error=1; |
|
1344 |
}
|
|
1345 |
pthread_mutex_lock(&LOCK_thread_count); |
|
1346 |
thd->query= old_query; |
|
1347 |
thd->query_length= old_query_length; |
|
1348 |
pthread_mutex_unlock(&LOCK_thread_count); |
|
1349 |
DBUG_RETURN(error); |
|
1350 |
}
|
|
1351 |
||
1352 |
bool ha_myisam::is_crashed() const |
|
1353 |
{
|
|
1354 |
return (file->s->state.changed & STATE_CRASHED || |
|
1355 |
(my_disable_locking && file->s->state.open_count)); |
|
1356 |
}
|
|
1357 |
||
1358 |
int ha_myisam::update_row(const uchar *old_data, uchar *new_data) |
|
1359 |
{
|
|
1360 |
ha_statistic_increment(&SSV::ha_update_count); |
|
1361 |
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE) |
|
1362 |
table->timestamp_field->set_time(); |
|
1363 |
return mi_update(file,old_data,new_data); |
|
1364 |
}
|
|
1365 |
||
1366 |
int ha_myisam::delete_row(const uchar *buf) |
|
1367 |
{
|
|
1368 |
ha_statistic_increment(&SSV::ha_delete_count); |
|
1369 |
return mi_delete(file,buf); |
|
1370 |
}
|
|
1371 |
||
1372 |
C_MODE_START
|
|
1373 |
||
1374 |
my_bool index_cond_func_myisam(void *arg) |
|
1375 |
{
|
|
1376 |
ha_myisam *h= (ha_myisam*)arg; |
|
1377 |
/*if (h->in_range_read)*/
|
|
1378 |
if (h->end_range) |
|
1379 |
{
|
|
1380 |
if (h->compare_key2(h->end_range) > 0) |
|
1381 |
return 2; /* caller should return HA_ERR_END_OF_FILE already */ |
|
1382 |
}
|
|
1383 |
return (my_bool)h->pushed_idx_cond->val_int(); |
|
1384 |
}
|
|
1385 |
||
1386 |
C_MODE_END
|
|
1387 |
||
1388 |
||
77.1.9
by Monty Taylor
All of storage/ compiles clean now. |
1389 |
int ha_myisam::index_init(uint idx, bool sorted __attribute__((__unused__))) |
1
by brian
clean slate |
1390 |
{
|
1391 |
active_index=idx; |
|
1392 |
//in_range_read= FALSE;
|
|
1393 |
if (pushed_idx_cond_keyno == idx) |
|
1394 |
mi_set_index_cond_func(file, index_cond_func_myisam, this); |
|
1395 |
return 0; |
|
1396 |
}
|
|
1397 |
||
1398 |
||
1399 |
int ha_myisam::index_end() |
|
1400 |
{
|
|
1401 |
active_index=MAX_KEY; |
|
1402 |
//pushed_idx_cond_keyno= MAX_KEY;
|
|
1403 |
mi_set_index_cond_func(file, NULL, 0); |
|
1404 |
in_range_check_pushed_down= FALSE; |
|
1405 |
ds_mrr.dsmrr_close(); |
|
1406 |
return 0; |
|
1407 |
}
|
|
1408 |
||
1409 |
||
1410 |
int ha_myisam::index_read_map(uchar *buf, const uchar *key, |
|
1411 |
key_part_map keypart_map, |
|
1412 |
enum ha_rkey_function find_flag) |
|
1413 |
{
|
|
1414 |
DBUG_ASSERT(inited==INDEX); |
|
1415 |
ha_statistic_increment(&SSV::ha_read_key_count); |
|
1416 |
int error=mi_rkey(file, buf, active_index, key, keypart_map, find_flag); |
|
1417 |
table->status=error ? STATUS_NOT_FOUND: 0; |
|
1418 |
return error; |
|
1419 |
}
|
|
1420 |
||
1421 |
int ha_myisam::index_read_idx_map(uchar *buf, uint index, const uchar *key, |
|
1422 |
key_part_map keypart_map, |
|
1423 |
enum ha_rkey_function find_flag) |
|
1424 |
{
|
|
1425 |
ha_statistic_increment(&SSV::ha_read_key_count); |
|
1426 |
int error=mi_rkey(file, buf, index, key, keypart_map, find_flag); |
|
1427 |
table->status=error ? STATUS_NOT_FOUND: 0; |
|
1428 |
return error; |
|
1429 |
}
|
|
1430 |
||
1431 |
int ha_myisam::index_read_last_map(uchar *buf, const uchar *key, |
|
1432 |
key_part_map keypart_map) |
|
1433 |
{
|
|
1434 |
DBUG_ENTER("ha_myisam::index_read_last"); |
|
1435 |
DBUG_ASSERT(inited==INDEX); |
|
1436 |
ha_statistic_increment(&SSV::ha_read_key_count); |
|
1437 |
int error=mi_rkey(file, buf, active_index, key, keypart_map, |
|
1438 |
HA_READ_PREFIX_LAST); |
|
1439 |
table->status=error ? STATUS_NOT_FOUND: 0; |
|
1440 |
DBUG_RETURN(error); |
|
1441 |
}
|
|
1442 |
||
1443 |
int ha_myisam::index_next(uchar *buf) |
|
1444 |
{
|
|
1445 |
DBUG_ASSERT(inited==INDEX); |
|
1446 |
ha_statistic_increment(&SSV::ha_read_next_count); |
|
1447 |
int error=mi_rnext(file,buf,active_index); |
|
1448 |
table->status=error ? STATUS_NOT_FOUND: 0; |
|
1449 |
return error; |
|
1450 |
}
|
|
1451 |
||
1452 |
int ha_myisam::index_prev(uchar *buf) |
|
1453 |
{
|
|
1454 |
DBUG_ASSERT(inited==INDEX); |
|
1455 |
ha_statistic_increment(&SSV::ha_read_prev_count); |
|
1456 |
int error=mi_rprev(file,buf, active_index); |
|
1457 |
table->status=error ? STATUS_NOT_FOUND: 0; |
|
1458 |
return error; |
|
1459 |
}
|
|
1460 |
||
1461 |
int ha_myisam::index_first(uchar *buf) |
|
1462 |
{
|
|
1463 |
DBUG_ASSERT(inited==INDEX); |
|
1464 |
ha_statistic_increment(&SSV::ha_read_first_count); |
|
1465 |
int error=mi_rfirst(file, buf, active_index); |
|
1466 |
table->status=error ? STATUS_NOT_FOUND: 0; |
|
1467 |
return error; |
|
1468 |
}
|
|
1469 |
||
1470 |
int ha_myisam::index_last(uchar *buf) |
|
1471 |
{
|
|
1472 |
DBUG_ASSERT(inited==INDEX); |
|
1473 |
ha_statistic_increment(&SSV::ha_read_last_count); |
|
1474 |
int error=mi_rlast(file, buf, active_index); |
|
1475 |
table->status=error ? STATUS_NOT_FOUND: 0; |
|
1476 |
return error; |
|
1477 |
}
|
|
1478 |
||
1479 |
int ha_myisam::index_next_same(uchar *buf, |
|
1480 |
const uchar *key __attribute__((unused)), |
|
1481 |
uint length __attribute__((unused))) |
|
1482 |
{
|
|
1483 |
int error; |
|
1484 |
DBUG_ASSERT(inited==INDEX); |
|
1485 |
ha_statistic_increment(&SSV::ha_read_next_count); |
|
1486 |
do
|
|
1487 |
{
|
|
1488 |
error= mi_rnext_same(file,buf); |
|
1489 |
} while (error == HA_ERR_RECORD_DELETED); |
|
1490 |
table->status=error ? STATUS_NOT_FOUND: 0; |
|
1491 |
return error; |
|
1492 |
}
|
|
1493 |
||
1494 |
int ha_myisam::read_range_first(const key_range *start_key, |
|
1495 |
const key_range *end_key, |
|
1496 |
bool eq_range_arg, |
|
1497 |
bool sorted /* ignored */) |
|
1498 |
{
|
|
1499 |
int res; |
|
1500 |
//if (!eq_range_arg)
|
|
1501 |
// in_range_read= TRUE;
|
|
1502 |
||
1503 |
res= handler::read_range_first(start_key, end_key, eq_range_arg, sorted); |
|
1504 |
||
1505 |
//if (res)
|
|
1506 |
// in_range_read= FALSE;
|
|
1507 |
return res; |
|
1508 |
}
|
|
1509 |
||
1510 |
||
1511 |
int ha_myisam::read_range_next() |
|
1512 |
{
|
|
1513 |
int res= handler::read_range_next(); |
|
1514 |
//if (res)
|
|
1515 |
// in_range_read= FALSE;
|
|
1516 |
return res; |
|
1517 |
}
|
|
1518 |
||
1519 |
||
1520 |
int ha_myisam::rnd_init(bool scan) |
|
1521 |
{
|
|
1522 |
if (scan) |
|
1523 |
return mi_scan_init(file); |
|
1524 |
return mi_reset(file); // Free buffers |
|
1525 |
}
|
|
1526 |
||
1527 |
int ha_myisam::rnd_next(uchar *buf) |
|
1528 |
{
|
|
1529 |
ha_statistic_increment(&SSV::ha_read_rnd_next_count); |
|
1530 |
int error=mi_scan(file, buf); |
|
1531 |
table->status=error ? STATUS_NOT_FOUND: 0; |
|
1532 |
return error; |
|
1533 |
}
|
|
1534 |
||
1535 |
int ha_myisam::restart_rnd_next(uchar *buf, uchar *pos) |
|
1536 |
{
|
|
1537 |
return rnd_pos(buf,pos); |
|
1538 |
}
|
|
1539 |
||
1540 |
int ha_myisam::rnd_pos(uchar *buf, uchar *pos) |
|
1541 |
{
|
|
1542 |
ha_statistic_increment(&SSV::ha_read_rnd_count); |
|
1543 |
int error=mi_rrnd(file, buf, my_get_ptr(pos,ref_length)); |
|
1544 |
table->status=error ? STATUS_NOT_FOUND: 0; |
|
1545 |
return error; |
|
1546 |
}
|
|
1547 |
||
1548 |
||
77.1.9
by Monty Taylor
All of storage/ compiles clean now. |
1549 |
void ha_myisam::position(const uchar *record __attribute__((__unused__))) |
1
by brian
clean slate |
1550 |
{
|
1551 |
my_off_t row_position= mi_position(file); |
|
1552 |
my_store_ptr(ref, ref_length, row_position); |
|
1553 |
}
|
|
1554 |
||
1555 |
int ha_myisam::info(uint flag) |
|
1556 |
{
|
|
1557 |
MI_ISAMINFO misam_info; |
|
1558 |
char name_buff[FN_REFLEN]; |
|
1559 |
||
1560 |
(void) mi_status(file,&misam_info,flag); |
|
1561 |
if (flag & HA_STATUS_VARIABLE) |
|
1562 |
{
|
|
1563 |
stats.records= misam_info.records; |
|
1564 |
stats.deleted= misam_info.deleted; |
|
1565 |
stats.data_file_length= misam_info.data_file_length; |
|
1566 |
stats.index_file_length= misam_info.index_file_length; |
|
1567 |
stats.delete_length= misam_info.delete_length; |
|
1568 |
stats.check_time= misam_info.check_time; |
|
1569 |
stats.mean_rec_length= misam_info.mean_reclength; |
|
1570 |
}
|
|
1571 |
if (flag & HA_STATUS_CONST) |
|
1572 |
{
|
|
1573 |
TABLE_SHARE *share= table->s; |
|
1574 |
stats.max_data_file_length= misam_info.max_data_file_length; |
|
1575 |
stats.max_index_file_length= misam_info.max_index_file_length; |
|
1576 |
stats.create_time= misam_info.create_time; |
|
1577 |
ref_length= misam_info.reflength; |
|
1578 |
share->db_options_in_use= misam_info.options; |
|
1579 |
stats.block_size= myisam_block_size; /* record block size */ |
|
1580 |
||
1581 |
/* Update share */
|
|
1582 |
if (share->tmp_table == NO_TMP_TABLE) |
|
1583 |
pthread_mutex_lock(&share->mutex); |
|
1584 |
share->keys_in_use.set_prefix(share->keys); |
|
1585 |
share->keys_in_use.intersect_extended(misam_info.key_map); |
|
1586 |
share->keys_for_keyread.intersect(share->keys_in_use); |
|
1587 |
share->db_record_offset= misam_info.record_offset; |
|
1588 |
if (share->key_parts) |
|
1589 |
memcpy((char*) table->key_info[0].rec_per_key, |
|
1590 |
(char*) misam_info.rec_per_key, |
|
1591 |
sizeof(table->key_info[0].rec_per_key)*share->key_parts); |
|
1592 |
if (share->tmp_table == NO_TMP_TABLE) |
|
1593 |
pthread_mutex_unlock(&share->mutex); |
|
1594 |
||
1595 |
/*
|
|
1596 |
Set data_file_name and index_file_name to point at the symlink value
|
|
1597 |
if table is symlinked (Ie; Real name is not same as generated name)
|
|
1598 |
*/
|
|
1599 |
data_file_name= index_file_name= 0; |
|
1600 |
fn_format(name_buff, file->filename, "", MI_NAME_DEXT, |
|
1601 |
MY_APPEND_EXT | MY_UNPACK_FILENAME); |
|
1602 |
if (strcmp(name_buff, misam_info.data_file_name)) |
|
1603 |
data_file_name=misam_info.data_file_name; |
|
1604 |
fn_format(name_buff, file->filename, "", MI_NAME_IEXT, |
|
1605 |
MY_APPEND_EXT | MY_UNPACK_FILENAME); |
|
1606 |
if (strcmp(name_buff, misam_info.index_file_name)) |
|
1607 |
index_file_name=misam_info.index_file_name; |
|
1608 |
}
|
|
1609 |
if (flag & HA_STATUS_ERRKEY) |
|
1610 |
{
|
|
1611 |
errkey = misam_info.errkey; |
|
1612 |
my_store_ptr(dup_ref, ref_length, misam_info.dupp_key_pos); |
|
1613 |
}
|
|
1614 |
if (flag & HA_STATUS_TIME) |
|
1615 |
stats.update_time = misam_info.update_time; |
|
1616 |
if (flag & HA_STATUS_AUTO) |
|
1617 |
stats.auto_increment_value= misam_info.auto_increment; |
|
1618 |
||
1619 |
return 0; |
|
1620 |
}
|
|
1621 |
||
1622 |
||
1623 |
int ha_myisam::extra(enum ha_extra_function operation) |
|
1624 |
{
|
|
1625 |
if ((specialflag & SPECIAL_SAFE_MODE) && operation == HA_EXTRA_KEYREAD) |
|
1626 |
return 0; |
|
1627 |
return mi_extra(file, operation, 0); |
|
1628 |
}
|
|
1629 |
||
1630 |
int ha_myisam::reset(void) |
|
1631 |
{
|
|
1632 |
pushed_idx_cond= NULL; |
|
1633 |
pushed_idx_cond_keyno= MAX_KEY; |
|
1634 |
mi_set_index_cond_func(file, NULL, 0); |
|
1635 |
ds_mrr.dsmrr_close(); |
|
1636 |
return mi_reset(file); |
|
1637 |
}
|
|
1638 |
||
1639 |
/* To be used with WRITE_CACHE and EXTRA_CACHE */
|
|
1640 |
||
61
by Brian Aker
Conversion of handler type. |
1641 |
int ha_myisam::extra_opt(enum ha_extra_function operation, uint32_t cache_size) |
1
by brian
clean slate |
1642 |
{
|
1643 |
if ((specialflag & SPECIAL_SAFE_MODE) && operation == HA_EXTRA_WRITE_CACHE) |
|
1644 |
return 0; |
|
1645 |
return mi_extra(file, operation, (void*) &cache_size); |
|
1646 |
}
|
|
1647 |
||
1648 |
int ha_myisam::delete_all_rows() |
|
1649 |
{
|
|
1650 |
return mi_delete_all_rows(file); |
|
1651 |
}
|
|
1652 |
||
1653 |
int ha_myisam::delete_table(const char *name) |
|
1654 |
{
|
|
1655 |
return mi_delete_table(name); |
|
1656 |
}
|
|
1657 |
||
1658 |
||
1659 |
int ha_myisam::external_lock(THD *thd, int lock_type) |
|
1660 |
{
|
|
1661 |
file->in_use.data= thd; |
|
1662 |
return mi_lock_database(file, !table->s->tmp_table ? |
|
1663 |
lock_type : ((lock_type == F_UNLCK) ? |
|
1664 |
F_UNLCK : F_EXTRA_LCK)); |
|
1665 |
}
|
|
1666 |
||
77.1.9
by Monty Taylor
All of storage/ compiles clean now. |
1667 |
THR_LOCK_DATA **ha_myisam::store_lock(THD *thd __attribute__((__unused__)), |
1
by brian
clean slate |
1668 |
THR_LOCK_DATA **to, |
1669 |
enum thr_lock_type lock_type) |
|
1670 |
{
|
|
1671 |
if (lock_type != TL_IGNORE && file->lock.type == TL_UNLOCK) |
|
1672 |
file->lock.type=lock_type; |
|
1673 |
*to++= &file->lock; |
|
1674 |
return to; |
|
1675 |
}
|
|
1676 |
||
1677 |
void ha_myisam::update_create_info(HA_CREATE_INFO *create_info) |
|
1678 |
{
|
|
1679 |
ha_myisam::info(HA_STATUS_AUTO | HA_STATUS_CONST); |
|
1680 |
if (!(create_info->used_fields & HA_CREATE_USED_AUTO)) |
|
1681 |
{
|
|
1682 |
create_info->auto_increment_value= stats.auto_increment_value; |
|
1683 |
}
|
|
1684 |
create_info->data_file_name=data_file_name; |
|
1685 |
create_info->index_file_name=index_file_name; |
|
1686 |
}
|
|
1687 |
||
1688 |
||
1689 |
int ha_myisam::create(const char *name, register TABLE *table_arg, |
|
1690 |
HA_CREATE_INFO *ha_create_info) |
|
1691 |
{
|
|
1692 |
int error; |
|
1693 |
uint create_flags= 0, records, i; |
|
1694 |
char buff[FN_REFLEN]; |
|
1695 |
MI_KEYDEF *keydef; |
|
1696 |
MI_COLUMNDEF *recinfo; |
|
1697 |
MI_CREATE_INFO create_info; |
|
1698 |
TABLE_SHARE *share= table_arg->s; |
|
1699 |
uint options= share->db_options_in_use; |
|
1700 |
DBUG_ENTER("ha_myisam::create"); |
|
1701 |
for (i= 0; i < share->keys; i++) |
|
1702 |
{
|
|
1703 |
if (table_arg->key_info[i].flags & HA_USES_PARSER) |
|
1704 |
{
|
|
1705 |
create_flags|= HA_CREATE_RELIES_ON_SQL_LAYER; |
|
1706 |
break; |
|
1707 |
}
|
|
1708 |
}
|
|
1709 |
if ((error= table2myisam(table_arg, &keydef, &recinfo, &records))) |
|
1710 |
DBUG_RETURN(error); /* purecov: inspected */ |
|
1711 |
bzero((char*) &create_info, sizeof(create_info)); |
|
1712 |
create_info.max_rows= share->max_rows; |
|
1713 |
create_info.reloc_rows= share->min_rows; |
|
1714 |
create_info.with_auto_increment= share->next_number_key_offset == 0; |
|
1715 |
create_info.auto_increment= (ha_create_info->auto_increment_value ? |
|
1716 |
ha_create_info->auto_increment_value -1 : |
|
1717 |
(uint64_t) 0); |
|
1718 |
create_info.data_file_length= ((uint64_t) share->max_rows * |
|
1719 |
share->avg_row_length); |
|
1720 |
create_info.data_file_name= ha_create_info->data_file_name; |
|
1721 |
create_info.index_file_name= ha_create_info->index_file_name; |
|
1722 |
create_info.language= share->table_charset->number; |
|
1723 |
||
1724 |
if (ha_create_info->options & HA_LEX_CREATE_TMP_TABLE) |
|
1725 |
create_flags|= HA_CREATE_TMP_TABLE; |
|
1726 |
if (ha_create_info->options & HA_CREATE_KEEP_FILES) |
|
1727 |
create_flags|= HA_CREATE_KEEP_FILES; |
|
1728 |
if (options & HA_OPTION_PACK_RECORD) |
|
1729 |
create_flags|= HA_PACK_RECORD; |
|
1730 |
if (options & HA_OPTION_CHECKSUM) |
|
1731 |
create_flags|= HA_CREATE_CHECKSUM; |
|
1732 |
if (options & HA_OPTION_DELAY_KEY_WRITE) |
|
1733 |
create_flags|= HA_CREATE_DELAY_KEY_WRITE; |
|
1734 |
||
1735 |
/* TODO: Check that the following fn_format is really needed */
|
|
1736 |
error= mi_create(fn_format(buff, name, "", "", |
|
1737 |
MY_UNPACK_FILENAME|MY_APPEND_EXT), |
|
1738 |
share->keys, keydef, |
|
1739 |
records, recinfo, |
|
1740 |
0, (MI_UNIQUEDEF*) 0, |
|
1741 |
&create_info, create_flags); |
|
1742 |
my_free((uchar*) recinfo, MYF(0)); |
|
1743 |
DBUG_RETURN(error); |
|
1744 |
}
|
|
1745 |
||
1746 |
||
1747 |
int ha_myisam::rename_table(const char * from, const char * to) |
|
1748 |
{
|
|
1749 |
return mi_rename(from,to); |
|
1750 |
}
|
|
1751 |
||
1752 |
||
77.1.9
by Monty Taylor
All of storage/ compiles clean now. |
1753 |
void ha_myisam::get_auto_increment(uint64_t offset __attribute__((__unused__)), |
1754 |
uint64_t increment __attribute__((__unused__)), |
|
1755 |
uint64_t nb_desired_values __attribute__((__unused__)), |
|
1
by brian
clean slate |
1756 |
uint64_t *first_value, |
1757 |
uint64_t *nb_reserved_values) |
|
1758 |
{
|
|
1759 |
uint64_t nr; |
|
1760 |
int error; |
|
1761 |
uchar key[MI_MAX_KEY_LENGTH]; |
|
1762 |
||
1763 |
if (!table->s->next_number_key_offset) |
|
1764 |
{ // Autoincrement at key-start |
|
1765 |
ha_myisam::info(HA_STATUS_AUTO); |
|
1766 |
*first_value= stats.auto_increment_value; |
|
1767 |
/* MyISAM has only table-level lock, so reserves to +inf */
|
|
1768 |
*nb_reserved_values= ULONGLONG_MAX; |
|
1769 |
return; |
|
1770 |
}
|
|
1771 |
||
1772 |
/* it's safe to call the following if bulk_insert isn't on */
|
|
1773 |
mi_flush_bulk_insert(file, table->s->next_number_index); |
|
1774 |
||
1775 |
(void) extra(HA_EXTRA_KEYREAD); |
|
1776 |
key_copy(key, table->record[0], |
|
1777 |
table->key_info + table->s->next_number_index, |
|
1778 |
table->s->next_number_key_offset); |
|
1779 |
error= mi_rkey(file, table->record[1], (int) table->s->next_number_index, |
|
1780 |
key, make_prev_keypart_map(table->s->next_number_keypart), |
|
1781 |
HA_READ_PREFIX_LAST); |
|
1782 |
if (error) |
|
1783 |
nr= 1; |
|
1784 |
else
|
|
1785 |
{
|
|
1786 |
/* Get data from record[1] */
|
|
1787 |
nr= ((uint64_t) table->next_number_field-> |
|
1788 |
val_int_offset(table->s->rec_buff_length)+1); |
|
1789 |
}
|
|
1790 |
extra(HA_EXTRA_NO_KEYREAD); |
|
1791 |
*first_value= nr; |
|
1792 |
/*
|
|
1793 |
MySQL needs to call us for next row: assume we are inserting ("a",null)
|
|
1794 |
here, we return 3, and next this statement will want to insert ("b",null):
|
|
1795 |
there is no reason why ("b",3+1) would be the good row to insert: maybe it
|
|
1796 |
already exists, maybe 3+1 is too large...
|
|
1797 |
*/
|
|
1798 |
*nb_reserved_values= 1; |
|
1799 |
}
|
|
1800 |
||
1801 |
||
1802 |
/*
|
|
1803 |
Find out how many rows there is in the given range
|
|
1804 |
||
1805 |
SYNOPSIS
|
|
1806 |
records_in_range()
|
|
1807 |
inx Index to use
|
|
1808 |
min_key Start of range. Null pointer if from first key
|
|
1809 |
max_key End of range. Null pointer if to last key
|
|
1810 |
||
1811 |
NOTES
|
|
1812 |
min_key.flag can have one of the following values:
|
|
1813 |
HA_READ_KEY_EXACT Include the key in the range
|
|
1814 |
HA_READ_AFTER_KEY Don't include key in range
|
|
1815 |
||
1816 |
max_key.flag can have one of the following values:
|
|
1817 |
HA_READ_BEFORE_KEY Don't include key in range
|
|
1818 |
HA_READ_AFTER_KEY Include all 'end_key' values in the range
|
|
1819 |
||
1820 |
RETURN
|
|
1821 |
HA_POS_ERROR Something is wrong with the index tree.
|
|
1822 |
0 There is no matching keys in the given range
|
|
1823 |
number > 0 There is approximately 'number' matching rows in
|
|
1824 |
the range.
|
|
1825 |
*/
|
|
1826 |
||
1827 |
ha_rows ha_myisam::records_in_range(uint inx, key_range *min_key, |
|
1828 |
key_range *max_key) |
|
1829 |
{
|
|
1830 |
return (ha_rows) mi_records_in_range(file, (int) inx, min_key, max_key); |
|
1831 |
}
|
|
1832 |
||
1833 |
||
1834 |
uint ha_myisam::checksum() const |
|
1835 |
{
|
|
1836 |
return (uint)file->state->checksum; |
|
1837 |
}
|
|
1838 |
||
1839 |
||
1840 |
bool ha_myisam::check_if_incompatible_data(HA_CREATE_INFO *info, |
|
1841 |
uint table_changes) |
|
1842 |
{
|
|
1843 |
uint options= table->s->db_options_in_use; |
|
1844 |
||
1845 |
if (info->auto_increment_value != stats.auto_increment_value || |
|
1846 |
info->data_file_name != data_file_name || |
|
1847 |
info->index_file_name != index_file_name || |
|
1848 |
table_changes == IS_EQUAL_NO || |
|
1849 |
table_changes & IS_EQUAL_PACK_LENGTH) // Not implemented yet |
|
1850 |
return COMPATIBLE_DATA_NO; |
|
1851 |
||
1852 |
if ((options & (HA_OPTION_PACK_RECORD | HA_OPTION_CHECKSUM | |
|
1853 |
HA_OPTION_DELAY_KEY_WRITE)) != |
|
1854 |
(info->table_options & (HA_OPTION_PACK_RECORD | HA_OPTION_CHECKSUM | |
|
1855 |
HA_OPTION_DELAY_KEY_WRITE))) |
|
1856 |
return COMPATIBLE_DATA_NO; |
|
1857 |
return COMPATIBLE_DATA_YES; |
|
1858 |
}
|
|
1859 |
||
77.1.9
by Monty Taylor
All of storage/ compiles clean now. |
1860 |
int myisam_panic(handlerton *hton __attribute__((__unused__)), ha_panic_function flag) |
1
by brian
clean slate |
1861 |
{
|
1862 |
return mi_panic(flag); |
|
1863 |
}
|
|
1864 |
||
1865 |
static int myisam_init(void *p) |
|
1866 |
{
|
|
1867 |
handlerton *myisam_hton; |
|
1868 |
||
1869 |
myisam_hton= (handlerton *)p; |
|
1870 |
myisam_hton->state= SHOW_OPTION_YES; |
|
1871 |
myisam_hton->db_type= DB_TYPE_MYISAM; |
|
1872 |
myisam_hton->create= myisam_create_handler; |
|
1873 |
myisam_hton->panic= myisam_panic; |
|
1874 |
myisam_hton->flags= HTON_CAN_RECREATE | HTON_SUPPORT_LOG_TABLES; |
|
1875 |
return 0; |
|
1876 |
}
|
|
1877 |
||
1878 |
||
1879 |
||
1880 |
/****************************************************************************
|
|
1881 |
* MyISAM MRR implementation: use DS-MRR
|
|
1882 |
***************************************************************************/
|
|
1883 |
||
1884 |
int ha_myisam::multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param, |
|
1885 |
uint n_ranges, uint mode, |
|
1886 |
HANDLER_BUFFER *buf) |
|
1887 |
{
|
|
1888 |
return ds_mrr.dsmrr_init(this, &table->key_info[active_index], |
|
1889 |
seq, seq_init_param, n_ranges, mode, buf); |
|
1890 |
}
|
|
1891 |
||
1892 |
int ha_myisam::multi_range_read_next(char **range_info) |
|
1893 |
{
|
|
1894 |
return ds_mrr.dsmrr_next(this, range_info); |
|
1895 |
}
|
|
1896 |
||
1897 |
ha_rows ha_myisam::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq, |
|
1898 |
void *seq_init_param, |
|
1899 |
uint n_ranges, uint *bufsz, |
|
1900 |
uint *flags, COST_VECT *cost) |
|
1901 |
{
|
|
1902 |
/*
|
|
1903 |
This call is here because there is no location where this->table would
|
|
1904 |
already be known.
|
|
1905 |
TODO: consider moving it into some per-query initialization call.
|
|
1906 |
*/
|
|
1907 |
ds_mrr.init(this, table); |
|
1908 |
return ds_mrr.dsmrr_info_const(keyno, seq, seq_init_param, n_ranges, bufsz, |
|
1909 |
flags, cost); |
|
1910 |
}
|
|
1911 |
||
1912 |
int ha_myisam::multi_range_read_info(uint keyno, uint n_ranges, uint keys, |
|
1913 |
uint *bufsz, uint *flags, COST_VECT *cost) |
|
1914 |
{
|
|
1915 |
ds_mrr.init(this, table); |
|
1916 |
return ds_mrr.dsmrr_info(keyno, n_ranges, keys, bufsz, flags, cost); |
|
1917 |
}
|
|
1918 |
||
1919 |
/* MyISAM MRR implementation ends */
|
|
1920 |
||
1921 |
||
1922 |
/* Index condition pushdown implementation*/
|
|
1923 |
||
1924 |
||
1925 |
Item *ha_myisam::idx_cond_push(uint keyno_arg, Item* idx_cond_arg) |
|
1926 |
{
|
|
1927 |
pushed_idx_cond_keyno= keyno_arg; |
|
1928 |
pushed_idx_cond= idx_cond_arg; |
|
1929 |
in_range_check_pushed_down= TRUE; |
|
1930 |
if (active_index == pushed_idx_cond_keyno) |
|
1931 |
mi_set_index_cond_func(file, index_cond_func_myisam, this); |
|
1932 |
return NULL; |
|
1933 |
}
|
|
1934 |
||
1935 |
||
1936 |
struct st_mysql_storage_engine myisam_storage_engine= |
|
1937 |
{ MYSQL_HANDLERTON_INTERFACE_VERSION }; |
|
1938 |
||
1939 |
mysql_declare_plugin(myisam) |
|
1940 |
{
|
|
1941 |
MYSQL_STORAGE_ENGINE_PLUGIN, |
|
1942 |
&myisam_storage_engine, |
|
1943 |
"MyISAM", |
|
1944 |
"MySQL AB", |
|
1945 |
"Default engine as of MySQL 3.23 with great performance", |
|
1946 |
PLUGIN_LICENSE_GPL, |
|
1947 |
myisam_init, /* Plugin Init */ |
|
1948 |
NULL, /* Plugin Deinit */ |
|
1949 |
0x0100, /* 1.0 */ |
|
1950 |
NULL, /* status variables */ |
|
1951 |
NULL, /* system variables */ |
|
1952 |
NULL /* config options */ |
|
1953 |
}
|
|
1954 |
mysql_declare_plugin_end; |
|
1955 |
||
1956 |
||
1957 |
#ifdef HAVE_QUERY_CACHE
|
|
1958 |
/**
|
|
1959 |
@brief Register a named table with a call back function to the query cache.
|
|
1960 |
||
1961 |
@param thd The thread handle
|
|
1962 |
@param table_key A pointer to the table name in the table cache
|
|
1963 |
@param key_length The length of the table name
|
|
1964 |
@param[out] engine_callback The pointer to the storage engine call back
|
|
1965 |
function, currently 0
|
|
1966 |
@param[out] engine_data Engine data will be set to 0.
|
|
1967 |
||
1968 |
@note Despite the name of this function, it is used to check each statement
|
|
1969 |
before it is cached and not to register a table or callback function.
|
|
1970 |
||
1971 |
@see handler::register_query_cache_table
|
|
1972 |
||
1973 |
@return The error code. The engine_data and engine_callback will be set to 0.
|
|
1974 |
@retval TRUE Success
|
|
1975 |
@retval FALSE An error occured
|
|
1976 |
*/
|
|
1977 |
||
1978 |
my_bool ha_myisam::register_query_cache_table(THD *thd, char *table_name, |
|
1979 |
uint table_name_len, |
|
1980 |
qc_engine_callback
|
|
1981 |
*engine_callback, |
|
1982 |
uint64_t *engine_data) |
|
1983 |
{
|
|
1984 |
DBUG_ENTER("ha_myisam::register_query_cache_table"); |
|
1985 |
/*
|
|
1986 |
No call back function is needed to determine if a cached statement
|
|
1987 |
is valid or not.
|
|
1988 |
*/
|
|
1989 |
*engine_callback= 0; |
|
1990 |
||
1991 |
/*
|
|
1992 |
No engine data is needed.
|
|
1993 |
*/
|
|
1994 |
*engine_data= 0; |
|
1995 |
||
1996 |
if (file->s->concurrent_insert) |
|
1997 |
{
|
|
1998 |
/*
|
|
1999 |
If a concurrent INSERT has happened just before the currently
|
|
2000 |
processed SELECT statement, the total size of the table is
|
|
2001 |
unknown.
|
|
2002 |
||
2003 |
To determine if the table size is known, the current thread's snap
|
|
2004 |
shot of the table size with the actual table size are compared.
|
|
2005 |
||
2006 |
If the table size is unknown the SELECT statement can't be cached.
|
|
2007 |
||
2008 |
When concurrent inserts are disabled at table open, mi_open()
|
|
2009 |
does not assign a get_status() function. In this case the local
|
|
2010 |
("current") status is never updated. We would wrongly think that
|
|
2011 |
we cannot cache the statement.
|
|
2012 |
*/
|
|
2013 |
uint64_t actual_data_file_length; |
|
2014 |
uint64_t current_data_file_length; |
|
2015 |
||
2016 |
/*
|
|
2017 |
POSIX visibility rules specify that "2. Whatever memory values a
|
|
2018 |
thread can see when it unlocks a mutex <...> can also be seen by any
|
|
2019 |
thread that later locks the same mutex". In this particular case,
|
|
2020 |
concurrent insert thread had modified the data_file_length in
|
|
2021 |
MYISAM_SHARE before it has unlocked (or even locked)
|
|
2022 |
structure_guard_mutex. So, here we're guaranteed to see at least that
|
|
2023 |
value after we've locked the same mutex. We can see a later value
|
|
2024 |
(modified by some other thread) though, but it's ok, as we only want
|
|
2025 |
to know if the variable was changed, the actual new value doesn't matter
|
|
2026 |
*/
|
|
2027 |
actual_data_file_length= file->s->state.state.data_file_length; |
|
2028 |
current_data_file_length= file->save_state.data_file_length; |
|
2029 |
||
2030 |
if (current_data_file_length != actual_data_file_length) |
|
2031 |
{
|
|
2032 |
/* Don't cache current statement. */
|
|
2033 |
DBUG_RETURN(FALSE); |
|
2034 |
}
|
|
2035 |
}
|
|
2036 |
||
2037 |
/* It is ok to try to cache current statement. */
|
|
2038 |
DBUG_RETURN(TRUE); |
|
2039 |
}
|
|
2040 |
#endif
|