Пример #1
0
static int check_ptr(const char *where, byte *ptr, const char *sFile,
		     uint uLine)
{
  if (!ptr)
  {
    fprintf (stderr, "%s NULL pointer at line %d, '%s'\n",
	     where,uLine, sFile);
    DBUG_PRINT("safe",("Null pointer at line %d '%s'", uLine, sFile));
    (void) fflush(stderr);
    return 1;
  }
#ifndef _MSC_VER
  if ((long) ptr & (MY_ALIGN(1,sizeof(char *))-1))
  {
    fprintf (stderr, "%s wrong aligned pointer at line %d, '%s'\n",
	     where,uLine, sFile);
    DBUG_PRINT("safe",("Wrong aligned pointer at line %d, '%s'",
		       uLine,sFile));
    (void) fflush(stderr);
    return 1;
  }
#endif
  if (ptr < sf_min_adress || ptr > sf_max_adress)
  {
    fprintf (stderr, "%s pointer out of range at line %d, '%s'\n",
	     where,uLine, sFile);
    DBUG_PRINT("safe",("Pointer out of range at line %d '%s'",
		       uLine,sFile));
    (void) fflush(stderr);
    return 1;
  }
  return 0;
}
Пример #2
0
static Bigint *Balloc(int k, Stack_alloc *alloc)
{
  Bigint *rv;
  DBUG_ASSERT(k <= Kmax);
  if (k <= Kmax &&  alloc->freelist[k])
  {
    rv= alloc->freelist[k];
    alloc->freelist[k]= rv->p.next;
  }
  else
  {
    int x, len;

    x= 1 << k;
    len= MY_ALIGN(sizeof(Bigint) + x * sizeof(ULong), SIZEOF_CHARP);

    if (alloc->free + len <= alloc->end)
    {
      rv= (Bigint*) alloc->free;
      alloc->free+= len;
    }
    else
      rv= (Bigint*) malloc(len);

    rv->k= k;
    rv->maxwds= x;
  }
  rv->sign= rv->wds= 0;
  rv->p.x= (ULong*) (rv + 1);
  return rv;
}
Пример #3
0
static char *dtoa_alloc(int i, Stack_alloc *alloc)
{
  char *rv;
  int aligned_size= MY_ALIGN(i, SIZEOF_CHARP);
  if (alloc->free + aligned_size <= alloc->end)
  {
    rv= alloc->free;
    alloc->free+= aligned_size;
  }
  else
    rv= malloc(i);
  return rv;
}
Пример #4
0
void init_tree(TREE *tree, ulong default_alloc_size, ulong memory_limit,
               int size, qsort_cmp2 compare, my_bool with_delete,
	       tree_element_free free_element, const void *custom_arg)
{
  DBUG_ENTER("init_tree");
  DBUG_PRINT("enter",("tree: 0x%lx  size: %d", (long) tree, size));

  if (default_alloc_size < DEFAULT_ALLOC_SIZE)
    default_alloc_size= DEFAULT_ALLOC_SIZE;
  default_alloc_size= MY_ALIGN(default_alloc_size, DEFAULT_ALIGN_SIZE);
  memset(&tree->null_element, 0, sizeof(tree->null_element));
  tree->root= &tree->null_element;
  tree->compare=compare;
  tree->size_of_element=size > 0 ? (uint) size : 0;
  tree->memory_limit=memory_limit;
  tree->free=free_element;
  tree->allocated=0;
  tree->elements_in_tree=0;
  tree->custom_arg = custom_arg;
  tree->null_element.colour=BLACK;
  tree->null_element.left=tree->null_element.right=0;
  tree->flag= 0;
  if (!free_element && size >= 0 &&
      ((uint) size <= sizeof(void*) || ((uint) size & (sizeof(void*)-1))))
  {
    /*
      We know that the data doesn't have to be aligned (like if the key
      contains a double), so we can store the data combined with the
      TREE_ELEMENT.
    */
    tree->offset_to_key=sizeof(TREE_ELEMENT); /* Put key after element */
    /* Fix allocation size so that we don't lose any memory */
    default_alloc_size/=(sizeof(TREE_ELEMENT)+size);
    if (!default_alloc_size)
      default_alloc_size=1;
    default_alloc_size*=(sizeof(TREE_ELEMENT)+size);
  }
  else
  {
    tree->offset_to_key=0;		/* use key through pointer */
    tree->size_of_element+=sizeof(void*);
  }
  if (!(tree->with_delete=with_delete))
  {
    init_alloc_root(key_memory_TREE,
                    &tree->mem_root, (uint) default_alloc_size, 0);
    tree->mem_root.min_malloc=(sizeof(TREE_ELEMENT)+tree->size_of_element);
  }
  DBUG_VOID_RETURN;
}
Пример #5
0
uchar* my_large_malloc_int(size_t size, myf my_flags)
{
    int shmid;
    uchar* ptr;
    struct shmid_ds buf;
    DBUG_ENTER("my_large_malloc_int");

    /* Align block size to my_large_page_size */
    size= MY_ALIGN(size, (size_t) my_large_page_size);

    shmid = shmget(IPC_PRIVATE, size, SHM_HUGETLB | SHM_R | SHM_W);
    if (shmid < 0)
    {
        if (my_flags & MY_WME)
            /* purecov: begin inspected */
            my_message_local(WARNING_LEVEL,
                             "Failed to allocate %lu bytes from HugeTLB memory."
                             " errno %d", (ulong) size, errno);
        /* purecov: end */
        DBUG_RETURN(NULL);
    }

    ptr = (uchar*) shmat(shmid, NULL, 0);
    if (ptr == (uchar *) -1)
    {
        if (my_flags& MY_WME)
            /* purecov: begin inspected */
            my_message_local(WARNING_LEVEL, "Failed to attach shared memory segment,"
                             " errno %d", errno);
        /* purecov: end */
        shmctl(shmid, IPC_RMID, &buf);

        DBUG_RETURN(NULL);
    }

    /*
      Remove the shared memory segment so that it will be automatically freed
      after memory is detached or process exits
    */
    shmctl(shmid, IPC_RMID, &buf);

    DBUG_RETURN(ptr);
}
Пример #6
0
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 */
}
Пример #7
0
/*
my_ascii_to_lattice - ASCII字符转换成点阵
fontdata:点阵字库指针
character_width:点阵宽度(比如32*32的点阵,宽度是32)
strings:字符串
lattice:转换后的点阵数据
w/h:转换后的点阵数据的宽、高
注:fontdata取模是' '开始(前32个字符是不可打印字符),使用PCtoLCD2002.exe软件,取模方式:逐列式,低位在前
*/
static void my_ascii_to_lattice(unsigned char* fontdata, int char_width, char* strings, unsigned char* lattice, int* w, int* h)
{
#define MY_ALIGN(x, a) (((x)+(a)-1)&~((a)-1))          // 字节对齐(此处点阵只使用8字节对齐)

	unsigned char tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8;
	int offset_byte = 0;    // 点阵所占字节偏移
	char* q = NULL;
	int i,j, k;
	int len = 0;

	int width = 0;
	int height = 0;

	int half_width = char_width / 2; // 半角
	int char_height = MY_ALIGN(char_width, 8); // 高(必须是8的整数倍)
	int char_halfwidth_size = MY_ALIGN(char_width, 8)*char_width/2/8; // 半角点阵总大小

	if (fontdata == NULL || strings == NULL || lattice == NULL || w == NULL || h == NULL) return;

	len = (int)strlen((const char *)strings);
	width = len * half_width;
	height = char_height;
	q = (char*)lattice;

	*w = width;
	*h = height;

	// 多少个字符
	for ( i = 0; i < len; ++i )
	{
		// 前面32(0x20)个是不可打印字符,故要减去0x20
		unsigned char* p = fontdata + ((strings[i] - 0x20) * char_halfwidth_size);

		// 每个字符宽是半角
		for ( j = 0; j < half_width; ++j )
		{
			// 每个字符高有多少个字节
			for (k = 0; k < char_height/8; k++)
			{
				offset_byte = k * 8;
				// 分解点阵一个字节所有的位
				// 注: 低位在前
				tmp1 = (*p & 0x01) >> 0;
				tmp2 = (*p & 0x02) >> 1;
				tmp3 = (*p & 0x04) >> 2;
				tmp4 = (*p & 0x08) >> 3;
				tmp5 = (*p & 0x10) >> 4;
				tmp6 = (*p & 0x20) >> 5;
				tmp7 = (*p & 0x40) >> 6;
				tmp8 = (*p & 0x80) >> 7;

				// height/8个字节
				q[width * (0+offset_byte) + half_width * i + j] = tmp1;
				q[width * (1+offset_byte) + half_width * i + j] = tmp2;
				q[width * (2+offset_byte) + half_width * i + j] = tmp3;
				q[width * (3+offset_byte) + half_width * i + j] = tmp4;
				q[width * (4+offset_byte) + half_width * i + j] = tmp5;
				q[width * (5+offset_byte) + half_width * i + j] = tmp6;
				q[width * (6+offset_byte) + half_width * i + j] = tmp7;
				q[width * (7+offset_byte) + half_width * i + j] = tmp8;

				p++;
			}
		}
	}
}
Пример #8
0
static void get_options( int argc, char *argv[])
{
  char *pos,*progname;
  DEBUGGER_OFF;

  progname= argv[0];

  while (--argc >0 && *(pos = *(++argv)) == '-' ) {
    switch(*++pos) {
    case 'b':
      if (*++pos)
	nisam_block_size= MY_ALIGN(atoi(pos),512);
      set_if_bigger(nisam_block_size,8192);	/* Max block size */
      set_if_smaller(nisam_block_size,1024);
      break;
    case 'B':
      use_blob=1;
      break;
    case 'K':				/* Use key cacheing */
      key_cacheing=1;
      break;
    case 'W':				/* Use write cacheing */
      write_cacheing=1;
      if (*++pos)
	my_default_record_cache_size=atoi(pos);
      break;
    case 'i':
      if (*++pos)
	srand(atoi(pos));
      break;
    case 'l':
      use_log=1;
      break;
    case 'L':
      locking=1;
      break;
    case 'A':				/* use asyncron io */
      async_io=1;
      if (*++pos)
	my_default_record_cache_size=atoi(pos);
      break;
    case 'v':				/* verbose */
      verbose=1;
      break;
    case 'm':				/* records */
      recant=atoi(++pos);
      break;
    case 'f':
      if ((first_key=atoi(++pos)) <0 || first_key >= NISAM_KEYS)
	first_key=0;
      break;
    case 'k':
      if ((keys=(uint) atoi(++pos)) < 1 ||
	   keys > (uint) (NISAM_KEYS-first_key))
	keys=NISAM_KEYS-first_key;
      break;
    case 'P':
      pack_type=0;			/* Don't use DIFF_LENGTH */
      break;
    case 'R':				/* Length of record pointer */
      rec_pointer_size=atoi(++pos);
      if (rec_pointer_size > 3)
	rec_pointer_size=0;
      break;
    case 'S':
      pack_fields=0;			/* Static-length-records */
      break;
    case 't':
      testflag=atoi(++pos);		/* testmod */
      break;
    case '?':
    case 'I':
    case 'V':
      printf("%s  Ver 1.4 for %s at %s\n",progname,SYSTEM_TYPE,MACHINE_TYPE);
      puts("TCX Datakonsult AB, by Monty, for your professional use\n");
      printf("Usage: %s [-?ABIKLPRSVWltv] [-b#] [-k#] [-f#] [-m#] [-t#]\n",progname);
      exit(0);
    case '#':
      DEBUGGER_ON;
      DBUG_PUSH (++pos);
      break;
    default:
      printf("Illegal option: '%c'\n",*pos);
      break;
    }
  }
  return;
} /* get options */
Пример #9
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 */