| 1 | /* |
| 2 | Copyright (c) 2000, 2011, Oracle and/or its affiliates |
| 3 | |
| 4 | This program is free software; you can redistribute it and/or modify |
| 5 | it under the terms of the GNU General Public License as published by |
| 6 | the Free Software Foundation; version 2 of the License. |
| 7 | |
| 8 | This program is distributed in the hope that it will be useful, |
| 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 11 | GNU General Public License for more details. |
| 12 | |
| 13 | You should have received a copy of the GNU General Public License |
| 14 | along with this program; if not, write to the Free Software |
| 15 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ |
| 16 | |
| 17 | /* Testing of the basic functions of a MyISAM table */ |
| 18 | |
| 19 | #include <my_global.h> |
| 20 | #include "myisam.h" |
| 21 | #include <my_getopt.h> |
| 22 | #include <m_string.h> |
| 23 | |
| 24 | #define MAX_REC_LENGTH 1024 |
| 25 | |
| 26 | static void usage(); |
| 27 | |
| 28 | static int rec_pointer_size=0, flags[50]; |
| 29 | static int key_field=FIELD_SKIP_PRESPACE,=FIELD_SKIP_ENDSPACE; |
| 30 | static int key_type=HA_KEYTYPE_NUM; |
| 31 | static int create_flag=0; |
| 32 | |
| 33 | static uint insert_count, update_count, remove_count; |
| 34 | static uint pack_keys=0, pack_seg=0, key_length; |
| 35 | static uint unique_key=HA_NOSAME; |
| 36 | static my_bool key_cacheing, null_fields, silent, skip_update, opt_unique, |
| 37 | verbose; |
| 38 | static MI_COLUMNDEF recinfo[4]; |
| 39 | static MI_KEYDEF keyinfo[10]; |
| 40 | static HA_KEYSEG keyseg[10]; |
| 41 | static HA_KEYSEG uniqueseg[10]; |
| 42 | |
| 43 | static int run_test(const char *filename); |
| 44 | static void get_options(int argc, char *argv[]); |
| 45 | static void create_key(uchar *key,uint rownr); |
| 46 | static void create_record(uchar *record,uint rownr); |
| 47 | static void update_record(uchar *record); |
| 48 | |
| 49 | int main(int argc,char *argv[]) |
| 50 | { |
| 51 | MY_INIT(argv[0]); |
| 52 | my_init(); |
| 53 | if (key_cacheing) |
| 54 | init_key_cache(dflt_key_cache,KEY_CACHE_BLOCK_SIZE,IO_SIZE*16,0,0, |
| 55 | 0, DEFAULT_KEY_CACHE_PARTITIONS); |
| 56 | get_options(argc,argv); |
| 57 | |
| 58 | exit(run_test("test1" )); |
| 59 | } |
| 60 | |
| 61 | |
| 62 | static int run_test(const char *filename) |
| 63 | { |
| 64 | MI_INFO *file; |
| 65 | int i,j,error,deleted,rec_length,uniques=0; |
| 66 | ha_rows found,row_count; |
| 67 | my_off_t pos; |
| 68 | uchar record[MAX_REC_LENGTH],key[MAX_REC_LENGTH],read_record[MAX_REC_LENGTH]; |
| 69 | MI_UNIQUEDEF uniquedef; |
| 70 | MI_CREATE_INFO create_info; |
| 71 | |
| 72 | bzero((char*) recinfo,sizeof(recinfo)); |
| 73 | |
| 74 | /* First define 2 columns */ |
| 75 | recinfo[0].type=FIELD_NORMAL; recinfo[0].length=1; /* For NULL bits */ |
| 76 | recinfo[1].type=key_field; |
| 77 | recinfo[1].length= (key_field == FIELD_BLOB ? 4+portable_sizeof_char_ptr : |
| 78 | key_length); |
| 79 | if (key_field == FIELD_VARCHAR) |
| 80 | recinfo[1].length+= HA_VARCHAR_PACKLENGTH(key_length);; |
| 81 | recinfo[2].type=extra_field; |
| 82 | recinfo[2].length= (extra_field == FIELD_BLOB ? 4 + portable_sizeof_char_ptr : 24); |
| 83 | if (extra_field == FIELD_VARCHAR) |
| 84 | recinfo[2].length+= HA_VARCHAR_PACKLENGTH(recinfo[2].length); |
| 85 | recinfo[1].null_bit= null_fields ? 2 : 0; |
| 86 | |
| 87 | if (opt_unique) |
| 88 | { |
| 89 | recinfo[3].type=FIELD_CHECK; |
| 90 | recinfo[3].length=MI_UNIQUE_HASH_LENGTH; |
| 91 | } |
| 92 | rec_length=recinfo[0].length+recinfo[1].length+recinfo[2].length+ |
| 93 | recinfo[3].length; |
| 94 | |
| 95 | if (key_type == HA_KEYTYPE_VARTEXT1 && |
| 96 | key_length > 255) |
| 97 | key_type= HA_KEYTYPE_VARTEXT2; |
| 98 | |
| 99 | /* Define a key over the first column */ |
| 100 | keyinfo[0].seg=keyseg; |
| 101 | keyinfo[0].keysegs=1; |
| 102 | keyinfo[0].block_length= 0; /* Default block length */ |
| 103 | keyinfo[0].key_alg=HA_KEY_ALG_BTREE; |
| 104 | keyinfo[0].seg[0].type= key_type; |
| 105 | keyinfo[0].seg[0].flag= pack_seg; |
| 106 | keyinfo[0].seg[0].start=1; |
| 107 | keyinfo[0].seg[0].length=key_length; |
| 108 | keyinfo[0].seg[0].null_bit= null_fields ? 2 : 0; |
| 109 | keyinfo[0].seg[0].null_pos=0; |
| 110 | keyinfo[0].seg[0].language= default_charset_info->number; |
| 111 | if (pack_seg & HA_BLOB_PART) |
| 112 | { |
| 113 | keyinfo[0].seg[0].bit_start=4; /* Length of blob length */ |
| 114 | } |
| 115 | keyinfo[0].flag = (uint8) (pack_keys | unique_key); |
| 116 | |
| 117 | bzero((uchar*) flags,sizeof(flags)); |
| 118 | if (opt_unique) |
| 119 | { |
| 120 | uint start; |
| 121 | uniques=1; |
| 122 | bzero((char*) &uniquedef,sizeof(uniquedef)); |
| 123 | bzero((char*) uniqueseg,sizeof(uniqueseg)); |
| 124 | uniquedef.seg=uniqueseg; |
| 125 | uniquedef.keysegs=2; |
| 126 | |
| 127 | /* Make a unique over all columns (except first NULL fields) */ |
| 128 | for (i=0, start=1 ; i < 2 ; i++) |
| 129 | { |
| 130 | uniqueseg[i].start=start; |
| 131 | start+=recinfo[i+1].length; |
| 132 | uniqueseg[i].length=recinfo[i+1].length; |
| 133 | uniqueseg[i].language= default_charset_info->number; |
| 134 | } |
| 135 | uniqueseg[0].type= key_type; |
| 136 | uniqueseg[0].null_bit= null_fields ? 2 : 0; |
| 137 | uniqueseg[1].type= HA_KEYTYPE_TEXT; |
| 138 | if (extra_field == FIELD_BLOB) |
| 139 | { |
| 140 | uniqueseg[1].length=0; /* The whole blob */ |
| 141 | uniqueseg[1].bit_start=4; /* long blob */ |
| 142 | uniqueseg[1].flag|= HA_BLOB_PART; |
| 143 | } |
| 144 | else if (extra_field == FIELD_VARCHAR) |
| 145 | uniqueseg[1].flag|= HA_VAR_LENGTH_PART; |
| 146 | } |
| 147 | else |
| 148 | uniques=0; |
| 149 | |
| 150 | if (!silent) |
| 151 | printf("- Creating isam-file\n" ); |
| 152 | bzero((char*) &create_info,sizeof(create_info)); |
| 153 | create_info.max_rows=(ulong) (rec_pointer_size ? |
| 154 | (1L << (rec_pointer_size*8))/40 : |
| 155 | 0); |
| 156 | if (mi_create(filename,1,keyinfo,3+opt_unique,recinfo, |
| 157 | uniques, &uniquedef, &create_info, |
| 158 | create_flag)) |
| 159 | goto err; |
| 160 | if (!(file=mi_open(filename,2,HA_OPEN_ABORT_IF_LOCKED))) |
| 161 | goto err; |
| 162 | if (!silent) |
| 163 | printf("- Writing key:s\n" ); |
| 164 | |
| 165 | my_errno=0; |
| 166 | row_count=deleted=0; |
| 167 | for (i=49 ; i>=1 ; i-=2 ) |
| 168 | { |
| 169 | if (insert_count-- == 0) { (void) mi_close(file); exit(0) ; } |
| 170 | j=i%25 +1; |
| 171 | create_record(record,j); |
| 172 | error=mi_write(file,record); |
| 173 | if (!error) |
| 174 | row_count++; |
| 175 | flags[j]=1; |
| 176 | if (verbose || error) |
| 177 | printf("J= %2d mi_write: %d errno: %d\n" , j,error,my_errno); |
| 178 | } |
| 179 | |
| 180 | /* Insert 2 rows with null values */ |
| 181 | if (null_fields) |
| 182 | { |
| 183 | create_record(record,0); |
| 184 | error=mi_write(file,record); |
| 185 | if (!error) |
| 186 | row_count++; |
| 187 | if (verbose || error) |
| 188 | printf("J= NULL mi_write: %d errno: %d\n" , error,my_errno); |
| 189 | error=mi_write(file,record); |
| 190 | if (!error) |
| 191 | row_count++; |
| 192 | if (verbose || error) |
| 193 | printf("J= NULL mi_write: %d errno: %d\n" , error,my_errno); |
| 194 | flags[0]=2; |
| 195 | } |
| 196 | |
| 197 | if (!skip_update) |
| 198 | { |
| 199 | if (opt_unique) |
| 200 | { |
| 201 | if (!silent) |
| 202 | printf("- Checking unique constraint\n" ); |
| 203 | create_record(record,j); |
| 204 | if (!mi_write(file,record) || my_errno != HA_ERR_FOUND_DUPP_UNIQUE) |
| 205 | { |
| 206 | printf("unique check failed\n" ); |
| 207 | } |
| 208 | } |
| 209 | if (!silent) |
| 210 | printf("- Updating rows\n" ); |
| 211 | |
| 212 | /* Update first last row to force extend of file */ |
| 213 | if (mi_rsame(file,read_record,-1)) |
| 214 | { |
| 215 | printf("Can't find last row with mi_rsame\n" ); |
| 216 | } |
| 217 | else |
| 218 | { |
| 219 | memcpy(record,read_record,rec_length); |
| 220 | update_record(record); |
| 221 | if (mi_update(file,read_record,record)) |
| 222 | { |
| 223 | printf("Can't update last row: %.*s\n" , |
| 224 | keyinfo[0].seg[0].length,read_record+1); |
| 225 | } |
| 226 | } |
| 227 | |
| 228 | /* Read through all rows and update them */ |
| 229 | pos=(my_off_t) 0; |
| 230 | found=0; |
| 231 | while ((error=mi_rrnd(file,read_record,pos)) == 0) |
| 232 | { |
| 233 | if (update_count-- == 0) { (void) mi_close(file); exit(0) ; } |
| 234 | memcpy(record,read_record,rec_length); |
| 235 | update_record(record); |
| 236 | if (mi_update(file,read_record,record)) |
| 237 | { |
| 238 | printf("Can't update row: %.*s, error: %d\n" , |
| 239 | keyinfo[0].seg[0].length,record+1,my_errno); |
| 240 | } |
| 241 | found++; |
| 242 | pos=HA_OFFSET_ERROR; |
| 243 | } |
| 244 | if (found != row_count) |
| 245 | printf("Found %ld of %ld rows\n" , (ulong) found, (ulong) row_count); |
| 246 | } |
| 247 | |
| 248 | if (!silent) |
| 249 | printf("- Reopening file\n" ); |
| 250 | if (mi_close(file)) goto err; |
| 251 | if (!(file=mi_open(filename,2,HA_OPEN_ABORT_IF_LOCKED))) goto err; |
| 252 | if (!skip_update) |
| 253 | { |
| 254 | if (!silent) |
| 255 | printf("- Removing keys\n" ); |
| 256 | |
| 257 | for (i=0 ; i <= 10 ; i++) |
| 258 | { |
| 259 | /* testing */ |
| 260 | if (remove_count-- == 0) { (void) mi_close(file); exit(0) ; } |
| 261 | j=i*2; |
| 262 | if (!flags[j]) |
| 263 | continue; |
| 264 | create_key(key,j); |
| 265 | my_errno=0; |
| 266 | if ((error = mi_rkey(file,read_record,0,key,HA_WHOLE_KEY, |
| 267 | HA_READ_KEY_EXACT))) |
| 268 | { |
| 269 | if (verbose || (flags[j] >= 1 || |
| 270 | (error && my_errno != HA_ERR_KEY_NOT_FOUND))) |
| 271 | printf("key: '%.*s' mi_rkey: %3d errno: %3d\n" , |
| 272 | (int) key_length, key + MY_TEST(null_fields), error, my_errno); |
| 273 | } |
| 274 | else |
| 275 | { |
| 276 | error=mi_delete(file,read_record); |
| 277 | if (verbose || error) |
| 278 | printf("key: '%.*s' mi_delete: %3d errno: %3d\n" , |
| 279 | (int) key_length, key + MY_TEST(null_fields), error, my_errno); |
| 280 | if (! error) |
| 281 | { |
| 282 | deleted++; |
| 283 | flags[j]--; |
| 284 | } |
| 285 | } |
| 286 | } |
| 287 | } |
| 288 | if (!silent) |
| 289 | printf("- Reading rows with key\n" ); |
| 290 | for (i=0 ; i <= 25 ; i++) |
| 291 | { |
| 292 | create_key(key,i); |
| 293 | my_errno=0; |
| 294 | error=mi_rkey(file,read_record,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT); |
| 295 | if (verbose || |
| 296 | (error == 0 && flags[i] == 0 && unique_key) || |
| 297 | (error && (flags[i] != 0 || my_errno != HA_ERR_KEY_NOT_FOUND))) |
| 298 | { |
| 299 | printf("key: '%.*s' mi_rkey: %3d errno: %3d record: %s\n" , |
| 300 | (int) key_length, key + MY_TEST(null_fields), error, my_errno, |
| 301 | record + 1); |
| 302 | } |
| 303 | } |
| 304 | |
| 305 | if (!silent) |
| 306 | printf("- Reading rows with position\n" ); |
| 307 | for (i=1,found=0 ; i <= 30 ; i++) |
| 308 | { |
| 309 | my_errno=0; |
| 310 | if ((error=mi_rrnd(file,read_record,i == 1 ? 0L : HA_OFFSET_ERROR)) == -1) |
| 311 | { |
| 312 | if (found != row_count-deleted) |
| 313 | printf("Found only %ld of %ld rows\n" , (ulong) found, |
| 314 | (ulong) (row_count - deleted)); |
| 315 | break; |
| 316 | } |
| 317 | if (!error) |
| 318 | found++; |
| 319 | if (verbose || (error != 0 && error != HA_ERR_RECORD_DELETED && |
| 320 | error != HA_ERR_END_OF_FILE)) |
| 321 | { |
| 322 | printf("pos: %2d mi_rrnd: %3d errno: %3d record: %s\n" , |
| 323 | i-1,error,my_errno,read_record+1); |
| 324 | } |
| 325 | } |
| 326 | if (mi_close(file)) goto err; |
| 327 | my_end(MY_CHECK_ERROR); |
| 328 | |
| 329 | return (0); |
| 330 | err: |
| 331 | printf("got error: %3d when using myisam-database\n" ,my_errno); |
| 332 | return 1; /* skip warning */ |
| 333 | } |
| 334 | |
| 335 | |
| 336 | static void create_key_part(uchar *key,uint rownr) |
| 337 | { |
| 338 | if (!unique_key) |
| 339 | rownr&=7; /* Some identical keys */ |
| 340 | if (keyinfo[0].seg[0].type == HA_KEYTYPE_NUM) |
| 341 | { |
| 342 | sprintf((char*) key,"%*d" ,keyinfo[0].seg[0].length,rownr); |
| 343 | } |
| 344 | else if (keyinfo[0].seg[0].type == HA_KEYTYPE_VARTEXT1 || |
| 345 | keyinfo[0].seg[0].type == HA_KEYTYPE_VARTEXT2) |
| 346 | { /* Alpha record */ |
| 347 | /* Create a key that may be easily packed */ |
| 348 | bfill(key,keyinfo[0].seg[0].length,rownr < 10 ? 'A' : 'B'); |
| 349 | sprintf((char*) key+keyinfo[0].seg[0].length-2,"%-2d" ,rownr); |
| 350 | if ((rownr & 7) == 0) |
| 351 | { |
| 352 | /* Change the key to force a unpack of the next key */ |
| 353 | bfill(key+3,keyinfo[0].seg[0].length-4,rownr < 10 ? 'a' : 'b'); |
| 354 | } |
| 355 | } |
| 356 | else |
| 357 | { /* Alpha record */ |
| 358 | if (keyinfo[0].seg[0].flag & HA_SPACE_PACK) |
| 359 | sprintf((char*) key,"%-*d" ,keyinfo[0].seg[0].length,rownr); |
| 360 | else |
| 361 | { |
| 362 | /* Create a key that may be easily packed */ |
| 363 | bfill(key,keyinfo[0].seg[0].length,rownr < 10 ? 'A' : 'B'); |
| 364 | sprintf((char*) key+keyinfo[0].seg[0].length-2,"%-2d" ,rownr); |
| 365 | if ((rownr & 7) == 0) |
| 366 | { |
| 367 | /* Change the key to force a unpack of the next key */ |
| 368 | key[1]= (rownr < 10 ? 'a' : 'b'); |
| 369 | } |
| 370 | } |
| 371 | } |
| 372 | } |
| 373 | |
| 374 | |
| 375 | static void create_key(uchar *key,uint rownr) |
| 376 | { |
| 377 | if (keyinfo[0].seg[0].null_bit) |
| 378 | { |
| 379 | if (rownr == 0) |
| 380 | { |
| 381 | key[0]=1; /* null key */ |
| 382 | key[1]=0; /* Fore easy print of key */ |
| 383 | return; |
| 384 | } |
| 385 | *key++=0; |
| 386 | } |
| 387 | if (keyinfo[0].seg[0].flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART)) |
| 388 | { |
| 389 | size_t tmp; |
| 390 | create_key_part(key+2,rownr); |
| 391 | tmp=strlen((char*) key+2); |
| 392 | int2store(key,tmp); |
| 393 | } |
| 394 | else |
| 395 | create_key_part(key,rownr); |
| 396 | } |
| 397 | |
| 398 | |
| 399 | static uchar blob_key[MAX_REC_LENGTH]; |
| 400 | static uchar blob_record[MAX_REC_LENGTH+20*20]; |
| 401 | |
| 402 | |
| 403 | static void create_record(uchar *record,uint rownr) |
| 404 | { |
| 405 | uchar *pos; |
| 406 | bzero((char*) record,MAX_REC_LENGTH); |
| 407 | record[0]=1; /* delete marker */ |
| 408 | if (rownr == 0 && keyinfo[0].seg[0].null_bit) |
| 409 | record[0]|=keyinfo[0].seg[0].null_bit; /* Null key */ |
| 410 | |
| 411 | pos=record+1; |
| 412 | if (recinfo[1].type == FIELD_BLOB) |
| 413 | { |
| 414 | size_t tmp; |
| 415 | uchar *ptr; |
| 416 | create_key_part(blob_key,rownr); |
| 417 | tmp=strlen((char*) blob_key); |
| 418 | int4store(pos,tmp); |
| 419 | ptr=blob_key; |
| 420 | memcpy(pos+4, &ptr, sizeof(char*)); |
| 421 | pos+=recinfo[1].length; |
| 422 | } |
| 423 | else if (recinfo[1].type == FIELD_VARCHAR) |
| 424 | { |
| 425 | size_t tmp, pack_length= HA_VARCHAR_PACKLENGTH(recinfo[1].length-1); |
| 426 | create_key_part(pos+pack_length,rownr); |
| 427 | tmp= strlen((char*) pos+pack_length); |
| 428 | if (pack_length == 1) |
| 429 | *(uchar*) pos= (uchar) tmp; |
| 430 | else |
| 431 | int2store(pos,tmp); |
| 432 | pos+= recinfo[1].length; |
| 433 | } |
| 434 | else |
| 435 | { |
| 436 | create_key_part(pos,rownr); |
| 437 | pos+=recinfo[1].length; |
| 438 | } |
| 439 | if (recinfo[2].type == FIELD_BLOB) |
| 440 | { |
| 441 | size_t tmp; |
| 442 | uchar *ptr;; |
| 443 | sprintf((char*) blob_record,"... row: %d" , rownr); |
| 444 | strappend((char*) blob_record,MY_MAX(MAX_REC_LENGTH-rownr,10),' '); |
| 445 | tmp=strlen((char*) blob_record); |
| 446 | int4store(pos,tmp); |
| 447 | ptr=blob_record; |
| 448 | memcpy(pos+4, &ptr, sizeof(char*)); |
| 449 | } |
| 450 | else if (recinfo[2].type == FIELD_VARCHAR) |
| 451 | { |
| 452 | size_t tmp, pack_length= HA_VARCHAR_PACKLENGTH(recinfo[1].length-1); |
| 453 | sprintf((char*) pos+pack_length, "... row: %d" , rownr); |
| 454 | tmp= strlen((char*) pos+pack_length); |
| 455 | if (pack_length == 1) |
| 456 | *pos= (uchar) tmp; |
| 457 | else |
| 458 | int2store(pos,tmp); |
| 459 | } |
| 460 | else |
| 461 | { |
| 462 | sprintf((char*) pos,"... row: %d" , rownr); |
| 463 | strappend((char*) pos,recinfo[2].length,' '); |
| 464 | } |
| 465 | } |
| 466 | |
| 467 | /* change row to test re-packing of rows and reallocation of keys */ |
| 468 | |
| 469 | static void update_record(uchar *record) |
| 470 | { |
| 471 | uchar *pos=record+1; |
| 472 | if (recinfo[1].type == FIELD_BLOB) |
| 473 | { |
| 474 | uchar *column,*ptr; |
| 475 | int length; |
| 476 | length=uint4korr(pos); /* Long blob */ |
| 477 | memcpy(&column, pos+4, sizeof(char*)); |
| 478 | memcpy(blob_key,column,length); /* Move old key */ |
| 479 | ptr=blob_key; |
| 480 | memcpy(pos+4, &ptr, sizeof(char*)); /* Store pointer to new key */ |
| 481 | if (keyinfo[0].seg[0].type != HA_KEYTYPE_NUM) |
| 482 | default_charset_info->cset->casedn(default_charset_info, |
| 483 | (char*) blob_key, length, |
| 484 | (char*) blob_key, length); |
| 485 | pos+=recinfo[1].length; |
| 486 | } |
| 487 | else if (recinfo[1].type == FIELD_VARCHAR) |
| 488 | { |
| 489 | uint pack_length= HA_VARCHAR_PACKLENGTH(recinfo[1].length-1); |
| 490 | uint length= pack_length == 1 ? (uint) *(uchar*) pos : uint2korr(pos); |
| 491 | default_charset_info->cset->casedn(default_charset_info, |
| 492 | (char*) pos + pack_length, length, |
| 493 | (char*) pos + pack_length, length); |
| 494 | pos+=recinfo[1].length; |
| 495 | } |
| 496 | else |
| 497 | { |
| 498 | if (keyinfo[0].seg[0].type != HA_KEYTYPE_NUM) |
| 499 | default_charset_info->cset->casedn(default_charset_info, |
| 500 | (char*) pos, keyinfo[0].seg[0].length, |
| 501 | (char*) pos, keyinfo[0].seg[0].length); |
| 502 | pos+=recinfo[1].length; |
| 503 | } |
| 504 | |
| 505 | if (recinfo[2].type == FIELD_BLOB) |
| 506 | { |
| 507 | uchar *column; |
| 508 | int length; |
| 509 | length=uint4korr(pos); |
| 510 | memcpy(&column, pos+4, sizeof(char*)); |
| 511 | memcpy(blob_record,column,length); |
| 512 | bfill(blob_record+length,20,'.'); /* Make it larger */ |
| 513 | length+=20; |
| 514 | int4store(pos,length); |
| 515 | column= blob_record; |
| 516 | memcpy(pos+4, &column, sizeof(char*)); |
| 517 | } |
| 518 | else if (recinfo[2].type == FIELD_VARCHAR) |
| 519 | { |
| 520 | /* Second field is longer than 10 characters */ |
| 521 | uint pack_length= HA_VARCHAR_PACKLENGTH(recinfo[1].length-1); |
| 522 | uint length= pack_length == 1 ? (uint) *(uchar*) pos : uint2korr(pos); |
| 523 | bfill(pos+pack_length+length,recinfo[2].length-length-pack_length,'.'); |
| 524 | length=recinfo[2].length-pack_length; |
| 525 | if (pack_length == 1) |
| 526 | *(uchar*) pos= (uchar) length; |
| 527 | else |
| 528 | int2store(pos,length); |
| 529 | } |
| 530 | else |
| 531 | { |
| 532 | bfill(pos+recinfo[2].length-10,10,'.'); |
| 533 | } |
| 534 | } |
| 535 | |
| 536 | |
| 537 | static struct my_option my_long_options[] = |
| 538 | { |
| 539 | {"checksum" , 'c', "Undocumented" , |
| 540 | 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 541 | #ifndef DBUG_OFF |
| 542 | {"debug" , '#', "Undocumented" , |
| 543 | 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
| 544 | #endif |
| 545 | {"delete_rows" , 'd', "Undocumented" , &remove_count, |
| 546 | &remove_count, 0, GET_UINT, REQUIRED_ARG, 1000, 0, 0, 0, 0, 0}, |
| 547 | {"help" , '?', "Display help and exit" , |
| 548 | 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 549 | {"insert_rows" , 'i', "Undocumented" , &insert_count, |
| 550 | &insert_count, 0, GET_UINT, REQUIRED_ARG, 1000, 0, 0, 0, 0, 0}, |
| 551 | {"key_alpha" , 'a', "Use a key of type HA_KEYTYPE_TEXT" , |
| 552 | 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 553 | {"key_binary_pack" , 'B', "Undocumented" , |
| 554 | 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 555 | {"key_blob" , 'b', "Undocumented" , |
| 556 | 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 557 | {"key_cache" , 'K', "Undocumented" , &key_cacheing, |
| 558 | &key_cacheing, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 559 | {"key_length" , 'k', "Undocumented" , &key_length, &key_length, |
| 560 | 0, GET_UINT, REQUIRED_ARG, 6, 0, 0, 0, 0, 0}, |
| 561 | {"key_multiple" , 'm', "Undocumented" , |
| 562 | 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 563 | {"key_prefix_pack" , 'P', "Undocumented" , |
| 564 | 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 565 | {"key_space_pack" , 'p', "Undocumented" , |
| 566 | 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 567 | {"key_varchar" , 'w', "Test VARCHAR keys" , |
| 568 | 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 569 | {"null_fields" , 'N', "Define fields with NULL" , |
| 570 | &null_fields, &null_fields, 0, GET_BOOL, NO_ARG, |
| 571 | 0, 0, 0, 0, 0, 0}, |
| 572 | {"row_fixed_size" , 'S', "Undocumented" , |
| 573 | 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 574 | {"row_pointer_size" , 'R', "Undocumented" , &rec_pointer_size, |
| 575 | &rec_pointer_size, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
| 576 | {"silent" , 's', "Undocumented" , |
| 577 | &silent, &silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 578 | {"skip_update" , 'U', "Undocumented" , &skip_update, |
| 579 | &skip_update, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 580 | {"unique" , 'C', "Undocumented" , &opt_unique, &opt_unique, 0, |
| 581 | GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 582 | {"update_rows" , 'u', "Undocumented" , &update_count, |
| 583 | &update_count, 0, GET_UINT, REQUIRED_ARG, 1000, 0, 0, 0, 0, 0}, |
| 584 | {"verbose" , 'v', "Be more verbose" , &verbose, &verbose, 0, |
| 585 | GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 586 | {"version" , 'V', "Print version number and exit" , |
| 587 | 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 588 | { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} |
| 589 | }; |
| 590 | |
| 591 | |
| 592 | static my_bool |
| 593 | get_one_option(int optid, const struct my_option *opt __attribute__((unused)), |
| 594 | char *argument __attribute__((unused))) |
| 595 | { |
| 596 | switch(optid) { |
| 597 | case 'a': |
| 598 | key_type= HA_KEYTYPE_TEXT; |
| 599 | break; |
| 600 | case 'c': |
| 601 | create_flag|= HA_CREATE_CHECKSUM; |
| 602 | break; |
| 603 | case 'R': /* Length of record pointer */ |
| 604 | if (rec_pointer_size > 3) |
| 605 | rec_pointer_size=0; |
| 606 | break; |
| 607 | case 'P': |
| 608 | pack_keys= HA_PACK_KEY; /* Use prefix compression */ |
| 609 | break; |
| 610 | case 'B': |
| 611 | pack_keys= HA_BINARY_PACK_KEY; /* Use binary compression */ |
| 612 | break; |
| 613 | case 'S': |
| 614 | if (key_field == FIELD_VARCHAR) |
| 615 | { |
| 616 | create_flag=0; /* Static sized varchar */ |
| 617 | } |
| 618 | else if (key_field != FIELD_BLOB) |
| 619 | { |
| 620 | key_field=FIELD_NORMAL; /* static-size record */ |
| 621 | extra_field=FIELD_NORMAL; |
| 622 | } |
| 623 | break; |
| 624 | case 'p': |
| 625 | pack_keys=HA_PACK_KEY; /* Use prefix + space packing */ |
| 626 | pack_seg=HA_SPACE_PACK; |
| 627 | key_type=HA_KEYTYPE_TEXT; |
| 628 | break; |
| 629 | case 'm': |
| 630 | unique_key=0; |
| 631 | break; |
| 632 | case 'b': |
| 633 | key_field=FIELD_BLOB; /* blob key */ |
| 634 | extra_field= FIELD_BLOB; |
| 635 | pack_seg|= HA_BLOB_PART; |
| 636 | key_type= HA_KEYTYPE_VARTEXT1; |
| 637 | break; |
| 638 | case 'k': |
| 639 | if (key_length < 4 || key_length > HA_MAX_KEY_LENGTH) |
| 640 | { |
| 641 | fprintf(stderr,"Wrong key length\n" ); |
| 642 | exit(1); |
| 643 | } |
| 644 | break; |
| 645 | case 'w': |
| 646 | key_field=FIELD_VARCHAR; /* varchar keys */ |
| 647 | extra_field= FIELD_VARCHAR; |
| 648 | key_type= HA_KEYTYPE_VARTEXT1; |
| 649 | pack_seg|= HA_VAR_LENGTH_PART; |
| 650 | create_flag|= HA_PACK_RECORD; |
| 651 | break; |
| 652 | case 'K': /* Use key cacheing */ |
| 653 | key_cacheing=1; |
| 654 | break; |
| 655 | case 'V': |
| 656 | printf("test1 Ver 1.2 \n" ); |
| 657 | exit(0); |
| 658 | case '#': |
| 659 | DBUG_PUSH (argument); |
| 660 | break; |
| 661 | case '?': |
| 662 | usage(); |
| 663 | exit(1); |
| 664 | } |
| 665 | return 0; |
| 666 | } |
| 667 | |
| 668 | |
| 669 | /* Read options */ |
| 670 | |
| 671 | static void get_options(int argc, char *argv[]) |
| 672 | { |
| 673 | int ho_error; |
| 674 | |
| 675 | if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option))) |
| 676 | exit(ho_error); |
| 677 | |
| 678 | return; |
| 679 | } /* get options */ |
| 680 | |
| 681 | |
| 682 | static void usage() |
| 683 | { |
| 684 | printf("Usage: %s [options]\n\n" , my_progname); |
| 685 | my_print_help(my_long_options); |
| 686 | my_print_variables(my_long_options); |
| 687 | } |
| 688 | |
| 689 | #include "mi_extrafunc.h" |
| 690 | |