Beispiel #1
0
int myrg_rkey(MYRG_INFO *info,uchar *buf,int inx, const uchar *key,
            key_part_map keypart_map, enum ha_rkey_function search_flag)
{
  uchar *key_buff;
  uint pack_key_length;
  uint16 last_used_keyseg;
  MYRG_TABLE *table;
  MI_INFO *mi;
  int err;
  DBUG_ENTER("myrg_rkey");
  LINT_INIT(key_buff);
  LINT_INIT(pack_key_length);
  LINT_INIT(last_used_keyseg);

  if (_myrg_init_queue(info,inx,search_flag))
    DBUG_RETURN(my_errno);

  for (table=info->open_tables ; table != info->end_table ; table++)
  {
    mi=table->table;

    if (table == info->open_tables)
    {
      err=mi_rkey(mi, 0, inx, key, keypart_map, search_flag);
      /* Get the saved packed key and packed key length. */
      key_buff=(uchar*) mi->lastkey+mi->s->base.max_key_length;
      pack_key_length=mi->pack_key_length;
      last_used_keyseg= mi->last_used_keyseg;
    }
    else
    {
      mi->once_flags|= USE_PACKED_KEYS;
      mi->last_used_keyseg= last_used_keyseg;
      err=mi_rkey(mi, 0, inx, key_buff, pack_key_length, search_flag);
    }
    info->last_used_table=table+1;

    if (err)
    {
      if (err == HA_ERR_KEY_NOT_FOUND)
	continue;
      DBUG_PRINT("exit", ("err: %d", err));
      DBUG_RETURN(err);
    }
    /* adding to queue */
    queue_insert(&(info->by_key),(uchar *)table);

  }

  DBUG_PRINT("info", ("tables with matches: %u", info->by_key.elements));
  if (!info->by_key.elements)
    DBUG_RETURN(HA_ERR_KEY_NOT_FOUND);

  mi=(info->current_table=(MYRG_TABLE *)queue_top(&(info->by_key)))->table;
  mi->once_flags|= RRND_PRESERVE_LASTINX;
  DBUG_PRINT("info", ("using table no: %d",
                      (int) (info->current_table - info->open_tables + 1)));
  DBUG_DUMP("result key", (uchar*) mi->lastkey, mi->lastkey_length);
  DBUG_RETURN(_myrg_mi_read_record(mi,buf));
}
static uchar *rtree_pick_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key, 
			     uint key_length, uchar *page_buf, uint nod_flag)
{
  double increase;
  double best_incr = DBL_MAX;
  double perimeter;
  double best_perimeter;
  uchar *best_key;
  uchar *k = rt_PAGE_FIRST_KEY(page_buf, nod_flag);
  uchar *last = rt_PAGE_END(page_buf);

  LINT_INIT(best_perimeter);
  LINT_INIT(best_key);

  for (; k < last; k = rt_PAGE_NEXT_KEY(k, key_length, nod_flag))
  {
    if ((increase = rtree_perimeter_increase(keyinfo->seg, k, key, key_length,
					     &perimeter)) == -1)
      return NULL;
    if ((increase < best_incr)||
	(increase == best_incr && perimeter < best_perimeter))
    {
      best_key = k;
      best_perimeter= perimeter;
      best_incr = increase;
    }
  }
  return best_key;
}
static uchar *rtree_pick_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key, 
			     uint key_length, uchar *page_buf, uint nod_flag)
{
  double increase;
  double best_incr;
  double area;
  double best_area;
  uchar *best_key= NULL;
  uchar *k = rt_PAGE_FIRST_KEY(page_buf, nod_flag);
  uchar *last = rt_PAGE_END(page_buf);

  LINT_INIT(best_area);
  LINT_INIT(best_key);
  LINT_INIT(best_incr);

  for (; k < last; k = rt_PAGE_NEXT_KEY(k, key_length, nod_flag))
  {
    /* The following is safe as -1.0 is an exact number */
    if ((increase = rtree_area_increase(keyinfo->seg, k, key, key_length, 
                                        &area)) == -1.0)
      return NULL;
    /* The following should be safe, even if we compare doubles */
    if (!best_key || increase < best_incr ||
        ((increase == best_incr) && (area < best_area)))
    {
      best_key = k;
      best_area = area;
      best_incr = increase;
    }
  }
  return best_key;
}
Beispiel #4
0
static int check_lock(struct st_lock_list *list, const char* lock_type,
		      const char *where, my_bool same_owner, bool no_cond)
{
  THR_LOCK_DATA *data,**prev;
  uint count=0;
  THR_LOCK_OWNER *first_owner;
  LINT_INIT(first_owner);

  prev= &list->data;
  if (list->data)
  {
    enum thr_lock_type last_lock_type=list->data->type;

    if (same_owner && list->data)
      first_owner= list->data->owner;
    for (data=list->data; data && count++ < MAX_LOCKS ; data=data->next)
    {
      if (data->type != last_lock_type)
	last_lock_type=TL_IGNORE;
      if (data->prev != prev)
      {
	fprintf(stderr,
		"Warning: prev link %d didn't point at previous lock at %s: %s\n",
		count, lock_type, where);
	return 1;
      }
      if (same_owner &&
          !thr_lock_owner_equal(data->owner, first_owner) &&
	  last_lock_type != TL_WRITE_ALLOW_WRITE)
      {
	fprintf(stderr,
		"Warning: Found locks from different threads in %s: %s\n",
		lock_type,where);
	return 1;
      }
      if (no_cond && data->cond)
      {
	fprintf(stderr,
		"Warning: Found active lock with not reset cond %s: %s\n",
		lock_type,where);
	return 1;
      }
      prev= &data->next;
    }
    if (data)
    {
      fprintf(stderr,"Warning: found too many locks at %s: %s\n",
	      lock_type,where);
      return 1;
    }
  }
  if (prev != list->last)
  {
    fprintf(stderr,"Warning: last didn't point at last lock at %s: %s\n",
	    lock_type, where);
    return 1;
  }
  return 0;
}
Beispiel #5
0
int maria_update(register MARIA_HA *info, const uchar *oldrec, uchar *newrec)
{
  int flag,key_changed,save_errno;
  reg3 my_off_t pos;
  uint i;
  uchar old_key_buff[MARIA_MAX_KEY_BUFF],*new_key_buff;
  my_bool auto_key_changed= 0;
  ulonglong changed;
  MARIA_SHARE *share= info->s;
  MARIA_KEYDEF *keyinfo;
  DBUG_ENTER("maria_update");
  LINT_INIT(new_key_buff);
  LINT_INIT(changed);

  DBUG_EXECUTE_IF("maria_pretend_crashed_table_on_usage",
                  maria_print_error(info->s, HA_ERR_CRASHED);
                  DBUG_RETURN(my_errno= HA_ERR_CRASHED););
Beispiel #6
0
int mi_update(register MI_INFO *info, const byte *oldrec, byte *newrec)
{
  int flag,key_changed,save_errno;
  reg3 my_off_t pos;
  uint i;
  uchar old_key[MI_MAX_KEY_BUFF],*new_key;
  bool auto_key_changed=0;
  ulonglong changed;
  MYISAM_SHARE *share=info->s;
  ha_checksum old_checksum;
  DBUG_ENTER("mi_update");
  LINT_INIT(new_key);
  LINT_INIT(changed);
  LINT_INIT(old_checksum);

  DBUG_EXECUTE_IF("myisam_pretend_crashed_table_on_usage",
                  mi_print_error(info->s, HA_ERR_CRASHED);
                  DBUG_RETURN(my_errno= HA_ERR_CRASHED););
Beispiel #7
0
static int create_header_files(struct errors *error_head)
{
  uint er_last;
  FILE *er_definef, *sql_statef, *er_namef;
  struct errors *tmp_error;
  DBUG_ENTER("create_header_files");
  LINT_INIT(er_last);

  if (!(er_definef= my_fopen(HEADERFILE, O_WRONLY, MYF(MY_WME))))
  {
    DBUG_RETURN(1);
  }
  if (!(sql_statef= my_fopen(STATEFILE, O_WRONLY, MYF(MY_WME))))
  {
    my_fclose(er_definef, MYF(0));
    DBUG_RETURN(1);
  }
  if (!(er_namef= my_fopen(NAMEFILE, O_WRONLY, MYF(MY_WME))))
  {
    my_fclose(er_definef, MYF(0));
    my_fclose(sql_statef, MYF(0));
    DBUG_RETURN(1);
  }

  fprintf(er_definef, "/* Autogenerated file, please don't edit */\n\n");
  fprintf(sql_statef, "/* Autogenerated file, please don't edit */\n\n");
  fprintf(er_namef, "/* Autogenerated file, please don't edit */\n\n");

  fprintf(er_definef, "#define ER_ERROR_FIRST %d\n", error_head->d_code);

  for (tmp_error= error_head; tmp_error; tmp_error= tmp_error->next_error)
  {
    /*
       generating mysqld_error.h
       fprintf() will automatically add \r on windows
    */
    fprintf(er_definef, "#define %s %d\n", tmp_error->er_name,
	    tmp_error->d_code);
    er_last= tmp_error->d_code;

    /* generating sql_state.h file */
    if (tmp_error->sql_code1[0] || tmp_error->sql_code2[0])
      fprintf(sql_statef,
	      "{ %-40s,\"%s\", \"%s\" },\n", tmp_error->er_name,
	      tmp_error->sql_code1, tmp_error->sql_code2);
    /*generating er_name file */
    fprintf(er_namef, "{ \"%s\", %d },\n", tmp_error->er_name,
	    tmp_error->d_code);

  }
  /* finishing off with mysqld_error.h */
  fprintf(er_definef, "#define ER_ERROR_LAST %d\n", er_last);
  my_fclose(er_definef, MYF(0));
  my_fclose(sql_statef, MYF(0));
  my_fclose(er_namef, MYF(0));
  DBUG_RETURN(0);
}
MI_INFO *mi_open(const char *name, int mode, uint open_flags)
{
  int lock_error,kfile,open_mode,save_errno,have_rtree=0, realpath_err;
  uint i,j,len,errpos,head_length,base_pos,offset,info_length,keys,
    key_parts,unique_key_parts,fulltext_keys,uniques;
  char name_buff[FN_REFLEN], org_name[FN_REFLEN], index_name[FN_REFLEN],
       data_name[FN_REFLEN];
  uchar *disk_cache, *disk_pos, *end_pos;
  MI_INFO info,*m_info,*old_info;
  MYISAM_SHARE share_buff,*share;
  ulong rec_per_key_part[HA_MAX_POSSIBLE_KEY*MI_MAX_KEY_SEG];
  my_off_t key_root[HA_MAX_POSSIBLE_KEY],key_del[MI_MAX_KEY_BLOCK_SIZE];
  ulonglong max_key_file_length, max_data_file_length;
  DBUG_ENTER("mi_open");

  LINT_INIT(m_info);
  kfile= -1;
  lock_error=1;
  errpos=0;
  head_length=sizeof(share_buff.state.header);
  memset(&info, 0, sizeof(info));

  realpath_err= my_realpath(name_buff,
                  fn_format(org_name,name,"",MI_NAME_IEXT,4),MYF(0));
  if (my_is_symlink(org_name) &&
      (realpath_err || (*myisam_test_invalid_symlink)(name_buff)))
  {
    my_errno= HA_WRONG_CREATE_OPTION;
    DBUG_RETURN (NULL);
  }

  mysql_mutex_lock(&THR_LOCK_myisam);
  if (!(old_info=test_if_reopen(name_buff)))
  {
    share= &share_buff;
    memset(&share_buff, 0, sizeof(share_buff));
    share_buff.state.rec_per_key_part=rec_per_key_part;
    share_buff.state.key_root=key_root;
    share_buff.state.key_del=key_del;
    share_buff.key_cache= multi_key_cache_search((uchar*) name_buff,
                                                 strlen(name_buff));

    DBUG_EXECUTE_IF("myisam_pretend_crashed_table_on_open",
                    if (strstr(name, "/t1"))
                    {
                      my_errno= HA_ERR_CRASHED;
                      goto err;
                    });
Beispiel #9
0
int find_type(my_string x, TYPELIB *typelib, uint full_name)
{
  int find,pos,findpos;
  reg1 my_string i;
  reg2 const char *j;
  DBUG_ENTER("find_type");
  DBUG_PRINT("enter",("x: '%s'  lib: %lx",x,typelib));

  if (!typelib->count)
  {
    DBUG_PRINT("exit",("no count"));
    DBUG_RETURN(0);
  }
  LINT_INIT(findpos);
  find=0;
  for (pos=0 ; (j=typelib->type_names[pos]) ; pos++)
  {
    for (i=x ; *i && toupper(*i) == toupper(*j) ; i++, j++) ;
    if (! *j)
    {
      while (*i == ' ')
	i++;					/* skipp_end_space */
      if (! *i)
	DBUG_RETURN(pos+1);
    }
    if (! *i && (!*j || !(full_name & 1)))
    {
      find++;
      findpos=pos;
    }
  }
  if (find == 0 && (full_name & 4) && x[0] == '#' && strend(x)[-1] == '#' &&
      (findpos=atoi(x+1)-1) >= 0 && (uint) findpos < typelib->count)
    find=1;
  else if (find == 0 || ! x[0])
  {
    DBUG_PRINT("exit",("Couldn't find type"));
    DBUG_RETURN(0);
  }
  else if (find != 1 || (full_name & 1))
  {
    DBUG_PRINT("exit",("Too many possybilities"));
    DBUG_RETURN(-1);
  }
  if (!(full_name & 2))
    (void) strmov(x,typelib->type_names[findpos]);
  DBUG_RETURN(findpos+1);
} /* find_type */
Beispiel #10
0
void pack_dirname(my_string to, const char *from)
{
  int cwd_err;
  uint d_length,length,buff_length;
  my_string start;
  char buff[FN_REFLEN];
  DBUG_ENTER("pack_dirname");

  LINT_INIT(buff_length);
  (void) intern_filename(to,from);		/* Change to intern name */

#ifdef FN_DEVCHAR
  if ((start=strrchr(to,FN_DEVCHAR)) != 0)	/* Skipp device part */
    start++;
  else
#endif
    start=to;

  if (!(cwd_err= my_getwd(buff,FN_REFLEN,MYF(0))))
  {
    buff_length= (uint) strlen(buff);
    d_length=(uint) (start-to);
    if ((start == to ||
	 (buff_length == d_length && !bcmp(buff,start,d_length))) &&
	*start != FN_LIBCHAR && *start)
    {						/* Put current dir before */
      bchange(to,d_length,buff,buff_length,(uint) strlen(to)+1);
    }
  }

  if ((d_length= cleanup_dirname(to,to)) != 0)
  {
    length=0;
    if (home_dir)
    {
      length= (uint) strlen(home_dir);
      if (home_dir[length-1] == FN_LIBCHAR)
	length--;				/* Don't test last '/' */
    }
    if (length > 1 && length < d_length)
    {						/* test if /xx/yy -> ~/yy */
      if (bcmp(to,home_dir,length) == 0 && to[length] == FN_LIBCHAR)
      {
	to[0]=FN_HOMELIB;			/* Filename begins with ~ */
	(void) strmov_overlapp(to+1,to+length);
      }
    }
    if (! cwd_err)
    {						/* Test if cwd is ~/... */
      if (length > 1 && length < buff_length)
      {
	if (bcmp(buff,home_dir,length) == 0 && buff[length] == FN_LIBCHAR)
	{
	  buff[0]=FN_HOMELIB;
	  (void) strmov_overlapp(buff+1,buff+length);
	}
      }
      if (is_prefix(to,buff))
      {
	length= (uint) strlen(buff);
	if (to[length])
	  (void) strmov_overlapp(to,to+length);	/* Remove everything before */
	else
	{
	  to[0]= FN_CURLIB;			/* Put ./ instead of cwd */
	  to[1]= FN_LIBCHAR;
	  to[2]= '\0';
	}
      }
    }
  }
  DBUG_PRINT("exit",("to: '%s'",to));
  DBUG_VOID_RETURN;
} /* pack_dirname */
Beispiel #11
0
int nisam_create(const char *name,uint keys,N_KEYDEF *keyinfo,
		 N_RECINFO *recinfo,
		 ulong records,ulong reloc, uint flags,uint old_options,
		 ulong data_file_length)
{
  register uint i,j;
  File dfile,file;
  int errpos,save_errno;
  uint fields,length,max_key_length,packed,pointer,reclength,min_pack_length,
       key_length,info_length,key_segs,options,min_key_length_skipp,max_block,
       base_pos;
  char buff[max(FN_REFLEN,512)];
  ulong tot_length,pack_reclength;
  enum en_fieldtype type;
  ISAM_SHARE share;
  N_KEYDEF *keydef;
  N_KEYSEG *keyseg;
  N_RECINFO *rec;
  DBUG_ENTER("nisam_create");

  LINT_INIT(dfile);
  pthread_mutex_lock(&THR_LOCK_isam);
  errpos=0;
  options=0;
  base_pos=512;					/* Enough for N_STATE_INFO */
  bzero((byte*) &share,sizeof(share));
  if ((file = my_create(fn_format(buff,name,"",N_NAME_IEXT,4),0,
       O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
    goto err;
  errpos=1;
  VOID(fn_format(buff,name,"",N_NAME_DEXT,2+4));
  if (!(flags & HA_DONT_TOUCH_DATA))
  {
    if ((dfile = my_create(buff,0,O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
      goto err;
    errpos=2;
  }
  else if (!(old_options & HA_OPTION_TEMP_COMPRESS_RECORD))
    options=old_options & (HA_OPTION_COMPRESS_RECORD |
			   HA_OPTION_READ_ONLY_DATA | HA_OPTION_PACK_RECORD);
  if (reloc > records)
    reloc=records;				/* Check if wrong parameter */

	/* Start by checking fields and field-types used */
  reclength=0;
  for (rec=recinfo, fields=packed=min_pack_length=0, pack_reclength=0L;
       rec->base.type != (int) FIELD_LAST;
       rec++,fields++)
  {
    reclength+=rec->base.length;
    if ((type=(enum en_fieldtype) rec->base.type))
    {
      packed++;
      if (type == FIELD_BLOB)
      {
	share.base.blobs++;
	rec->base.length-= sizeof(char*);	/* Don't calc pointer */
	if (pack_reclength != NI_POS_ERROR)
	{
	  if (rec->base.length == 4)
	    pack_reclength= (ulong) NI_POS_ERROR;
	  else
	    pack_reclength+=sizeof(char*)+(1 << (rec->base.length*8));
	}
      }
      else if (type == FIELD_SKIP_PRESPACE ||
	       type == FIELD_SKIP_ENDSPACE)
      {
	if (pack_reclength != NI_POS_ERROR)
	  pack_reclength+= rec->base.length > 255 ? 2 : 1;
	min_pack_length++;
      }
      else if (type == FIELD_ZERO)
	packed--;
      else if (type != FIELD_SKIP_ZERO)
      {
	min_pack_length+=rec->base.length;
	packed--;				/* Not a pack record type */
      }
    }
    else
      min_pack_length+=rec->base.length;
  }
  if ((packed & 7) == 1)
  {				/* Bad packing, try to remove a zero-field */
    while (rec != recinfo)
    {
      rec--;
      if (rec->base.type == (int) FIELD_SKIP_ZERO && rec->base.length == 1)
      {
	rec->base.type=(int) FIELD_NORMAL;
	packed--;
	min_pack_length++;
	break;
      }
    }
  }
  if (packed && !(options & HA_OPTION_COMPRESS_RECORD))
    options|=HA_OPTION_PACK_RECORD;	/* Must use packed records */

  packed=(packed+7)/8;
  if (pack_reclength != NI_POS_ERROR)
    pack_reclength+= reclength+packed;
  min_pack_length+=packed;

  if (options & HA_OPTION_COMPRESS_RECORD)
  {
    if (data_file_length >= (1L << 24))
      pointer=4;
    else if (data_file_length >= (1L << 16))
      pointer=3;
    else
      pointer=2;
  }
  else if (((records == 0L && pack_reclength < 255) ||
	    options & HA_OPTION_PACK_RECORD) ||
	   records >= (ulong) 16000000L ||
	   pack_reclength == (ulong) NI_POS_ERROR ||
	   ((options & HA_OPTION_PACK_RECORD) &&
	    pack_reclength+4 >= (ulong) 14000000L/records))
    pointer=4;
  else if (records == 0L || records >= (ulong) 65000L ||
	   ((options & HA_OPTION_PACK_RECORD) &&
	    pack_reclength+4 >= (ulong) 60000L/records))
    pointer=3;
  else
    pointer=2;

  max_block=max_key_length=0; tot_length=key_segs=0;
  for (i=0, keydef=keyinfo ; i < keys ; i++ , keydef++)
  {
    share.state.key_root[i]= share.state.key_del[i]= NI_POS_ERROR;
    share.base.rec_per_key[i]= (keydef->base.flag & HA_NOSAME) ? 1L : 0L;
    min_key_length_skipp=length=0;
    key_length=pointer;

    if (keydef->base.flag & HA_PACK_KEY &&
	keydef->seg[0].base.length > 127)
      keydef->base.flag&= ~HA_PACK_KEY;		/* Can't pack long keys */
    if (keydef->base.flag & HA_PACK_KEY)
    {
      if ((keydef->seg[0].base.flag & HA_SPACE_PACK) &&
	  keydef->seg[0].base.type == (int) HA_KEYTYPE_NUM)
	keydef->seg[0].base.flag&= ~HA_SPACE_PACK;
      if (!(keydef->seg[0].base.flag & HA_SPACE_PACK))
	length++;
      keydef->seg[0].base.flag|=HA_PACK_KEY;	/* for easyer intern test */
      options|=HA_OPTION_PACK_KEYS;		/* Using packed keys */
      if (!(keydef->seg[0].base.flag & HA_SPACE_PACK))
	min_key_length_skipp+=keydef->seg[0].base.length;
    }
    keydef->base.keysegs=0;
    for (keyseg=keydef->seg ; keyseg->base.type ; keyseg++)
    {
      keydef->base.keysegs++;
      if (keyseg->base.length > 127)
	keyseg->base.flag&= ~(HA_SPACE_PACK | HA_PACK_KEY);
      if (keyseg->base.flag & HA_SPACE_PACK)
      {
	keydef->base.flag |= HA_SPACE_PACK_USED;
	options|=HA_OPTION_PACK_KEYS;		/* Using packed keys */
	length++;
	min_key_length_skipp+=keyseg->base.length;
      }
      key_length+= keyseg->base.length;
    }
    bzero((gptr) keyseg,sizeof(keyseg[0]));
    keyseg->base.length=(uint16) pointer;	/* Last key part is pointer */
    key_segs+=keydef->base.keysegs;
    length+=key_length;
    keydef->base.block_length=nisam_block_size;
    keydef->base.keylength= (uint16) key_length;
    keydef->base.minlength= (uint16) (length-min_key_length_skipp);
    keydef->base.maxlength= (uint16) length;

    if ((uint) keydef->base.block_length > max_block)
      max_block=(uint) keydef->base.block_length;
    if (length > max_key_length)
      max_key_length= length;
    tot_length+= (records/(ulong) (((uint) keydef->base.block_length-5)/
				   (length*2)))*
      (ulong) keydef->base.block_length;
  }
  info_length=(uint) (base_pos+sizeof(N_BASE_INFO)+keys*sizeof(N_SAVE_KEYDEF)+
		      (keys+key_segs)*sizeof(N_SAVE_KEYSEG)+
		      fields*sizeof(N_SAVE_RECINFO));

  bmove(share.state.header.file_version,(byte*) nisam_file_magic,4);
  old_options=options| (old_options & HA_OPTION_TEMP_COMPRESS_RECORD ?
			HA_OPTION_COMPRESS_RECORD |
			HA_OPTION_TEMP_COMPRESS_RECORD: 0);
  int2store(share.state.header.options,old_options);
  int2store(share.state.header.header_length,info_length);
  int2store(share.state.header.state_info_length,sizeof(N_STATE_INFO));
  int2store(share.state.header.base_info_length,sizeof(N_BASE_INFO));
  int2store(share.state.header.base_pos,base_pos);

  share.state.dellink = NI_POS_ERROR;
  share.state.process=	(ulong) getpid();
  share.state.uniq=	(ulong) file;
  share.state.loop=	0;
  share.state.version=	(ulong) time((time_t*) 0);
  share.base.options=options;
  share.base.rec_reflength=pointer;
  share.base.key_reflength=((!tot_length || tot_length > 30000000L) ? 3 :
			   tot_length > 120000L ? 2 : 1);
  share.base.keys= share.state.keys = keys;
  share.base.keystart = share.state.key_file_length=MY_ALIGN(info_length,
							  nisam_block_size);
  share.base.max_block=max_block;
  share.base.max_key_length=(uint) ALIGN_SIZE(max_key_length+4);
  share.base.records=records;
  share.base.reloc=reloc;
  share.base.reclength=reclength;
  share.base.pack_reclength=
    (uint) (reclength+packed-share.base.blobs*sizeof(char*));
  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;
  share.base.sortkey= (ushort) ~0;
  share.base.max_data_file_length= (pointer == 4) ? (ulong) ~0L :
    (options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ?
    (ulong) (1L << (pointer*8)) :
    (pointer == 3 && reclength >= 256L) ? (ulong) NI_POS_ERROR :
    ((ulong) reclength * (1L << (pointer*8)));
  share.base.max_key_file_length= (share.base.key_reflength == 3 ?
				   NI_POS_ERROR :
				   (ulong)
				   (1L << (share.base.key_reflength*8))*512);
  share.base.min_block_length=
    (share.base.pack_reclength+3 < N_EXTEND_BLOCK_LENGTH &&
     ! share.base.blobs) ?
    max(share.base.pack_reclength,N_MIN_BLOCK_LENGTH) :
    N_EXTEND_BLOCK_LENGTH;
  if (! (flags & HA_DONT_TOUCH_DATA))
    share.base.create_time= (long) time((time_t*) 0);

  bzero(buff,base_pos);
  if (my_write(file,(char*) &share.state,sizeof(N_STATE_INFO),MYF(MY_NABP)) ||
      my_write(file,buff,base_pos-sizeof(N_STATE_INFO),MYF(MY_NABP)) ||
      my_write(file,(char*) &share.base,sizeof(N_BASE_INFO),MYF(MY_NABP)))
    goto err;

  for (i=0 ; i < share.base.keys ; i++)
  {
    if (my_write(file,(char*) &keyinfo[i].base,sizeof(N_SAVE_KEYDEF),
		 MYF(MY_NABP)))
      goto err;
    for (j=0 ; j <= keyinfo[i].base.keysegs ; j++)
    {
      if (my_write(file,(char*) &keyinfo[i].seg[j].base,sizeof(N_SAVE_KEYSEG),
		   MYF(MY_NABP)))
	goto err;
    }
  }
  for (i=0 ; i < share.base.fields ; i++)
    if (my_write(file,(char*) &recinfo[i].base, (uint) sizeof(N_SAVE_RECINFO),
		 MYF(MY_NABP)))
      goto err;

	/* Enlarge files */
  if (my_chsize(file, (ulong) share.base.keystart, 0, MYF(0)))
    goto err;

  if (! (flags & HA_DONT_TOUCH_DATA))
  {
#ifdef USE_RELOC
    if (my_chsize(dfile, share.base.min_pack_length*reloc, 0, MYF(0)))
      goto err;
#endif
    errpos=1;
    if (my_close(dfile,MYF(0)))
      goto err;
  }
  errpos=0;
  pthread_mutex_unlock(&THR_LOCK_isam);
  if (my_close(file,MYF(0)))
    goto err;
  DBUG_RETURN(0);

err:
  pthread_mutex_unlock(&THR_LOCK_isam);
  save_errno=my_errno;
  switch (errpos) {
  case 2:
    VOID(my_close(dfile,MYF(0)));
    /* fall through */
  case 1:
    VOID(my_close(file,MYF(0)));
  }
  my_errno=save_errno;				/* R{tt felkod tillbaka */
  DBUG_RETURN(-1);
} /* nisam_create */
Beispiel #12
0
int main(int argc, char *argv[])
{
  register uint i,j;
  uint ant,n1,n2,n3;
  uint write_count,update,opt_delete,check2,dupp_keys,found_key;
  int error;
  ulong pos;
  unsigned long key_check;
  char record[128],record2[128],record3[128],key[10];
  const char *filename,*filename2;
  HP_INFO *file,*file2;
  HP_KEYDEF keyinfo[MAX_KEYS];
  HA_KEYSEG keyseg[MAX_KEYS*5];
  HEAP_PTR position;
  HP_CREATE_INFO hp_create_info;
  CHARSET_INFO *cs= &my_charset_latin1;
  MY_INIT(argv[0]);		/* init my_sys library & pthreads */
  LINT_INIT(position);

  filename= "test2";
  filename2= "test2_2";
  file=file2=0;
  get_options(argc,argv);
  
  bzero(&hp_create_info, sizeof(hp_create_info));
  hp_create_info.max_table_size= 1024L*1024L;

  write_count=update=opt_delete=0;
  key_check=0;

  keyinfo[0].seg=keyseg;
  keyinfo[0].keysegs=1;
  keyinfo[0].flag= 0;
  keyinfo[0].algorithm= HA_KEY_ALG_HASH;
  keyinfo[0].seg[0].type=HA_KEYTYPE_BINARY;
  keyinfo[0].seg[0].start=0;
  keyinfo[0].seg[0].length=6;
  keyinfo[0].seg[0].null_bit=0;
  keyinfo[0].seg[0].charset=cs;
  keyinfo[1].seg=keyseg+1;
  keyinfo[1].keysegs=2;
  keyinfo[1].flag=0;
  keyinfo[1].algorithm= HA_KEY_ALG_HASH;
  keyinfo[1].seg[0].type=HA_KEYTYPE_BINARY;
  keyinfo[1].seg[0].start=7;
  keyinfo[1].seg[0].length=6;
  keyinfo[1].seg[0].null_bit=0;
  keyinfo[1].seg[0].charset=cs;
  keyinfo[1].seg[1].type=HA_KEYTYPE_TEXT;
  keyinfo[1].seg[1].start=0;			/* key in two parts */
  keyinfo[1].seg[1].length=6;
  keyinfo[1].seg[1].null_bit=0;
  keyinfo[1].seg[1].charset=cs;
  keyinfo[2].seg=keyseg+3;
  keyinfo[2].keysegs=1;
  keyinfo[2].flag=HA_NOSAME;
  keyinfo[2].algorithm= HA_KEY_ALG_HASH;
  keyinfo[2].seg[0].type=HA_KEYTYPE_BINARY;
  keyinfo[2].seg[0].start=12;
  keyinfo[2].seg[0].length=8;
  keyinfo[2].seg[0].null_bit=0;
  keyinfo[2].seg[0].charset=cs;
  keyinfo[3].seg=keyseg+4;
  keyinfo[3].keysegs=1;
  keyinfo[3].flag=HA_NOSAME;
  keyinfo[3].algorithm= HA_KEY_ALG_HASH;
  keyinfo[3].seg[0].type=HA_KEYTYPE_BINARY;
  keyinfo[3].seg[0].start=37;
  keyinfo[3].seg[0].length=1;
  keyinfo[3].seg[0].null_bit=1;
  keyinfo[3].seg[0].null_pos=38;
  keyinfo[3].seg[0].charset=cs;

  bzero((char*) key1,sizeof(key1));
  bzero((char*) key3,sizeof(key3));

  printf("- Creating heap-file\n");
  if (heap_create(filename,keys,keyinfo,reclength,(ulong) flag*100000L, 
		(ulong) recant/2, &hp_create_info) ||
      !(file= heap_open(filename, 2)))
    goto err;
  signal(SIGINT,endprog);

  printf("- Writing records:s\n");
  strmov(record,"          ..... key");

  for (i=0 ; i < recant ; i++)
  {
    n1=rnd(1000); n2=rnd(100); n3=rnd(min(recant*5,MAX_RECORDS));
    make_record(record,n1,n2,n3,"Pos",write_count);

    if (heap_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\n",n3);
    }
    else
    {
      if (key3[n3] == 1)
      {
	printf("Error: Didn't get error when writing second key: '%8d'\n",n3);
	goto err;
      }
      write_count++; key1[n1]++; key3[n3]=1;
      key_check+=n1;
    }
    if (testflag == 1 && heap_check_heap(file,0))
    {
      puts("Heap keys crashed");
      goto err;
    }
  }
  if (testflag == 1)
    goto end;
  if (heap_check_heap(file,0))
  {
    puts("Heap keys crashed");
    goto err;
  }

  printf("- Delete\n");
  for (i=0 ; i < write_count/10 ; i++)
  {
    for (j=rnd(1000)+1 ; j>0 && key1[j] == 0 ; j--) ;
    if (j != 0)
    {
      sprintf(key,"%6d",j);
      if (heap_rkey(file,record,0,key,6, HA_READ_KEY_EXACT))
      {
	printf("can't find key1: \"%s\"\n",key);
	goto err;
      }
#ifdef NOT_USED
      if (file->current_ptr == hp_find_block(&file->s->block,0) ||
	  file->current_ptr == hp_find_block(&file->s->block,1))
	continue;			/* Don't remove 2 first records */
#endif
      if (heap_delete(file,record))
      {
	printf("error: %d; can't delete record: \"%s\"\n", my_errno,record);
	goto err;
      }
      opt_delete++;
      key1[atoi(record+keyinfo[0].seg[0].start)]--;
      key3[atoi(record+keyinfo[2].seg[0].start)]=0;
      key_check-=atoi(record);
      if (testflag == 2 && heap_check_heap(file,0))
      {
	puts("Heap keys crashed");
	goto err;
      }
    }
    else
      puts("Warning: Skipping delete test because no dupplicate keys");
  }
  if (testflag==2) goto end;
  if (heap_check_heap(file,0))
  {
    puts("Heap keys crashed");
    goto err;
  }

  printf("- Update\n");
  for (i=0 ; i < write_count/10 ; i++)
  {
    n1=rnd(1000); n2=rnd(100); n3=rnd(min(recant*2,MAX_RECORDS));
    make_record(record2, n1, n2, n3, "XXX", update);
    if (rnd(2) == 1)
    {
      if (heap_scan_init(file))
	goto err;
      j=rnd(write_count-opt_delete);
      while ((error=heap_scan(file,record) == HA_ERR_RECORD_DELETED) ||
	     (!error && j))
      {
	if (!error)
	  j--;
      }
      if (error)
	goto err;
    }
    else
    {
      for (j=rnd(1000)+1 ; j>0 && key1[j] == 0 ; j--) ;
      if (!key1[j])
	continue;
      sprintf(key,"%6d",j);
      if (heap_rkey(file,record,0,key,6, HA_READ_KEY_EXACT))
      {
	printf("can't find key1: \"%s\"\n",key);
	goto err;
      }
    }
    if (heap_update(file,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,record,record2);
	goto err;
      }
      if (verbose)
	printf("Double key when tried to update:\nFrom: \"%s\"\nTo:   \"%s\"\n",record,record2);
    }
    else
    {
      key1[atoi(record+keyinfo[0].seg[0].start)]--;
      key3[atoi(record+keyinfo[2].seg[0].start)]=0;
      key1[n1]++; key3[n3]=1;
      update++;
      key_check=key_check-atoi(record)+n1;
    }
    if (testflag == 3 && heap_check_heap(file,0))
    {
      puts("Heap keys crashed");
      goto err;
    }
  }
  if (testflag == 3) goto end;
  if (heap_check_heap(file,0))
  {
    puts("Heap keys crashed");
    goto err;
  }

  for (i=999, dupp_keys=found_key=0 ; i>0 ; i--)
  {
    if (key1[i] > dupp_keys) { dupp_keys=key1[i]; found_key=i; }
    sprintf(key,"%6d",found_key);
  }

  if (dupp_keys > 3)
  {
    if (!silent)
      printf("- Read first key - next - delete - next -> last\n");
    DBUG_PRINT("progpos",("first - next - delete - next -> last"));

    if (heap_rkey(file,record,0,key,6, HA_READ_KEY_EXACT))
      goto err;
    if (heap_rnext(file,record3)) goto err;
    if (heap_delete(file,record3)) goto err;
    key_check-=atoi(record3);
    key1[atoi(record+keyinfo[0].seg[0].start)]--;
    key3[atoi(record+keyinfo[2].seg[0].start)]=0;
    opt_delete++;
    ant=2;
    while ((error=heap_rnext(file,record3)) == 0 ||
	   error == HA_ERR_RECORD_DELETED)
      if (! error)
	ant++;
    if (ant != dupp_keys)
    {
      printf("next: I can only find: %d records of %d\n",
	     ant,dupp_keys);
      goto end;
    }
    dupp_keys--;
    if (heap_check_heap(file,0))
    {
      puts("Heap keys crashed");
      goto err;
    }

    if (!silent)
      printf("- Read last key - delete - prev - prev - opt_delete - prev -> first\n");

    if (heap_rlast(file,record3,0)) goto err;
    if (heap_delete(file,record3)) goto err;
    key_check-=atoi(record3);
    key1[atoi(record+keyinfo[0].seg[0].start)]--;
    key3[atoi(record+keyinfo[2].seg[0].start)]=0;
    opt_delete++;
    if (heap_rprev(file,record3) || heap_rprev(file,record3))
      goto err;
    if (heap_delete(file,record3)) goto err;
    key_check-=atoi(record3);
    key1[atoi(record+keyinfo[0].seg[0].start)]--;
    key3[atoi(record+keyinfo[2].seg[0].start)]=0;
    opt_delete++;
    ant=3;
    while ((error=heap_rprev(file,record3)) == 0 ||
	   error == HA_ERR_RECORD_DELETED)
    {
      if (! error)
	ant++;
    }
    if (ant != dupp_keys)
    {
      printf("next: I can only find: %d records of %d\n",
	     ant,dupp_keys);
      goto end;
    }
    dupp_keys-=2;
    if (heap_check_heap(file,0))
    {
      puts("Heap keys crashed");
      goto err;
    }
  }
  else
    puts("Warning: Not enough duplicated keys:  Skipping delete key check");

  if (!silent)
    printf("- Read (first) - next - delete - next -> last\n");
  DBUG_PRINT("progpos",("first - next - delete - next -> last"));

  if (heap_scan_init(file))
    goto err;
  while ((error=heap_scan(file,record3) == HA_ERR_RECORD_DELETED)) ;
  if (error)
    goto err;
  if (heap_delete(file,record3)) goto err;
  key_check-=atoi(record3);
  opt_delete++;
  key1[atoi(record+keyinfo[0].seg[0].start)]--;
  key3[atoi(record+keyinfo[2].seg[0].start)]=0;
  ant=0;
  while ((error=heap_scan(file,record3)) == 0 ||
	 error == HA_ERR_RECORD_DELETED)
    if (! error)
      ant++;
  if (ant != write_count-opt_delete)
  {
    printf("next: Found: %d records of %d\n",ant,write_count-opt_delete);
    goto end;
  }
  if (heap_check_heap(file,0))
  {
    puts("Heap keys crashed");
    goto err;
  }

  puts("- Test if: Read rrnd - same - rkey - same");
  DBUG_PRINT("progpos",("Read rrnd - same"));
  pos=rnd(write_count-opt_delete-5)+5;
  heap_scan_init(file);
  i=5;
  while ((error=heap_scan(file,record)) == HA_ERR_RECORD_DELETED ||
	 (error == 0 && pos))
  {
    if (!error)
      pos--;
    if (i-- == 0)
    {
      bmove(record3,record,reclength);
      position=heap_position(file);
    }
  }
  if (error)
    goto err;
  bmove(record2,record,reclength);
  if (heap_rsame(file,record,-1) || heap_rsame(file,record2,2))
    goto err;
  if (bcmp(record2,record,reclength))
  {
    puts("heap_rsame didn't find right record");
    goto end;
  }

  puts("- Test of read through position");
  if (heap_rrnd(file,record,position))
    goto err;
  if (bcmp(record3,record,reclength))
  {
    puts("heap_frnd didn't find right record");
    goto end;
  }

  printf("- heap_info\n");
  {
    HEAPINFO info;
    heap_info(file,&info,0);
    /* We have to test with opt_delete +1 as this may be the case if the last
       inserted row was a duplicate key */
    if (info.records != write_count-opt_delete ||
	(info.deleted != opt_delete && info.deleted != opt_delete+1))
    {
      puts("Wrong info from heap_info");
      printf("Got: records: %ld(%d)  deleted: %ld(%d)\n",
	     info.records,write_count-opt_delete,info.deleted,opt_delete);
    }
  }

#ifdef OLD_HEAP_VERSION
  {
    uint check;
    printf("- Read through all records with rnd\n");
    if (heap_extra(file,HA_EXTRA_RESET) || heap_extra(file,HA_EXTRA_CACHE))
    {
      puts("got error from heap_extra");
      goto end;
    }
    ant=check=0;
    while ((error=heap_rrnd(file,record,(ulong) -1)) != HA_ERR_END_OF_FILE &&
	   ant < write_count + 10)
    {
      if (!error)
      {
	ant++;
	check+=calc_check(record,reclength);
      }
    }
    if (ant != write_count-opt_delete)
    {
      printf("rrnd: I can only find: %d records of %d\n", ant,
	     write_count-opt_delete);
      goto end;
    }
    if (heap_extra(file,HA_EXTRA_NO_CACHE))
    {
      puts("got error from heap_extra(HA_EXTRA_NO_CACHE)");
      goto end;
    }
  }
#endif

  printf("- Read through all records with scan\n");
  if (heap_extra(file,HA_EXTRA_RESET) || heap_extra(file,HA_EXTRA_CACHE))
  {
    puts("got error from heap_extra");
    goto end;
  }
  ant=check2=0;
  heap_scan_init(file);
  while ((error=heap_scan(file,record)) != HA_ERR_END_OF_FILE &&
	 ant < write_count + 10)
  {
    if (!error)
    {
      ant++;
      check2+=calc_check(record,reclength);
    }
  }
  if (ant != write_count-opt_delete)
  {
    printf("scan: I can only find: %d records of %d\n", ant,
	   write_count-opt_delete);
    goto end;
  }
#ifdef OLD_HEAP_VERSION
  if (check != check2)
  {
    puts("scan: Checksum didn't match reading with rrnd");
    goto end;
  }
#endif


  if (heap_extra(file,HA_EXTRA_NO_CACHE))
  {
    puts("got error from heap_extra(HA_EXTRA_NO_CACHE)");
    goto end;
  }

  for (i=999, dupp_keys=found_key=0 ; i>0 ; i--)
  {
    if (key1[i] > dupp_keys) { dupp_keys=key1[i]; found_key=i; }
    sprintf(key,"%6d",found_key);
  }
  printf("- Read through all keys with first-next-last-prev\n");
  ant=0;
  for (error=heap_rkey(file,record,0,key,6, HA_READ_KEY_EXACT);
      ! error ;
       error=heap_rnext(file,record))
    ant++;
  if (ant != dupp_keys)
  {
    printf("first-next: I can only find: %d records of %d\n", ant,
	   dupp_keys);
    goto end;
  }

  ant=0;
  for (error=heap_rlast(file,record,0) ;
      ! error ;
      error=heap_rprev(file,record))
  {
    ant++;
    check2+=calc_check(record,reclength);
  }
  if (ant != dupp_keys)
  {
    printf("last-prev: I can only find: %d records of %d\n", ant,
	   dupp_keys);
    goto end;
  }

  if (testflag == 4) goto end;

  printf("- Reading through all rows through keys\n");
  if (!(file2=heap_open(filename, 2)))
    goto err;
  if (heap_scan_init(file))
    goto err;
  while ((error=heap_scan(file,record)) != HA_ERR_END_OF_FILE)
  {
    if (error == 0)
    {
      if (heap_rkey(file2,record2,2,record+keyinfo[2].seg[0].start,8,
		    HA_READ_KEY_EXACT))
      {
	printf("can't find key3: \"%.8s\"\n",
	       record+keyinfo[2].seg[0].start);
	goto err;
      }
    }
  }
  heap_close(file2);

  printf("- Creating output heap-file 2\n");
  if (heap_create(filename2,1,keyinfo,reclength,0L,0L,&hp_create_info) ||
      !(file2= heap_open(filename2, 2)))
    goto err;

  printf("- Copying and removing records\n");
  if (heap_scan_init(file))
    goto err;
  while ((error=heap_scan(file,record)) != HA_ERR_END_OF_FILE)
  {
    if (error == 0)
    {
      if (heap_write(file2,record))
	goto err;
      key_check-=atoi(record);
      write_count++;
      if (heap_delete(file,record))
	goto err;
      opt_delete++;
    }
    pos++;
  }
  printf("- Checking heap tables\n");
  if (heap_check_heap(file,1) || heap_check_heap(file2,1))
  {
    puts("Heap keys crashed");
    goto err;
  }

  if (my_errno != HA_ERR_END_OF_FILE)
    printf("error: %d from heap_rrnd\n",my_errno);
  if (key_check)
    printf("error: Some read got wrong: check is %ld\n",(long) key_check);

end:
  printf("\nFollowing test have been made:\n");
  printf("Write records: %d\nUpdate records: %d\nDelete records: %d\n", write_count,update,opt_delete);
  heap_clear(file);
  if (heap_close(file) || (file2 && heap_close(file2)))
    goto err;
  heap_delete_table(filename2);
  heap_panic(HA_PANIC_CLOSE);
  my_end(MY_GIVE_INFO);
  return(0);
err:
  printf("Got error: %d when using heap-database\n",my_errno);
  VOID(heap_close(file));
  return(1);
} /* main */
Beispiel #13
0
my_bool str_to_time(const char *str, uint length, MYSQL_TIME *l_time,
                    int *warning)
{
  ulong date[5];
  ulonglong value;
  const char *end=str+length, *end_of_days;
  my_bool found_days,found_hours;
  uint state;

  l_time->neg=0;
  *warning= 0;
  for (; str != end && my_isspace(&my_charset_latin1,*str) ; str++)
    length--;
  if (str != end && *str == '-')
  {
    l_time->neg=1;
    str++;
    length--;
  }
  if (str == end)
    return 1;

  /* Check first if this is a full TIMESTAMP */
  if (length >= 12)
  {                                             /* Probably full timestamp */
    int was_cut;
    enum enum_mysql_timestamp_type
      res= str_to_datetime(str, length, l_time,
                           (TIME_FUZZY_DATE | TIME_DATETIME_ONLY), &was_cut);
    if ((int) res >= (int) MYSQL_TIMESTAMP_ERROR)
    {
      if (was_cut)
        *warning|= MYSQL_TIME_WARN_TRUNCATED;
      return res == MYSQL_TIMESTAMP_ERROR;
    }
  }

  /* Not a timestamp. Try to get this as a DAYS_TO_SECOND string */
  for (value=0; str != end && my_isdigit(&my_charset_latin1,*str) ; str++)
    value=value*10L + (long) (*str - '0');

  /* Skip all space after 'days' */
  end_of_days= str;
  for (; str != end && my_isspace(&my_charset_latin1, str[0]) ; str++)
    ;

  LINT_INIT(state);
  found_days=found_hours=0;
  if ((uint) (end-str) > 1 && str != end_of_days &&
      my_isdigit(&my_charset_latin1, *str))
  {                                             /* Found days part */
    date[0]= (ulong) value;
    state= 1;                                   /* Assume next is hours */
    found_days= 1;
  }
  else if ((end-str) > 1 &&  *str == time_separator &&
           my_isdigit(&my_charset_latin1, str[1]))
  {
    date[0]= 0;                                 /* Assume we found hours */
    date[1]= (ulong) value;
    state=2;
    found_hours=1;
    str++;                                      /* skip ':' */
  }
  else
  {
    /* String given as one number; assume HHMMSS format */
    date[0]= 0;
    date[1]= (ulong) (value/10000);
    date[2]= (ulong) (value/100 % 100);
    date[3]= (ulong) (value % 100);
    state=4;
    goto fractional;
  }

  /* Read hours, minutes and seconds */
  for (;;)
  {
    for (value=0; str != end && my_isdigit(&my_charset_latin1,*str) ; str++)
      value=value*10L + (long) (*str - '0');
    date[state++]= (ulong) value;
    if (state == 4 || (end-str) < 2 || *str != time_separator ||
        !my_isdigit(&my_charset_latin1,str[1]))
      break;
    str++;                                      /* Skip time_separator (':') */
  }

  if (state != 4)
  {                                             /* Not HH:MM:SS */
    /* Fix the date to assume that seconds was given */
    if (!found_hours && !found_days)
    {
      bmove_upp((uchar*) (date+4), (uchar*) (date+state),
                sizeof(long)*(state-1));
      bzero((uchar*) date, sizeof(long)*(4-state));
    }
    else
      bzero((uchar*) (date+state), sizeof(long)*(4-state));
  }

fractional:
  /* Get fractional second part */
  if ((end-str) >= 2 && *str == '.' && my_isdigit(&my_charset_latin1,str[1]))
  {
    int field_length= 5;
    str++; value=(uint) (uchar) (*str - '0');
    while (++str != end && my_isdigit(&my_charset_latin1, *str))
    {
      if (field_length-- > 0)
        value= value*10 + (uint) (uchar) (*str - '0');
    }
    if (field_length > 0)
      value*= (long) log_10_int[field_length];
    else if (field_length < 0)
      *warning|= MYSQL_TIME_WARN_TRUNCATED;
    date[4]= (ulong) value;
  }
  else
    date[4]=0;
    
  /* Check for exponent part: E<gigit> | E<sign><digit> */
  /* (may occur as result of %g formatting of time value) */
  if ((end - str) > 1 &&
      (*str == 'e' || *str == 'E') &&
      (my_isdigit(&my_charset_latin1, str[1]) ||
       ((str[1] == '-' || str[1] == '+') &&
        (end - str) > 2 &&
        my_isdigit(&my_charset_latin1, str[2]))))
    return 1;

  if (internal_format_positions[7] != 255)
  {
    /* Read a possible AM/PM */
    while (str != end && my_isspace(&my_charset_latin1, *str))
      str++;
    if (str+2 <= end && (str[1] == 'M' || str[1] == 'm'))
    {
      if (str[0] == 'p' || str[0] == 'P')
      {
        str+= 2;
        date[1]= date[1]%12 + 12;
      }
      else if (str[0] == 'a' || str[0] == 'A')
        str+=2;
    }
  }

  /* Integer overflow checks */
  if (date[0] > UINT_MAX || date[1] > UINT_MAX ||
      date[2] > UINT_MAX || date[3] > UINT_MAX ||
      date[4] > UINT_MAX)
    return 1;
  
  l_time->year=         0;                      /* For protocol::store_time */
  l_time->month=        0;
  l_time->day=          date[0];
  l_time->hour=         date[1];
  l_time->minute=       date[2];
  l_time->second=       date[3];
  l_time->second_part=  date[4];
  l_time->time_type= MYSQL_TIMESTAMP_TIME;

  /* Check if the value is valid and fits into MYSQL_TIME range */
  if (check_time_range(l_time, warning))
    return 1;
  
  /* Check if there is garbage at end of the MYSQL_TIME specification */
  if (str != end)
  {
    do
    {
      if (!my_isspace(&my_charset_latin1,*str))
      {
        *warning|= MYSQL_TIME_WARN_TRUNCATED;
        break;
      }
    } while (++str != end);
  }
  return 0;
}
Beispiel #14
0
enum enum_mysql_timestamp_type
str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time,
                ulonglong flags, int *was_cut)
{
  uint field_length, UNINIT_VAR(year_length), digits, i, number_of_fields;
  uint date[MAX_DATE_PARTS], date_len[MAX_DATE_PARTS];
  uint add_hours= 0, start_loop;
  ulong not_zero_date, allow_space;
  my_bool is_internal_format;
  const char *pos, *UNINIT_VAR(last_field_pos);
  const char *end=str+length;
  const uchar *format_position;
  my_bool found_delimitier= 0, found_space= 0;
  uint frac_pos, frac_len;
  DBUG_ENTER("str_to_datetime");
  DBUG_PRINT("ENTER",("str: %.*s",length,str));

  LINT_INIT(field_length);

  *was_cut= 0;

  /* Skip space at start */
  for (; str != end && my_isspace(&my_charset_latin1, *str) ; str++)
    ;
  if (str == end || ! my_isdigit(&my_charset_latin1, *str))
  {
    *was_cut= 1;
    DBUG_RETURN(MYSQL_TIMESTAMP_NONE);
  }

  is_internal_format= 0;
  /* This has to be changed if want to activate different timestamp formats */
  format_position= internal_format_positions;

  /*
    Calculate number of digits in first part.
    If length= 8 or >= 14 then year is of format YYYY.
    (YYYY-MM-DD,  YYYYMMDD, YYYYYMMDDHHMMSS)
  */
  for (pos=str;
       pos != end && (my_isdigit(&my_charset_latin1,*pos) || *pos == 'T');
       pos++)
    ;

  digits= (uint) (pos-str);
  start_loop= 0;                                /* Start of scan loop */
  date_len[format_position[0]]= 0;              /* Length of year field */
  if (pos == end || *pos == '.')
  {
    /* Found date in internal format (only numbers like YYYYMMDD) */
    year_length= (digits == 4 || digits == 8 || digits >= 14) ? 4 : 2;
    field_length= year_length;
    is_internal_format= 1;
    format_position= internal_format_positions;
  }
  else
  {
    if (format_position[0] >= 3)                /* If year is after HHMMDD */
    {
      /*
        If year is not in first part then we have to determinate if we got
        a date field or a datetime field.
        We do this by checking if there is two numbers separated by
        space in the input.
      */
      while (pos < end && !my_isspace(&my_charset_latin1, *pos))
        pos++;
      while (pos < end && !my_isdigit(&my_charset_latin1, *pos))
        pos++;
      if (pos == end)
      {
        if (flags & TIME_DATETIME_ONLY)
        {
          *was_cut= 1;
          DBUG_RETURN(MYSQL_TIMESTAMP_NONE);   /* Can't be a full datetime */
        }
        /* Date field.  Set hour, minutes and seconds to 0 */
        date[0]= date[1]= date[2]= date[3]= date[4]= 0;
        start_loop= 5;                         /* Start with first date part */
      }
    }

    field_length= format_position[0] == 0 ? 4 : 2;
  }

  /*
    Only allow space in the first "part" of the datetime field and:
    - after days, part seconds
    - before and after AM/PM (handled by code later)

    2003-03-03 20:00:20 AM
    20:00:20.000000 AM 03-03-2000
  */
  i= max((uint) format_position[0], (uint) format_position[1]);
  set_if_bigger(i, (uint) format_position[2]);
  allow_space= ((1 << i) | (1 << format_position[6]));
  allow_space&= (1 | 2 | 4 | 8);

  not_zero_date= 0;
  for (i = start_loop;
       i < MAX_DATE_PARTS-1 && str != end &&
         my_isdigit(&my_charset_latin1,*str);
       i++)
  {
    const char *start= str;
    ulong tmp_value= (uint) (uchar) (*str++ - '0');

    /*
      Internal format means no delimiters; every field has a fixed
      width. Otherwise, we scan until we find a delimiter and discard
      leading zeroes -- except for the microsecond part, where leading
      zeroes are significant, and where we never process more than six
      digits.
    */
    my_bool     scan_until_delim= !is_internal_format &&
                                  ((i != format_position[6]));

    while (str != end && my_isdigit(&my_charset_latin1,str[0]) &&
           (scan_until_delim || --field_length))
    {
      tmp_value=tmp_value*10 + (ulong) (uchar) (*str - '0');
      str++;
    }
    date_len[i]= (uint) (str - start);
    if (tmp_value > 999999)                     /* Impossible date part */
    {
      *was_cut= 1;
      DBUG_RETURN(MYSQL_TIMESTAMP_NONE);
    }
    date[i]=tmp_value;
    not_zero_date|= tmp_value;

    /* Length of next field */
    field_length= format_position[i+1] == 0 ? 4 : 2;

    if ((last_field_pos= str) == end)
    {
      i++;                                      /* Register last found part */
      break;
    }
    /* Allow a 'T' after day to allow CCYYMMDDT type of fields */
    if (i == format_position[2] && *str == 'T')
    {
      str++;                                    /* ISO8601:  CCYYMMDDThhmmss */
      continue;
    }
    if (i == format_position[5])                /* Seconds */
    {
      if (*str == '.')                          /* Followed by part seconds */
      {
        str++;
        field_length= 6;                        /* 6 digits */
      }
      continue;
    }
    while (str != end &&
           (my_ispunct(&my_charset_latin1,*str) ||
            my_isspace(&my_charset_latin1,*str)))
    {
      if (my_isspace(&my_charset_latin1,*str))
      {
        if (!(allow_space & (1 << i)))
        {
          *was_cut= 1;
          DBUG_RETURN(MYSQL_TIMESTAMP_NONE);
        }
        found_space= 1;
      }
      str++;
      found_delimitier= 1;                      /* Should be a 'normal' date */
    }
    /* Check if next position is AM/PM */
    if (i == format_position[6])                /* Seconds, time for AM/PM */
    {
      i++;                                      /* Skip AM/PM part */
      if (format_position[7] != 255)            /* If using AM/PM */
      {
        if (str+2 <= end && (str[1] == 'M' || str[1] == 'm'))
        {
          if (str[0] == 'p' || str[0] == 'P')
            add_hours= 12;
          else if (str[0] != 'a' || str[0] != 'A')
            continue;                           /* Not AM/PM */
          str+= 2;                              /* Skip AM/PM */
          /* Skip space after AM/PM */
          while (str != end && my_isspace(&my_charset_latin1,*str))
            str++;
        }
      }
    }
    last_field_pos= str;
  }
  if (found_delimitier && !found_space && (flags & TIME_DATETIME_ONLY))
  {
    *was_cut= 1;
    DBUG_RETURN(MYSQL_TIMESTAMP_NONE);          /* Can't be a datetime */
  }

  str= last_field_pos;

  number_of_fields= i - start_loop;
  while (i < MAX_DATE_PARTS)
  {
    date_len[i]= 0;
    date[i++]= 0;
  }

  if (!is_internal_format)
  {
    year_length= date_len[(uint) format_position[0]];
    if (!year_length)                           /* Year must be specified */
    {
      *was_cut= 1;
      DBUG_RETURN(MYSQL_TIMESTAMP_NONE);
    }

    l_time->year=               date[(uint) format_position[0]];
    l_time->month=              date[(uint) format_position[1]];
    l_time->day=                date[(uint) format_position[2]];
    l_time->hour=               date[(uint) format_position[3]];
    l_time->minute=             date[(uint) format_position[4]];
    l_time->second=             date[(uint) format_position[5]];

    frac_pos= (uint) format_position[6];
    frac_len= date_len[frac_pos];
    if (frac_len < 6)
      date[frac_pos]*= (uint) log_10_int[6 - frac_len];
    l_time->second_part= date[frac_pos];

    if (format_position[7] != (uchar) 255)
    {
      if (l_time->hour > 12)
      {
        *was_cut= 1;
        goto err;
      }
      l_time->hour= l_time->hour%12 + add_hours;
    }
  }
  else
  {
    l_time->year=       date[0];
    l_time->month=      date[1];
    l_time->day=        date[2];
    l_time->hour=       date[3];
    l_time->minute=     date[4];
    l_time->second=     date[5];
    if (date_len[6] < 6)
      date[6]*= (uint) log_10_int[6 - date_len[6]];
    l_time->second_part=date[6];
  }
  l_time->neg= 0;

  if (year_length == 2 && not_zero_date)
    l_time->year+= (l_time->year < YY_PART_YEAR ? 2000 : 1900);

  if (number_of_fields < 3 ||
      l_time->year > 9999 || l_time->month > 12 ||
      l_time->day > 31 || l_time->hour > 23 ||
      l_time->minute > 59 || l_time->second > 59)
  {
    /* Only give warning for a zero date if there is some garbage after */
    if (!not_zero_date)                         /* If zero date */
    {
      for (; str != end ; str++)
      {
        if (!my_isspace(&my_charset_latin1, *str))
        {
          not_zero_date= 1;                     /* Give warning */
          break;
        }
      }
    }
    *was_cut= test(not_zero_date);
    goto err;
  }

  if (check_date(l_time, not_zero_date != 0, flags, was_cut))
    goto err;

  l_time->time_type= (number_of_fields <= 3 ?
                      MYSQL_TIMESTAMP_DATE : MYSQL_TIMESTAMP_DATETIME);

  for (; str != end ; str++)
  {
    if (!my_isspace(&my_charset_latin1,*str))
    {
      *was_cut= 1;
      break;
    }
  }

  DBUG_RETURN(l_time->time_type);

err:
  bzero((char*) l_time, sizeof(*l_time));
  DBUG_RETURN(MYSQL_TIMESTAMP_ERROR);
}
Beispiel #15
0
MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking)
{
  int save_errno,errpos=0;
  uint files= 0, i, dir_length, length, key_parts, min_keys= 0;
  ulonglong file_offset=0;
  char name_buff[FN_REFLEN*2],buff[FN_REFLEN],*end;
  MYRG_INFO *m_info=0;
  File fd;
  IO_CACHE file;
  MI_INFO *isam=0;
  uint found_merge_insert_method= 0;
  size_t name_buff_length;
  DBUG_ENTER("myrg_open");

  LINT_INIT(key_parts);

  bzero((char*) &file,sizeof(file));
  if ((fd=my_open(fn_format(name_buff,name,"",MYRG_NAME_EXT,
                            MY_UNPACK_FILENAME|MY_APPEND_EXT),
		  O_RDONLY | O_SHARE,MYF(0))) < 0)
    goto err;
  errpos=1;
  if (init_io_cache(&file, fd, 4*IO_SIZE, READ_CACHE, 0, 0,
		    MYF(MY_WME | MY_NABP)))
    goto err;
  errpos=2;
  dir_length=dirname_part(name_buff, name, &name_buff_length);
  while ((length=my_b_gets(&file,buff,FN_REFLEN-1)))
  {
    if ((end=buff+length)[-1] == '\n')
      end[-1]='\0';
    if (buff[0] && buff[0] != '#')
      files++;
  }

  my_b_seek(&file, 0);
  while ((length=my_b_gets(&file,buff,FN_REFLEN-1)))
  {
    if ((end=buff+length)[-1] == '\n')
      *--end='\0';
    if (!buff[0])
      continue;		/* Skip empty lines */
    if (buff[0] == '#')
    {
      if (!strncmp(buff+1,"INSERT_METHOD=",14))
      {			/* Lookup insert method */
	int tmp=find_type(buff+15,&merge_insert_method,2);
	found_merge_insert_method = (uint) (tmp >= 0 ? tmp : 0);
      }
      continue;		/* Skip comments */
    }

    if (!has_path(buff))
    {
      VOID(strmake(name_buff+dir_length,buff,
                   sizeof(name_buff)-1-dir_length));
      VOID(cleanup_dirname(buff,name_buff));
    }
    else
      fn_format(buff, buff, "", "", 0);
    if (!(isam=mi_open(buff,mode,(handle_locking?HA_OPEN_WAIT_IF_LOCKED:0))))
    {
      my_errno= HA_ERR_WRONG_MRG_TABLE_DEF;
      if (handle_locking & HA_OPEN_FOR_REPAIR)
      {
        myrg_print_wrong_table(buff);
        continue;
      }
      goto err;
    }
    if (!m_info)                                /* First file */
    {
      key_parts=isam->s->base.key_parts;
      if (!(m_info= (MYRG_INFO*) my_malloc(sizeof(MYRG_INFO) +
                                           files*sizeof(MYRG_TABLE) +
                                           key_parts*sizeof(long),
                                           MYF(MY_WME|MY_ZEROFILL))))
        goto err;
      DBUG_ASSERT(files);
      m_info->open_tables=(MYRG_TABLE *) (m_info+1);
      m_info->rec_per_key_part=(ulong *) (m_info->open_tables+files);
      m_info->tables= files;
      files= 0;
      m_info->reclength=isam->s->base.reclength;
      min_keys= isam->s->base.keys;
      errpos=3;
    }
    m_info->open_tables[files].table= isam;
    m_info->open_tables[files].file_offset=(my_off_t) file_offset;
    file_offset+=isam->state->data_file_length;
    files++;
    if (m_info->reclength != isam->s->base.reclength)
    {
      my_errno=HA_ERR_WRONG_MRG_TABLE_DEF;
      if (handle_locking & HA_OPEN_FOR_REPAIR)
      {
        myrg_print_wrong_table(buff);
        continue;
      }
      goto err;
    }
    m_info->options|= isam->s->options;
    m_info->records+= isam->state->records;
    m_info->del+= isam->state->del;
    m_info->data_file_length+= isam->state->data_file_length;
    if (min_keys > isam->s->base.keys)
      min_keys= isam->s->base.keys;
    for (i=0; i < key_parts; i++)
      m_info->rec_per_key_part[i]+= (isam->s->state.rec_per_key_part[i] /
                                     m_info->tables);
  }

  if (my_errno == HA_ERR_WRONG_MRG_TABLE_DEF)
    goto err;
  if (!m_info && !(m_info= (MYRG_INFO*) my_malloc(sizeof(MYRG_INFO),
                                                  MYF(MY_WME | MY_ZEROFILL))))
    goto err;
  /* Don't mark table readonly, for ALTER TABLE ... UNION=(...) to work */
  m_info->options&= ~(HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA);
  m_info->merge_insert_method= found_merge_insert_method;

  if (sizeof(my_off_t) == 4 && file_offset > (ulonglong) (ulong) ~0L)
  {
    my_errno=HA_ERR_RECORD_FILE_FULL;
    goto err;
  }
  m_info->keys= min_keys;
  bzero((char*) &m_info->by_key,sizeof(m_info->by_key));

  /* this works ok if the table list is empty */
  m_info->end_table=m_info->open_tables+files;
  m_info->last_used_table=m_info->open_tables;
  m_info->children_attached= TRUE;

  VOID(my_close(fd,MYF(0)));
  end_io_cache(&file);
  VOID(pthread_mutex_init(&m_info->mutex, MY_MUTEX_INIT_FAST));
  m_info->open_list.data=(void*) m_info;
  pthread_mutex_lock(&THR_LOCK_open);
  myrg_open_list=list_add(myrg_open_list,&m_info->open_list);
  pthread_mutex_unlock(&THR_LOCK_open);
  DBUG_RETURN(m_info);

err:
  save_errno=my_errno;
  switch (errpos) {
  case 3:
    while (files)
      mi_close(m_info->open_tables[--files].table);
    my_free((char*) m_info,MYF(0));
    /* Fall through */
  case 2:
    end_io_cache(&file);
    /* Fall through */
  case 1:
    VOID(my_close(fd,MYF(0)));
  }
  my_errno=save_errno;
  DBUG_RETURN (NULL);
}
Beispiel #16
0
int _nisam_read_rnd_static_record(N_INFO *info, byte *buf,
				  register ulong filepos,
				  int skipp_deleted_blocks)
{
  int locked,error,cache_read;
  uint cache_length;
  ISAM_SHARE *share=info->s;
  DBUG_ENTER("_nisam_read_rnd_static_record");

  cache_read=0;
  LINT_INIT(cache_length);
  if (info->opt_flag & WRITE_CACHE_USED &&
      (info->rec_cache.pos_in_file <= filepos || skipp_deleted_blocks) &&
      flush_io_cache(&info->rec_cache))
    DBUG_RETURN(-1);
  if (info->opt_flag & READ_CACHE_USED)
  {						/* Cash in use */
    if (filepos == my_b_tell(&info->rec_cache) &&
	(skipp_deleted_blocks || !filepos))
    {
      cache_read=1;				/* Read record using cache */
      cache_length=(uint) (info->rec_cache.rc_end - info->rec_cache.rc_pos);
    }
    else
      info->rec_cache.seek_not_done=1;		/* Filepos is changed */
  }
#ifndef NO_LOCKING
  locked=0;
  if (info->lock_type == F_UNLCK)
  {
    if (filepos >= share->state.data_file_length)
    {						/* Test if new records */
      if (_nisam_readinfo(info,F_RDLCK,0))
	DBUG_RETURN(-1);
      locked=1;
    }
    else
    {						/* We don't nead new info */
#ifndef UNSAFE_LOCKING
      if ((! cache_read || share->base.reclength > cache_length) &&
	  share->r_locks == 0 && share->w_locks == 0)
      {						/* record not in cache */
	if (my_lock(share->kfile,F_RDLCK,0L,F_TO_EOF,
		    MYF(MY_SEEK_NOT_DONE) | info->lock_wait))
	  DBUG_RETURN(-1);
	locked=1;
      }
#else
      info->tmp_lock_type=F_RDLCK;
#endif
    }
  }
#endif
  if (filepos >= share->state.data_file_length)
  {
#ifndef NO_LOCKING
    DBUG_PRINT("test",("filepos: %ld (%ld)  records: %ld  del: %ld",
		       filepos/share->base.reclength,filepos,
		       share->state.records, share->state.del));
    VOID(_nisam_writeinfo(info,0));
#endif
    my_errno=HA_ERR_END_OF_FILE;
    DBUG_RETURN(-1);
  }
  info->lastpos= filepos;
  info->nextpos= filepos+share->base.reclength;

  if (! cache_read)			/* No cacheing */
  {
    error=_nisam_read_static_record(info,filepos,buf);
    if (error > 0)
      my_errno=HA_ERR_RECORD_DELETED;
    DBUG_RETURN(error);
  }

	/* Read record with cacheing */
  error=my_b_read(&info->rec_cache,(byte*) buf,share->base.reclength);

#ifndef NO_LOCKING
  if (locked)
    VOID(_nisam_writeinfo(info,0));		/* Unlock keyfile */
#endif
  if (!error)
  {
    if (!buf[0])
    {						/* Record is removed */
      my_errno=HA_ERR_RECORD_DELETED;
      DBUG_RETURN(1);
    }
						/* Found and may be updated */
    info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED;
    DBUG_RETURN(0);
  }
  if (info->rec_cache.error != -1 || my_errno == 0)
    my_errno=HA_ERR_WRONG_IN_RECORD;
  DBUG_RETURN(-1);				/* Something wrong (EOF?) */
}
Beispiel #17
0
int handle_options(int *argc, char ***argv, 
		   const struct my_option *longopts, 
		   my_bool (*get_one_option)(int,
					     const struct my_option *,
					     char *))
{
  uint opt_found, argvpos= 0, length, i;
  my_bool end_of_options= 0, must_be_var, set_maximum_value, special_used,
          option_is_loose;
  char *progname= *(*argv), **pos, **pos_end, *optend, *prev_found;
  const struct my_option *optp;
  int error;

  LINT_INIT(opt_found);
  (*argc)--; /* Skip the program name */
  (*argv)++; /*      --- || ----      */
  init_variables(longopts);

  for (pos= *argv, pos_end=pos+ *argc; pos != pos_end ; pos++)
  {
    char *cur_arg= *pos;
    if (cur_arg[0] == '-' && cur_arg[1] && !end_of_options) /* must be opt */
    {
      char *argument=    0;
      must_be_var=       0;
      set_maximum_value= 0;
      special_used=      0;
      option_is_loose=   0;

      cur_arg++;		/* skip '-' */
      if (*cur_arg == '-' || *cur_arg == 'O') /* check for long option, */
      {                                       /* --set-variable, or -O  */
	if (*cur_arg == 'O')
	{
	  must_be_var= 1;

	  if (!(*++cur_arg))	/* If not -Ovar=# */
	  {
	    /* the argument must be in next argv */
	    if (!*++pos)
	    {
	      if (my_getopt_print_errors)
		fprintf(stderr, "%s: Option '-O' requires an argument\n",
			progname);
	      return EXIT_ARGUMENT_REQUIRED;
	    }
	    cur_arg= *pos;
	    (*argc)--;
	  }
	}
	else if (!getopt_compare_strings(cur_arg, "-set-variable", 13))
	{
	  must_be_var= 1;
	  if (cur_arg[13] == '=')
	  {
	    cur_arg+= 14;
	    if (!*cur_arg)
	    {
	      if (my_getopt_print_errors)
		fprintf(stderr,
			"%s: Option '--set-variable' requires an argument\n",
			progname);
	      return EXIT_ARGUMENT_REQUIRED;
	    }
	  }
	  else if (cur_arg[14]) /* garbage, or another option. break out */
	    must_be_var= 0;
	  else
	  {
	    /* the argument must be in next argv */
	    if (!*++pos)
	    {
	      if (my_getopt_print_errors)
		fprintf(stderr,
			"%s: Option '--set-variable' requires an argument\n",
			progname);
	      return EXIT_ARGUMENT_REQUIRED;
	    }
	    cur_arg= *pos;
	    (*argc)--;
	  }
	}
	else if (!must_be_var)
	{
	  if (!*++cur_arg)	/* skip the double dash */
	  {
	    /* '--' means end of options, look no further */
	    end_of_options= 1;
	    (*argc)--;
	    continue;
	  }
	}
	optend= strcend(cur_arg, '=');
	length= optend - cur_arg;
	if (*optend == '=')
	  optend++;
	else
	  optend=0;

	/*
	  Find first the right option. Return error in case of an ambiguous,
	  or unknown option
	*/
	optp= longopts;
	if (!(opt_found= findopt(cur_arg, length, &optp, &prev_found)))
	{
	  /*
	    Didn't find any matching option. Let's see if someone called
	    option with a special option prefix
	  */
	  if (!must_be_var)
	  {
	    if (optend)
	      must_be_var= 1; /* option is followed by an argument */
	    for (i= 0; special_opt_prefix[i]; i++)
	    {
	      if (!getopt_compare_strings(special_opt_prefix[i], cur_arg,
					  special_opt_prefix_lengths[i]) &&
		  cur_arg[special_opt_prefix_lengths[i]] == '-')
	      {
		/*
		  We were called with a special prefix, we can reuse opt_found
		*/
		special_used= 1;
		cur_arg+= (special_opt_prefix_lengths[i] + 1);
		if (i == OPT_LOOSE)
		  option_is_loose= 1;
		if ((opt_found= findopt(cur_arg, length -
					(special_opt_prefix_lengths[i] + 1),
					&optp, &prev_found)))
		{
		  if (opt_found > 1)
		  {
		    if (my_getopt_print_errors)
		      fprintf(stderr,
			      "%s: ambiguous option '--%s-%s' (--%s-%s)\n",
			      progname, special_opt_prefix[i], cur_arg,
			      special_opt_prefix[i], prev_found);
		    return EXIT_AMBIGUOUS_OPTION;
		  }
		  switch (i) {
		  case OPT_SKIP:
		  case OPT_DISABLE: /* fall through */
		    /*
		      double negation is actually enable again,
		      for example: --skip-option=0 -> option = TRUE
		    */
		    optend= (optend && *optend == '0' && !(*(optend + 1))) ?
		      (char*) "1" : disabled_my_option;
		    break;
		  case OPT_ENABLE:
		    optend= (optend && *optend == '0' && !(*(optend + 1))) ?
 		      disabled_my_option : (char*) "1";
		    break;
		  case OPT_MAXIMUM:
		    set_maximum_value= 1;
		    must_be_var= 1;
		    break;
		  }
		  break; /* break from the inner loop, main loop continues */
		}
	      }
	    }
	  }
	  if (!opt_found)
	  {
	    if (must_be_var)
	    {
	      if (my_getopt_print_errors)
		fprintf(stderr,
			"%s: %s: unknown variable '%s'\n", progname,
			option_is_loose ? "WARNING" : "ERROR", cur_arg);
	      if (!option_is_loose)
		return EXIT_UNKNOWN_VARIABLE;
	    }
	    else
	    {
	      if (my_getopt_print_errors)
		fprintf(stderr,
			"%s: %s: unknown option '--%s'\n", progname,
			option_is_loose ? "WARNING" : "ERROR", cur_arg);
	      if (!option_is_loose)
		return EXIT_UNKNOWN_OPTION;
	    }
	    if (option_is_loose)
	    {
	      (*argc)--;
	      continue;
	    }
	  }
	}
	if (opt_found > 1)
	{
	  if (must_be_var)
	  {
	    if (my_getopt_print_errors)
	      fprintf(stderr, "%s: variable prefix '%s' is not unique\n",
		      progname, cur_arg);
	    return EXIT_VAR_PREFIX_NOT_UNIQUE;
	  }
	  else
	  {
	    if (my_getopt_print_errors)
	      fprintf(stderr, "%s: ambiguous option '--%s' (%s, %s)\n",
		      progname, cur_arg, prev_found, optp->name);
	    return EXIT_AMBIGUOUS_OPTION;
	  }
	}
	if (must_be_var && optp->var_type == GET_NO_ARG)
	{
	  if (my_getopt_print_errors)
	    fprintf(stderr, "%s: option '%s' cannot take an argument\n",
		    progname, optp->name);
	  return EXIT_NO_ARGUMENT_ALLOWED;
	}
	if (optp->arg_type == NO_ARG)
	{
	  if (optend && optp->var_type != GET_BOOL)
	  {
	    if (my_getopt_print_errors)
	      fprintf(stderr, "%s: option '--%s' cannot take an argument\n",
		      progname, optp->name);
	    return EXIT_NO_ARGUMENT_ALLOWED;
	  }
	  if (optp->var_type == GET_BOOL)
	  {
	    /*
	      Set bool to 1 if no argument or if the user has used
	      --enable-'option-name'.
	      *optend was set to '0' if one used --disable-option
	      */
	    *((my_bool*) optp->value)= 	(my_bool) (!optend || *optend == '1');
	    (*argc)--;	    
	    get_one_option(optp->id, optp, argument);
	    continue;
	  }
	  argument= optend;
	}
	else if (optp->arg_type == OPT_ARG && optp->var_type == GET_BOOL)
	{
	  if (optend == disabled_my_option)
	    *((my_bool*) optp->value)= (my_bool) 0;
	  else
	  {
	    if (!optend) /* No argument -> enable option */
	      *((my_bool*) optp->value)= (my_bool) 1;
	    else /* If argument differs from 0, enable option, else disable */
	      *((my_bool*) optp->value)= (my_bool) atoi(optend) != 0;
	  }
	  (*argc)--;	    
	  continue;
	}
	else if (optp->arg_type == REQUIRED_ARG && !optend)
	{
	  /* Check if there are more arguments after this one */
	  if (!*++pos)
	  {
	    if (my_getopt_print_errors)
	      fprintf(stderr, "%s: option '--%s' requires an argument\n",
		      progname, optp->name);
	    return EXIT_ARGUMENT_REQUIRED;
	  }
	  argument= *pos;
	  (*argc)--;
	}
	else
	  argument= optend;
      }
      else  /* must be short option */
      {
	for (optend= cur_arg; *optend; optend++)
	{
	  opt_found= 0;
	  for (optp= longopts; optp->id; optp++)
	  {
	    if (optp->id == (int) (uchar) *optend)
	    {
	      /* Option recognized. Find next what to do with it */
	      opt_found= 1;
	      if (optp->var_type == GET_BOOL && optp->arg_type == NO_ARG)
	      {
		*((my_bool*) optp->value)= (my_bool) 1;
		get_one_option(optp->id, optp, argument);
		continue;
	      }
	      else if (optp->arg_type == REQUIRED_ARG ||
		       optp->arg_type == OPT_ARG)
	      {
		if (*(optend + 1))
		{
		  /* The rest of the option is option argument */
		  argument= optend + 1;
		  /* This is in effect a jump out of the outer loop */
		  optend= (char*) " ";
		}
		else if (optp->arg_type == REQUIRED_ARG)
		{
		  /* Check if there are more arguments after this one */
		  if (!*++pos)
		  {
		    if (my_getopt_print_errors)
		      fprintf(stderr,
			      "%s: option '-%c' requires an argument\n",
			      progname, optp->id);
		    return EXIT_ARGUMENT_REQUIRED;
		  }
		  argument= *pos;
		  (*argc)--;
		  /* the other loop will break, because *optend + 1 == 0 */
		}
	      }
	      if ((error= setval(optp, argument, set_maximum_value)))
	      {
		fprintf(stderr,
			"%s: Error while setting value '%s' to '%s'\n",
			progname, argument, optp->name);
		return error;
	      }
	      get_one_option(optp->id, optp, argument);
	      break;
	    }
	  }
	  if (!opt_found)
	  {
	    if (my_getopt_print_errors)
	      fprintf(stderr,
		      "%s: unknown option '-%c'\n", progname, *optend);
	    return EXIT_UNKNOWN_OPTION;
	  }
	}
	(*argc)--; /* option handled (short), decrease argument count */
	continue;
      }
      if ((error= setval(optp, argument, set_maximum_value)))
      {
	fprintf(stderr,
		"%s: Error while setting value '%s' to '%s'\n",
		progname, argument, optp->name);
	return error;
      }
      get_one_option(optp->id, optp, argument);

      (*argc)--; /* option handled (short�or�long), decrease argument count */
    }
    else /* non-option found */
      (*argv)[argvpos++]= cur_arg;
  }
  /*
    Destroy the first, already handled option, so that programs that look
    for arguments in 'argv', without checking 'argc', know when to stop.
    Items in argv, before the destroyed one, are all non-option -arguments
    to the program, yet to be (possibly) handled.
  */
  (*argv)[argvpos]= 0;
  return 0;
}
Beispiel #18
0
static void read_huff_table(BIT_BUFF *bit_buff, DECODE_TREE *decode_tree,
			    uint16 **decode_table, byte **intervall_buff,
			    uint16 *tmp_buff)
{
  uint min_chr,elements,char_bits,offset_bits,size,intervall_length,table_bits,
  next_free_offset;
  uint16 *ptr,*end;

  LINT_INIT(ptr);
  if (!get_bits(bit_buff,1))
  {
    min_chr=get_bits(bit_buff,8);
    elements=get_bits(bit_buff,9);
    char_bits=get_bits(bit_buff,5);
    offset_bits=get_bits(bit_buff,5);
    intervall_length=0;
    ptr=tmp_buff;
  }
  else
  {
    min_chr=0;
    elements=get_bits(bit_buff,15);
    intervall_length=get_bits(bit_buff,16);
    char_bits=get_bits(bit_buff,5);
    offset_bits=get_bits(bit_buff,5);
    decode_tree->quick_table_bits=0;
    ptr= *decode_table;
  }
  size=elements*2-2;

  for (end=ptr+size ; ptr < end ; ptr++)
  {
    if (get_bit(bit_buff))
      *ptr= (uint16) get_bits(bit_buff,offset_bits);
    else
      *ptr= (uint16) (IS_CHAR + (get_bits(bit_buff,char_bits) + min_chr));
  }
  skipp_to_next_byte(bit_buff);

  decode_tree->table= *decode_table;
  decode_tree->intervalls= *intervall_buff;
  if (! intervall_length)
  {
    table_bits=find_longest_bitstream(tmp_buff);
    if (table_bits > nisam_quick_table_bits)
      table_bits=nisam_quick_table_bits;
    next_free_offset= (1 << table_bits);
    make_quick_table(*decode_table,tmp_buff,&next_free_offset,0,table_bits,
		     table_bits);
    (*decode_table)+= next_free_offset;
    decode_tree->quick_table_bits=table_bits;
  }
  else
  {
    (*decode_table)=end;
    bit_buff->pos-= bit_buff->bits/8;
    memcpy(*intervall_buff,bit_buff->pos,(size_t) intervall_length);
    (*intervall_buff)+=intervall_length;
    bit_buff->pos+=intervall_length;
    bit_buff->bits=0;
  }
  return;
}
Beispiel #19
0
int myrg_attach_children(MYRG_INFO *m_info, int handle_locking,
                         MI_INFO *(*callback)(void*),
                         void *callback_param)
{
  ulonglong  file_offset;
  MI_INFO    *myisam;
  int        rc;
  int        errpos;
  int        save_errno;
  uint       idx;
  uint       child_nr;
  uint       key_parts;
  uint       min_keys;
  DBUG_ENTER("myrg_attach_children");
  DBUG_PRINT("myrg", ("handle_locking: %d", handle_locking));

  /*
    This function can be called while another thread is trying to abort
    locks of this MERGE table. If the processor reorders instructions or
    write to memory, 'children_attached' could be set before
    'open_tables' has all the pointers to the children. Use of a mutex
    here and in ha_myisammrg::store_lock() forces consistent data.
  */
  pthread_mutex_lock(&m_info->mutex);
  rc= 1;
  errpos= 0;
  file_offset= 0;
  LINT_INIT(key_parts);
  min_keys= 0;
  child_nr= 0;
  while ((myisam= (*callback)(callback_param)))
  {
    DBUG_PRINT("myrg", ("child_nr: %u  table: '%s'",
                        child_nr, myisam->filename));
    DBUG_ASSERT(child_nr < m_info->tables);

    /* Special handling when the first child is attached. */
    if (!child_nr)
    {
      m_info->reclength= myisam->s->base.reclength;
      min_keys=  myisam->s->base.keys;
      key_parts= myisam->s->base.key_parts;
      if (!m_info->rec_per_key_part)
      {
        if(!(m_info->rec_per_key_part= (ulong*)
             my_malloc(key_parts * sizeof(long), MYF(MY_WME|MY_ZEROFILL))))
          goto err; /* purecov: inspected */
        errpos= 1;
      }
    }

    /* Add MyISAM table info. */
    m_info->open_tables[child_nr].table= myisam;
    m_info->open_tables[child_nr].file_offset= (my_off_t) file_offset;
    file_offset+= myisam->state->data_file_length;

    /* Check table definition match. */
    if (m_info->reclength != myisam->s->base.reclength)
    {
      DBUG_PRINT("error", ("definition mismatch table: '%s'  repair: %d",
                           myisam->filename,
                           (handle_locking & HA_OPEN_FOR_REPAIR)));
      my_errno= HA_ERR_WRONG_MRG_TABLE_DEF;
      if (handle_locking & HA_OPEN_FOR_REPAIR)
      {
        myrg_print_wrong_table(myisam->filename);
        continue;
      }
      goto err;
    }

    m_info->options|= myisam->s->options;
    m_info->records+= myisam->state->records;
    m_info->del+= myisam->state->del;
    m_info->data_file_length+= myisam->state->data_file_length;
    if (min_keys > myisam->s->base.keys)
      min_keys= myisam->s->base.keys; /* purecov: inspected */
    for (idx= 0; idx < key_parts; idx++)
      m_info->rec_per_key_part[idx]+= (myisam->s->state.rec_per_key_part[idx] /
                                       m_info->tables);
    child_nr++;
  }

  if (my_errno == HA_ERR_WRONG_MRG_TABLE_DEF)
    goto err;
  if (sizeof(my_off_t) == 4 && file_offset > (ulonglong) (ulong) ~0L)
  {
    my_errno= HA_ERR_RECORD_FILE_FULL;
    goto err;
  }
  /* Don't mark table readonly, for ALTER TABLE ... UNION=(...) to work */
  m_info->options&= ~(HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA);
  m_info->keys= min_keys;
  m_info->last_used_table= m_info->open_tables;
  m_info->children_attached= TRUE;
  pthread_mutex_unlock(&m_info->mutex);
  DBUG_RETURN(0);

err:
  save_errno= my_errno;
  switch (errpos) {
  case 1:
    my_free((char*) m_info->rec_per_key_part, MYF(0));
    m_info->rec_per_key_part= NULL;
  }
  pthread_mutex_unlock(&m_info->mutex);
  my_errno= save_errno;
  DBUG_RETURN(1);
}
Beispiel #20
0
/*
  Scan the purgatory and free everything that can be freed
*/
static void _lf_pinbox_real_free(LF_PINS *pins)
{
  int npins;
  void *list, **addr;
  void *first, *last= NULL;
  LF_PINBOX *pinbox= pins->pinbox;

  first = NULL;

  LINT_INIT(first);
  npins= pinbox->pins_in_array+1;

#ifdef HAVE_ALLOCA
  int alloca_size= sizeof(void *)*LF_PINBOX_PINS*npins;
  /* create a sorted list of pinned addresses, to speed up searches */
  if (available_stack_size(&pinbox, *pins->stack_ends_here) > alloca_size)
  {
    struct st_harvester hv;
    addr= (void **) alloca(alloca_size);
    hv.granary= addr;
    hv.npins= npins;
    /* scan the dynarray and accumulate all pinned addresses */
    _lf_dynarray_iterate(&pinbox->pinarray,
                         (lf_dynarray_func)harvest_pins, &hv);

    npins= hv.granary-addr;
    /* and sort them */
    if (npins)
      qsort(addr, npins, sizeof(void *), (qsort_cmp)ptr_cmp);
  }
  else
#endif
    addr= 0;

  list= pins->purgatory;
  pins->purgatory= 0;
  pins->purgatory_count= 0;
  while (list)
  {
    void *cur= list;
    list= *(void **)((char *)cur+pinbox->free_ptr_offset);
    if (npins)
    {
      if (addr) /* use binary search */
      {
        void **a, **b, **c;
        for (a= addr, b= addr+npins-1, c= a+(b-a)/2; (b-a) > 1; c= a+(b-a)/2)
          if (cur == *c)
            a= b= c;
          else if (cur > *c)
            a= c;
          else
            b= c;
        if (cur == *a || cur == *b)
          goto found;
      }
      else /* no alloca - no cookie. linear search here */
      {
        if (_lf_dynarray_iterate(&pinbox->pinarray,
                                 (lf_dynarray_func)match_pins, cur))
          goto found;
      }
    }
    /* not pinned - freeing */
    if (last)
      last= next_node(pinbox, last)= (uchar *)cur;
    else
      first= last= (uchar *)cur;
    continue;
found:
    /* pinned - keeping */
    add_to_purgatory(pins, cur);
  }
  if (last)
    pinbox->free_func(first, last, pinbox->free_func_arg);
}
Beispiel #21
0
MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking)
{
  int save_errno,i,errpos;
  uint files,dir_length,length,key_parts;
  ulonglong file_offset;
  char name_buff[FN_REFLEN*2],buff[FN_REFLEN],*end;
  MYRG_INFO info,*m_info;
  File fd;
  IO_CACHE file;
  MI_INFO *isam,*last_isam;
  DBUG_ENTER("myrg_open");

  LINT_INIT(last_isam);
  LINT_INIT(m_info);
  isam=0;
  errpos=files=0;
  bzero((gptr) &info,sizeof(info));
  bzero((char*) &file,sizeof(file));
  if ((fd=my_open(fn_format(name_buff,name,"",MYRG_NAME_EXT,4),
		  O_RDONLY | O_SHARE,MYF(0))) < 0 ||
      init_io_cache(&file, fd, IO_SIZE, READ_CACHE, 0, 0,
		    MYF(MY_WME | MY_NABP)))
    goto err;
  errpos=1;
  dir_length=dirname_part(name_buff,name);
  info.reclength=0;
  while ((length=my_b_gets(&file,buff,FN_REFLEN-1)))
  {
    if ((end=buff+length)[-1] == '\n')
      end[-1]='\0';
    if (!buff[0])
      continue;		/* Skip empty lines */
    if (buff[0] == '#')
    {
      if( !strncmp(buff+1,"INSERT_METHOD=",14))
      {			/* Lookup insert method */
	int tmp=find_type(buff+15,&merge_insert_method,2);
	info.merge_insert_method = (uint) (tmp >= 0 ? tmp : 0);
      }
      continue;		/* Skip comments */
    }

    if (!test_if_hard_path(buff))
    {
      VOID(strmake(name_buff+dir_length,buff,
                   sizeof(name_buff)-1-dir_length));
      VOID(cleanup_dirname(buff,name_buff));
    }
    if (!(isam=mi_open(buff,mode,(handle_locking?HA_OPEN_WAIT_IF_LOCKED:0))))
	goto err;
    files++;
    last_isam=isam;
    if (info.reclength && info.reclength != isam->s->base.reclength)
    {
      my_errno=HA_ERR_WRONG_MRG_TABLE_DEF;
      goto err;
    }
    info.reclength=isam->s->base.reclength;
  }
  key_parts=(isam ? isam->s->base.key_parts : 0);
  if (!(m_info= (MYRG_INFO*) my_malloc(sizeof(MYRG_INFO)+
                                       files*sizeof(MYRG_TABLE)+
                                       sizeof(long)*key_parts,
				       MYF(MY_WME))))
    goto err;
  *m_info=info;
  m_info->tables=files;
  if (files)
  {
    m_info->open_tables=(MYRG_TABLE *) (m_info+1);
    m_info->rec_per_key_part=(ulong *) (m_info->open_tables+files);
    bzero((char*) m_info->rec_per_key_part,sizeof(long)*key_parts);
  }
  else
  {
    m_info->open_tables=0;
    m_info->rec_per_key_part=0;
  }
  errpos=2;

  for (i=files ; i-- > 0 ; )
  {
    uint j;
    m_info->open_tables[i].table=isam;
    m_info->options|=isam->s->options;
    m_info->records+=isam->state->records;
    m_info->del+=isam->state->del;
    m_info->data_file_length+=isam->state->data_file_length;
    for (j=0; j < key_parts; j++)
      m_info->rec_per_key_part[j]+=isam->s->state.rec_per_key_part[j] / files;
    if (i)
      isam=(MI_INFO*) (isam->open_list.next->data);
  }
  /* Don't mark table readonly, for ALTER TABLE ... UNION=(...) to work */
  m_info->options&= ~(HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA);

  /* Fix fileinfo for easyer debugging (actually set by rrnd) */
  file_offset=0;
  for (i=0 ; (uint) i < files ; i++)
  {
    m_info->open_tables[i].file_offset=(my_off_t) file_offset;
    file_offset+=m_info->open_tables[i].table->state->data_file_length;
  }
  if (sizeof(my_off_t) == 4 && file_offset > (ulonglong) (ulong) ~0L)
  {
    my_errno=HA_ERR_RECORD_FILE_FULL;
    goto err;
  }
  m_info->keys=(files) ? m_info->open_tables->table->s->base.keys : 0;
  bzero((char*) &m_info->by_key,sizeof(m_info->by_key));

  /* this works ok if the table list is empty */
  m_info->end_table=m_info->open_tables+files;
  m_info->last_used_table=m_info->open_tables;

  VOID(my_close(fd,MYF(0)));
  end_io_cache(&file);
  m_info->open_list.data=(void*) m_info;
  pthread_mutex_lock(&THR_LOCK_open);
  myrg_open_list=list_add(myrg_open_list,&m_info->open_list);
  pthread_mutex_unlock(&THR_LOCK_open);
  DBUG_RETURN(m_info);

err:
  save_errno=my_errno;
  switch (errpos) {
  case 2:
    my_free((char*) m_info,MYF(0));
    /* Fall through */
  case 1:
    VOID(my_close(fd,MYF(0)));
    end_io_cache(&file);
    for (i=files ; i-- > 0 ; )
    {
      isam=last_isam;
      if (i)
	last_isam=(MI_INFO*) (isam->open_list.next->data);
      mi_close(isam);
    }
  }
  my_errno=save_errno;
  DBUG_RETURN (NULL);
}
Beispiel #22
0
int nisam_update(register N_INFO *info, const byte *oldrec, const byte *newrec)
{
  int flag,key_changed,save_errno;
  reg3 ulong pos;
  uint i,length;
  uchar old_key[N_MAX_KEY_BUFF],*new_key;
  DBUG_ENTER("nisam_update");

  LINT_INIT(save_errno);
  if (!(info->update & HA_STATE_AKTIV))
  {
    my_errno=HA_ERR_KEY_NOT_FOUND;
    DBUG_RETURN(-1);
  }
  if (info->s->base.options & HA_OPTION_READ_ONLY_DATA)
  {
    my_errno=EACCES;
    DBUG_RETURN(-1);
  }
  pos=info->lastpos;
#ifndef NO_LOCKING
  if (_nisam_readinfo(info,F_WRLCK,1)) DBUG_RETURN(-1);
#endif
  if ((*info->s->compare_record)(info,oldrec))
  {
    save_errno=my_errno;
    goto err_end;			/* Record has changed */
  }
  if (info->s->state.key_file_length >=
      info->s->base.max_key_file_length -
      info->s->blocksize* INDEX_BLOCK_MARGIN *info->s->state.keys)
  {
    save_errno=HA_ERR_INDEX_FILE_FULL;
    goto err_end;
  }

	/* Flyttar de element i isamfilen som m}ste flyttas */

  new_key=info->lastkey+info->s->base.max_key_length;
  key_changed=HA_STATE_KEY_CHANGED;	/* We changed current database */
					/* Remove key that didn't change */
  for (i=0 ; i < info->s->state.keys ; i++)
  {
    length=_nisam_make_key(info,i,new_key,newrec,pos);
    if (length != _nisam_make_key(info,i,old_key,oldrec,pos) ||
	memcmp((byte*) old_key,(byte*) new_key,length))
    {
      if ((int) i == info->lastinx)
	key_changed|=HA_STATE_WRITTEN;		/* Mark that keyfile changed */
      if (_nisam_ck_delete(info,i,old_key)) goto err;
      if (_nisam_ck_write(info,i,new_key)) goto err;
    }
  }

  if ((*info->s->update_record)(info,pos,newrec))
    goto err;

  info->update= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED | HA_STATE_AKTIV |
		 key_changed);
  nisam_log_record(LOG_UPDATE,info,newrec,info->lastpos,0);
  VOID(_nisam_writeinfo(info,test(key_changed)));
  allow_break();				/* Allow SIGHUP & SIGINT */
  DBUG_RETURN(0);

err:
  DBUG_PRINT("error",("key: %d  errno: %d",i,my_errno));
  save_errno=my_errno;
  if (my_errno == HA_ERR_FOUND_DUPP_KEY || my_errno == HA_ERR_RECORD_FILE_FULL)
  {
    info->errkey= (int) i;
    flag=0;
    do
    {
      length=_nisam_make_key(info,i,new_key,newrec,pos);
      if (length != _nisam_make_key(info,i,old_key,oldrec,pos) ||
	  memcmp((byte*) old_key,(byte*) new_key,length))
      {
	if ((flag++ && _nisam_ck_delete(info,i,new_key)) ||
	    _nisam_ck_write(info,i,old_key))
	  break;
      }
    } while (i-- != 0);
  }
  info->update= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED | HA_STATE_AKTIV |
		 key_changed);
 err_end:
  nisam_log_record(LOG_UPDATE,info,newrec,info->lastpos,save_errno);
  VOID(_nisam_writeinfo(info,1));
  allow_break();				/* Allow SIGHUP & SIGINT */
  my_errno=(save_errno == HA_ERR_KEY_NOT_FOUND) ? HA_ERR_CRASHED : save_errno;
  DBUG_RETURN(-1);
} /* nisam_update */