static zip_int64_t buffer_read(buffer_t *buffer, zip_uint8_t *data, zip_uint64_t length, zip_error_t *error) { zip_uint64_t n, i, fragment_offset; length = MY_MIN(length, buffer->size - buffer->offset); if (length == 0) { return 0; } if (length > ZIP_INT64_MAX) { return -1; } i = buffer->offset / buffer->fragment_size; fragment_offset = buffer->offset % buffer->fragment_size; n = 0; while (n < length) { zip_uint64_t left = MY_MIN(length - n, buffer->fragment_size - fragment_offset); if (buffer->fragment[i]) { memcpy(data + n, buffer->fragment[i] + fragment_offset, left); } else { memset(data + n, 0, left); } n += left; i++; fragment_offset = 0; } buffer->offset += n; return (zip_int64_t)n; }
void CHRBLK::SetValue(char *sp, uint len, int n) { char *p = Chrp + n * Long; #if defined(_DEBUG) if (Check && (signed)len > Long) { PGLOBAL& g = Global; strcpy(g->Message, MSG(SET_STR_TRUNC)); longjmp(g->jumper[g->jump_level], Type); } // endif Check #endif // _DEBUG if (sp) memcpy(p, sp, MY_MIN((unsigned)Long, len)); if (Blanks) { // Suppress eventual ending zero and right fill with blanks for (register int i = len; i < Long; i++) p[i] = ' '; } else if ((signed)len < Long) p[len] = 0; SetNull(n, false); } // end of SetValue
size_t my_strnxfrm_simple(const CHARSET_INFO *cs, uchar *dst, size_t dstlen, uint nweights, const uchar *src, size_t srclen, uint flags) { uchar *map= cs->sort_order; uchar *d0= dst; uint frmlen; if ((frmlen= MY_MIN(dstlen, nweights)) > srclen) frmlen= srclen; if (dst != src) { const uchar *end; for (end= src + frmlen; src < end;) *dst++= map[*src++]; } else { const uchar *end; for (end= dst + frmlen; dst < end; dst++) *dst= map[(uchar) *dst]; } return my_strxfrm_pad_desc_and_reverse(cs, d0, dst, d0 + dstlen, nweights - frmlen, flags, 0); }
/** Access the pages of this process through /proc/self/task/<tid>/mem in order to safely print the contents of a memory address range. @param addr The address at the start of the memory region. @param max_len The length of the memory region. @return Zero on success. */ static int safe_print_str(const char *addr, int max_len) { int fd; pid_t tid; off_t offset; ssize_t nbytes= 0; size_t total, count; char buf[256]; tid= (pid_t) syscall(SYS_gettid); sprintf(buf, "/proc/self/task/%d/mem", tid); if ((fd= open(buf, O_RDONLY)) < 0) return -1; /* Ensure that off_t can hold a pointer. */ compile_time_assert(sizeof(off_t) >= sizeof(intptr)); total= max_len; offset= (intptr) addr; /* Read up to the maximum number of bytes. */ while (total) { count= MY_MIN(sizeof(buf), total); if ((nbytes= pread(fd, buf, count, offset)) < 0) { /* Just in case... */ if (errno == EINTR) continue; else break; } /* Advance offset into memory. */ total-= nbytes; offset+= nbytes; addr+= nbytes; /* Output the printable characters. */ print_buffer(buf, nbytes); /* Break if less than requested... */ if ((count - nbytes)) break; } /* Output a new line if something was printed. */ if (total != (size_t) max_len) my_safe_printf_stderr("%s", "\n"); if (nbytes == -1) my_safe_printf_stderr("Can't read from address %p\n", addr); close(fd); return 0; }
size_t my_strnxfrm_simple(const CHARSET_INFO *cs, uchar *dst, size_t dstlen, uint nweights, const uchar *src, size_t srclen, uint flags) { const uchar *map= cs->sort_order; uchar *d0= dst; const uchar *end; const uchar *remainder; size_t frmlen; if ((frmlen= MY_MIN(dstlen, nweights)) > srclen) frmlen= srclen; end= src + frmlen; // Do the first few bytes. remainder= src + (frmlen % 8); for (; src < remainder;) *dst++= map[*src++]; // Unroll loop for rest of string. for (; src < end;) { *dst++= map[*src++]; *dst++= map[*src++]; *dst++= map[*src++]; *dst++= map[*src++]; *dst++= map[*src++]; *dst++= map[*src++]; *dst++= map[*src++]; *dst++= map[*src++]; } return my_strxfrm_pad_desc_and_reverse(cs, d0, dst, d0 + dstlen, (uint)(nweights - frmlen), flags, 0); }
int main(int argc, char** argv) { char* srcFileName1; char* srcFileName2; char* dstFileName; GDALDataset* srcDS1, *srcDS2; GDALDataset* dstDS; if(argc != 4) error("Usage: prog infile1 infile2 outfile"); srcFileName1 = argv[1]; srcFileName2 = argv[2]; dstFileName = argv[3]; GDALAllRegister(); srcDS1 = (GDALDataset*) GDALOpen( srcFileName1, GA_ReadOnly ); srcDS2 = (GDALDataset*) GDALOpen( srcFileName2, GA_ReadOnly ); if(srcDS1 == NULL || srcDS2 == NULL) error("Could not open source dataset"); printf("Got image %d x %d x %d\n", srcDS1->GetRasterXSize(), srcDS1->GetRasterYSize(), srcDS1->GetRasterCount() ); printf("Got image %d x %d x %d\n", srcDS2->GetRasterXSize(), srcDS2->GetRasterYSize(), srcDS2->GetRasterCount() ); if((srcDS1->GetRasterXSize() != srcDS2->GetRasterXSize()) || (srcDS1->GetRasterYSize() != srcDS2->GetRasterYSize()) || (srcDS1->GetRasterCount() != srcDS2->GetRasterCount())) fprintf(stderr, "Warning: Source dataset geometries should match!\n"); int x_size, y_size, n_bands; x_size = MY_MAX(srcDS1->GetRasterXSize(), srcDS2->GetRasterXSize()); y_size = MY_MAX(srcDS1->GetRasterYSize(), srcDS2->GetRasterYSize()); n_bands = MY_MIN(srcDS1->GetRasterCount(), srcDS2->GetRasterCount()); dstDS = CreateOutputDataset(dstFileName, x_size, y_size, n_bands ); if(dstDS == NULL) error("Could not create destination dataset"); CalcFFT(srcDS1, srcDS2, dstDS); delete srcDS1; delete srcDS2; delete dstDS; return 0; }
static void init_block(HP_BLOCK *block, uint reclength, ulong min_records, ulong max_records) { uint i,recbuffer,records_in_block; /* If not min_records and max_records are given, optimize for 1000 rows */ if (!min_records) min_records= MY_MIN(1000, max_records); if (!max_records) max_records= MY_MAX(min_records, 1000); /* We don't want too few records_in_block as otherwise the overhead of of the HP_PTRS block will be too notable */ records_in_block= MY_MAX(1000, min_records); records_in_block= MY_MIN(records_in_block, max_records); /* If big max_records is given, allocate bigger blocks */ records_in_block= MY_MAX(records_in_block, max_records / 10); /* We don't want too few blocks per row either */ if (records_in_block < 10) records_in_block= 10; recbuffer= (uint) (reclength + sizeof(uchar**) - 1) & ~(sizeof(uchar**) - 1); /* Don't allocate more than my_default_record_cache_size per level. The + 1 is there to ensure that we get at least 1 row per level (for the exceptional case of very long rows) */ if (records_in_block*recbuffer > (my_default_record_cache_size-sizeof(HP_PTRS)*HP_MAX_LEVELS)) records_in_block= (my_default_record_cache_size - sizeof(HP_PTRS) * HP_MAX_LEVELS) / recbuffer + 1; block->records_in_block= records_in_block; block->recbuffer= recbuffer; block->last_allocated= 0L; for (i= 0; i <= HP_MAX_LEVELS; i++) block->level_info[i].records_under_level= (!i ? 1 : i == 1 ? records_in_block : HP_PTRS_IN_NOD * block->level_info[i - 1].records_under_level); }
static char *process_int_arg(char *to, char *end, size_t length, longlong par, char arg_type, uint print_type) { size_t res_length, to_length; char *store_start= to, *store_end; char buff[32]; if ((to_length= (size_t) (end-to)) < 16 || length) store_start= buff; if (arg_type == 'd' || arg_type == 'i') store_end= longlong10_to_str(par, store_start, -10); else if (arg_type == 'u') store_end= longlong10_to_str(par, store_start, 10); else if (arg_type == 'p') { store_start[0]= '0'; store_start[1]= 'x'; store_end= ll2str(par, store_start + 2, 16, 0); } else if (arg_type == 'o') { store_end= ll2str(par, store_start, 8, 0); } else { DBUG_ASSERT(arg_type == 'X' || arg_type =='x'); store_end= ll2str(par, store_start, 16, (arg_type == 'X')); } if ((res_length= (size_t) (store_end - store_start)) > to_length) return to; /* num doesn't fit in output */ /* If %#d syntax was used, we have to pre-zero/pre-space the string */ if (store_start == buff) { length= MY_MIN(length, to_length); if (res_length < length) { size_t diff= (length- res_length); memset(to, (print_type & PREZERO_ARG) ? '0' : ' ', diff); if (arg_type == 'p' && print_type & PREZERO_ARG) { if (diff > 1) to[1]= 'x'; else store_start[0]= 'x'; store_start[1]= '0'; } to+= diff; } memmove(to, store_start, res_length); } to+= res_length; return to; }
static void print_c(char *data, unsigned int min, unsigned int max) { size_t len = strlen(data); if(min >= len) return; len = MY_MIN(max-min, len-min); print_data_n(data+min, len); }
uint32 my_convert(char *to, uint32 to_length, const CHARSET_INFO *to_cs, const char *from, uint32 from_length, const CHARSET_INFO *from_cs, uint *errors) { uint32 length, length2; /* If any of the character sets is not ASCII compatible, immediately switch to slow mb_wc->wc_mb method. */ if ((to_cs->state | from_cs->state) & MY_CS_NONASCII) return my_convert_internal(to, to_length, to_cs, from, from_length, from_cs, errors); length= length2= MY_MIN(to_length, from_length); #if defined(__i386__) /* Special loop for i386, it allows to refer to a non-aligned memory block as UINT32, which makes it possible to copy four bytes at once. This gives about 10% performance improvement comparing to byte-by-byte loop. */ for ( ; length >= 4; length-= 4, from+= 4, to+= 4) { if ((*(uint32*)from) & 0x80808080) break; *((uint32*) to)= *((const uint32*) from); } #endif /* __i386__ */ for (; ; *to++= *from++, length--) { if (!length) { *errors= 0; return length2; } if (*((unsigned char*) from) > 0x7F) /* A non-ASCII character */ { uint32 copied_length= length2 - length; to_length-= copied_length; from_length-= copied_length; return copied_length + my_convert_internal(to, to_length, to_cs, from, from_length, from_cs, errors); } } DBUG_ASSERT(FALSE); // Should never get to here return 0; // Make compiler happy }
PVOID NTAPI HookRtlReAllocateHeap(HANDLE HeapBase, ULONG Flags, PVOID Memory, SIZE_T Bytes) { PVOID NewMemory; NewMemory = HookRtlAllocateHeap(HeapBase, Flags, Bytes); Bytes = MY_MIN(((PULONG_PTR)Memory)[-1], Bytes); CopyMemory(NewMemory, Memory, Bytes); HookRtlFreeHeap(HeapBase, Flags, Memory); return NewMemory; }
int main(int argc, char **argv) { int error,i,first; ulong total_count,total_error,total_recover; MY_INIT(argv[0]); memset(&main_thread_keycache_var, 0, sizeof(st_keycache_thread_var)); mysql_cond_init(PSI_NOT_INSTRUMENTED, &main_thread_keycache_var.suspend); log_filename=myisam_log_filename; get_options(&argc,&argv); /* Number of MyISAM files we can have open at one time */ max_files= (my_set_max_open_files(MY_MIN(max_files, 8)) - 6) / 2; if (update) printf("Trying to %s MyISAM files according to log '%s'\n", (recover ? "recover" : "update"),log_filename); error= examine_log(log_filename,argv); if (update && ! error) puts("Tables updated successfully"); total_count=total_error=total_recover=0; for (i=first=0 ; command_name[i] ; i++) { if (com_count[i][0]) { if (!first++) { if (verbose || update) puts(""); puts("Commands Used count Errors Recover errors"); } printf("%-12s%9ld%10ld%17ld\n",command_name[i],com_count[i][0], com_count[i][1],com_count[i][2]); total_count+=com_count[i][0]; total_error+=com_count[i][1]; total_recover+=com_count[i][2]; } } if (total_count) printf("%-12s%9ld%10ld%17ld\n","Total",total_count,total_error, total_recover); if (re_open_count) printf("Had to do %d re-open because of too few possibly open files\n", re_open_count); (void) mi_panic(HA_PANIC_CLOSE); my_free_open_file_info(); my_end(test_info ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR); mysql_cond_destroy(&main_thread_keycache_var.suspend); exit(error); return 0; /* No compiler warning */ } /* main */
int cmpCIN(const QString & sz1, const QString & sz2, unsigned int uLen) { if(uLen == 0) { // assume equal return 0; } unsigned int u1 = MY_MIN(uLen,(unsigned)sz1.length()); unsigned int u2 = MY_MIN(u1,(unsigned)sz2.length()); // FIXME: THIS IS NOT OK const QChar * pC1 = sz1.unicode(); const QChar * pC2 = sz2.unicode(); const QChar * pC1e = pC1 + u2; if(!pC1) { if(!pC2) { return 0; } return -1; } if(!pC2) { return 1; } int iDiff = 0; while((pC1 < pC1e) && !(iDiff = (pC1->toLower().unicode() - pC2->toLower().unicode()))) { pC1++; pC2++; } return iDiff; }
static char *process_dbl_arg(char *to, char *end, size_t width, double par, char arg_type) { if (width == SIZE_T_MAX) width= FLT_DIG; /* width not set, use default */ else if (width >= NOT_FIXED_DEC) width= NOT_FIXED_DEC - 1; /* max.precision for my_fcvt() */ width= MY_MIN(width, (size_t)(end-to) - 1); if (arg_type == 'f') to+= my_fcvt(par, (int)width , to, NULL); else to+= my_gcvt(par, MY_GCVT_ARG_DOUBLE, (int) width , to, NULL); return to; }
int my_strnncollsp_simple(const CHARSET_INFO *cs, const uchar *a, size_t a_length, const uchar *b, size_t b_length, my_bool diff_if_only_endspace_difference) { const uchar *map= cs->sort_order, *end; size_t length; int res; #ifndef VARCHAR_WITH_DIFF_ENDSPACE_ARE_DIFFERENT_FOR_UNIQUE diff_if_only_endspace_difference= 0; #endif end= a + (length= MY_MIN(a_length, b_length)); while (a < end) { if (map[*a++] != map[*b++]) return ((int) map[a[-1]] - (int) map[b[-1]]); } res= 0; if (a_length != b_length) { int swap= 1; if (diff_if_only_endspace_difference) res= 1; /* Assume 'a' is bigger */ /* Check the next not space character of the longer key. If it's < ' ', then it's smaller than the other key. */ if (a_length < b_length) { /* put shorter key in s */ a_length= b_length; a= b; swap= -1; /* swap sign of result */ res= -res; } for (end= a + a_length-length; a < end ; a++) { if (map[*a] != map[' ']) return (map[*a] < map[' ']) ? -swap : swap; } } return res; }
void transliterate(QString & szSrc, const QString & szToFind, const QString & szReplacement) { int i = 0; int il = MY_MIN(szToFind.length(),szReplacement.length()); while(i < il) { int k = 0; int kl = szSrc.length(); while(k < kl) { if(szSrc[k] == szToFind[i]) { szSrc[k] = szReplacement[i]; } k++; } i++; } }
void hp_make_key(HP_KEYDEF *keydef, uchar *key, const uchar *rec) { HA_KEYSEG *seg,*endseg; for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++) { const CHARSET_INFO *cs= seg->charset; uint char_length= seg->length; const uchar *pos= rec + seg->start; if (seg->null_bit) *key++= MY_TEST(rec[seg->null_pos] & seg->null_bit); if (seg->flag & HA_BLOB_PART) { uint tmp_length= hp_calc_blob_length(seg->bit_start, pos); uint length= MY_MIN(seg->length, tmp_length); memcpy(&pos, rec + seg->bit_start, sizeof(char *)); if (cs->mbmaxlen > 1) { char_length= my_charpos(cs, pos, pos + seg->length, char_length / cs->mbmaxlen); set_if_smaller(char_length, length); /* QQ: ok to remove? */ } store_key_length_inc(key, char_length); } else { if (cs->mbmaxlen > 1) { char_length= my_charpos(cs, pos, pos + seg->length, char_length / cs->mbmaxlen); set_if_smaller(char_length, seg->length); /* QQ: ok to remove? */ } if (seg->type == HA_KEYTYPE_VARTEXT1) char_length+= seg->bit_start; /* Copy also length */ } memcpy(key, pos, (size_t) char_length); key+= char_length; } }
static int compare_bin(const uchar *a, uint a_length, const uchar *b, uint b_length, my_bool part_key, my_bool skip_end_space) { uint length= MY_MIN(a_length,b_length); const uchar *end= a+ length; int flag; while (a < end) if ((flag= (int) *a++ - (int) *b++)) return flag; if (part_key && b_length < a_length) return 0; if (skip_end_space && a_length != b_length) { int swap= 1; /* We are using space compression. We have to check if longer key has next character < ' ', in which case it's less than the shorter key that has an implicite space afterwards. This code is identical to the one in strings/ctype-simple.c:my_strnncollsp_simple */ if (a_length < b_length) { /* put shorter key in a */ a_length= b_length; a= b; swap= -1; /* swap sign of result */ } for (end= a + a_length-length; a < end ; a++) { if (*a != ' ') return (*a < ' ') ? -swap : swap; } return 0; } return (int) (a_length-b_length); }
/* callback for _lf_dynarray_iterate: scan all pins of all threads and accumulate all pins */ static int harvest_pins(LF_PINS *el, struct st_harvester *hv) { int i; LF_PINS *el_end= el + MY_MIN(hv->npins, LF_DYNARRAY_LEVEL_LENGTH); for (; el < el_end; el++) { for (i= 0; i < LF_PINBOX_PINS; i++) { void *p= el->pin[i]; if (p) *hv->granary++= p; } } /* hv->npins may become negative below, but it means that we're on the last dynarray page and harvest_pins() won't be called again. We don't bother to make hv->npins() correct (that is 0) in this case. */ hv->npins-= LF_DYNARRAY_LEVEL_LENGTH; return 0; }
static int extract_variable_from_show(DYNAMIC_STRING* ds, char* value) { char *value_start, *value_end; size_t len; /* The query returns "datadir\t<datadir>\n", skip past the tab */ if ((value_start= strchr(ds->str, '\t')) == NULL) return 1; /* Unexpected result */ value_start++; /* Don't copy the ending newline */ if ((value_end= strchr(value_start, '\n')) == NULL) return 1; /* Unexpected result */ len= (size_t) MY_MIN(FN_REFLEN, value_end-value_start); strncpy(value, value_start, len); value[len]= '\0'; return 0; }
void ARRAY::Print(PGLOBAL g, FILE *f, uint n) { char m[64]; int lim = MY_MIN(Nval,10); memset(m, ' ', n); // Make margin string m[n] = '\0'; fprintf(f, "%sARRAY: type=%d\n", m, Type); memset(m, ' ', n + 2); // Make margin string m[n] = '\0'; if (Type != TYPE_LIST) { fprintf(f, "%sblock=%p numval=%d\n", m, Valblk->GetMemp(), Nval); if (Vblp) for (int i = 0; i < lim; i++) { Value->SetValue_pvblk(Vblp, i); Value->Print(g, f, n+4); } // endfor i } else fprintf(f, "%sVALLST: numval=%d\n", m, Nval); } // end of Print
int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, uint columns, MI_COLUMNDEF *recinfo, uint uniques, MI_UNIQUEDEF *uniquedefs, MI_CREATE_INFO *ci,uint flags) { register uint i,j; File UNINIT_VAR(dfile), UNINIT_VAR(file); int errpos,save_errno, create_mode= O_RDWR | O_TRUNC; myf create_flag; uint fields,length,max_key_length,packed,pointer,real_length_diff, key_length,info_length,key_segs,options,min_key_length_skip, base_pos,long_varchar_count,varchar_length, max_key_block_length,unique_key_parts,fulltext_keys,offset; uint aligned_key_start, block_length; uint internal_table= flags & HA_CREATE_INTERNAL_TABLE; ulong reclength, real_reclength,min_pack_length; char filename[FN_REFLEN],linkname[FN_REFLEN], *linkname_ptr; ulong pack_reclength; ulonglong tot_length,max_rows, tmp; enum en_fieldtype type; MYISAM_SHARE share; MI_KEYDEF *keydef,tmp_keydef; MI_UNIQUEDEF *uniquedef; HA_KEYSEG *keyseg,tmp_keyseg; MI_COLUMNDEF *rec; ulong *rec_per_key_part; my_off_t key_root[HA_MAX_POSSIBLE_KEY],key_del[MI_MAX_KEY_BLOCK_SIZE]; MI_CREATE_INFO tmp_create_info; DBUG_ENTER("mi_create"); DBUG_PRINT("enter", ("keys: %u columns: %u uniques: %u flags: %u", keys, columns, uniques, flags)); if (!ci) { memset(&tmp_create_info, 0, sizeof(tmp_create_info)); ci=&tmp_create_info; } if (keys + uniques > MI_MAX_KEY || columns == 0) { DBUG_RETURN(my_errno=HA_WRONG_CREATE_OPTION); } errpos=0; options=0; memset(&share, 0, sizeof(share)); if (flags & HA_DONT_TOUCH_DATA) { if (!(ci->old_options & HA_OPTION_TEMP_COMPRESS_RECORD)) options=ci->old_options & (HA_OPTION_COMPRESS_RECORD | HA_OPTION_PACK_RECORD | HA_OPTION_READ_ONLY_DATA | HA_OPTION_CHECKSUM | HA_OPTION_TMP_TABLE | HA_OPTION_DELAY_KEY_WRITE); else options=ci->old_options & (HA_OPTION_CHECKSUM | HA_OPTION_TMP_TABLE | HA_OPTION_DELAY_KEY_WRITE); } if (ci->reloc_rows > ci->max_rows) ci->reloc_rows=ci->max_rows; /* Check if wrong parameter */ if (!(rec_per_key_part= (ulong*) my_malloc((keys + uniques)*MI_MAX_KEY_SEG*sizeof(long), MYF(MY_WME | MY_ZEROFILL)))) DBUG_RETURN(my_errno); /* Start by checking fields and field-types used */ reclength=varchar_length=long_varchar_count=packed= min_pack_length=pack_reclength=0; for (rec=recinfo, fields=0 ; fields != columns ; rec++,fields++) { reclength+=rec->length; if ((type=(enum en_fieldtype) rec->type) != FIELD_NORMAL && type != FIELD_CHECK) { packed++; if (type == FIELD_BLOB) { share.base.blobs++; if (pack_reclength != INT_MAX32) { if (rec->length == 4+portable_sizeof_char_ptr) pack_reclength= INT_MAX32; else pack_reclength+=(1 << ((rec->length-portable_sizeof_char_ptr)*8)); /* Max blob length */ } } else if (type == FIELD_SKIP_PRESPACE || type == FIELD_SKIP_ENDSPACE) { if (pack_reclength != INT_MAX32) pack_reclength+= rec->length > 255 ? 2 : 1; min_pack_length++; } else if (type == FIELD_VARCHAR) { varchar_length+= rec->length-1; /* Used for min_pack_length */ packed--; pack_reclength++; min_pack_length++; /* We must test for 257 as length includes pack-length */ if (test(rec->length >= 257)) { long_varchar_count++; pack_reclength+= 2; /* May be packed on 3 bytes */ } } else if (type != FIELD_SKIP_ZERO) { min_pack_length+=rec->length; packed--; /* Not a pack record type */ } } else /* FIELD_NORMAL */ min_pack_length+=rec->length; } if ((packed & 7) == 1) { /* Bad packing, try to remove a zero-field */ while (rec != recinfo) { rec--; if (rec->type == (int) FIELD_SKIP_ZERO && rec->length == 1) { /* NOTE1: here we change a field type FIELD_SKIP_ZERO -> FIELD_NORMAL */ rec->type=(int) FIELD_NORMAL; packed--; min_pack_length++; break; } } } if (packed || (flags & HA_PACK_RECORD)) options|=HA_OPTION_PACK_RECORD; /* Must use packed records */ /* We can't use checksum with static length rows */ if (!(options & HA_OPTION_PACK_RECORD)) options&= ~HA_OPTION_CHECKSUM; if (!(options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD))) min_pack_length+= varchar_length; if (flags & HA_CREATE_TMP_TABLE) { options|= HA_OPTION_TMP_TABLE; create_mode|= O_EXCL | O_NOFOLLOW; } if (flags & HA_CREATE_CHECKSUM || (options & HA_OPTION_CHECKSUM)) { options|= HA_OPTION_CHECKSUM; min_pack_length++; } if (flags & HA_CREATE_DELAY_KEY_WRITE) options|= HA_OPTION_DELAY_KEY_WRITE; if (flags & HA_CREATE_RELIES_ON_SQL_LAYER) options|= HA_OPTION_RELIES_ON_SQL_LAYER; packed=(packed+7)/8; if (pack_reclength != INT_MAX32) pack_reclength+= reclength+packed + test(test_all_bits(options, HA_OPTION_CHECKSUM | HA_OPTION_PACK_RECORD)); min_pack_length+=packed; if (!ci->data_file_length && ci->max_rows) { if (pack_reclength == INT_MAX32 || (~(ulonglong) 0)/ci->max_rows < (ulonglong) pack_reclength) ci->data_file_length= ~(ulonglong) 0; else ci->data_file_length=(ulonglong) ci->max_rows*pack_reclength; } else if (!ci->max_rows) ci->max_rows=(ha_rows) (ci->data_file_length/(min_pack_length + ((options & HA_OPTION_PACK_RECORD) ? 3 : 0))); if (options & (HA_OPTION_COMPRESS_RECORD | HA_OPTION_PACK_RECORD)) pointer=mi_get_pointer_length(ci->data_file_length,myisam_data_pointer_size); else pointer=mi_get_pointer_length(ci->max_rows,myisam_data_pointer_size); if (!(max_rows=(ulonglong) ci->max_rows)) max_rows= ((((ulonglong) 1 << (pointer*8)) -1) / min_pack_length); real_reclength=reclength; if (!(options & (HA_OPTION_COMPRESS_RECORD | HA_OPTION_PACK_RECORD))) { if (reclength <= pointer) reclength=pointer+1; /* reserve place for delete link */ } else reclength+= long_varchar_count; /* We need space for varchar! */ max_key_length=0; tot_length=0 ; key_segs=0; fulltext_keys=0; max_key_block_length=0; share.state.rec_per_key_part=rec_per_key_part; share.state.key_root=key_root; share.state.key_del=key_del; if (uniques) { max_key_block_length= myisam_block_size; max_key_length= MI_UNIQUE_HASH_LENGTH + pointer; } for (i=0, keydef=keydefs ; i < keys ; i++ , keydef++) { share.state.key_root[i]= HA_OFFSET_ERROR; min_key_length_skip=length=real_length_diff=0; key_length=pointer; if (keydef->flag & HA_SPATIAL) { #ifdef HAVE_SPATIAL /* BAR TODO to support 3D and more dimensions in the future */ uint sp_segs=SPDIMS*2; keydef->flag=HA_SPATIAL; if (flags & HA_DONT_TOUCH_DATA) { /* called by myisamchk - i.e. table structure was taken from MYI file and SPATIAL key *does have* additional sp_segs keysegs. keydef->seg here points right at the GEOMETRY segment, so we only need to decrease keydef->keysegs. (see recreate_table() in mi_check.c) */ keydef->keysegs-=sp_segs-1; } for (j=0, keyseg=keydef->seg ; (int) j < keydef->keysegs ; j++, keyseg++) { if (keyseg->type != HA_KEYTYPE_BINARY && keyseg->type != HA_KEYTYPE_VARBINARY1 && keyseg->type != HA_KEYTYPE_VARBINARY2) { my_errno=HA_WRONG_CREATE_OPTION; goto err_no_lock; } } keydef->keysegs+=sp_segs; key_length+=SPLEN*sp_segs; length++; /* At least one length byte */ min_key_length_skip+=SPLEN*2*SPDIMS; #else my_errno= HA_ERR_UNSUPPORTED; goto err_no_lock; #endif /*HAVE_SPATIAL*/ } else if (keydef->flag & HA_FULLTEXT) { keydef->flag=HA_FULLTEXT | HA_PACK_KEY | HA_VAR_LENGTH_KEY; options|=HA_OPTION_PACK_KEYS; /* Using packed keys */ for (j=0, keyseg=keydef->seg ; (int) j < keydef->keysegs ; j++, keyseg++) { if (keyseg->type != HA_KEYTYPE_TEXT && keyseg->type != HA_KEYTYPE_VARTEXT1 && keyseg->type != HA_KEYTYPE_VARTEXT2) { my_errno=HA_WRONG_CREATE_OPTION; goto err_no_lock; } if (!(keyseg->flag & HA_BLOB_PART) && (keyseg->type == HA_KEYTYPE_VARTEXT1 || keyseg->type == HA_KEYTYPE_VARTEXT2)) { /* Make a flag that this is a VARCHAR */ keyseg->flag|= HA_VAR_LENGTH_PART; /* Store in bit_start number of bytes used to pack the length */ keyseg->bit_start= ((keyseg->type == HA_KEYTYPE_VARTEXT1)? 1 : 2); } } fulltext_keys++; key_length+= HA_FT_MAXBYTELEN+HA_FT_WLEN; length++; /* At least one length byte */ min_key_length_skip+=HA_FT_MAXBYTELEN; real_length_diff=HA_FT_MAXBYTELEN-FT_MAX_WORD_LEN_FOR_SORT; } else { /* Test if prefix compression */ if (keydef->flag & HA_PACK_KEY) { /* Can't use space_compression on number keys */ if ((keydef->seg[0].flag & HA_SPACE_PACK) && keydef->seg[0].type == (int) HA_KEYTYPE_NUM) keydef->seg[0].flag&= ~HA_SPACE_PACK; /* Only use HA_PACK_KEY when first segment is a variable length key */ if (!(keydef->seg[0].flag & (HA_SPACE_PACK | HA_BLOB_PART | HA_VAR_LENGTH_PART))) { /* pack relative to previous key */ keydef->flag&= ~HA_PACK_KEY; keydef->flag|= HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY; } else { keydef->seg[0].flag|=HA_PACK_KEY; /* for easyer intern test */ keydef->flag|=HA_VAR_LENGTH_KEY; options|=HA_OPTION_PACK_KEYS; /* Using packed keys */ } } if (keydef->flag & HA_BINARY_PACK_KEY) options|=HA_OPTION_PACK_KEYS; /* Using packed keys */ if (keydef->flag & HA_AUTO_KEY && ci->with_auto_increment) share.base.auto_key=i+1; for (j=0, keyseg=keydef->seg ; j < keydef->keysegs ; j++, keyseg++) { /* numbers are stored with high by first to make compression easier */ switch (keyseg->type) { case HA_KEYTYPE_SHORT_INT: case HA_KEYTYPE_LONG_INT: case HA_KEYTYPE_FLOAT: case HA_KEYTYPE_DOUBLE: case HA_KEYTYPE_USHORT_INT: case HA_KEYTYPE_ULONG_INT: case HA_KEYTYPE_LONGLONG: case HA_KEYTYPE_ULONGLONG: case HA_KEYTYPE_INT24: case HA_KEYTYPE_UINT24: case HA_KEYTYPE_INT8: keyseg->flag|= HA_SWAP_KEY; break; case HA_KEYTYPE_VARTEXT1: case HA_KEYTYPE_VARTEXT2: case HA_KEYTYPE_VARBINARY1: case HA_KEYTYPE_VARBINARY2: if (!(keyseg->flag & HA_BLOB_PART)) { /* Make a flag that this is a VARCHAR */ keyseg->flag|= HA_VAR_LENGTH_PART; /* Store in bit_start number of bytes used to pack the length */ keyseg->bit_start= ((keyseg->type == HA_KEYTYPE_VARTEXT1 || keyseg->type == HA_KEYTYPE_VARBINARY1) ? 1 : 2); } break; default: break; } if (keyseg->flag & HA_SPACE_PACK) { DBUG_ASSERT(!(keyseg->flag & HA_VAR_LENGTH_PART)); keydef->flag |= HA_SPACE_PACK_USED | HA_VAR_LENGTH_KEY; options|=HA_OPTION_PACK_KEYS; /* Using packed keys */ length++; /* At least one length byte */ min_key_length_skip+=keyseg->length; if (keyseg->length >= 255) { /* prefix may be 3 bytes */ min_key_length_skip+=2; length+=2; } } if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART)) { DBUG_ASSERT(!test_all_bits(keyseg->flag, (HA_VAR_LENGTH_PART | HA_BLOB_PART))); keydef->flag|=HA_VAR_LENGTH_KEY; length++; /* At least one length byte */ options|=HA_OPTION_PACK_KEYS; /* Using packed keys */ min_key_length_skip+=keyseg->length; if (keyseg->length >= 255) { /* prefix may be 3 bytes */ min_key_length_skip+=2; length+=2; } } key_length+= keyseg->length; if (keyseg->null_bit) { key_length++; options|=HA_OPTION_PACK_KEYS; keyseg->flag|=HA_NULL_PART; keydef->flag|=HA_VAR_LENGTH_KEY | HA_NULL_PART_KEY; } } } /* if HA_FULLTEXT */ key_segs+=keydef->keysegs; if (keydef->keysegs > MI_MAX_KEY_SEG) { my_errno=HA_WRONG_CREATE_OPTION; goto err_no_lock; } /* key_segs may be 0 in the case when we only want to be able to add on row into the table. This can happen with some DISTINCT queries in MySQL */ if ((keydef->flag & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME && key_segs) share.state.rec_per_key_part[key_segs-1]=1L; length+=key_length; /* Get block length for key, if defined by user */ block_length= (keydef->block_length ? my_round_up_to_next_power(keydef->block_length) : myisam_block_size); block_length= MY_MAX(block_length, MI_MIN_KEY_BLOCK_LENGTH); block_length= MY_MIN(block_length, MI_MAX_KEY_BLOCK_LENGTH); keydef->block_length= (uint16) MI_BLOCK_SIZE(length-real_length_diff, pointer,MI_MAX_KEYPTR_SIZE, block_length); if (keydef->block_length > MI_MAX_KEY_BLOCK_LENGTH || length >= MI_MAX_KEY_BUFF) { my_errno=HA_WRONG_CREATE_OPTION; goto err_no_lock; } set_if_bigger(max_key_block_length,keydef->block_length); keydef->keylength= (uint16) key_length; keydef->minlength= (uint16) (length-min_key_length_skip); keydef->maxlength= (uint16) length; if (length > max_key_length) max_key_length= length; tot_length+= (max_rows/(ulong) (((uint) keydef->block_length-5)/ (length*2)))* (ulong) keydef->block_length; } for (i=max_key_block_length/MI_MIN_KEY_BLOCK_LENGTH ; i-- ; ) key_del[i]=HA_OFFSET_ERROR; unique_key_parts=0; for (i=0, uniquedef=uniquedefs ; i < uniques ; i++ , uniquedef++) { uniquedef->key=keys+i; unique_key_parts+=uniquedef->keysegs; share.state.key_root[keys+i]= HA_OFFSET_ERROR; tot_length+= (max_rows/(ulong) (((uint) myisam_block_size-5)/ ((MI_UNIQUE_HASH_LENGTH + pointer)*2)))* (ulong) myisam_block_size; } keys+=uniques; /* Each unique has 1 key */ key_segs+=uniques; /* Each unique has 1 key seg */ base_pos=(MI_STATE_INFO_SIZE + keys * MI_STATE_KEY_SIZE + max_key_block_length/MI_MIN_KEY_BLOCK_LENGTH* MI_STATE_KEYBLOCK_SIZE+ key_segs*MI_STATE_KEYSEG_SIZE); info_length=base_pos+(uint) (MI_BASE_INFO_SIZE+ keys * MI_KEYDEF_SIZE+ uniques * MI_UNIQUEDEF_SIZE + (key_segs + unique_key_parts)*HA_KEYSEG_SIZE+ columns*MI_COLUMNDEF_SIZE); DBUG_PRINT("info", ("info_length: %u", info_length)); /* There are only 16 bits for the total header length. */ if (info_length > 65535) { my_printf_error(0, "MyISAM table '%s' has too many columns and/or " "indexes and/or unique constraints.", MYF(0), name + dirname_length(name)); my_errno= HA_WRONG_CREATE_OPTION; goto err_no_lock; } bmove(share.state.header.file_version,(uchar*) myisam_file_magic,4); ci->old_options=options| (ci->old_options & HA_OPTION_TEMP_COMPRESS_RECORD ? HA_OPTION_COMPRESS_RECORD | HA_OPTION_TEMP_COMPRESS_RECORD: 0); mi_int2store(share.state.header.options,ci->old_options); mi_int2store(share.state.header.header_length,info_length); mi_int2store(share.state.header.state_info_length,MI_STATE_INFO_SIZE); mi_int2store(share.state.header.base_info_length,MI_BASE_INFO_SIZE); mi_int2store(share.state.header.base_pos,base_pos); share.state.header.language= (ci->language ? ci->language : default_charset_info->number); share.state.header.max_block_size_index= max_key_block_length/MI_MIN_KEY_BLOCK_LENGTH; share.state.dellink = HA_OFFSET_ERROR; share.state.process= (ulong) getpid(); share.state.unique= (ulong) 0; share.state.update_count=(ulong) 0; share.state.version= (ulong) time((time_t*) 0); share.state.sortkey= (ushort) ~0; share.state.auto_increment=ci->auto_increment; share.options=options; share.base.rec_reflength=pointer; /* Get estimate for index file length (this may be wrong for FT keys) */ tmp= (tot_length + max_key_block_length * keys * MI_INDEX_BLOCK_MARGIN) / MI_MIN_KEY_BLOCK_LENGTH; /* use maximum of key_file_length we calculated and key_file_length value we got from MYI file header (see also myisampack.c:save_state) */ share.base.key_reflength= mi_get_pointer_length(MY_MAX(ci->key_file_length, tmp), 3); share.base.keys= share.state.header.keys= keys; share.state.header.uniques= uniques; share.state.header.fulltext_keys= fulltext_keys; mi_int2store(share.state.header.key_parts,key_segs); mi_int2store(share.state.header.unique_key_parts,unique_key_parts); mi_set_all_keys_active(share.state.key_map, keys); aligned_key_start= my_round_up_to_next_power(max_key_block_length ? max_key_block_length : myisam_block_size); share.base.keystart= share.state.state.key_file_length= MY_ALIGN(info_length, aligned_key_start); share.base.max_key_block_length=max_key_block_length; share.base.max_key_length=ALIGN_SIZE(max_key_length+4); share.base.records=ci->max_rows; share.base.reloc= ci->reloc_rows; share.base.reclength=real_reclength; share.base.pack_reclength=reclength+ test(options & HA_OPTION_CHECKSUM); share.base.max_pack_length=pack_reclength; share.base.min_pack_length=min_pack_length; share.base.pack_bits=packed; share.base.fields=fields; share.base.pack_fields=packed; /* max_data_file_length and max_key_file_length are recalculated on open */ if (options & HA_OPTION_TMP_TABLE) share.base.max_data_file_length=(my_off_t) ci->data_file_length; share.base.min_block_length= (share.base.pack_reclength+3 < MI_EXTEND_BLOCK_LENGTH && ! share.base.blobs) ? MY_MAX(share.base.pack_reclength, MI_MIN_BLOCK_LENGTH) : MI_EXTEND_BLOCK_LENGTH; if (! (flags & HA_DONT_TOUCH_DATA)) share.state.create_time= (long) time((time_t*) 0); if (!internal_table) mysql_mutex_lock(&THR_LOCK_myisam); /* NOTE: For test_if_reopen() we need a real path name. Hence we need MY_RETURN_REAL_PATH for every fn_format(filename, ...). */ if (ci->index_file_name) { char *iext= strrchr(ci->index_file_name, '.'); int have_iext= iext && !strcmp(iext, MI_NAME_IEXT); if (options & HA_OPTION_TMP_TABLE) { char *path; /* chop off the table name, tempory tables use generated name */ if ((path= strrchr(ci->index_file_name, FN_LIBCHAR))) *path= '\0'; fn_format(filename, name, ci->index_file_name, MI_NAME_IEXT, MY_REPLACE_DIR | MY_UNPACK_FILENAME | MY_RETURN_REAL_PATH | MY_APPEND_EXT); } else { fn_format(filename, ci->index_file_name, "", MI_NAME_IEXT, MY_UNPACK_FILENAME | MY_RETURN_REAL_PATH | (have_iext ? MY_REPLACE_EXT : MY_APPEND_EXT)); } fn_format(linkname, name, "", MI_NAME_IEXT, MY_UNPACK_FILENAME|MY_APPEND_EXT); linkname_ptr=linkname; /* Don't create the table if the link or file exists to ensure that one doesn't accidently destroy another table. */ create_flag=0; } else { char *iext= strrchr(name, '.'); int have_iext= iext && !strcmp(iext, MI_NAME_IEXT); fn_format(filename, name, "", MI_NAME_IEXT, MY_UNPACK_FILENAME | MY_RETURN_REAL_PATH | (have_iext ? MY_REPLACE_EXT : MY_APPEND_EXT)); linkname_ptr=0; /* Replace the current file */ create_flag=(flags & HA_CREATE_KEEP_FILES) ? 0 : MY_DELETE_OLD; } /* If a MRG_MyISAM table is in use, the mapped MyISAM tables are open, but no entry is made in the table cache for them. A TRUNCATE command checks for the table in the cache only and could be fooled to believe, the table is not open. Pull the emergency brake in this situation. (Bug #8306) NOTE: The filename is compared against unique_file_name of every open table. Hence we need a real path here. */ if (!internal_table && test_if_reopen(filename)) { my_printf_error(0, "MyISAM table '%s' is in use " "(most likely by a MERGE table). Try FLUSH TABLES.", MYF(0), name + dirname_length(name)); my_errno= HA_ERR_TABLE_EXIST; goto err; } if ((file= mysql_file_create_with_symlink(mi_key_file_kfile, linkname_ptr, filename, 0, create_mode, MYF(MY_WME | create_flag))) < 0) goto err; errpos=1; if (!(flags & HA_DONT_TOUCH_DATA)) { { if (ci->data_file_name) { char *dext= strrchr(ci->data_file_name, '.'); int have_dext= dext && !strcmp(dext, MI_NAME_DEXT); if (options & HA_OPTION_TMP_TABLE) { char *path; /* chop off the table name, tempory tables use generated name */ if ((path= strrchr(ci->data_file_name, FN_LIBCHAR))) *path= '\0'; fn_format(filename, name, ci->data_file_name, MI_NAME_DEXT, MY_REPLACE_DIR | MY_UNPACK_FILENAME | MY_APPEND_EXT); } else { fn_format(filename, ci->data_file_name, "", MI_NAME_DEXT, MY_UNPACK_FILENAME | (have_dext ? MY_REPLACE_EXT : MY_APPEND_EXT)); } fn_format(linkname, name, "",MI_NAME_DEXT, MY_UNPACK_FILENAME | MY_APPEND_EXT); linkname_ptr=linkname; create_flag=0; } else { fn_format(filename,name,"", MI_NAME_DEXT, MY_UNPACK_FILENAME | MY_APPEND_EXT); linkname_ptr=0; create_flag=(flags & HA_CREATE_KEEP_FILES) ? 0 : MY_DELETE_OLD; } if ((dfile= mysql_file_create_with_symlink(mi_key_file_dfile, linkname_ptr, filename, 0, create_mode, MYF(MY_WME | create_flag))) < 0) goto err; } errpos=3; } DBUG_PRINT("info", ("write state info and base info")); if (mi_state_info_write(file, &share.state, 2) || mi_base_info_write(file, &share.base)) goto err; #ifndef DBUG_OFF if ((uint) mysql_file_tell(file, MYF(0)) != base_pos + MI_BASE_INFO_SIZE) { uint pos=(uint) mysql_file_tell(file, MYF(0)); DBUG_PRINT("warning",("base_length: %d != used_length: %d", base_pos+ MI_BASE_INFO_SIZE, pos)); } #endif /* Write key and keyseg definitions */ DBUG_PRINT("info", ("write key and keyseg definitions")); for (i=0 ; i < share.base.keys - uniques; i++) { uint sp_segs=(keydefs[i].flag & HA_SPATIAL) ? 2*SPDIMS : 0; if (mi_keydef_write(file, &keydefs[i])) goto err; for (j=0 ; j < keydefs[i].keysegs-sp_segs ; j++) if (mi_keyseg_write(file, &keydefs[i].seg[j])) goto err; #ifdef HAVE_SPATIAL for (j=0 ; j < sp_segs ; j++) { HA_KEYSEG sseg; sseg.type=SPTYPE; sseg.language= 7; /* Binary */ sseg.null_bit=0; sseg.bit_start=0; sseg.bit_end=0; sseg.bit_length= 0; sseg.bit_pos= 0; sseg.length=SPLEN; sseg.null_pos=0; sseg.start=j*SPLEN; sseg.flag= HA_SWAP_KEY; if (mi_keyseg_write(file, &sseg)) goto err; } #endif } /* Create extra keys for unique definitions */ offset= real_reclength - uniques * MI_UNIQUE_HASH_LENGTH; memset(&tmp_keydef, 0, sizeof(tmp_keydef)); memset(&tmp_keyseg, 0, sizeof(tmp_keyseg)); for (i=0; i < uniques ; i++) { tmp_keydef.keysegs=1; tmp_keydef.flag= HA_UNIQUE_CHECK; tmp_keydef.block_length= (uint16)myisam_block_size; tmp_keydef.keylength= MI_UNIQUE_HASH_LENGTH + pointer; tmp_keydef.minlength=tmp_keydef.maxlength=tmp_keydef.keylength; tmp_keyseg.type= MI_UNIQUE_HASH_TYPE; tmp_keyseg.length= MI_UNIQUE_HASH_LENGTH; tmp_keyseg.start= offset; offset+= MI_UNIQUE_HASH_LENGTH; if (mi_keydef_write(file,&tmp_keydef) || mi_keyseg_write(file,(&tmp_keyseg))) goto err; } /* Save unique definition */ DBUG_PRINT("info", ("write unique definitions")); for (i=0 ; i < share.state.header.uniques ; i++) { HA_KEYSEG *keyseg_end; keyseg= uniquedefs[i].seg; if (mi_uniquedef_write(file, &uniquedefs[i])) goto err; for (keyseg= uniquedefs[i].seg, keyseg_end= keyseg+ uniquedefs[i].keysegs; keyseg < keyseg_end; keyseg++) { switch (keyseg->type) { case HA_KEYTYPE_VARTEXT1: case HA_KEYTYPE_VARTEXT2: case HA_KEYTYPE_VARBINARY1: case HA_KEYTYPE_VARBINARY2: if (!(keyseg->flag & HA_BLOB_PART)) { keyseg->flag|= HA_VAR_LENGTH_PART; keyseg->bit_start= ((keyseg->type == HA_KEYTYPE_VARTEXT1 || keyseg->type == HA_KEYTYPE_VARBINARY1) ? 1 : 2); } break; default: break; } if (mi_keyseg_write(file, keyseg)) goto err; } } DBUG_PRINT("info", ("write field definitions")); for (i=0 ; i < share.base.fields ; i++) if (mi_recinfo_write(file, &recinfo[i])) goto err; #ifndef DBUG_OFF if ((uint) mysql_file_tell(file, MYF(0)) != info_length) { uint pos= (uint) mysql_file_tell(file, MYF(0)); DBUG_PRINT("warning",("info_length: %d != used_length: %d", info_length, pos)); } #endif /* Enlarge files */ DBUG_PRINT("info", ("enlarge to keystart: %lu", (ulong) share.base.keystart)); if (mysql_file_chsize(file, (ulong) share.base.keystart, 0, MYF(0))) goto err; if (! (flags & HA_DONT_TOUCH_DATA)) { #ifdef USE_RELOC if (mysql_file_chsize(dfile, share.base.min_pack_length*ci->reloc_rows, 0, MYF(0))) goto err; #endif errpos=2; if (mysql_file_close(dfile, MYF(0))) goto err; } errpos=0; if (!internal_table) mysql_mutex_unlock(&THR_LOCK_myisam); if (mysql_file_close(file, MYF(0))) goto err_no_lock; my_free(rec_per_key_part); DBUG_RETURN(0); err: if (!internal_table) mysql_mutex_unlock(&THR_LOCK_myisam); err_no_lock: save_errno=my_errno; switch (errpos) { case 3: (void) mysql_file_close(dfile, MYF(0)); /* fall through */ case 2: if (! (flags & HA_DONT_TOUCH_DATA)) mysql_file_delete_with_symlink(mi_key_file_dfile, fn_format(filename, name, "", MI_NAME_DEXT, MY_UNPACK_FILENAME | MY_APPEND_EXT), MYF(0)); /* fall through */ case 1: (void) mysql_file_close(file, MYF(0)); if (! (flags & HA_DONT_TOUCH_DATA)) mysql_file_delete_with_symlink(mi_key_file_kfile, fn_format(filename, name, "", MI_NAME_IEXT, MY_UNPACK_FILENAME | MY_APPEND_EXT), MYF(0)); } my_free(rec_per_key_part); DBUG_RETURN(my_errno=save_errno); /* return the fatal errno */ }
char * fn_format(char * to, const char *name, const char *dir, const char *extension, uint flag) { char dev[FN_REFLEN], buff[FN_REFLEN], *pos, *startpos; const char *ext; reg1 size_t length; size_t dev_length; my_bool not_used; DBUG_ENTER("fn_format"); DBUG_ASSERT(name != NULL); DBUG_ASSERT(extension != NULL); DBUG_PRINT("enter",("name: %s dir: %s extension: %s flag: %d", name,dir,extension,flag)); /* Copy and skip directory */ name+=(length=dirname_part(dev, (startpos=(char *) name), &dev_length)); if (length == 0 || (flag & MY_REPLACE_DIR)) { DBUG_ASSERT(dir != NULL); /* Use given directory */ convert_dirname(dev,dir,NullS); /* Fix to this OS */ } else if ((flag & MY_RELATIVE_PATH) && !test_if_hard_path(dev)) { DBUG_ASSERT(dir != NULL); /* Put 'dir' before the given path */ strmake(buff,dev,sizeof(buff)-1); pos=convert_dirname(dev,dir,NullS); strmake(pos,buff,sizeof(buff)-1- (int) (pos-dev)); } if (flag & MY_PACK_FILENAME) pack_dirname(dev,dev); /* Put in ./.. and ~/.. */ if (flag & MY_UNPACK_FILENAME) (void) unpack_dirname(dev, dev, ¬_used); /* Replace ~/.. with dir */ if (!(flag & MY_APPEND_EXT) && (pos= (char*) strchr(name,FN_EXTCHAR)) != NullS) { if ((flag & MY_REPLACE_EXT) == 0) /* If we should keep old ext */ { length=strlength(name); /* Use old extension */ ext = ""; } else { length= (size_t) (pos-(char*) name); /* Change extension */ ext= extension; } } else { length=strlength(name); /* No ext, use the now one */ ext=extension; } if (strlen(dev)+length+strlen(ext) >= FN_REFLEN || length >= FN_LEN ) { /* To long path, return original or NULL */ size_t tmp_length; if (flag & MY_SAFE_PATH) DBUG_RETURN(NullS); tmp_length= strlength(startpos); DBUG_PRINT("error",("dev: '%s' ext: '%s' length: %u",dev,ext, (uint) length)); (void) strmake(to, startpos, MY_MIN(tmp_length, FN_REFLEN-1)); } else { if (to == startpos) { bmove(buff,(uchar*) name,length); /* Save name for last copy */ name=buff; } pos=strmake(strmov(to,dev),name,length); (void) strmov(pos,ext); /* Don't convert extension */ } /* If MY_RETURN_REAL_PATH and MY_RESOLVE_SYMLINK is given, only do realpath if the file is a symbolic link */ if (flag & MY_RETURN_REAL_PATH) (void) my_realpath(to, to, MYF(flag & MY_RESOLVE_SYMLINKS ? MY_RESOLVE_LINK: 0)); else if (flag & MY_RESOLVE_SYMLINKS) { strmov(buff,to); (void) my_readlink(to, buff, MYF(0)); } DBUG_RETURN(to); } /* fn_format */
int main(int argc, char *argv[]) { uint i; int j,n1,n2,n3,error,k; uint write_count,update,dupp_keys,opt_delete,start,length,blob_pos, reclength,ant,found_parts; my_off_t lastpos; ha_rows range_records,records; MARIA_HA *file; MARIA_KEYDEF keyinfo[10]; MARIA_COLUMNDEF recinfo[10]; MARIA_INFO info; char *blob_buffer; MARIA_CREATE_INFO create_info; char filename[FN_REFLEN]; #ifdef SAFE_MUTEX safe_mutex_deadlock_detector= 1; #endif MY_INIT(argv[0]); maria_data_root= (char *)"."; get_options(argc,argv); fn_format(filename, "test2", maria_data_root, "", MYF(0)); if (! async_io) my_disable_async_io=1; /* If we sync or not have no affect on this test */ my_disable_sync= 1; /* Maria requires that we always have a page cache */ if (maria_init() || (init_pagecache(maria_pagecache, pagecache_size, 0, 0, maria_block_size, 0, MY_WME) == 0) || ma_control_file_open(TRUE, TRUE) || (init_pagecache(maria_log_pagecache, TRANSLOG_PAGECACHE_SIZE, 0, 0, TRANSLOG_PAGE_SIZE, 0, MY_WME) == 0) || translog_init(maria_data_root, TRANSLOG_FILE_SIZE, 0, 0, maria_log_pagecache, TRANSLOG_DEFAULT_FLAGS, 0) || (transactional && (trnman_init(0) || ma_checkpoint_init(0)))) { fprintf(stderr, "Error in initialization"); exit(1); } if (opt_versioning) init_thr_lock(); reclength=STANDARD_LENGTH+60+(use_blob ? 8 : 0); blob_pos=STANDARD_LENGTH+60; keyinfo[0].seg= &glob_keyseg[0][0]; keyinfo[0].seg[0].start=0; keyinfo[0].seg[0].length=6; keyinfo[0].seg[0].type=HA_KEYTYPE_TEXT; keyinfo[0].seg[0].language= default_charset_info->number; keyinfo[0].seg[0].flag=(uint8) pack_seg; keyinfo[0].seg[0].null_bit=0; keyinfo[0].seg[0].null_pos=0; keyinfo[0].key_alg=HA_KEY_ALG_BTREE; keyinfo[0].keysegs=1; keyinfo[0].flag = pack_type; keyinfo[0].block_length= 0; /* Default block length */ keyinfo[1].seg= &glob_keyseg[1][0]; keyinfo[1].seg[0].start=7; keyinfo[1].seg[0].length=6; keyinfo[1].seg[0].type=HA_KEYTYPE_BINARY; keyinfo[1].seg[0].flag=0; keyinfo[1].seg[0].null_bit=0; keyinfo[1].seg[0].null_pos=0; keyinfo[1].seg[1].start=0; /* two part key */ keyinfo[1].seg[1].length=6; keyinfo[1].seg[1].type=HA_KEYTYPE_NUM; keyinfo[1].seg[1].flag=HA_REVERSE_SORT; keyinfo[1].seg[1].null_bit=0; keyinfo[1].seg[1].null_pos=0; keyinfo[1].key_alg=HA_KEY_ALG_BTREE; keyinfo[1].keysegs=2; keyinfo[1].flag =0; keyinfo[1].block_length= MARIA_MIN_KEY_BLOCK_LENGTH; /* Diff blocklength */ keyinfo[2].seg= &glob_keyseg[2][0]; keyinfo[2].seg[0].start=12; keyinfo[2].seg[0].length=8; keyinfo[2].seg[0].type=HA_KEYTYPE_BINARY; keyinfo[2].seg[0].flag=HA_REVERSE_SORT; keyinfo[2].seg[0].null_bit=0; keyinfo[2].seg[0].null_pos=0; keyinfo[2].key_alg=HA_KEY_ALG_BTREE; keyinfo[2].keysegs=1; keyinfo[2].flag =HA_NOSAME; keyinfo[2].block_length= 0; /* Default block length */ keyinfo[3].seg= &glob_keyseg[3][0]; keyinfo[3].seg[0].start=0; keyinfo[3].seg[0].length=reclength-(use_blob ? 8 : 0); keyinfo[3].seg[0].type=HA_KEYTYPE_TEXT; keyinfo[3].seg[0].language=default_charset_info->number; keyinfo[3].seg[0].flag=(uint8) pack_seg; keyinfo[3].seg[0].null_bit=0; keyinfo[3].seg[0].null_pos=0; keyinfo[3].key_alg=HA_KEY_ALG_BTREE; keyinfo[3].keysegs=1; keyinfo[3].flag = pack_type; keyinfo[3].block_length= 0; /* Default block length */ keyinfo[4].seg= &glob_keyseg[4][0]; keyinfo[4].seg[0].start=0; keyinfo[4].seg[0].length=5; keyinfo[4].seg[0].type=HA_KEYTYPE_TEXT; keyinfo[4].seg[0].language=default_charset_info->number; keyinfo[4].seg[0].flag=0; keyinfo[4].seg[0].null_bit=0; keyinfo[4].seg[0].null_pos=0; keyinfo[4].key_alg=HA_KEY_ALG_BTREE; keyinfo[4].keysegs=1; keyinfo[4].flag = pack_type; keyinfo[4].block_length= 0; /* Default block length */ keyinfo[5].seg= &glob_keyseg[5][0]; keyinfo[5].seg[0].start=0; keyinfo[5].seg[0].length=4; keyinfo[5].seg[0].type=HA_KEYTYPE_TEXT; keyinfo[5].seg[0].language=default_charset_info->number; keyinfo[5].seg[0].flag=pack_seg; keyinfo[5].seg[0].null_bit=0; keyinfo[5].seg[0].null_pos=0; keyinfo[5].key_alg=HA_KEY_ALG_BTREE; keyinfo[5].keysegs=1; keyinfo[5].flag = pack_type; keyinfo[5].block_length= 0; /* Default block length */ recinfo[0].type=pack_fields ? FIELD_SKIP_PRESPACE : 0; recinfo[0].length=7; recinfo[0].null_bit=0; recinfo[0].null_pos=0; recinfo[1].type=pack_fields ? FIELD_SKIP_PRESPACE : 0; recinfo[1].length=5; recinfo[1].null_bit=0; recinfo[1].null_pos=0; recinfo[2].type=pack_fields ? FIELD_SKIP_PRESPACE : 0; recinfo[2].length=9; recinfo[2].null_bit=0; recinfo[2].null_pos=0; recinfo[3].type=FIELD_NORMAL; recinfo[3].length=STANDARD_LENGTH-7-5-9-4; recinfo[3].null_bit=0; recinfo[3].null_pos=0; recinfo[4].type=pack_fields ? FIELD_SKIP_ZERO : 0; recinfo[4].length=4; recinfo[4].null_bit=0; recinfo[4].null_pos=0; recinfo[5].type=pack_fields ? FIELD_SKIP_ENDSPACE : 0; recinfo[5].length=60; recinfo[5].null_bit=0; recinfo[5].null_pos=0; if (use_blob) { recinfo[6].type=FIELD_BLOB; recinfo[6].length=4+portable_sizeof_char_ptr; recinfo[6].null_bit=0; recinfo[6].null_pos=0; } write_count=update=dupp_keys=opt_delete=0; blob_buffer=0; for (i=1000 ; i>0 ; i--) key1[i]=0; for (i=5000 ; i>0 ; i--) key3[i]=0; if (!silent) printf("- Creating maria-file\n"); file= 0; bzero((char*) &create_info,sizeof(create_info)); create_info.max_rows=(ha_rows) (rec_pointer_size ? (1L << (rec_pointer_size*8))/ reclength : 0); create_info.reloc_rows=(ha_rows) 100; create_info.transactional= transactional; if (maria_create(filename, record_type, keys,&keyinfo[first_key], use_blob ? 7 : 6, &recinfo[0], 0,(MARIA_UNIQUEDEF*) 0, &create_info,create_flag)) goto err; if (!(file=maria_open(filename,2,HA_OPEN_ABORT_IF_LOCKED))) goto err; maria_begin(file); if (opt_versioning) maria_versioning(file, 1); if (testflag == 1) goto end; if (checkpoint == 1 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE)) goto err; if (!silent) printf("- Writing key:s\n"); if (do_locking) maria_lock_database(file,F_WRLCK); if (write_cacheing) maria_extra(file,HA_EXTRA_WRITE_CACHE,0); if (opt_quick_mode) maria_extra(file,HA_EXTRA_QUICK,0); for (i=0 ; i < recant ; i++) { ulong blob_length; n1=rnd(1000); n2=rnd(100); n3=rnd(5000); sprintf((char*) record,"%6d:%4d:%8d:Pos: %4d ",n1,n2,n3,write_count); int4store(record+STANDARD_LENGTH-4,(long) i); fix_length(record,(uint) STANDARD_LENGTH+rnd(60)); put_blob_in_record(record+blob_pos,&blob_buffer, &blob_length); DBUG_PRINT("test",("record: %d blob_length: %lu", i, blob_length)); if (maria_write(file,record)) { if (my_errno != HA_ERR_FOUND_DUPP_KEY || key3[n3] == 0) { printf("Error: %d in write at record: %d\n",my_errno,i); goto err; } if (verbose) printf(" Double key: %d at record# %d\n", n3, i); } else { if (key3[n3] == 1 && first_key <3 && first_key+keys >= 3) { printf("Error: Didn't get error when writing second key: '%8d'\n",n3); goto err2; } write_count++; key1[n1]++; key3[n3]=1; } /* Check if we can find key without flushing database */ if (i % 10 == 0) { for (j=rnd(1000)+1 ; j>0 && key1[j] == 0 ; j--) ; if (!j) for (j=999 ; j>0 && key1[j] == 0 ; j--) ; sprintf((char*) key,"%6d",j); if (maria_rkey(file,read_record,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT)) { printf("Test in loop: Can't find key: \"%s\"\n",key); goto err; } } } if (checkpoint == 2 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE)) goto err; if (write_cacheing) { if (maria_extra(file,HA_EXTRA_NO_CACHE,0)) { puts("got error from maria_extra(HA_EXTRA_NO_CACHE)"); goto err; } } if (testflag == 2) goto end; #ifdef REMOVE_WHEN_WE_HAVE_RESIZE if (pagecacheing) resize_pagecache(maria_pagecache, maria_block_size, pagecache_size * 2, 0, 0); #endif if (!silent) printf("- Delete\n"); if (srand_arg) srand(srand_arg); if (!update_count) update_count= recant/10; for (i=0 ; i < update_count ; i++) { for (j=rnd(1000)+1 ; j>0 && key1[j] == 0 ; j--) ; if (j != 0) { sprintf((char*) key,"%6d",j); if (maria_rkey(file,read_record,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT)) { printf("can't find key1: \"%s\"\n",key); goto err; } if (bcmp(read_record+keyinfo[0].seg[0].start, key, keyinfo[0].seg[0].length)) { printf("Found wrong record when searching for key: \"%s\"\n",key); goto err2; } if (opt_delete == (uint) remove_count) /* While testing */ goto end; if (maria_delete(file,read_record)) { printf("error: %d; can't delete record: \"%s\"\n", my_errno,read_record); goto err; } opt_delete++; key1[atoi((char*) read_record+keyinfo[0].seg[0].start)]--; key3[atoi((char*) read_record+keyinfo[2].seg[0].start)]=0; } else { puts("Warning: Skipping delete test because no dupplicate keys"); break; } } if (testflag == 3) goto end; if (checkpoint == 3 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE)) goto err; if (!silent) printf("- Update\n"); if (srand_arg) srand(srand_arg); if (!update_count) update_count= recant/10; for (i=0 ; i < update_count ; i++) { n1=rnd(1000); n2=rnd(100); n3=rnd(5000); sprintf((char*) record2,"%6d:%4d:%8d:XXX: %4d ",n1,n2,n3,update); int4store(record2+STANDARD_LENGTH-4,(long) i); fix_length(record2,(uint) STANDARD_LENGTH+rnd(60)); for (j=rnd(1000)+1 ; j>0 && key1[j] == 0 ; j--) ; if (j != 0) { sprintf((char*) key,"%6d",j); if (maria_rkey(file,read_record,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT)) { printf("can't find key1: \"%s\"\n", (char*) key); goto err; } if (bcmp(read_record+keyinfo[0].seg[0].start, key, keyinfo[0].seg[0].length)) { printf("Found wrong record when searching for key: \"%s\"; Found \"%.*s\"\n", key, keyinfo[0].seg[0].length, read_record+keyinfo[0].seg[0].start); goto err2; } if (use_blob) { ulong blob_length; if (i & 1) put_blob_in_record(record2+blob_pos,&blob_buffer, &blob_length); else bmove(record2+blob_pos, read_record+blob_pos, 4 + sizeof(char*)); } if (skip_update) continue; if (maria_update(file,read_record,record2)) { if (my_errno != HA_ERR_FOUND_DUPP_KEY || key3[n3] == 0) { printf("error: %d; can't update:\nFrom: \"%s\"\nTo: \"%s\"\n", my_errno,read_record,record2); goto err; } if (verbose) printf("Double key when tried to update:\nFrom: \"%s\"\nTo: \"%s\"\n",record,record2); } else { key1[atoi((char*) read_record+keyinfo[0].seg[0].start)]--; key3[atoi((char*) read_record+keyinfo[2].seg[0].start)]=0; key1[n1]++; key3[n3]=1; update++; } } } if (testflag == 4) goto end; if (checkpoint == 4 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE)) goto err; for (i=999, dupp_keys=j=0 ; i>0 ; i--) { if (key1[i] > dupp_keys) { dupp_keys=key1[i]; j=i; } } sprintf((char*) key,"%6d",j); start=keyinfo[0].seg[0].start; length=keyinfo[0].seg[0].length; if (dupp_keys) { if (!silent) printf("- Same key: first - next -> last - prev -> first\n"); DBUG_PRINT("progpos",("first - next -> last - prev -> first")); if (verbose) printf(" Using key: \"%s\" Keys: %d\n",key,dupp_keys); if (maria_rkey(file,read_record,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT)) goto err; if (maria_rsame(file,read_record2,-1)) goto err; if (memcmp(read_record,read_record2,reclength) != 0) { printf("maria_rsame didn't find same record\n"); goto err2; } info.recpos=maria_position(file); if (maria_rfirst(file,read_record2,0) || maria_rsame_with_pos(file,read_record2,0,info.recpos) || memcmp(read_record,read_record2,reclength) != 0) { printf("maria_rsame_with_pos didn't find same record\n"); goto err2; } { int skr; info.recpos= maria_position(file); skr= maria_rnext(file,read_record2,0); if ((skr && my_errno != HA_ERR_END_OF_FILE) || maria_rprev(file,read_record2,0) || memcmp(read_record,read_record2,reclength) != 0 || info.recpos != maria_position(file)) { printf("maria_rsame_with_pos lost position\n"); goto err; } } ant=1; while (maria_rnext(file,read_record2,0) == 0 && memcmp(read_record2+start,key,length) == 0) ant++; if (ant != dupp_keys) { printf("next: Found: %d keys of %d\n",ant,dupp_keys); goto err2; } ant=0; while (maria_rprev(file,read_record3,0) == 0 && bcmp(read_record3+start,key,length) == 0) ant++; if (ant != dupp_keys) { printf("prev: Found: %d records of %d\n",ant,dupp_keys); goto err2; } /* Check of maria_rnext_same */ if (maria_rkey(file,read_record,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT)) goto err; ant=1; while (!maria_rnext_same(file,read_record3) && ant < dupp_keys+10) ant++; if (ant != dupp_keys || my_errno != HA_ERR_END_OF_FILE) { printf("maria_rnext_same: Found: %d records of %d\n",ant,dupp_keys); goto err2; } } if (!silent) printf("- All keys: first - next -> last - prev -> first\n"); DBUG_PRINT("progpos",("All keys: first - next -> last - prev -> first")); ant=1; if (maria_rfirst(file,read_record,0)) { printf("Can't find first record\n"); goto err; } while ((error=maria_rnext(file,read_record3,0)) == 0 && ant < write_count+10) ant++; if (ant != write_count - opt_delete || error != HA_ERR_END_OF_FILE) { printf("next: I found: %d records of %d (error: %d)\n", ant, write_count - opt_delete, error); goto err; } if (maria_rlast(file,read_record2,0) || bcmp(read_record2,read_record3,reclength)) { printf("Can't find last record\n"); DBUG_DUMP("record2", read_record2, reclength); DBUG_DUMP("record3", read_record3, reclength); goto err2; } ant=1; while (maria_rprev(file,read_record3,0) == 0 && ant < write_count+10) ant++; if (ant != write_count - opt_delete) { printf("prev: I found: %d records of %d\n",ant,write_count); goto err2; } if (bcmp(read_record,read_record3,reclength)) { printf("Can't find first record\n"); goto err2; } if (!silent) printf("- Test if: Read first - next - prev - prev - next == first\n"); DBUG_PRINT("progpos",("- Read first - next - prev - prev - next == first")); if (maria_rfirst(file,read_record,0) || maria_rnext(file,read_record3,0) || maria_rprev(file,read_record3,0) || maria_rprev(file,read_record3,0) == 0 || maria_rnext(file,read_record3,0)) goto err; if (bcmp(read_record,read_record3,reclength) != 0) printf("Can't find first record\n"); if (!silent) printf("- Test if: Read last - prev - next - next - prev == last\n"); DBUG_PRINT("progpos",("Read last - prev - next - next - prev == last")); if (maria_rlast(file,read_record2,0) || maria_rprev(file,read_record3,0) || maria_rnext(file,read_record3,0) || maria_rnext(file,read_record3,0) == 0 || maria_rprev(file,read_record3,0)) goto err; if (bcmp(read_record2,read_record3,reclength)) printf("Can't find last record\n"); #ifdef NOT_ANYMORE if (!silent) puts("- Test read key-part"); strmov(key2,key); for(i=strlen(key2) ; i-- > 1 ;) { key2[i]=0; /* The following row is just to catch some bugs in the key code */ bzero((char*) file->lastkey,file->s->base.max_key_length*2); if (maria_rkey(file,read_record,0,key2,(uint) i,HA_READ_PREFIX)) goto err; if (bcmp(read_record+start,key,(uint) i)) { puts("Didn't find right record"); goto err2; } } #endif if (dupp_keys > 2) { if (!silent) printf("- Read key (first) - next - delete - next -> last\n"); DBUG_PRINT("progpos",("first - next - delete - next -> last")); if (maria_rkey(file,read_record,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT)) goto err; if (maria_rnext(file,read_record3,0)) goto err; if (maria_delete(file,read_record3)) goto err; opt_delete++; ant=1; while (maria_rnext(file,read_record3,0) == 0 && bcmp(read_record3+start,key,length) == 0) ant++; if (ant != dupp_keys-1) { printf("next: I can only find: %d keys of %d\n",ant,dupp_keys-1); goto err2; } } if (dupp_keys>4) { if (!silent) printf("- Read last of key - prev - delete - prev -> first\n"); DBUG_PRINT("progpos",("last - prev - delete - prev -> first")); if (maria_rprev(file,read_record3,0)) goto err; if (maria_rprev(file,read_record3,0)) goto err; if (maria_delete(file,read_record3)) goto err; opt_delete++; ant=1; while (maria_rprev(file,read_record3,0) == 0 && bcmp(read_record3+start,key,length) == 0) ant++; if (ant != dupp_keys-2) { printf("next: I can only find: %d keys of %d\n",ant,dupp_keys-2); goto err2; } } if (dupp_keys > 6) { if (!silent) printf("- Read first - delete - next -> last\n"); DBUG_PRINT("progpos",("first - delete - next -> last")); if (maria_rkey(file,read_record3,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT)) goto err; if (maria_delete(file,read_record3)) goto err; opt_delete++; ant=1; if (maria_rnext(file,read_record,0)) goto err; /* Skall finnas poster */ while (maria_rnext(file,read_record3,0) == 0 && bcmp(read_record3+start,key,length) == 0) ant++; if (ant != dupp_keys-3) { printf("next: I can only find: %d keys of %d\n",ant,dupp_keys-3); goto err2; } if (!silent) printf("- Read last - delete - prev -> first\n"); DBUG_PRINT("progpos",("last - delete - prev -> first")); if (maria_rprev(file,read_record3,0)) goto err; if (maria_delete(file,read_record3)) goto err; opt_delete++; ant=0; while (maria_rprev(file,read_record3,0) == 0 && bcmp(read_record3+start,key,length) == 0) ant++; if (ant != dupp_keys-4) { printf("next: I can only find: %d keys of %d\n",ant,dupp_keys-4); goto err2; } } if (!silent) puts("- Test if: Read rrnd - same"); DBUG_PRINT("progpos",("Read rrnd - same")); maria_scan_init(file); for (i=0 ; i < write_count ; i++) { int tmp; if ((tmp= maria_scan(file,read_record)) && tmp != HA_ERR_END_OF_FILE && tmp != HA_ERR_RECORD_DELETED) { printf("Got error %d when scanning table\n", tmp); break; } if (!tmp) { /* Remember position to last found row */ info.recpos= maria_position(file); bmove(read_record2,read_record,reclength); } } maria_scan_end(file); if (i != write_count && i != write_count - opt_delete) { printf("Found wrong number of rows while scanning table\n"); goto err2; } if (maria_rsame_with_pos(file,read_record,0,info.recpos)) goto err; if (bcmp(read_record,read_record2,reclength) != 0) { printf("maria_rsame_with_pos didn't find same record\n"); goto err2; } for (i=MY_MIN(2,keys) ; i-- > 0 ;) { if (maria_rsame(file,read_record2,(int) i)) goto err; if (bcmp(read_record,read_record2,reclength) != 0) { printf("maria_rsame didn't find same record\n"); goto err2; } } if (!silent) puts("- Test maria_records_in_range"); maria_status(file,&info,HA_STATUS_VARIABLE); for (i=0 ; i < info.keys ; i++) { key_range min_key, max_key; if (maria_rfirst(file,read_record,(int) i) || maria_rlast(file,read_record2,(int) i)) goto err; copy_key(file,(uint) i, read_record, key); copy_key(file,(uint) i, read_record2, key2); min_key.key= key; min_key.keypart_map= HA_WHOLE_KEY; min_key.flag= HA_READ_KEY_EXACT; max_key.key= key2; max_key.keypart_map= HA_WHOLE_KEY; max_key.flag= HA_READ_AFTER_KEY; range_records= maria_records_in_range(file,(int) i, &min_key, &max_key); if (range_records < info.records*8/10 || range_records > info.records*12/10) { printf("maria_records_range returned %ld; Should be about %ld\n", (long) range_records,(long) info.records); goto err2; } if (verbose) { printf("maria_records_range returned %ld; Exact is %ld (diff: %4.2g %%)\n", (long) range_records, (long) info.records, labs((long) range_records - (long) info.records)*100.0/ info.records); } } for (i=0 ; i < 5 ; i++) { for (j=rnd(1000)+1 ; j>0 && key1[j] == 0 ; j--) ; for (k=rnd(1000)+1 ; k>0 && key1[k] == 0 ; k--) ; if (j != 0 && k != 0) { key_range min_key, max_key; if (j > k) swap_variables(int, j, k); sprintf((char*) key,"%6d",j); sprintf((char*) key2,"%6d",k); min_key.key= key; min_key.keypart_map= HA_WHOLE_KEY; min_key.flag= HA_READ_AFTER_KEY; max_key.key= key2; max_key.keypart_map= HA_WHOLE_KEY; max_key.flag= HA_READ_BEFORE_KEY; range_records= maria_records_in_range(file, 0, &min_key, &max_key); records=0; for (j++ ; j < k ; j++) records+=key1[j]; if ((long) range_records < (long) records*6/10-2 || (long) range_records > (long) records*14/10+2) { printf("maria_records_range for key: %d returned %lu; Should be about %lu\n", i, (ulong) range_records, (ulong) records); goto err2; } if (verbose && records) { printf("maria_records_range returned %lu; Exact is %lu (diff: %4.2g %%)\n", (ulong) range_records, (ulong) records, labs((long) range_records-(long) records)*100.0/records); } } } if (!silent) printf("- maria_info\n"); maria_status(file,&info,HA_STATUS_VARIABLE | HA_STATUS_CONST); if (info.records != write_count-opt_delete || info.deleted > opt_delete + update || info.keys != keys) { puts("Wrong info from maria_info"); printf("Got: records: %lu delete: %lu i_keys: %d\n", (ulong) info.records, (ulong) info.deleted, info.keys); goto err2; } if (verbose) { char buff[80]; get_date(buff,3,info.create_time); printf("info: Created %s\n",buff); get_date(buff,3,info.check_time); printf("info: checked %s\n",buff); get_date(buff,3,info.update_time); printf("info: Modified %s\n",buff); } maria_panic(HA_PANIC_WRITE); maria_panic(HA_PANIC_READ); if (maria_is_changed(file)) puts("Warning: maria_is_changed reported that datafile was changed"); if (!silent) printf("- maria_extra(CACHE) + maria_rrnd.... + maria_extra(NO_CACHE)\n"); if (maria_reset(file) || maria_extra(file,HA_EXTRA_CACHE,0)) { if (do_locking || (!use_blob && !pack_fields)) { puts("got error from maria_extra(HA_EXTRA_CACHE)"); goto err; } } ant=0; maria_scan_init(file); while ((error= maria_scan(file,record)) != HA_ERR_END_OF_FILE && ant < write_count + 10) ant+= error ? 0 : 1; maria_scan_end(file); if (ant != write_count-opt_delete) { printf("scan with cache: I can only find: %d records of %d\n", ant,write_count-opt_delete); maria_scan_end(file); goto err2; } if (maria_extra(file,HA_EXTRA_NO_CACHE,0)) { puts("got error from maria_extra(HA_EXTRA_NO_CACHE)"); maria_scan_end(file); goto err; } maria_scan_end(file); ant=0; maria_scan_init(file); while ((error=maria_scan(file,record)) != HA_ERR_END_OF_FILE && ant < write_count + 10) ant+= error ? 0 : 1; if (ant != write_count-opt_delete) { printf("scan with cache: I can only find: %d records of %d\n", ant,write_count-opt_delete); maria_scan_end(file); goto err2; } maria_scan_end(file); if (testflag == 5) goto end; if (checkpoint == 5 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE)) goto err; if (!silent) printf("- Removing keys\n"); DBUG_PRINT("progpos",("Removing keys")); lastpos = HA_OFFSET_ERROR; /* DBUG_POP(); */ maria_reset(file); found_parts=0; maria_scan_init(file); while ((error= maria_scan(file,read_record)) != HA_ERR_END_OF_FILE) { info.recpos=maria_position(file); if (lastpos >= info.recpos && lastpos != HA_OFFSET_ERROR) { printf("maria_rrnd didn't advance filepointer; old: %ld, new: %ld\n", (long) lastpos, (long) info.recpos); goto err2; } lastpos=info.recpos; if (error == 0) { if (opt_delete == (uint) remove_count) /* While testing */ goto end; if (rnd(2) == 1 && maria_rsame(file,read_record,-1)) { printf("can't find record %lx\n",(long) info.recpos); goto err; } if (use_blob) { ulong blob_length,pos; uchar *ptr; memcpy(&ptr, read_record+blob_pos+4, sizeof(ptr)); blob_length= uint4korr(read_record+blob_pos); for (pos=0 ; pos < blob_length ; pos++) { if (ptr[pos] != (uchar) (blob_length+pos)) { printf("Found blob with wrong info at %ld\n",(long) lastpos); maria_scan_end(file); my_errno= 0; goto err2; } } } if (maria_delete(file,read_record)) { printf("can't delete record: %6.6s, delete_count: %d\n", read_record, opt_delete); maria_scan_end(file); goto err; } opt_delete++; } else found_parts++; } if (my_errno != HA_ERR_END_OF_FILE && my_errno != HA_ERR_RECORD_DELETED) printf("error: %d from maria_rrnd\n",my_errno); if (write_count != opt_delete) { printf("Deleted only %d of %d records (%d parts)\n",opt_delete,write_count, found_parts); maria_scan_end(file); goto err2; } if (testflag == 6) goto end; if (checkpoint == 6 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE)) goto err; end: maria_scan_end(file); if (die_in_middle_of_transaction) { /* As commit record is not done, UNDO entries needs to be rolled back */ switch (die_in_middle_of_transaction) { case 1: /* Flush changed data and index pages go to disk That will also flush log. Recovery will skip REDOs and apply UNDOs. */ _ma_flush_table_files(file, MARIA_FLUSH_DATA | MARIA_FLUSH_INDEX, FLUSH_RELEASE, FLUSH_RELEASE); break; case 2: /* Just flush log. Pages are likely to not be on disk. Recovery will then execute REDOs and UNDOs. */ if (translog_flush(file->trn->undo_lsn)) goto err; break; case 3: /* Flush nothing. Pages and log are likely to not be on disk. Recovery will then do nothing. */ break; case 4: /* Flush changed data pages go to disk. Changed index pages are not flushed. Recovery will skip some REDOs and apply UNDOs. */ _ma_flush_table_files(file, MARIA_FLUSH_DATA, FLUSH_RELEASE, FLUSH_RELEASE); /* We have to flush log separately as the redo for the last key page may not be flushed */ if (translog_flush(file->trn->undo_lsn)) goto err; break; } printf("Dying on request without maria_commit()/maria_close()\n"); sf_leaking_memory= 1; /* no memory leak reports here */ exit(0); } if (maria_commit(file)) goto err; if (maria_close(file)) { file= 0; goto err; } file= 0; maria_panic(HA_PANIC_CLOSE); /* Should close log */ if (!silent) { printf("\nFollowing test have been made:\n"); printf("Write records: %d\nUpdate records: %d\nSame-key-read: %d\nDelete records: %d\n", write_count,update,dupp_keys,opt_delete); if (rec_pointer_size) printf("Record pointer size: %d\n",rec_pointer_size); printf("maria_block_size: %lu\n", maria_block_size); if (write_cacheing) puts("Key cache resized"); if (write_cacheing) puts("Write cacheing used"); if (write_cacheing) puts("quick mode"); if (async_io && do_locking) puts("Asyncron io with locking used"); else if (do_locking) puts("Locking used"); if (use_blob) puts("blobs used"); printf("key cache status: \n\ blocks used:%10lu\n\ not flushed:%10lu\n\ w_requests: %10lu\n\ writes: %10lu\n\ r_requests: %10lu\n\ reads: %10lu\n", maria_pagecache->blocks_used, maria_pagecache->global_blocks_changed, (ulong) maria_pagecache->global_cache_w_requests, (ulong) maria_pagecache->global_cache_write, (ulong) maria_pagecache->global_cache_r_requests, (ulong) maria_pagecache->global_cache_read); }
static int search_default_file_with_ext(Process_option_func opt_handler, void *handler_ctx, const char *dir, const char *ext, const char *config_file, int recursion_level) { char name[FN_REFLEN + 10], buff[4096], curr_gr[4096], *ptr, *end, **tmp_ext; char *value, option[4096+2], tmp[FN_REFLEN]; static const char includedir_keyword[]= "includedir"; static const char include_keyword[]= "include"; const int max_recursion_level= 10; MYSQL_FILE *fp; uint line=0; my_bool found_group=0; uint i; MY_DIR *search_dir; FILEINFO *search_file; if ((dir ? strlen(dir) : 0 )+strlen(config_file) >= FN_REFLEN-3) return 0; /* Ignore wrong paths */ if (dir) { end=convert_dirname(name, dir, NullS); if (dir[0] == FN_HOMELIB) /* Add . to filenames in home */ *end++='.'; strxmov(end,config_file,ext,NullS); } else { strmov(name,config_file); } fn_format(name,name,"","",4); #if !defined(__WIN__) { MY_STAT stat_info; if (!my_stat(name,&stat_info,MYF(0))) return 1; /* Ignore world-writable regular files. This is mainly done to protect us to not read a file created by the mysqld server, but the check is still valid in most context. */ if ((stat_info.st_mode & S_IWOTH) && (stat_info.st_mode & S_IFMT) == S_IFREG) { fprintf(stderr, "Warning: World-writable config file '%s' is ignored\n", name); return 0; } } #endif if (!(fp= mysql_file_fopen(key_file_cnf, name, O_RDONLY, MYF(0)))) return 1; /* Ignore wrong files */ while (mysql_file_fgets(buff, sizeof(buff) - 1, fp)) { line++; /* Ignore comment and empty lines */ for (ptr= buff; my_isspace(&my_charset_latin1, *ptr); ptr++) {} if (*ptr == '#' || *ptr == ';' || !*ptr) continue; /* Configuration File Directives */ if (*ptr == '!') { if (recursion_level >= max_recursion_level) { for (end= ptr + strlen(ptr) - 1; my_isspace(&my_charset_latin1, *(end - 1)); end--) {} end[0]= 0; fprintf(stderr, "Warning: skipping '%s' directive as maximum include" "recursion level was reached in file %s at line %d\n", ptr, name, line); continue; } /* skip over `!' and following whitespace */ for (++ptr; my_isspace(&my_charset_latin1, ptr[0]); ptr++) {} if ((!strncmp(ptr, includedir_keyword, sizeof(includedir_keyword) - 1)) && my_isspace(&my_charset_latin1, ptr[sizeof(includedir_keyword) - 1])) { if (!(ptr= get_argument(includedir_keyword, sizeof(includedir_keyword), ptr, name, line))) goto err; if (!(search_dir= my_dir(ptr, MYF(MY_WME)))) goto err; for (i= 0; i < (uint) search_dir->number_of_files; i++) { search_file= search_dir->dir_entry + i; ext= fn_ext(search_file->name); /* check extension */ for (tmp_ext= (char**) f_extensions; *tmp_ext; tmp_ext++) { if (!strcmp(ext, *tmp_ext)) break; } if (*tmp_ext) { fn_format(tmp, search_file->name, ptr, "", MY_UNPACK_FILENAME | MY_SAFE_PATH); search_default_file_with_ext(opt_handler, handler_ctx, "", "", tmp, recursion_level + 1); } } my_dirend(search_dir); } else if ((!strncmp(ptr, include_keyword, sizeof(include_keyword) - 1)) && my_isspace(&my_charset_latin1, ptr[sizeof(include_keyword)-1])) { if (!(ptr= get_argument(include_keyword, sizeof(include_keyword), ptr, name, line))) goto err; search_default_file_with_ext(opt_handler, handler_ctx, "", "", ptr, recursion_level + 1); } continue; } if (*ptr == '[') /* Group name */ { found_group=1; if (!(end=(char *) strchr(++ptr,']'))) { fprintf(stderr, "error: Wrong group definition in config file: %s at line %d\n", name,line); goto err; } /* Remove end space */ for ( ; my_isspace(&my_charset_latin1,end[-1]) ; end--) ; end[0]=0; strmake(curr_gr, ptr, MY_MIN((size_t) (end-ptr)+1, sizeof(curr_gr)-1)); /* signal that a new group is found */ opt_handler(handler_ctx, curr_gr, NULL); continue; } if (!found_group) { fprintf(stderr, "error: Found option without preceding group in config file: %s at line: %d\n", name,line); goto err; } end= remove_end_comment(ptr); if ((value= strchr(ptr, '='))) end= value; /* Option without argument */ for ( ; my_isspace(&my_charset_latin1,end[-1]) ; end--) ; if (!value) { strmake(strmov(option,"--"),ptr, (size_t) (end-ptr)); if (opt_handler(handler_ctx, curr_gr, option)) goto err; } else { /* Remove pre- and end space */ char *value_end; for (value++ ; my_isspace(&my_charset_latin1,*value); value++) ; value_end=strend(value); /* We don't have to test for value_end >= value as we know there is an '=' before */ for ( ; my_isspace(&my_charset_latin1,value_end[-1]) ; value_end--) ; if (value_end < value) /* Empty string */ value_end=value; /* remove quotes around argument */ if ((*value == '\"' || *value == '\'') && /* First char is quote */ (value + 1 < value_end ) && /* String is longer than 1 */ *value == value_end[-1] ) /* First char is equal to last char */ { value++; value_end--; } ptr=strnmov(strmov(option,"--"),ptr,(size_t) (end-ptr)); *ptr++= '='; for ( ; value != value_end; value++) { if (*value == '\\' && value != value_end-1) { switch(*++value) { case 'n': *ptr++='\n'; break; case 't': *ptr++= '\t'; break; case 'r': *ptr++ = '\r'; break; case 'b': *ptr++ = '\b'; break; case 's': *ptr++= ' '; /* space */ break; case '\"': *ptr++= '\"'; break; case '\'': *ptr++= '\''; break; case '\\': *ptr++= '\\'; break; default: /* Unknown; Keep '\' */ *ptr++= '\\'; *ptr++= *value; break; } } else *ptr++= *value; } *ptr=0; if (opt_handler(handler_ctx, curr_gr, option)) goto err; } } mysql_file_fclose(fp, MYF(0)); return(0); err: mysql_file_fclose(fp, MYF(0)); return -1; /* Fatal error */ }
static int my_process_stmt_result(MYSQL_STMT *stmt) { int field_count; int row_count= 0; MYSQL_BIND buffer[MAX_RES_FIELDS]; MYSQL_FIELD *field; MYSQL_RES *result; char data[MAX_RES_FIELDS][MAX_FIELD_DATA_SIZE]; ulong length[MAX_RES_FIELDS]; my_bool is_null[MAX_RES_FIELDS]; int rc, i; if (!(result= mysql_stmt_result_metadata(stmt))) /* No meta info */ { while (!mysql_stmt_fetch(stmt)) row_count++; return row_count; } field_count= MY_MIN(mysql_num_fields(result), MAX_RES_FIELDS); memset(buffer, 0, sizeof(buffer)); memset(length, 0, sizeof(length)); memset(is_null, 0, sizeof(is_null)); for(i= 0; i < field_count; i++) { buffer[i].buffer_type= MYSQL_TYPE_STRING; buffer[i].buffer_length= MAX_FIELD_DATA_SIZE; buffer[i].length= &length[i]; buffer[i].buffer= (void *) data[i]; buffer[i].is_null= &is_null[i]; } rc= mysql_stmt_bind_result(stmt, buffer); check_execute(stmt, rc); rc= 1; mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*)&rc); rc= mysql_stmt_store_result(stmt); check_execute(stmt, rc); my_print_result_metadata(result); mysql_field_seek(result, 0); while ((rc= mysql_stmt_fetch(stmt)) == 0) { if (!opt_silent) { fputc('\t', stdout); fputc('|', stdout); } mysql_field_seek(result, 0); for (i= 0; i < field_count; i++) { field= mysql_fetch_field(result); if (!opt_silent) { if (is_null[i]) fprintf(stdout, " %-*s |", (int) field->max_length, "NULL"); else if (length[i] == 0) { data[i][0]= '\0'; /* unmodified buffer */ fprintf(stdout, " %*s |", (int) field->max_length, data[i]); } else if (IS_NUM(field->type)) fprintf(stdout, " %*s |", (int) field->max_length, data[i]); else fprintf(stdout, " %-*s |", (int) field->max_length, data[i]); } } if (!opt_silent) { fputc('\t', stdout); fputc('\n', stdout); } row_count++; } DIE_UNLESS(rc == MYSQL_NO_DATA); if (!opt_silent) { if (row_count) my_print_dashes(result); fprintf(stdout, "\n\t%d %s returned\n", row_count, row_count == 1 ? "row" : "rows"); } mysql_free_result(result); return row_count; }
int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg) { int error=0; ulong cache_size; MYISAM_SHARE *share=info->s; DBUG_ENTER("mi_extra"); DBUG_PRINT("enter",("function: %d",(int) function)); switch (function) { case HA_EXTRA_RESET_STATE: /* Reset state (don't free buffers) */ info->lastinx= 0; /* Use first index as def */ info->last_search_keypage=info->lastpos= HA_OFFSET_ERROR; info->page_changed=1; /* Next/prev gives first/last */ if (info->opt_flag & READ_CACHE_USED) { reinit_io_cache(&info->rec_cache,READ_CACHE,0, (pbool) (info->lock_type != F_UNLCK), (pbool) test(info->update & HA_STATE_ROW_CHANGED) ); } info->update= ((info->update & HA_STATE_CHANGED) | HA_STATE_NEXT_FOUND | HA_STATE_PREV_FOUND); break; case HA_EXTRA_CACHE: if (info->lock_type == F_UNLCK && (share->options & HA_OPTION_PACK_RECORD)) { error=1; /* Not possibly if not locked */ my_errno=EACCES; break; } if (info->s->file_map) /* Don't use cache if mmap */ break; #if defined(HAVE_MMAP) && defined(HAVE_MADVISE) if ((share->options & HA_OPTION_COMPRESS_RECORD)) { mysql_mutex_lock(&share->intern_lock); if (_mi_memmap_file(info)) { /* We don't nead MADV_SEQUENTIAL if small file */ madvise((char*) share->file_map, share->state.state.data_file_length, share->state.state.data_file_length <= RECORD_CACHE_SIZE*16 ? MADV_RANDOM : MADV_SEQUENTIAL); mysql_mutex_unlock(&share->intern_lock); break; } mysql_mutex_unlock(&share->intern_lock); } #endif if (info->opt_flag & WRITE_CACHE_USED) { info->opt_flag&= ~WRITE_CACHE_USED; if ((error=end_io_cache(&info->rec_cache))) break; } if (!(info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED | MEMMAP_USED))) { cache_size= (extra_arg ? *(ulong*) extra_arg : my_default_record_cache_size); if (!(init_io_cache(&info->rec_cache,info->dfile, (uint) MY_MIN(info->state->data_file_length + 1, cache_size), READ_CACHE,0L,(pbool) (info->lock_type != F_UNLCK), MYF(share->write_flag & MY_WAIT_IF_FULL)))) { info->opt_flag|=READ_CACHE_USED; info->update&= ~HA_STATE_ROW_CHANGED; } if (share->concurrent_insert) info->rec_cache.end_of_file=info->state->data_file_length; } break; case HA_EXTRA_REINIT_CACHE: if (info->opt_flag & READ_CACHE_USED) { reinit_io_cache(&info->rec_cache,READ_CACHE,info->nextpos, (pbool) (info->lock_type != F_UNLCK), (pbool) test(info->update & HA_STATE_ROW_CHANGED)); info->update&= ~HA_STATE_ROW_CHANGED; if (share->concurrent_insert) info->rec_cache.end_of_file=info->state->data_file_length; } break; case HA_EXTRA_WRITE_CACHE: if (info->lock_type == F_UNLCK) { error=1; /* Not possibly if not locked */ break; } cache_size= (extra_arg ? *(ulong*) extra_arg : my_default_record_cache_size); if (!(info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED | OPT_NO_ROWS)) && !share->state.header.uniques) if (!(init_io_cache(&info->rec_cache,info->dfile, cache_size, WRITE_CACHE,info->state->data_file_length, (pbool) (info->lock_type != F_UNLCK), MYF(share->write_flag & MY_WAIT_IF_FULL)))) { info->opt_flag|=WRITE_CACHE_USED; info->update&= ~(HA_STATE_ROW_CHANGED | HA_STATE_WRITE_AT_END | HA_STATE_EXTEND_BLOCK); } break; case HA_EXTRA_PREPARE_FOR_UPDATE: if (info->s->data_file_type != DYNAMIC_RECORD) break; /* Remove read/write cache if dynamic rows */ case HA_EXTRA_NO_CACHE: if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED)) { info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED); error=end_io_cache(&info->rec_cache); /* Sergei will insert full text index caching here */ } #if defined(HAVE_MMAP) && defined(HAVE_MADVISE) if (info->opt_flag & MEMMAP_USED) madvise((char*) share->file_map, share->state.state.data_file_length, MADV_RANDOM); #endif break; case HA_EXTRA_FLUSH_CACHE: if (info->opt_flag & WRITE_CACHE_USED) { if ((error=flush_io_cache(&info->rec_cache))) { mi_print_error(info->s, HA_ERR_CRASHED); mi_mark_crashed(info); /* Fatal error found */ } } break; case HA_EXTRA_NO_READCHECK: info->opt_flag&= ~READ_CHECK_USED; /* No readcheck */ break; case HA_EXTRA_READCHECK: info->opt_flag|= READ_CHECK_USED; break; case HA_EXTRA_KEYREAD: /* Read only keys to record */ case HA_EXTRA_REMEMBER_POS: info->opt_flag |= REMEMBER_OLD_POS; bmove((uchar*) info->lastkey+share->base.max_key_length*2, (uchar*) info->lastkey,info->lastkey_length); info->save_update= info->update; info->save_lastinx= info->lastinx; info->save_lastpos= info->lastpos; info->save_lastkey_length=info->lastkey_length; if (function == HA_EXTRA_REMEMBER_POS) break; /* fall through */ case HA_EXTRA_KEYREAD_CHANGE_POS: info->opt_flag |= KEY_READ_USED; info->read_record=_mi_read_key_record; break; case HA_EXTRA_NO_KEYREAD: case HA_EXTRA_RESTORE_POS: if (info->opt_flag & REMEMBER_OLD_POS) { bmove((uchar*) info->lastkey, (uchar*) info->lastkey+share->base.max_key_length*2, info->save_lastkey_length); info->update= info->save_update | HA_STATE_WRITTEN; info->lastinx= info->save_lastinx; info->lastpos= info->save_lastpos; info->lastkey_length=info->save_lastkey_length; } info->read_record= share->read_record; info->opt_flag&= ~(KEY_READ_USED | REMEMBER_OLD_POS); break; case HA_EXTRA_NO_USER_CHANGE: /* Database is somehow locked agains changes */ info->lock_type= F_EXTRA_LCK; /* Simulate as locked */ break; case HA_EXTRA_WAIT_LOCK: info->lock_wait=0; break; case HA_EXTRA_NO_WAIT_LOCK: info->lock_wait=MY_DONT_WAIT; break; case HA_EXTRA_NO_KEYS: if (info->lock_type == F_UNLCK) { error=1; /* Not possibly if not lock */ break; } if (mi_is_any_key_active(share->state.key_map)) { MI_KEYDEF *key=share->keyinfo; uint i; for (i=0 ; i < share->base.keys ; i++,key++) { if (!(key->flag & HA_NOSAME) && info->s->base.auto_key != i+1) { mi_clear_key_active(share->state.key_map, i); info->update|= HA_STATE_CHANGED; } } if (!share->changed) { share->state.changed|= STATE_CHANGED | STATE_NOT_ANALYZED; share->changed=1; /* Update on close */ if (!share->global_changed) { share->global_changed=1; share->state.open_count++; } } share->state.state= *info->state; error=mi_state_info_write(share->kfile,&share->state,1 | 2); } break; case HA_EXTRA_FORCE_REOPEN: mysql_mutex_lock(&THR_LOCK_myisam); share->last_version= 0L; /* Impossible version */ mysql_mutex_unlock(&THR_LOCK_myisam); break; case HA_EXTRA_PREPARE_FOR_DROP: mysql_mutex_lock(&THR_LOCK_myisam); share->last_version= 0L; /* Impossible version */ #ifdef __WIN__REMOVE_OBSOLETE_WORKAROUND /* Close the isam and data files as Win32 can't drop an open table */ mysql_mutex_lock(&share->intern_lock); if (flush_key_blocks(share->key_cache, share->kfile, (function == HA_EXTRA_FORCE_REOPEN ? FLUSH_RELEASE : FLUSH_IGNORE_CHANGED))) { error=my_errno; share->changed=1; mi_print_error(info->s, HA_ERR_CRASHED); mi_mark_crashed(info); /* Fatal error found */ } if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED)) { info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED); error=end_io_cache(&info->rec_cache); } if (info->lock_type != F_UNLCK && ! info->was_locked) { info->was_locked=info->lock_type; if (mi_lock_database(info,F_UNLCK)) error=my_errno; info->lock_type = F_UNLCK; } if (share->kfile >= 0) _mi_decrement_open_count(info); if (share->kfile >= 0 && mysql_file_close(share->kfile, MYF(0))) error=my_errno; { LIST *list_element ; for (list_element=myisam_open_list ; list_element ; list_element=list_element->next) { MI_INFO *tmpinfo=(MI_INFO*) list_element->data; if (tmpinfo->s == info->s) { if (tmpinfo->dfile >= 0 && mysql_file_close(tmpinfo->dfile, MYF(0))) error = my_errno; tmpinfo->dfile= -1; } } } share->kfile= -1; /* Files aren't open anymore */ mysql_mutex_unlock(&share->intern_lock); #endif mysql_mutex_unlock(&THR_LOCK_myisam); break; case HA_EXTRA_FLUSH: if (!share->temporary) flush_key_blocks(share->key_cache, share->kfile, FLUSH_KEEP); #ifdef HAVE_PWRITE _mi_decrement_open_count(info); #endif if (share->not_flushed) { share->not_flushed=0; if (mysql_file_sync(share->kfile, MYF(0))) error= my_errno; if (mysql_file_sync(info->dfile, MYF(0))) error= my_errno; if (error) { share->changed=1; mi_print_error(info->s, HA_ERR_CRASHED); mi_mark_crashed(info); /* Fatal error found */ } } if (share->base.blobs) mi_alloc_rec_buff(info, -1, &info->rec_buff); break; case HA_EXTRA_NORMAL: /* Theese isn't in use */ info->quick_mode=0; break; case HA_EXTRA_QUICK: info->quick_mode=1; break; case HA_EXTRA_NO_ROWS: if (!share->state.header.uniques) info->opt_flag|= OPT_NO_ROWS; break; case HA_EXTRA_PRELOAD_BUFFER_SIZE: info->preload_buff_size= *((ulong *) extra_arg); break; case HA_EXTRA_CHANGE_KEY_TO_UNIQUE: case HA_EXTRA_CHANGE_KEY_TO_DUP: mi_extra_keyflag(info, function); break; case HA_EXTRA_MMAP: #ifdef HAVE_MMAP mysql_mutex_lock(&share->intern_lock); /* Memory map the data file if it is not already mapped. It is safe to memory map a file while other threads are using file I/O on it. Assigning a new address to a function pointer is an atomic operation. intern_lock prevents that two or more mappings are done at the same time. */ if (!share->file_map) { if (mi_dynmap_file(info, share->state.state.data_file_length)) { DBUG_PRINT("warning",("mmap failed: errno: %d",errno)); error= my_errno= errno; } } mysql_mutex_unlock(&share->intern_lock); #endif break; case HA_EXTRA_MARK_AS_LOG_TABLE: mysql_mutex_lock(&share->intern_lock); share->is_log_table= TRUE; mysql_mutex_unlock(&share->intern_lock); break; case HA_EXTRA_KEY_CACHE: case HA_EXTRA_NO_KEY_CACHE: default: break; } { char tmp[1]; tmp[0]=function; myisam_log_command(MI_LOG_EXTRA,info,(uchar*) tmp,1,error); } DBUG_RETURN(error); } /* mi_extra */
static zip_int64_t buffer_write(buffer_t *buffer, const zip_uint8_t *data, zip_uint64_t length, zip_error_t *error) { if (buffer->offset + length > buffer->nfragments * buffer->fragment_size) { zip_uint64_t needed_fragments = (buffer->offset + length + buffer->fragment_size - 1) / buffer->fragment_size; zip_uint64_t new_capacity = buffer->nfragments; zip_uint64_t i; if (new_capacity == 0) { new_capacity = 4; } while (new_capacity < needed_fragments) { new_capacity *= 2; } zip_uint8_t **fragment = realloc(buffer->fragment, new_capacity * sizeof(*fragment)); if (fragment == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return -1; } for (i = buffer->nfragments; i < new_capacity; i++) { fragment[i] = NULL; } buffer->fragment = fragment; buffer->nfragments = new_capacity; } if (!only_nul(data, length)) { zip_uint64_t idx, n, fragment_offset; idx = buffer->offset / buffer->fragment_size; fragment_offset = buffer->offset % buffer->fragment_size; n = 0; while (n < length) { zip_uint64_t left = MY_MIN(length - n, buffer->fragment_size - fragment_offset); if (buffer->fragment[idx] == NULL) { if ((buffer->fragment[idx] = (zip_uint8_t *)malloc(buffer->fragment_size)) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return -1; } memset(buffer->fragment[idx], 0, buffer->fragment_size); } memcpy(buffer->fragment[idx] + fragment_offset, data + n, left); n += left; idx++; fragment_offset = 0; } } buffer->offset += length; if (buffer->offset > buffer->size) { buffer->size = buffer->offset; } return (zip_int64_t)length; }
int maria_extra(MARIA_HA *info, enum ha_extra_function function, void *extra_arg) { int error= 0; ulong cache_size; MARIA_SHARE *share= info->s; my_bool block_records= share->data_file_type == BLOCK_RECORD; DBUG_ENTER("maria_extra"); DBUG_PRINT("enter",("function: %d",(int) function)); switch (function) { case HA_EXTRA_RESET_STATE: /* Reset state (don't free buffers) */ info->lastinx= ~0; /* Detect index changes */ info->last_search_keypage= info->cur_row.lastpos= HA_OFFSET_ERROR; info->page_changed= 1; /* Next/prev gives first/last */ if (info->opt_flag & READ_CACHE_USED) { reinit_io_cache(&info->rec_cache,READ_CACHE,0, (pbool) (info->lock_type != F_UNLCK), (pbool) MY_TEST(info->update & HA_STATE_ROW_CHANGED) ); } info->update= ((info->update & HA_STATE_CHANGED) | HA_STATE_NEXT_FOUND | HA_STATE_PREV_FOUND); break; case HA_EXTRA_CACHE: if (block_records) break; /* Not supported */ if (info->lock_type == F_UNLCK && (share->options & HA_OPTION_PACK_RECORD)) { error= 1; /* Not possibly if not locked */ my_errno= EACCES; break; } if (info->s->file_map) /* Don't use cache if mmap */ break; #if defined(HAVE_MMAP) && defined(HAVE_MADVISE) if ((share->options & HA_OPTION_COMPRESS_RECORD)) { mysql_mutex_lock(&share->intern_lock); if (_ma_memmap_file(info)) { /* We don't nead MADV_SEQUENTIAL if small file */ madvise((char*) share->file_map, share->state.state.data_file_length, share->state.state.data_file_length <= RECORD_CACHE_SIZE*16 ? MADV_RANDOM : MADV_SEQUENTIAL); mysql_mutex_unlock(&share->intern_lock); break; } mysql_mutex_unlock(&share->intern_lock); } #endif if (info->opt_flag & WRITE_CACHE_USED) { info->opt_flag&= ~WRITE_CACHE_USED; if ((error= end_io_cache(&info->rec_cache))) break; } if (!(info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED | MEMMAP_USED))) { cache_size= (extra_arg ? *(ulong*) extra_arg : my_default_record_cache_size); if (!(init_io_cache(&info->rec_cache, info->dfile.file, (uint) MY_MIN(share->state.state.data_file_length+1, cache_size), READ_CACHE,0L,(pbool) (info->lock_type != F_UNLCK), MYF(share->write_flag & MY_WAIT_IF_FULL)))) { info->opt_flag|= READ_CACHE_USED; info->update&= ~HA_STATE_ROW_CHANGED; } if (share->non_transactional_concurrent_insert) info->rec_cache.end_of_file= info->state->data_file_length; } break; case HA_EXTRA_REINIT_CACHE: if (info->opt_flag & READ_CACHE_USED) { reinit_io_cache(&info->rec_cache, READ_CACHE, info->cur_row.nextpos, (pbool) (info->lock_type != F_UNLCK), (pbool) MY_TEST(info->update & HA_STATE_ROW_CHANGED)); info->update&= ~HA_STATE_ROW_CHANGED; if (share->non_transactional_concurrent_insert) info->rec_cache.end_of_file= info->state->data_file_length; } break; case HA_EXTRA_WRITE_CACHE: if (info->lock_type == F_UNLCK) { error= 1; /* Not possibly if not locked */ break; } if (block_records) break; /* Not supported */ cache_size= (extra_arg ? *(ulong*) extra_arg : my_default_record_cache_size); if (!(info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED | OPT_NO_ROWS)) && !share->state.header.uniques) if (!(init_io_cache(&info->rec_cache, info->dfile.file, cache_size, WRITE_CACHE, info->state->data_file_length, (pbool) (info->lock_type != F_UNLCK), MYF(share->write_flag & MY_WAIT_IF_FULL)))) { info->opt_flag|= WRITE_CACHE_USED; info->update&= ~(HA_STATE_ROW_CHANGED | HA_STATE_WRITE_AT_END | HA_STATE_EXTEND_BLOCK); } break; case HA_EXTRA_PREPARE_FOR_UPDATE: if (info->s->data_file_type != DYNAMIC_RECORD) break; /* Remove read/write cache if dynamic rows */ case HA_EXTRA_NO_CACHE: if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED)) { info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED); error= end_io_cache(&info->rec_cache); /* Sergei will insert full text index caching here */ } #if defined(HAVE_MMAP) && defined(HAVE_MADVISE) if (info->opt_flag & MEMMAP_USED) madvise((char*) share->file_map, share->state.state.data_file_length, MADV_RANDOM); #endif break; case HA_EXTRA_FLUSH_CACHE: if (info->opt_flag & WRITE_CACHE_USED) { if ((error= flush_io_cache(&info->rec_cache))) { /* Fatal error found */ _ma_set_fatal_error(share, HA_ERR_CRASHED); } } break; case HA_EXTRA_NO_READCHECK: info->opt_flag&= ~READ_CHECK_USED; /* No readcheck */ break; case HA_EXTRA_READCHECK: info->opt_flag|= READ_CHECK_USED; break; case HA_EXTRA_KEYREAD: /* Read only keys to record */ case HA_EXTRA_REMEMBER_POS: info->opt_flag|= REMEMBER_OLD_POS; bmove(info->last_key.data + share->base.max_key_length*2, info->last_key.data, info->last_key.data_length + info->last_key.ref_length); info->save_update= info->update; info->save_lastinx= info->lastinx; info->save_lastpos= info->cur_row.lastpos; info->save_lastkey_data_length= info->last_key.data_length; info->save_lastkey_ref_length= info->last_key.ref_length; if (function == HA_EXTRA_REMEMBER_POS) break; /* fall through */ case HA_EXTRA_KEYREAD_CHANGE_POS: info->opt_flag|= KEY_READ_USED; info->read_record= _ma_read_key_record; break; case HA_EXTRA_NO_KEYREAD: case HA_EXTRA_RESTORE_POS: if (info->opt_flag & REMEMBER_OLD_POS) { bmove(info->last_key.data, info->last_key.data + share->base.max_key_length*2, info->save_lastkey_data_length + info->save_lastkey_ref_length); info->update= info->save_update | HA_STATE_WRITTEN; info->lastinx= info->save_lastinx; info->cur_row.lastpos= info->save_lastpos; info->last_key.data_length= info->save_lastkey_data_length; info->last_key.ref_length= info->save_lastkey_ref_length; info->last_key.flag= 0; } info->read_record= share->read_record; info->opt_flag&= ~(KEY_READ_USED | REMEMBER_OLD_POS); break; case HA_EXTRA_NO_USER_CHANGE: /* Database is somehow locked agains changes */ info->lock_type= F_EXTRA_LCK; /* Simulate as locked */ break; case HA_EXTRA_WAIT_LOCK: info->lock_wait= 0; break; case HA_EXTRA_NO_WAIT_LOCK: info->lock_wait= MY_SHORT_WAIT; break; case HA_EXTRA_NO_KEYS: /* we're going to modify pieces of the state, stall Checkpoint */ mysql_mutex_lock(&share->intern_lock); if (info->lock_type == F_UNLCK) { mysql_mutex_unlock(&share->intern_lock); error= 1; /* Not possibly if not lock */ break; } if (maria_is_any_key_active(share->state.key_map)) { MARIA_KEYDEF *key= share->keyinfo; uint i; for (i =0 ; i < share->base.keys ; i++,key++) { if (!(key->flag & HA_NOSAME) && info->s->base.auto_key != i+1) { maria_clear_key_active(share->state.key_map, i); info->update|= HA_STATE_CHANGED; } } if (!share->changed) { share->changed= 1; /* Update on close */ share->state.changed|= STATE_CHANGED | STATE_NOT_ANALYZED; if (!share->global_changed) { share->global_changed= 1; share->state.open_count++; } } if (!share->now_transactional) share->state.state= *info->state; /* That state write to disk must be done, even for transactional tables; indeed the table's share is going to be lost (there was a HA_EXTRA_FORCE_REOPEN before, which set share->last_version to 0), and so the only way it leaves information (share->state.key_map) for the posterity is by writing it to disk. */ DBUG_ASSERT(!maria_in_recovery); error= _ma_state_info_write(share, MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET | MA_STATE_INFO_WRITE_FULL_INFO); } mysql_mutex_unlock(&share->intern_lock); break; case HA_EXTRA_FORCE_REOPEN: /* MySQL uses this case after it has closed all other instances of this table. We however do a flush here for additional safety. */ /** @todo consider porting these flush-es to MyISAM */ DBUG_ASSERT(share->reopen == 1); error= _ma_flush_table_files(info, MARIA_FLUSH_DATA | MARIA_FLUSH_INDEX, FLUSH_FORCE_WRITE, FLUSH_FORCE_WRITE); if (!error && share->changed) { mysql_mutex_lock(&share->intern_lock); error= _ma_state_info_write(share, MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET| MA_STATE_INFO_WRITE_FULL_INFO); mysql_mutex_unlock(&share->intern_lock); } mysql_mutex_lock(&THR_LOCK_maria); mysql_mutex_lock(&share->intern_lock); /* protect against Checkpoint */ /* Safety against assert in checkpoint */ share->bitmap.changed_not_flushed= 0; /* this makes the share not be re-used next time the table is opened */ share->last_version= 0L; /* Impossible version */ mysql_mutex_unlock(&share->intern_lock); mysql_mutex_unlock(&THR_LOCK_maria); break; case HA_EXTRA_PREPARE_FOR_DROP: /* Signals about intent to delete this table */ share->deleting= TRUE; share->global_changed= FALSE; /* force writing changed flag */ /* To force repair if reopened */ share->state.open_count= 1; share->changed= 1; _ma_mark_file_changed_now(share); /* Fall trough */ case HA_EXTRA_PREPARE_FOR_RENAME: { my_bool do_flush= MY_TEST(function != HA_EXTRA_PREPARE_FOR_DROP); my_bool save_global_changed; enum flush_type type; /* This share, to have last_version=0, needs to save all its data/index blocks to disk if this is not for a DROP TABLE. Otherwise they would be invisible to future openers; and they could even go to disk late and cancel the work of future openers. */ if (info->lock_type != F_UNLCK && !info->was_locked) { info->was_locked= info->lock_type; if (maria_lock_database(info, F_UNLCK)) error= my_errno; info->lock_type= F_UNLCK; } /* We don't need to call _mi_decrement_open_count() if we are dropping the table, as the files will be removed anyway. If we are aborted before the files is removed, it's better to not call it as in that case the automatic repair on open will add the missing index entries */ mysql_mutex_lock(&share->intern_lock); if (share->kfile.file >= 0 && function != HA_EXTRA_PREPARE_FOR_DROP) _ma_decrement_open_count(info, 0); if (info->trn) { _ma_remove_table_from_trnman(share, info->trn); /* Ensure we don't point to the deleted data in trn */ info->state= info->state_start= &share->state.state; } /* Remove history for table */ _ma_reset_state(info); type= do_flush ? FLUSH_RELEASE : FLUSH_IGNORE_CHANGED; save_global_changed= share->global_changed; share->global_changed= 1; /* Don't increment open count */ mysql_mutex_unlock(&share->intern_lock); if (_ma_flush_table_files(info, MARIA_FLUSH_DATA | MARIA_FLUSH_INDEX, type, type)) { error=my_errno; share->changed= 1; } mysql_mutex_lock(&share->intern_lock); share->global_changed= save_global_changed; if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED)) { info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED); if (end_io_cache(&info->rec_cache)) error= 1; } if (share->kfile.file >= 0) { if (do_flush) { /* Save the state so that others can find it from disk. */ if ((share->changed && _ma_state_info_write(share, MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET | MA_STATE_INFO_WRITE_FULL_INFO)) || mysql_file_sync(share->kfile.file, MYF(0))) error= my_errno; } else { /* be sure that state is not tried for write as file may be closed */ share->changed= 0; share->global_changed= 0; share->state.open_count= 0; } } if (share->data_file_type == BLOCK_RECORD && share->bitmap.file.file >= 0) { DBUG_ASSERT(share->bitmap.non_flushable == 0 && share->bitmap.changed == 0); if (do_flush && my_sync(share->bitmap.file.file, MYF(0))) error= my_errno; share->bitmap.changed_not_flushed= 0; } /* last_version must be protected by intern_lock; See collect_tables() */ share->last_version= 0L; /* Impossible version */ mysql_mutex_unlock(&share->intern_lock); break; } case HA_EXTRA_PREPARE_FOR_FORCED_CLOSE: if (info->trn) { mysql_mutex_lock(&share->intern_lock); _ma_remove_table_from_trnman(share, info->trn); /* Ensure we don't point to the deleted data in trn */ info->state= info->state_start= &share->state.state; mysql_mutex_unlock(&share->intern_lock); } break; case HA_EXTRA_FLUSH: if (!share->temporary) error= _ma_flush_table_files(info, MARIA_FLUSH_DATA | MARIA_FLUSH_INDEX, FLUSH_KEEP, FLUSH_KEEP); _ma_decrement_open_count(info, 1); if (share->not_flushed) { share->not_flushed= 0; if (_ma_sync_table_files(info)) error= my_errno; if (error) { /* Fatal error found */ share->changed= 1; _ma_set_fatal_error(share, HA_ERR_CRASHED); } } break; case HA_EXTRA_NORMAL: /* Theese isn't in use */ info->quick_mode= 0; break; case HA_EXTRA_QUICK: info->quick_mode= 1; break; case HA_EXTRA_NO_ROWS: if (!share->state.header.uniques) info->opt_flag|= OPT_NO_ROWS; break; case HA_EXTRA_PRELOAD_BUFFER_SIZE: info->preload_buff_size= *((ulong *) extra_arg); break; case HA_EXTRA_CHANGE_KEY_TO_UNIQUE: case HA_EXTRA_CHANGE_KEY_TO_DUP: maria_extra_keyflag(info, function); break; case HA_EXTRA_MMAP: #ifdef HAVE_MMAP if (block_records) break; /* Not supported */ mysql_mutex_lock(&share->intern_lock); /* Memory map the data file if it is not already mapped. It is safe to memory map a file while other threads are using file I/O on it. Assigning a new address to a function pointer is an atomic operation. intern_lock prevents that two or more mappings are done at the same time. */ if (!share->file_map) { if (_ma_dynmap_file(info, share->state.state.data_file_length)) { DBUG_PRINT("warning",("mmap failed: errno: %d",errno)); error= my_errno= errno; } else { share->file_read= _ma_mmap_pread; share->file_write= _ma_mmap_pwrite; } } mysql_mutex_unlock(&share->intern_lock); #endif break; case HA_EXTRA_MARK_AS_LOG_TABLE: mysql_mutex_lock(&share->intern_lock); share->is_log_table= TRUE; mysql_mutex_unlock(&share->intern_lock); break; case HA_EXTRA_KEY_CACHE: case HA_EXTRA_NO_KEY_CACHE: default: break; } DBUG_RETURN(error); } /* maria_extra */
PQRYRES CSVColumns(PGLOBAL g, const char *fn, char sep, char q, int hdr, int mxr, bool info) { static int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT, TYPE_INT, TYPE_SHORT}; static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME, FLD_PREC, FLD_LENGTH, FLD_SCALE}; static unsigned int length[] = {6, 6, 8, 10, 10, 6}; char *p, *colname[MAXCOL], dechar, filename[_MAX_PATH], buf[4096]; int i, imax, hmax, n, nerr, phase, blank, digit, dec, type; int ncol = sizeof(buftyp) / sizeof(int); int num_read = 0, num_max = 10000000; // Statistics int len[MAXCOL], typ[MAXCOL], prc[MAXCOL]; FILE *infile; PQRYRES qrp; PCOLRES crp; if (info) { imax = hmax = 0; length[0] = 128; goto skipit; } // endif info // num_max = atoi(p+1); // Max num of record to test #if defined(WIN32) if (sep == ',' || strnicmp(setlocale(LC_NUMERIC, NULL), "French", 6)) dechar = '.'; else dechar = ','; #else // !WIN32 dechar = '.'; #endif // !WIN32 if (trace) htrc("File %s sep=%c q=%c hdr=%d mxr=%d\n", SVP(fn), sep, q, hdr, mxr); if (!fn) { strcpy(g->Message, MSG(MISSING_FNAME)); return NULL; } // endif fn imax = hmax = nerr = 0; mxr = MY_MAX(0, mxr); for (i = 0; i < MAXCOL; i++) { colname[i] = NULL; len[i] = 0; typ[i] = TYPE_UNKNOWN; prc[i] = 0; } // endfor i /*********************************************************************/ /* Open the input file. */ /*********************************************************************/ PlugSetPath(filename, fn, PlgGetDataPath(g)); if (!(infile= global_fopen(g, MSGID_CANNOT_OPEN, filename, "r"))) return NULL; if (hdr) { /*******************************************************************/ /* Make the column names from the first line. */ /*******************************************************************/ phase = 0; if (fgets(buf, sizeof(buf), infile)) { n = strlen(buf) + 1; buf[n - 2] = '\0'; #if defined(UNIX) // The file can be imported from Windows if (buf[n - 3] == '\r') buf[n - 3] = 0; #endif // UNIX p = (char*)PlugSubAlloc(g, NULL, n); memcpy(p, buf, n); //skip leading blanks for (; *p == ' '; p++) ; if (q && *p == q) { // Header is quoted p++; phase = 1; } // endif q colname[0] = p; } else { sprintf(g->Message, MSG(FILE_IS_EMPTY), fn); goto err; } // endif's for (i = 1; *p; p++) if (phase == 1 && *p == q) { *p = '\0'; phase = 0; } else if (*p == sep && !phase) { *p = '\0'; //skip leading blanks for (; *(p+1) == ' '; p++) ; if (q && *(p+1) == q) { // Header is quoted p++; phase = 1; } // endif q colname[i++] = p + 1; } // endif sep num_read++; imax = hmax = i; for (i = 0; i < hmax; i++) length[0] = MY_MAX(length[0], strlen(colname[i])); } // endif hdr for (num_read++; num_read <= num_max; num_read++) { /*******************************************************************/ /* Now start the reading process. Read one line. */ /*******************************************************************/ if (fgets(buf, sizeof(buf), infile)) { n = strlen(buf); buf[n - 1] = '\0'; #if defined(UNIX) // The file can be imported from Windows if (buf[n - 2] == '\r') buf[n - 2] = 0; #endif // UNIX } else if (feof(infile)) { sprintf(g->Message, MSG(EOF_AFTER_LINE), num_read -1); break; } else { sprintf(g->Message, MSG(ERR_READING_REC), num_read, fn); goto err; } // endif's /*******************************************************************/ /* Make the test for field lengths. */ /*******************************************************************/ i = n = phase = blank = digit = dec = 0; for (p = buf; *p; p++) if (*p == sep) { if (phase != 1) { if (i == MAXCOL - 1) { sprintf(g->Message, MSG(TOO_MANY_FIELDS), num_read, fn); goto err; } // endif i if (n) { len[i] = MY_MAX(len[i], n); type = (digit || (dec && n == 1)) ? TYPE_STRING : (dec) ? TYPE_DOUBLE : TYPE_INT; typ[i] = MY_MIN(type, typ[i]); prc[i] = MY_MAX((typ[i] == TYPE_DOUBLE) ? (dec - 1) : 0, prc[i]); } // endif n i++; n = phase = blank = digit = dec = 0; } else // phase == 1 n++; } else if (*p == ' ') { if (phase < 2) n++; if (blank) digit = 1; } else if (*p == q) { if (phase == 0) { if (blank) if (++nerr > mxr) { sprintf(g->Message, MSG(MISPLACED_QUOTE), num_read); goto err; } else goto skip; n = 0; phase = digit = 1; } else if (phase == 1) { if (*(p+1) == q) { // This is currently not implemented for CSV tables // if (++nerr > mxr) { // sprintf(g->Message, MSG(QUOTE_IN_QUOTE), num_read); // goto err; // } else // goto skip; p++; n++; } else phase = 2; } else if (++nerr > mxr) { // phase == 2 sprintf(g->Message, MSG(MISPLACED_QUOTE), num_read); goto err; } else goto skip; } else { if (phase == 2) if (++nerr > mxr) { sprintf(g->Message, MSG(MISPLACED_QUOTE), num_read); goto err; } else goto skip; // isdigit cannot be used here because of debug assert if (!strchr("0123456789", *p)) { if (!digit && *p == dechar) dec = 1; // Decimal point found else if (blank || !(*p == '-' || *p == '+')) digit = 1; } else if (dec) dec++; // More decimals n++; blank = 1; } // endif's *p if (phase == 1) if (++nerr > mxr) { sprintf(g->Message, MSG(UNBALANCE_QUOTE), num_read); goto err; } else goto skip; if (n) { len[i] = MY_MAX(len[i], n); type = (digit || n == 0 || (dec && n == 1)) ? TYPE_STRING : (dec) ? TYPE_DOUBLE : TYPE_INT; typ[i] = MY_MIN(type, typ[i]); prc[i] = MY_MAX((typ[i] == TYPE_DOUBLE) ? (dec - 1) : 0, prc[i]); } // endif n imax = MY_MAX(imax, i+1); skip: ; // Skip erroneous line } // endfor num_read if (trace) { htrc("imax=%d Lengths:", imax); for (i = 0; i < imax; i++) htrc(" %d", len[i]); htrc("\n"); } // endif trace fclose(infile); skipit: if (trace) htrc("CSVColumns: imax=%d hmax=%d len=%d\n", imax, hmax, length[0]); /*********************************************************************/ /* Allocate the structures used to refer to the result set. */ /*********************************************************************/ qrp = PlgAllocResult(g, ncol, imax, IDS_COLUMNS + 3, buftyp, fldtyp, length, false, false); if (info || !qrp) return qrp; qrp->Nblin = imax; /*********************************************************************/ /* Now get the results into blocks. */ /*********************************************************************/ for (i = 0; i < imax; i++) { if (i >= hmax) { sprintf(buf, "COL%.3d", i+1); p = buf; } else p = colname[i]; if (typ[i] == TYPE_UNKNOWN) // Void column typ[i] = TYPE_STRING; crp = qrp->Colresp; // Column Name crp->Kdata->SetValue(p, i); crp = crp->Next; // Data Type crp->Kdata->SetValue(typ[i], i); crp = crp->Next; // Type Name crp->Kdata->SetValue(GetTypeName(typ[i]), i); crp = crp->Next; // Precision crp->Kdata->SetValue(len[i], i); crp = crp->Next; // Length crp->Kdata->SetValue(len[i], i); crp = crp->Next; // Scale (precision) crp->Kdata->SetValue(prc[i], i); } // endfor i /*********************************************************************/ /* Return the result pointer for use by GetData routines. */ /*********************************************************************/ return qrp; err: fclose(infile); return NULL; } // end of CSVCColumns