Exemplo n.º 1
0
my_bool my_chmod(const char *filename, ulong perm_flags, myf my_flags)
{
  int ret_val;
  MY_MODE file_perm;
  DBUG_ENTER("my_chmod");
  DBUG_ASSERT(filename && filename[0]);

  file_perm= get_file_perm(perm_flags);
#ifdef _WIN32
  ret_val= _chmod(filename, file_perm);
#else
  ret_val= chmod(filename, file_perm);
#endif

  if (ret_val && (my_flags & (MY_FAE+MY_WME)))
  {
    char errbuf[MYSYS_STRERROR_SIZE];
    set_my_errno(errno);
    my_error(EE_CHANGE_PERMISSIONS, MYF(0), filename,
             errno, my_strerror(errbuf, sizeof(errbuf), errno));
  }

  DBUG_RETURN(ret_val ? TRUE : FALSE);
}
Exemplo n.º 2
0
/*
   allocates a new ssl object

   SYNOPSIS
     my_ssl_init
       mysql     connection object

   RETURN VALUES
     NULL on error
     SSL  new SSL object
*/
SSL *my_ssl_init(MYSQL *mysql)
{
    int verify;
    SSL *ssl= NULL;

    DBUG_ENTER("my_ssl_init");

    DBUG_ASSERT(mysql->net.vio->ssl == NULL);

    if (!my_ssl_initialized)
        my_ssl_start(mysql);

    pthread_mutex_lock(&LOCK_ssl_config);
    if (my_ssl_set_certs(mysql))
        goto error;

    if (!(ssl= SSL_new(SSL_context)))
        goto error;

    if (!SSL_set_app_data(ssl, mysql))
        goto error;

    verify= (!mysql->options.ssl_ca && !mysql->options.ssl_capath) ?
            SSL_VERIFY_NONE : SSL_VERIFY_PEER;

    SSL_CTX_set_verify(SSL_context, verify, my_verify_callback);
    SSL_CTX_set_verify_depth(SSL_context, 1);

    pthread_mutex_unlock(&LOCK_ssl_config);
    DBUG_RETURN(ssl);
error:
    pthread_mutex_unlock(&LOCK_ssl_config);
    if (ssl)
        SSL_free(ssl);
    DBUG_RETURN(NULL);
}
Exemplo n.º 3
0
int my_rw_unlock(my_rw_lock_t *rwp)
{
#ifdef _WIN32
  if (have_srwlock)
    return srw_unlock(rwp);
#endif

  DBUG_PRINT("rw_unlock",
	     ("state: %d waiters: %d", rwp->state, rwp->waiters));
  pthread_mutex_lock(&rwp->lock);

  DBUG_ASSERT(rwp->state != 0);

  if (rwp->state == -1)		/* writer releasing */
  {
    my_rw_lock_assert_write_owner(rwp);
    rwp->state= 0;		/* mark as available */
#ifdef SAFE_MUTEX
    rwp->write_thread= 0;
#endif

    if ( rwp->waiters )		/* writers queued */
      pthread_cond_signal( &rwp->writers );
    else
      pthread_cond_broadcast( &rwp->readers );
  }
  else
  {
    if ( --rwp->state == 0 &&   /* no more readers */
        rwp->waiters)
      pthread_cond_signal( &rwp->writers );
  }

  pthread_mutex_unlock( &rwp->lock );
  return(0);
}
Exemplo n.º 4
0
static void win_init_time(void)
{
  /* The following is used by time functions */
  FILETIME ft;
  LARGE_INTEGER li, t_cnt;

  DBUG_ASSERT(sizeof(LARGE_INTEGER) == sizeof(query_performance_frequency));

  if (QueryPerformanceFrequency((LARGE_INTEGER *)&query_performance_frequency) == 0)
    query_performance_frequency= 0;
  else
  {
    GetSystemTimeAsFileTime(&ft);
    li.LowPart=  ft.dwLowDateTime;
    li.HighPart= ft.dwHighDateTime;
    query_performance_offset= li.QuadPart-OFFSET_TO_EPOC;
    QueryPerformanceCounter(&t_cnt);
    query_performance_offset-= (t_cnt.QuadPart /
                                query_performance_frequency * MS +
                                t_cnt.QuadPart %
                                query_performance_frequency * MS /
                                query_performance_frequency);
  }
}
/*****************************************************************************
 * int indxInit();
 *
 * Return Value:  Return 0 : init was successful.
 *                Return -1: In all other case.  
 * Remark:        Initiates operation record after allocation.
 *****************************************************************************/
int
NdbIndexOperation::indxInit(const NdbIndexImpl * anIndex,
			    const NdbTableImpl * aTable, 
			    NdbTransaction* myConnection,
                            bool useRec)
{
  NdbOperation::init(aTable, myConnection, useRec);

  switch (anIndex->m_type) {
  case(NdbDictionary::Index::UniqueHashIndex):
    break;
  case(NdbDictionary::Index::Undefined):
  case(NdbDictionary::Index::OrderedIndex):
    setErrorCodeAbort(4003);
    return -1;
  default:
    DBUG_ASSERT(0);
    break;
  }
  m_theIndex = anIndex;
  m_accessTable = anIndex->m_table;
  theNoOfTupKeyLeft = m_accessTable->getNoOfPrimaryKeys();
  return 0;
}
int
unpack_row_old(Relay_log_info *rli,
               TABLE *table, uint const colcnt, uchar *record,
               uchar const *row, MY_BITMAP const *cols,
               uchar const **row_end, ulong *master_reclength,
               MY_BITMAP* const rw_set, Log_event_type const event_type)
{
  DBUG_ASSERT(record && row);
  my_ptrdiff_t const offset= record - (uchar*) table->record[0];
  size_t master_null_bytes= table->s->null_bytes;

  if (colcnt != table->s->fields)
  {
    Field **fptr= &table->field[colcnt-1];
    do
      master_null_bytes= (*fptr)->last_null_byte();
    while (master_null_bytes == Field::LAST_NULL_BYTE_UNDEF &&
           fptr-- > table->field);

    /*
      If master_null_bytes is LAST_NULL_BYTE_UNDEF (0) at this time,
      there were no nullable fields nor BIT fields at all in the
      columns that are common to the master and the slave. In that
      case, there is only one null byte holding the X bit.

      OBSERVE! There might still be nullable columns following the
      common columns, so table->s->null_bytes might be greater than 1.
     */
    if (master_null_bytes == Field::LAST_NULL_BYTE_UNDEF)
      master_null_bytes= 1;
  }

  DBUG_ASSERT(master_null_bytes <= table->s->null_bytes);
  memcpy(record, row, master_null_bytes);            // [1]
  int error= 0;

  bitmap_set_all(rw_set);

  Field **const begin_ptr = table->field;
  Field **field_ptr;
  uchar const *ptr= row + master_null_bytes;
  Field **const end_ptr= begin_ptr + colcnt;
  for (field_ptr= begin_ptr ; field_ptr < end_ptr ; ++field_ptr)
  {
    Field *const f= *field_ptr;

    if (bitmap_is_set(cols, field_ptr -  begin_ptr))
    {
      f->move_field_offset(offset);
      ptr= f->unpack(f->ptr, ptr);
      f->move_field_offset(-offset);
      /* Field...::unpack() cannot return 0 */
      DBUG_ASSERT(ptr != NULL);
    }
    else
      bitmap_clear_bit(rw_set, field_ptr - begin_ptr);
  }

  *row_end = ptr;
  if (master_reclength)
  {
    if (*field_ptr)
      *master_reclength = (*field_ptr)->ptr - table->record[0];
    else
      *master_reclength = table->s->reclength;
  }

  /*
    Set properties for remaining columns, if there are any. We let the
    corresponding bit in the write_set be set, to write the value if
    it was not there already. We iterate over all remaining columns,
    even if there were an error, to get as many error messages as
    possible.  We are still able to return a pointer to the next row,
    so redo that.

    This generation of error messages is only relevant when inserting
    new rows.
   */
  for ( ; *field_ptr ; ++field_ptr)
  {
    uint32 const mask= NOT_NULL_FLAG | NO_DEFAULT_VALUE_FLAG;

    DBUG_PRINT("debug", ("flags = 0x%x, mask = 0x%x, flags & mask = 0x%x",
                         (*field_ptr)->flags, mask,
                         (*field_ptr)->flags & mask));

    if (event_type == WRITE_ROWS_EVENT &&
        ((*field_ptr)->flags & mask) == mask)
    {
      rli->report(ERROR_LEVEL, ER_NO_DEFAULT_FOR_FIELD,
                  "Field `%s` of table `%s`.`%s` "
                  "has no default value and cannot be NULL",
                  (*field_ptr)->field_name, table->s->db.str,
                  table->s->table_name.str);
      error = ER_NO_DEFAULT_FOR_FIELD;
    }
    else
      (*field_ptr)->set_default();
  }

  return error;
}
Exemplo n.º 7
0
int main(int argc, char **argv)
{
  char self_name[FN_REFLEN];

  MY_INIT(argv[0]);

#if __WIN__
  if (GetModuleFileName(NULL, self_name, FN_REFLEN) == 0)
#endif
  {
    strncpy(self_name, argv[0], FN_REFLEN);
  }

  if (init_dynamic_string(&ds_args, "", 512, 256) ||
      init_dynamic_string(&conn_args, "", 512, 256))
    die("Out of memory");

  if (load_defaults("my", load_default_groups, &argc, &argv))
    die(NULL);
  defaults_argv= argv; /* Must be freed by 'free_defaults' */

  if (handle_options(&argc, &argv, my_long_options, get_one_option))
    die(NULL);
  if (debug_info_flag)
    my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO;
  if (debug_check_flag)
    my_end_arg= MY_CHECK_ERROR;

  if (tty_password)
  {
    opt_password= get_tty_password(NullS);
    /* add password to defaults file */
    dynstr_append_os_quoted(&ds_args, "--password="******" ");
  }
  /* add user to defaults file */
  dynstr_append_os_quoted(&ds_args, "--user="******" ");

  /* Find mysql */
  find_tool(mysql_path, IF_WIN("mysql.exe", "mysql"), self_name);

  /* Find mysqlcheck */
  find_tool(mysqlcheck_path, IF_WIN("mysqlcheck.exe", "mysqlcheck"), self_name);

  if (opt_systables_only && !opt_silent)
    printf("The --upgrade-system-tables option was used, user tables won't be touched.\n");


  /*
    Read the mysql_upgrade_info file to check if mysql_upgrade
    already has been run for this installation of MySQL
  */
  if (!opt_force && upgrade_already_done())
  {
    printf("This installation of MySQL is already upgraded to %s, "
           "use --force if you still need to run mysql_upgrade\n",
           MYSQL_SERVER_VERSION);
    goto end;
  }

  if (opt_version_check && check_version_match())
    die("Upgrade failed");

  upgrade_from_mysql= is_mysql();

  /*
    Run "mysqlcheck" and "mysql_fix_privilege_tables.sql"
  */
  if (run_mysqlcheck_upgrade(TRUE) ||
      run_mysqlcheck_views() ||
      run_sql_fix_privilege_tables() ||
      run_mysqlcheck_fixnames() ||
      run_mysqlcheck_upgrade(FALSE))
    die("Upgrade failed" );

  verbose("Phase %d/%d: Running 'FLUSH PRIVILEGES'", ++phase, phases_total);
  if (run_query("FLUSH PRIVILEGES", NULL, TRUE))
    die("Upgrade failed" );

  verbose("OK");

  /* Create a file indicating upgrade has been performed */
  create_mysql_upgrade_info_file();

  DBUG_ASSERT(phase == phases_total);

end:
  free_used_memory();
  my_end(my_end_arg);
  exit(0);
}
Exemplo n.º 8
0
pthread_handler_t test_lockman(void *arg)
{
  int    m= (*(int *)arg);
  uint   x, loid, row, table, res, locklevel, timeout= 0;
  TABLE_LOCK_OWNER *lo1;
  DBUG_ASSERT(Ntables <= Ntbls);
  DBUG_ASSERT(Nrows + Ntables <= Ntbls);

  pthread_mutex_lock(&rt_mutex);
  loid= ++thread_number;
  pthread_mutex_unlock(&rt_mutex);
  lo1= loid2lo1(loid);

  for (x= ((int)(intptr)(&m)); m > 0; m--)
  {
    /* three prime numbers */
    x= (uint) ((x*LL(3628273133) + LL(1500450271)) % LL(9576890767));
    row=  x % Nrows + Ntables;
    table= row % Ntables;
    locklevel= (x/Nrows) & 3;
    if (table_lock_ratio && (x/Nrows/4) % table_lock_ratio == 0)
    {
      /* table lock */
      res= tablockman_getlock(&tablockman, lo1, ltarray+table,
                              lock_array[locklevel]);
      DIAG(("loid %2d, table %d, lock %s, res %s", loid, table,
            lock2str[locklevel], res2str[res]));
      if (res < GOT_THE_LOCK)
      {
        reinit_tlo(&tablockman, lo1);
        DIAG(("loid %2d, release all locks", loid));
        timeout++;
        continue;
      }
      DBUG_ASSERT(res == GOT_THE_LOCK);
    }
    else
    { /* row lock */
      locklevel&= 1;
      res= tablockman_getlock(&tablockman, lo1, ltarray+table, lock_array[locklevel + 4]);
      DIAG(("loid %2d, row %d, lock %s, res %s", loid, row,
            lock2str[locklevel+4], res2str[res]));
      switch (res)
      {
      case GOT_THE_LOCK:
        continue;
      case GOT_THE_LOCK_NEED_TO_INSTANT_LOCK_A_SUBRESOURCE:
        /* not implemented, so take a regular lock */
      case GOT_THE_LOCK_NEED_TO_LOCK_A_SUBRESOURCE:
        res= tablockman_getlock(&tablockman, lo1, ltarray+row, lock_array[locklevel]);
        DIAG(("loid %2d, ROW %d, lock %s, res %s", loid, row,
              lock2str[locklevel], res2str[res]));
        if (res < GOT_THE_LOCK)
        {
          reinit_tlo(&tablockman, lo1);
          DIAG(("loid %2d, release all locks", loid));
          timeout++;
          continue;
        }
        DBUG_ASSERT(res == GOT_THE_LOCK);
        continue;
      default:
        reinit_tlo(&tablockman, lo1);
        DIAG(("loid %2d, release all locks", loid));
        timeout++;
        continue;
      }
    }
  }

  reinit_tlo(&tablockman, lo1);

  pthread_mutex_lock(&rt_mutex);
  rt_num_threads--;
  timeouts+= timeout;
  if (!rt_num_threads)
    diag("number of timeouts: %d", timeouts);
  pthread_mutex_unlock(&rt_mutex);

  return 0;
}
Exemplo n.º 9
0
my_bool my_thread_global_init(void)
{
  int pth_ret;

  if (my_thread_global_init_done)
    return 0;
  my_thread_global_init_done= 1;

#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
  /*
    Set mutex type to "fast" a.k.a "adaptive"

    In this case the thread may steal the mutex from some other thread
    that is waiting for the same mutex.  This will save us some
    context switches but may cause a thread to 'starve forever' while
    waiting for the mutex (not likely if the code within the mutex is
    short).
  */
  pthread_mutexattr_init(&my_fast_mutexattr);
  pthread_mutexattr_settype(&my_fast_mutexattr,
                            PTHREAD_MUTEX_ADAPTIVE_NP);
#endif

#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
  /*
    Set mutex type to "errorcheck"
  */
  pthread_mutexattr_init(&my_errorcheck_mutexattr);
  pthread_mutexattr_settype(&my_errorcheck_mutexattr,
                            PTHREAD_MUTEX_ERRORCHECK);
#endif

  DBUG_ASSERT(! THR_KEY_mysys_initialized);
  if ((pth_ret= my_create_thread_local_key(&THR_KEY_mysys, NULL)) != 0)
  { /* purecov: begin inspected */
    my_message_local(ERROR_LEVEL, "Can't initialize threads: error %d",
                     pth_ret);
    /* purecov: end */
    return 1;
  }

  THR_KEY_mysys_initialized= TRUE;
  mysql_mutex_init(key_THR_LOCK_malloc, &THR_LOCK_malloc, MY_MUTEX_INIT_FAST);
  mysql_mutex_init(key_THR_LOCK_open, &THR_LOCK_open, MY_MUTEX_INIT_FAST);
  mysql_mutex_init(key_THR_LOCK_charset, &THR_LOCK_charset, MY_MUTEX_INIT_FAST);
  mysql_mutex_init(key_THR_LOCK_threads, &THR_LOCK_threads, MY_MUTEX_INIT_FAST);

  if (my_thread_init())
    return 1;

  mysql_mutex_init(key_THR_LOCK_lock, &THR_LOCK_lock, MY_MUTEX_INIT_FAST);
  mysql_mutex_init(key_THR_LOCK_myisam, &THR_LOCK_myisam, MY_MUTEX_INIT_SLOW);
  mysql_mutex_init(key_THR_LOCK_myisam_mmap, &THR_LOCK_myisam_mmap, MY_MUTEX_INIT_FAST);
  mysql_mutex_init(key_THR_LOCK_heap, &THR_LOCK_heap, MY_MUTEX_INIT_FAST);
  mysql_mutex_init(key_THR_LOCK_net, &THR_LOCK_net, MY_MUTEX_INIT_FAST);
  mysql_cond_init(key_THR_COND_threads, &THR_COND_threads);

#ifdef _MSC_VER
  install_sigabrt_handler();
#endif

  return 0;
}
Exemplo n.º 10
0
enum enum_thr_lock_result
thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner,
         enum thr_lock_type lock_type, ulong lock_wait_timeout,
         struct st_my_thread_var *thread_var)
{
  THR_LOCK *lock=data->lock;
  enum enum_thr_lock_result result= THR_LOCK_SUCCESS;
  struct st_lock_list *wait_queue;
  MYSQL_TABLE_WAIT_VARIABLES(locker, state) /* no ';' */
  DBUG_ENTER("thr_lock");

  data->next=0;
  data->cond=0;					/* safety */
  data->type=lock_type;
  data->owner= owner;                           /* Must be reset ! */

  MYSQL_START_TABLE_LOCK_WAIT(locker, &state, data->m_psi,
                              PSI_TABLE_LOCK, lock_type);

  mysql_mutex_lock(&lock->mutex);
  DBUG_PRINT("lock",("data: 0x%lx  thread: 0x%x  lock: 0x%lx  type: %d",
                     (long) data, data->owner->thread_id,
                     (long) lock, (int) lock_type));
  check_locks(lock,(uint) lock_type <= (uint) TL_READ_NO_INSERT ?
	      "enter read_lock" : "enter write_lock",0);
  if ((int) lock_type <= (int) TL_READ_NO_INSERT)
  {
    /* Request for READ lock */
    if (lock->write.data)
    {
      /*
        We can allow a read lock even if there is already a
        write lock on the table if they are owned by the same
        thread or if they satisfy the following lock
        compatibility matrix:

           Request
          /-------
         H|++++  WRITE_ALLOW_WRITE
         e|+++-  WRITE_CONCURRENT_INSERT
         l ||||
         d ||||
           |||\= READ_NO_INSERT
           ||\ = READ_HIGH_PRIORITY
           |\  = READ_WITH_SHARED_LOCKS
           \   = READ

        + = Request can be satisified.
        - = Request cannot be satisified.

        READ_NO_INSERT and WRITE_ALLOW_WRITE should in principle
        be incompatible. Before this could have caused starvation of
        LOCK TABLE READ in InnoDB under high write load. However
        now READ_NO_INSERT is only used for LOCK TABLES READ and this
        statement is handled by the MDL subsystem.
        See Bug#42147 for more information.
      */

      DBUG_PRINT("lock",("write locked 1 by thread: 0x%x",
                         lock->write.data->owner->thread_id));
      if (thr_lock_owner_equal(data->owner, lock->write.data->owner) ||
          (lock->write.data->type < TL_WRITE_CONCURRENT_INSERT) ||
          ((lock->write.data->type == TL_WRITE_CONCURRENT_INSERT) &&
           ((int) lock_type <= (int) TL_READ_HIGH_PRIORITY)))
      {						/* Already got a write lock */
	(*lock->read.last)=data;		/* Add to running FIFO */
	data->prev=lock->read.last;
	lock->read.last= &data->next;
	if (lock_type == TL_READ_NO_INSERT)
	  lock->read_no_write_count++;
	check_locks(lock,"read lock with old write lock",0);
	if (lock->get_status)
	  (*lock->get_status)(data->status_param, 0);
	locks_immediate++;
	goto end;
      }
      if (lock->write.data->type == TL_WRITE_ONLY)
      {
	/* We are not allowed to get a READ lock in this case */
	data->type=TL_UNLOCK;
        result= THR_LOCK_ABORTED;               /* Can't wait for this one */
	goto end;
      }
    }
    else if (!lock->write_wait.data ||
	     lock->write_wait.data->type <= TL_WRITE_LOW_PRIORITY ||
	     lock_type == TL_READ_HIGH_PRIORITY ||
	     has_old_lock(lock->read.data, data->owner)) /* Has old read lock */
    {						/* No important write-locks */
      (*lock->read.last)=data;			/* Add to running FIFO */
      data->prev=lock->read.last;
      lock->read.last= &data->next;
      if (lock->get_status)
	(*lock->get_status)(data->status_param, 0);
      if (lock_type == TL_READ_NO_INSERT)
	lock->read_no_write_count++;
      check_locks(lock,"read lock with no write locks",0);
      locks_immediate++;
      goto end;
    }
    /*
      We're here if there is an active write lock or no write
      lock but a high priority write waiting in the write_wait queue.
      In the latter case we should yield the lock to the writer.
    */
    wait_queue= &lock->read_wait;
  }
  else						/* Request for WRITE lock */
  {
    if (lock_type == TL_WRITE_CONCURRENT_INSERT && ! lock->check_status)
      data->type=lock_type= thr_upgraded_concurrent_insert_lock;

    if (lock->write.data)			/* If there is a write lock */
    {
      if (lock->write.data->type == TL_WRITE_ONLY)
      {
        /* purecov: begin tested */
        /* Allow lock owner to bypass TL_WRITE_ONLY. */
        if (!thr_lock_owner_equal(data->owner, lock->write.data->owner))
        {
          /* We are not allowed to get a lock in this case */
          data->type=TL_UNLOCK;
          result= THR_LOCK_ABORTED;               /* Can't wait for this one */
          goto end;
        }
        /* purecov: end */
      }

      /*
        The idea is to allow us to get a lock at once if we already have
        a write lock or if there is no pending write locks and if all
        write locks are of TL_WRITE_ALLOW_WRITE type.

        Note that, since lock requests for the same table are sorted in
        such way that requests with higher thr_lock_type value come first
        (with one exception (*)), lock being requested usually has
        equal or "weaker" type than one which thread might have already
        acquired.
        *)  The only exception to this rule is case when type of old lock
            is TL_WRITE_LOW_PRIORITY and type of new lock is changed inside
            of thr_lock() from TL_WRITE_CONCURRENT_INSERT to TL_WRITE since
            engine turns out to be not supporting concurrent inserts.
            Note that since TL_WRITE has the same compatibility rules as
            TL_WRITE_LOW_PRIORITY (their only difference is priority),
            it is OK to grant new lock without additional checks in such
            situation.

        Therefore it is OK to allow acquiring write lock on the table if
        this thread already holds some write lock on it.

        (INSERT INTO t1 VALUES (f1()), where f1() is stored function which
        tries to update t1, is an example of statement which requests two
        different types of write lock on the same table).
      */
      DBUG_ASSERT(! has_old_lock(lock->write.data, data->owner) ||
                  ((lock_type <= lock->write.data->type ||
                    (lock_type == TL_WRITE &&
                     lock->write.data->type == TL_WRITE_LOW_PRIORITY))));

      if ((lock_type == TL_WRITE_ALLOW_WRITE &&
           ! lock->write_wait.data &&
           lock->write.data->type == TL_WRITE_ALLOW_WRITE) ||
          has_old_lock(lock->write.data, data->owner))
      {
	/*
          We have already got a write lock or all locks are
          TL_WRITE_ALLOW_WRITE
        */
        DBUG_PRINT("info", ("write_wait.data: 0x%lx  old_type: %d",
                            (ulong) lock->write_wait.data,
                            lock->write.data->type));

	(*lock->write.last)=data;	/* Add to running fifo */
	data->prev=lock->write.last;
	lock->write.last= &data->next;
	check_locks(lock,"second write lock",0);
	if (data->lock->get_status)
	  (*data->lock->get_status)(data->status_param, 0);
	locks_immediate++;
	goto end;
      }
      DBUG_PRINT("lock",("write locked 2 by thread: 0x%x",
			 lock->write.data->owner->thread_id));
    }
    else
    {
      DBUG_PRINT("info", ("write_wait.data: 0x%lx",
                          (ulong) lock->write_wait.data));
      if (!lock->write_wait.data)
      {						/* no scheduled write locks */
        my_bool concurrent_insert= 0;
	if (lock_type == TL_WRITE_CONCURRENT_INSERT)
        {
          concurrent_insert= 1;
          if ((*lock->check_status)(data->status_param))
          {
            concurrent_insert= 0;
            data->type=lock_type= thr_upgraded_concurrent_insert_lock;
          }
        }

	if (!lock->read.data ||
      (lock_type <= TL_WRITE_CONCURRENT_INSERT &&
       ((lock_type != TL_WRITE_CONCURRENT_INSERT &&
	       lock_type != TL_WRITE_ALLOW_WRITE) ||
	      !lock->read_no_write_count)))
	{
	  (*lock->write.last)=data;		/* Add as current write lock */
	  data->prev=lock->write.last;
	  lock->write.last= &data->next;
	  if (data->lock->get_status)
	    (*data->lock->get_status)(data->status_param, concurrent_insert);
	  check_locks(lock,"only write lock",0);
	  locks_immediate++;
	  goto end;
	}
      }
      DBUG_PRINT("lock",("write locked 3 by thread: 0x%x  type: %d",
			 lock->read.data->owner->thread_id, data->type));
    }
    wait_queue= &lock->write_wait;
  }
  /* Can't get lock yet;  Wait for it */
  result= wait_for_lock(wait_queue, data, 0, lock_wait_timeout, thread_var);
  MYSQL_END_TABLE_LOCK_WAIT(locker);
  DBUG_RETURN(result);
end:
  mysql_mutex_unlock(&lock->mutex);
  MYSQL_END_TABLE_LOCK_WAIT(locker);
  DBUG_RETURN(result);
}
Exemplo n.º 11
0
static int ftb_query_add_word(MYSQL_FTPARSER_PARAM *param,
                              char *word, int word_len,
                              MYSQL_FTPARSER_BOOLEAN_INFO *info)
{
  MY_FTB_PARAM *ftb_param= param->mysql_ftparam;
  FTB_WORD *ftbw;
  FTB_EXPR *ftbe, *tmp_expr;
  FT_WORD *phrase_word;
  LIST *tmp_element;
  int r= info->weight_adjust;
  float weight= (float)
        (info->wasign ? nwghts : wghts)[(r>5)?5:((r<-5)?-5:r)];

  switch (info->type) {
    case FT_TOKEN_WORD:
      ftbw= (FTB_WORD *)alloc_root(&ftb_param->ftb->mem_root,
                                   sizeof(FTB_WORD) +
                                   (info->trunc ? MI_MAX_KEY_BUFF :
                                    word_len * ftb_param->ftb->charset->mbmaxlen +
                                    HA_FT_WLEN +
                                    ftb_param->ftb->info->s->rec_reflength));
      ftbw->len= word_len + 1;
      ftbw->flags= 0;
      ftbw->off= 0;
      if (info->yesno > 0) ftbw->flags|= FTB_FLAG_YES;
      if (info->yesno < 0) ftbw->flags|= FTB_FLAG_NO;
      if (info->trunc) ftbw->flags|= FTB_FLAG_TRUNC;
      ftbw->weight= weight;
      ftbw->up= ftb_param->ftbe;
      ftbw->docid[0]= ftbw->docid[1]= HA_OFFSET_ERROR;
      ftbw->ndepth= (info->yesno < 0) + ftb_param->depth;
      ftbw->key_root= HA_OFFSET_ERROR;
      memcpy(ftbw->word + 1, word, word_len);
      ftbw->word[0]= word_len;
      if (info->yesno > 0) ftbw->up->ythresh++;
      ftb_param->ftb->queue.max_elements++;
      ftbw->prev= ftb_param->ftb->last_word;
      ftb_param->ftb->last_word= ftbw;
      ftb_param->ftb->with_scan|= (info->trunc & FTB_FLAG_TRUNC);
      for (tmp_expr= ftb_param->ftbe; tmp_expr->up; tmp_expr= tmp_expr->up)
        if (! (tmp_expr->flags & FTB_FLAG_YES))
          break;
      ftbw->max_docid_expr= tmp_expr;
      /* fall through */
    case FT_TOKEN_STOPWORD:
      if (! ftb_param->up_quot) break;
      phrase_word= (FT_WORD *)alloc_root(&ftb_param->ftb->mem_root, sizeof(FT_WORD));
      tmp_element= (LIST *)alloc_root(&ftb_param->ftb->mem_root, sizeof(LIST));
      phrase_word->pos= (uchar*) word;
      phrase_word->len= word_len;
      tmp_element->data= (void *)phrase_word;
      ftb_param->ftbe->phrase= list_add(ftb_param->ftbe->phrase, tmp_element);
      /* Allocate document list at this point.
         It allows to avoid huge amount of allocs/frees for each row.*/
      tmp_element= (LIST *)alloc_root(&ftb_param->ftb->mem_root, sizeof(LIST));
      tmp_element->data= alloc_root(&ftb_param->ftb->mem_root, sizeof(FT_WORD));
      ftb_param->ftbe->document=
        list_add(ftb_param->ftbe->document, tmp_element);
      break;
    case FT_TOKEN_LEFT_PAREN:
      ftbe=(FTB_EXPR *)alloc_root(&ftb_param->ftb->mem_root, sizeof(FTB_EXPR));
      ftbe->flags= 0;
      if (info->yesno > 0) ftbe->flags|= FTB_FLAG_YES;
      if (info->yesno < 0) ftbe->flags|= FTB_FLAG_NO;
      ftbe->weight= weight;
      ftbe->up= ftb_param->ftbe;
      ftbe->max_docid= ftbe->ythresh= ftbe->yweaks= 0;
      ftbe->docid[0]= ftbe->docid[1]= HA_OFFSET_ERROR;
      ftbe->phrase= NULL;
      ftbe->document= 0;
      if (info->quot) ftb_param->ftb->with_scan|= 2;
      if (info->yesno > 0) ftbe->up->ythresh++;
      ftb_param->ftbe= ftbe;
      ftb_param->depth++;
      ftb_param->up_quot= (uchar*) info->quot;
      break;
    case FT_TOKEN_RIGHT_PAREN:
      if (ftb_param->ftbe->document)
      {
        /* Circuit document list */
        for (tmp_element= ftb_param->ftbe->document;
             tmp_element->next; tmp_element= tmp_element->next) /* no-op */;
        tmp_element->next= ftb_param->ftbe->document;
        ftb_param->ftbe->document->prev= tmp_element;
      }
      info->quot= 0;
      if (ftb_param->ftbe->up)
      {
        DBUG_ASSERT(ftb_param->depth);
        ftb_param->ftbe= ftb_param->ftbe->up;
        ftb_param->depth--;
        ftb_param->up_quot= 0;
      }
      break;
    case FT_TOKEN_EOF:
    default:
      break;
  }
  return(0);
}
Exemplo n.º 12
0
/* 
  Set certification stuff.
*/
static int my_ssl_set_certs(SSL *ssl)
{
  int have_cert= 0;
  MYSQL *mysql;

  DBUG_ENTER("my_ssl_set_certs");

  /* Make sure that ssl was allocated and 
     ssl_system was initialized */
  DBUG_ASSERT(ssl != NULL);
  DBUG_ASSERT(my_ssl_initialized == TRUE);

  /* get connection for current ssl */
  mysql= (MYSQL *)SSL_get_app_data(ssl);

  /* add cipher */
  if ((mysql->options.ssl_cipher && 
        mysql->options.ssl_cipher[0] != 0) &&
      SSL_set_cipher_list(ssl, mysql->options.ssl_cipher) == 0)
    goto error;

  /* set cert */
  if (mysql->options.ssl_cert && mysql->options.ssl_cert[0] != 0)  
  {
    if (SSL_CTX_use_certificate_chain_file(SSL_context, mysql->options.ssl_cert) <= 0)
      goto error; 
    have_cert= 1;
  }

  /* set key */
  if (mysql->options.ssl_key && mysql->options.ssl_key[0])
  {
    if (SSL_CTX_use_PrivateKey_file(SSL_context, mysql->options.ssl_key, SSL_FILETYPE_PEM) <= 0)
      goto error;

    /* verify key */
    if (have_cert && SSL_CTX_check_private_key(SSL_context) != 1)
      goto error;
  }
  /* ca_file and ca_path */
  if (SSL_CTX_load_verify_locations(SSL_context, 
                                    mysql->options.ssl_ca,
                                    mysql->options.ssl_capath) == 0)
  {
    if (mysql->options.ssl_ca || mysql->options.ssl_capath)
      goto error;
    if (SSL_CTX_set_default_verify_paths(SSL_context) == 0)
      goto error;
  }
  if (mysql->options.extension &&
      (mysql->options.extension->ssl_crl || mysql->options.extension->ssl_crlpath))
  {
    X509_STORE *certstore;

    if ((certstore= SSL_CTX_get_cert_store(SSL_context)))
    {
      if (X509_STORE_load_locations(certstore, mysql->options.ssl_ca,
                                     mysql->options.ssl_capath) == 0 ||
			    X509_STORE_set_flags(certstore, X509_V_FLAG_CRL_CHECK |
                                         X509_V_FLAG_CRL_CHECK_ALL) == 0)
        goto error;
    }
  }

  DBUG_RETURN(0);

error:
  my_SSL_error(mysql);
  DBUG_RETURN(1);
}
Exemplo n.º 13
0
ulonglong TYPBLK<TYPE>::MaxVal(void) {DBUG_ASSERT(false); return 0;}
Exemplo n.º 14
0
/* ===========================================================================
  Opens a gzip (.gz) file for reading or writing. The mode parameter
  is as in fopen ("rb" or "wb"). The file is given either by file descriptor
  or path name (if fd == -1).
  az_open returns NULL if the file could not be opened or if there was
  insufficient memory to allocate the (de)compression state; errno
  can be checked to distinguish the two cases (if errno is zero, the
  zlib error is Z_MEM_ERROR).
*/
int az_open (azio_stream *s, const char *path, int Flags, File fd)
{
  int err;
  int level = Z_DEFAULT_COMPRESSION; /* compression level */
  int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */

  s->stream.zalloc = (alloc_func)0;
  s->stream.zfree = (free_func)0;
  s->stream.opaque = (voidpf)0;
  memset(s->inbuf, 0, AZ_BUFSIZE_READ);
  memset(s->outbuf, 0, AZ_BUFSIZE_WRITE);
  s->stream.next_in = s->inbuf;
  s->stream.next_out = s->outbuf;
  s->stream.avail_in = s->stream.avail_out = 0;
  s->z_err = Z_OK;
  s->z_eof = 0;
  s->in = 0;
  s->out = 0;
  s->back = EOF;
  s->crc = crc32(0L, Z_NULL, 0);
  s->transparent = 0;
  s->mode = 'r';
  s->version = (unsigned char)az_magic[1]; /* this needs to be a define to version */
  s->minor_version= (unsigned char) az_magic[2]; /* minor version */
  s->dirty= AZ_STATE_CLEAN;

  /*
    We do our own version of append by nature. 
    We must always have write access to take card of the header.
  */
  DBUG_ASSERT(Flags | O_APPEND);
  DBUG_ASSERT(Flags | O_WRONLY);

  if (Flags & O_RDWR) 
    s->mode = 'w';

  if (s->mode == 'w') 
  {
    err = deflateInit2(&(s->stream), level,
                       Z_DEFLATED, -MAX_WBITS, 8, strategy);
    /* windowBits is passed < 0 to suppress zlib header */

    s->stream.next_out = s->outbuf;
    if (err != Z_OK)
    {
      destroy(s);
      return Z_NULL;
    }
  } else {
    s->stream.next_in  = s->inbuf;

    err = inflateInit2(&(s->stream), -MAX_WBITS);
    /* windowBits is passed < 0 to tell that there is no zlib header.
     * Note that in this case inflate *requires* an extra "dummy" byte
     * after the compressed stream in order to complete decompression and
     * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
     * present after the compressed stream.
   */
    if (err != Z_OK)
    {
      destroy(s);
      return Z_NULL;
    }
  }
  s->stream.avail_out = AZ_BUFSIZE_WRITE;

  errno = 0;
  s->file = fd < 0 ? my_open(path, Flags, MYF(0)) : fd;

  if (s->file < 0 ) 
  {
    destroy(s);
    return Z_NULL;
  }

  if (Flags & O_CREAT || Flags & O_TRUNC) 
  {
    s->rows= 0;
    s->forced_flushes= 0;
    s->shortest_row= 0;
    s->longest_row= 0;
    s->auto_increment= 0;
    s->check_point= 0;
    s->comment_start_pos= 0;
    s->comment_length= 0;
    s->frm_start_pos= 0;
    s->frm_length= 0;
    s->dirty= 1; /* We create the file dirty */
    s->start = AZHEADER_SIZE + AZMETA_BUFFER_SIZE;
    write_header(s);
    my_seek(s->file, 0, MY_SEEK_END, MYF(0));
  }
  else if (s->mode == 'w') 
  {
    uchar buffer[AZHEADER_SIZE + AZMETA_BUFFER_SIZE];
    my_pread(s->file, buffer, AZHEADER_SIZE + AZMETA_BUFFER_SIZE, 0,
             MYF(0));
    read_header(s, buffer); /* skip the .az header */
    my_seek(s->file, 0, MY_SEEK_END, MYF(0));
  }
  else
  {
    check_header(s); /* skip the .az header */
  }

  return 1;
}
Exemplo n.º 15
0
 void init(void) {
   CHARSET_INFO **cs;
   MRN_DBUG_ENTER_FUNCTION();
   for (cs = all_charsets; cs < all_charsets + MY_ALL_CHARSETS_SIZE; cs++)
   {
     if (!cs[0])
       continue;
     if (!strcmp(cs[0]->csname, "utf8"))
     {
       DBUG_PRINT("info", ("mroonga: %s is %s [%p]",
                           cs[0]->name, cs[0]->csname, cs[0]->cset));
       if (!mrn_charset_utf8)
         mrn_charset_utf8 = cs[0];
       else if (mrn_charset_utf8->cset != cs[0]->cset)
         DBUG_ASSERT(0);
       continue;
     }
     if (!strcmp(cs[0]->csname, "utf8mb4"))
     {
       DBUG_PRINT("info", ("mroonga: %s is %s [%p]",
                           cs[0]->name, cs[0]->csname, cs[0]->cset));
       if (!mrn_charset_utf8mb4)
         mrn_charset_utf8mb4 = cs[0];
       else if (mrn_charset_utf8mb4->cset != cs[0]->cset)
         DBUG_ASSERT(0);
       continue;
     }
     if (!strcmp(cs[0]->csname, "binary"))
     {
       DBUG_PRINT("info", ("mroonga: %s is %s [%p]",
                           cs[0]->name, cs[0]->csname, cs[0]->cset));
       if (!mrn_charset_binary)
         mrn_charset_binary = cs[0];
       else if (mrn_charset_binary->cset != cs[0]->cset)
         DBUG_ASSERT(0);
       continue;
     }
     if (!strcmp(cs[0]->csname, "ascii"))
     {
       DBUG_PRINT("info", ("mroonga: %s is %s [%p]",
                           cs[0]->name, cs[0]->csname, cs[0]->cset));
       if (!mrn_charset_ascii)
         mrn_charset_ascii = cs[0];
       else if (mrn_charset_ascii->cset != cs[0]->cset)
         DBUG_ASSERT(0);
       continue;
     }
     if (!strcmp(cs[0]->csname, "latin1"))
     {
       DBUG_PRINT("info", ("mroonga: %s is %s [%p]",
                           cs[0]->name, cs[0]->csname, cs[0]->cset));
       if (!mrn_charset_latin1_1)
         mrn_charset_latin1_1 = cs[0];
       else if (mrn_charset_latin1_1->cset != cs[0]->cset)
       {
         if (!mrn_charset_latin1_2)
           mrn_charset_latin1_2 = cs[0];
         else if (mrn_charset_latin1_2->cset != cs[0]->cset)
           DBUG_ASSERT(0);
       }
       continue;
     }
     if (!strcmp(cs[0]->csname, "cp932"))
     {
       DBUG_PRINT("info", ("mroonga: %s is %s [%p]",
                           cs[0]->name, cs[0]->csname, cs[0]->cset));
       if (!mrn_charset_cp932)
         mrn_charset_cp932 = cs[0];
       else if (mrn_charset_cp932->cset != cs[0]->cset)
         DBUG_ASSERT(0);
       continue;
     }
     if (!strcmp(cs[0]->csname, "sjis"))
     {
       DBUG_PRINT("info", ("mroonga: %s is %s [%p]",
                           cs[0]->name, cs[0]->csname, cs[0]->cset));
       if (!mrn_charset_sjis)
         mrn_charset_sjis = cs[0];
       else if (mrn_charset_sjis->cset != cs[0]->cset)
         DBUG_ASSERT(0);
       continue;
     }
     if (!strcmp(cs[0]->csname, "eucjpms"))
     {
       DBUG_PRINT("info", ("mroonga: %s is %s [%p]",
                           cs[0]->name, cs[0]->csname, cs[0]->cset));
       if (!mrn_charset_eucjpms)
         mrn_charset_eucjpms = cs[0];
       else if (mrn_charset_eucjpms->cset != cs[0]->cset)
         DBUG_ASSERT(0);
       continue;
     }
     if (!strcmp(cs[0]->csname, "ujis"))
     {
       DBUG_PRINT("info", ("mroonga: %s is %s [%p]",
                           cs[0]->name, cs[0]->csname, cs[0]->cset));
       if (!mrn_charset_ujis)
         mrn_charset_ujis = cs[0];
       else if (mrn_charset_ujis->cset != cs[0]->cset)
         DBUG_ASSERT(0);
       continue;
     }
     if (!strcmp(cs[0]->csname, "koi8r"))
     {
       DBUG_PRINT("info", ("mroonga: %s is %s [%p]",
                           cs[0]->name, cs[0]->csname, cs[0]->cset));
       if (!mrn_charset_koi8r)
         mrn_charset_koi8r = cs[0];
       else if (mrn_charset_koi8r->cset != cs[0]->cset)
         DBUG_ASSERT(0);
       continue;
     }
     DBUG_PRINT("info", ("mroonga: %s[%s][%p] is not supported",
                         cs[0]->name, cs[0]->csname, cs[0]->cset));
   }
   DBUG_VOID_RETURN;
 }
Exemplo n.º 16
0
uint hp_rb_make_key(HP_KEYDEF *keydef, uchar *key, 
		    const uchar *rec, uchar *recpos)
{
  uchar *start_key= key;
  HA_KEYSEG *seg, *endseg;

  for (seg= keydef->seg, endseg= seg + keydef->keysegs; seg < endseg; seg++)
  {
    uint char_length;
    if (seg->null_bit)
    {
      if (!(*key++= 1 - MY_TEST(rec[seg->null_pos] & seg->null_bit)))
        continue;
    }
    if (seg->flag & HA_SWAP_KEY)
    {
      uint length= seg->length;
      uchar *pos= (uchar*) rec + seg->start;
      DBUG_ASSERT(seg->type != HA_KEYTYPE_BIT);

#ifdef HAVE_ISNAN
      if (seg->type == HA_KEYTYPE_FLOAT)
      {
	float nr;
	float4get(nr, pos);
	if (isnan(nr))
	{
	  /* Replace NAN with zero */
 	  bzero(key, length);
	  key+= length;
	  continue;
	}
      }
      else if (seg->type == HA_KEYTYPE_DOUBLE)
      {
	double nr;
	float8get(nr, pos);
	if (isnan(nr))
	{
 	  bzero(key, length);
	  key+= length;
	  continue;
	}
      }
#endif
      pos+= length;
      while (length--)
      {
	*key++= *--pos;
      }
      continue;
    }

    if (seg->flag & HA_VAR_LENGTH_PART)
    {
      uchar *pos=      (uchar*) rec + seg->start;
      uint length=     seg->length;
      uint pack_length= seg->bit_start;
      uint tmp_length= (pack_length == 1 ? (uint) *(uchar*) pos :
                        uint2korr(pos));
      CHARSET_INFO *cs= seg->charset;
      char_length= length/cs->mbmaxlen;

      pos+= pack_length;			/* Skip VARCHAR length */
      set_if_smaller(length,tmp_length);
      FIX_LENGTH(cs, pos, length, char_length);
      store_key_length_inc(key,char_length);
      memcpy((uchar*) key,(uchar*) pos,(size_t) char_length);
      key+= char_length;
      continue;
    }

    char_length= seg->length;
    if (seg->charset->mbmaxlen > 1)
    {
      char_length= my_charpos(seg->charset, 
                              rec + seg->start, rec + seg->start + char_length,
                              char_length / seg->charset->mbmaxlen);
      set_if_smaller(char_length, seg->length); /* QQ: ok to remove? */
      if (char_length < seg->length)
        seg->charset->cset->fill(seg->charset, (char*) key + char_length,
                                 seg->length - char_length, ' ');
    }
    if (seg->type == HA_KEYTYPE_BIT && seg->bit_length)
    {
      *key++= get_rec_bits(rec + seg->bit_pos,
                           seg->bit_start, seg->bit_length);
      char_length--;
    }
    memcpy(key, rec + seg->start, (size_t) char_length);
    key+= seg->length;
  }
  memcpy(key, &recpos, sizeof(uchar*));
  return (uint) (key - start_key);
}
Exemplo n.º 17
0
const char*
sslGetErrString(enum enum_ssl_init_error e)
{
  DBUG_ASSERT(SSL_INITERR_NOERROR < e && e < SSL_INITERR_LASTERR);
  return ssl_error_string[e];
}
Exemplo n.º 18
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, UNINIT_VAR(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;
  my_bool bad_children= FALSE;
  DBUG_ENTER("myrg_open");

  memset(&file, 0, sizeof(file));
  if ((fd= mysql_file_open(rg_key_file_MRG,
                           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, FIND_TYPE_BASIC);
	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))))
    {
      if (handle_locking & HA_OPEN_FOR_REPAIR)
      {
        myrg_print_wrong_table(buff);
        bad_children= TRUE;
        continue;
      }
      goto bad_children;
    }
    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)
    {
      if (handle_locking & HA_OPEN_FOR_REPAIR)
      {
        myrg_print_wrong_table(buff);
        bad_children= TRUE;
        continue;
      }
      goto bad_children;
    }
    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 (bad_children)
    goto bad_children;
  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;
  memset(&m_info->by_key, 0, 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) mysql_file_close(fd, MYF(0));
  end_io_cache(&file);
  mysql_mutex_init(rg_key_mutex_MYRG_INFO_mutex,
                   &m_info->mutex, MY_MUTEX_INIT_FAST);
  m_info->open_list.data=(void*) m_info;
  mysql_mutex_lock(&THR_LOCK_open);
  myrg_open_list=list_add(myrg_open_list,&m_info->open_list);
  mysql_mutex_unlock(&THR_LOCK_open);
  DBUG_RETURN(m_info);

bad_children:
  my_errno= HA_ERR_WRONG_MRG_TABLE_DEF;
err:
  save_errno=my_errno;
  switch (errpos) {
  case 3:
    while (files)
      (void) mi_close(m_info->open_tables[--files].table);
    my_free(m_info);
    /* Fall through */
  case 2:
    end_io_cache(&file);
    /* Fall through */
  case 1:
    (void) mysql_file_close(fd, MYF(0));
  }
  my_errno=save_errno;
  DBUG_RETURN (NULL);
}
Exemplo n.º 19
0
inline static void set_args_separator(char** arg)
{
  DBUG_ASSERT(my_getopt_use_args_separator);
  *arg= (char*)args_separator;
}
Exemplo n.º 20
0
size_t my_b_vprintf(IO_CACHE *info, const char* fmt, va_list args)
{
  size_t out_length= 0;
  uint minimum_width; /* as yet unimplemented */
  uint minimum_width_sign;
  uint precision; /* as yet unimplemented for anything but %b */
  my_bool is_zero_padded;

  /*
    Store the location of the beginning of a format directive, for the
    case where we learn we shouldn't have been parsing a format string
    at all, and we don't want to lose the flag/precision/width/size
    information.
   */
  const char* backtrack;

  for (; *fmt != '\0'; fmt++)
  {
    /* Copy everything until '%' or end of string */
    const char *start=fmt;
    size_t length;
    
    for (; (*fmt != '\0') && (*fmt != '%'); fmt++) ;

    length= (size_t) (fmt - start);
    out_length+=length;
    if (my_b_write(info, (const uchar*) start, length))
      goto err;

    if (*fmt == '\0')				/* End of format */
      return out_length;

    /* 
      By this point, *fmt must be a percent;  Keep track of this location and
      skip over the percent character. 
    */
    DBUG_ASSERT(*fmt == '%');
    backtrack= fmt;
    fmt++;

    is_zero_padded= FALSE;
    minimum_width_sign= 1;
    minimum_width= 0;
    precision= 0;
    /* Skip if max size is used (to be compatible with printf) */

process_flags:
    switch (*fmt)
    {
      case '-': 
        minimum_width_sign= -1; fmt++; goto process_flags;
      case '0':
        is_zero_padded= TRUE; fmt++; goto process_flags;
      case '#':
        /** @todo Implement "#" conversion flag. */  fmt++; goto process_flags;
      case ' ':
        /** @todo Implement " " conversion flag. */  fmt++; goto process_flags;
      case '+':
        /** @todo Implement "+" conversion flag. */  fmt++; goto process_flags;
    }

    if (*fmt == '*')
    {
      precision= (int) va_arg(args, int);
      fmt++;
    }
    else
    {
      while (my_isdigit(&my_charset_latin1, *fmt)) {
Exemplo n.º 21
0
char * fn_format(char * to, const char *name, const char *dir,
		    const char *extension, uint flag)
{
  char dev[FN_REFLEN], buff[FN_REFLEN], *pos, *startpos;
  const char *ext;
  reg1 size_t length;
  size_t dev_length;
  my_bool not_used;
  DBUG_ENTER("fn_format");
  DBUG_ASSERT(name != NULL);
  DBUG_ASSERT(extension != NULL);
  DBUG_PRINT("enter",("name: %s  dir: %s  extension: %s  flag: %d",
		       name,dir,extension,flag));

  /* Copy and skip directory */
  name+=(length=dirname_part(dev, (startpos=(char *) name), &dev_length));
  if (length == 0 || (flag & MY_REPLACE_DIR))
  {
    DBUG_ASSERT(dir != NULL);
    /* Use given directory */
    convert_dirname(dev,dir,NullS);		/* Fix to this OS */
  }
  else if ((flag & MY_RELATIVE_PATH) && !test_if_hard_path(dev))
  {
    DBUG_ASSERT(dir != NULL);
    /* Put 'dir' before the given path */
    strmake(buff,dev,sizeof(buff)-1);
    pos=convert_dirname(dev,dir,NullS);
    strmake(pos,buff,sizeof(buff)-1- (int) (pos-dev));
  }

  if (flag & MY_PACK_FILENAME)
    pack_dirname(dev,dev);			/* Put in ./.. and ~/.. */
  if (flag & MY_UNPACK_FILENAME)
    (void) unpack_dirname(dev, dev, &not_used);	/* Replace ~/.. with dir */

  if (!(flag & MY_APPEND_EXT) &&
      (pos= (char*) strchr(name,FN_EXTCHAR)) != NullS)
  {
    if ((flag & MY_REPLACE_EXT) == 0)		/* If we should keep old ext */
    {
      length=strlength(name);			/* Use old extension */
      ext = "";
    }
    else
    {
      length= (size_t) (pos-(char*) name);	/* Change extension */
      ext= extension;
    }
  }
  else
  {
    length=strlength(name);			/* No ext, use the now one */
    ext=extension;
  }

  if (strlen(dev)+length+strlen(ext) >= FN_REFLEN || length >= FN_LEN )
  {
    /* To long path, return original or NULL */
    size_t tmp_length;
    if (flag & MY_SAFE_PATH)
      DBUG_RETURN(NullS);
    tmp_length= strlength(startpos);
    DBUG_PRINT("error",("dev: '%s'  ext: '%s'  length: %u",dev,ext,
                        (uint) length));
    (void) strmake(to, startpos, MY_MIN(tmp_length, FN_REFLEN-1));
  }
  else
  {
    if (to == startpos)
    {
      bmove(buff,(uchar*) name,length);		/* Save name for last copy */
      name=buff;
    }
    pos=strmake(strmov(to,dev),name,length);
    (void) strmov(pos,ext);			/* Don't convert extension */
  }
  /*
    If MY_RETURN_REAL_PATH and MY_RESOLVE_SYMLINK is given, only do
    realpath if the file is a symbolic link
  */
  if (flag & MY_RETURN_REAL_PATH)
    (void) my_realpath(to, to, MYF(flag & MY_RESOLVE_SYMLINKS ?
				   MY_RESOLVE_LINK: 0));
  else if (flag & MY_RESOLVE_SYMLINKS)
  {
    strmov(buff,to);
    (void) my_readlink(to, buff, MYF(0));
  }
  DBUG_RETURN(to);
} /* fn_format */
Exemplo n.º 22
0
uint sp_make_key(register MI_INFO *info, uint keynr, uchar *key,
		 const uchar *record, my_off_t filepos)
{
  HA_KEYSEG *keyseg;
  MI_KEYDEF *keyinfo = &info->s->keyinfo[keynr];
  uint len = 0;
  uchar *pos;
  uint dlen;
  uchar *dptr;
  double mbr[SPDIMS * 2];
  uint i;
  
  keyseg = &keyinfo->seg[-1];
  pos = (uchar*)record + keyseg->start;
  
  dlen = _mi_calc_blob_length(keyseg->bit_start, pos);
  memcpy(&dptr, pos + keyseg->bit_start, sizeof(char*));
  if (!dptr)
  {
    my_errno= HA_ERR_NULL_IN_SPATIAL;
    return 0;
  }
  sp_mbr_from_wkb(dptr + 4, dlen - 4, SPDIMS, mbr);	/* SRID */
  
  for (i = 0, keyseg = keyinfo->seg; keyseg->type; keyseg++, i++)
  {
    uint length = keyseg->length, start= keyseg->start;
    double val;

    DBUG_ASSERT(length == sizeof(double));
    DBUG_ASSERT(!(start % sizeof(double)));
    DBUG_ASSERT(start < sizeof(mbr));
    DBUG_ASSERT(keyseg->type == HA_KEYTYPE_DOUBLE);
    
    val= mbr[start / sizeof (double)];
#ifdef HAVE_ISNAN
    if (isnan(val))
    {
      bzero(key, length);
      key+= length;
      len+= length;
      continue;
    }
#endif

    if (keyseg->flag & HA_SWAP_KEY)
    {
      uchar buf[sizeof(double)];

      float8store(buf, val);
      pos= &buf[length];
      while (pos > buf)
        *key++ = *--pos;
    }
    else
    {
      float8store((uchar *)key, val);
      key += length;
    }
    len+= length;
  }
  _mi_dpointer(info, key, filepos);
  return len;
}
Exemplo n.º 23
0
/* ===========================================================================
  Opens a gzip (.gz) file for reading or writing. The mode parameter
  is as in fopen ("rb" or "wb"). The file is given either by file descriptor
  or path name (if fd == -1).
  az_open returns NULL if the file could not be opened or if there was
  insufficient memory to allocate the (de)compression state; errno
  can be checked to distinguish the two cases (if errno is zero, the
  zlib error is Z_MEM_ERROR).
*/
int az_open (azio_stream *s, const char *path, int Flags, File fd)
{
  int err;
  int level = Z_DEFAULT_COMPRESSION; /* compression level */
  int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */

  memset(s, 0, sizeof(azio_stream));
  s->stream.next_in = s->inbuf;
  s->stream.next_out = s->outbuf;
  DBUG_ASSERT(s->z_err == Z_OK);
  s->back = EOF;
  s->crc = crc32(0L, Z_NULL, 0);
  s->mode = 'r';
  /* this needs to be a define to version */
  s->version = (unsigned char)az_magic[1];
  s->minor_version= (unsigned char) az_magic[2]; /* minor version */
  DBUG_ASSERT(s->dirty == AZ_STATE_CLEAN);

  /*
    We do our own version of append by nature.
    We must always have write access to take card of the header.
  */
  DBUG_ASSERT(Flags | O_APPEND);
  DBUG_ASSERT(Flags | O_WRONLY);

  if (Flags & O_RDWR) 
    s->mode = 'w';

  if (s->mode == 'w') 
  {
    err = deflateInit2(&(s->stream), level,
                       Z_DEFLATED, -MAX_WBITS, 8, strategy);
    /* windowBits is passed < 0 to suppress zlib header */

    s->stream.next_out = s->outbuf;
    if (err != Z_OK)
    {
      destroy(s);
      return Z_NULL;
    }
  } else {
    s->stream.next_in  = s->inbuf;

    err = inflateInit2(&(s->stream), -MAX_WBITS);
    /* windowBits is passed < 0 to tell that there is no zlib header.
     * Note that in this case inflate *requires* an extra "dummy" byte
     * after the compressed stream in order to complete decompression and
     * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
     * present after the compressed stream.
   */
    if (err != Z_OK)
    {
      destroy(s);
      return Z_NULL;
    }
  }
  s->stream.avail_out = AZ_BUFSIZE_WRITE;

  errno = 0;
  s->file = fd < 0 ? mysql_file_open(arch_key_file_data, path, Flags, MYF(0)) : fd;
  DBUG_EXECUTE_IF("simulate_archive_open_failure",
  {
    if (s->file >= 0)
    {
      my_close(s->file, MYF(0));
      s->file= -1;
      my_errno= EMFILE;
    }
  });
Exemplo n.º 24
0
static char *process_args(const CHARSET_INFO *cs, char *to, char *end,
                          const char* fmt, size_t arg_index, va_list ap)
{
  ARGS_INFO args_arr[MAX_ARGS];
  PRINT_INFO print_arr[MAX_PRINT_INFO];
  uint idx= 0, arg_count= arg_index;

start:
  /* Here we are at the beginning of positional argument, right after $ */
  arg_index--;
  print_arr[idx].flags= 0;
  if (*fmt == '`')
  {
    print_arr[idx].flags|= ESCAPED_ARG;
    fmt++;
  }
  if (*fmt == '-')
    fmt++;
  print_arr[idx].length= print_arr[idx].width= 0;
  /* Get print length */
  if (*fmt == '*')
  {          
    fmt++;
    fmt= get_length(fmt, &print_arr[idx].length, &print_arr[idx].flags);
    print_arr[idx].length--;    
    DBUG_ASSERT(*fmt == '$' && print_arr[idx].length < MAX_ARGS);
    args_arr[print_arr[idx].length].arg_type= 'd';
    args_arr[print_arr[idx].length].have_longlong= 0;
    print_arr[idx].flags|= LENGTH_ARG;
    arg_count= MY_MAX(arg_count, print_arr[idx].length + 1);
    fmt++;
  }
  else
    fmt= get_length(fmt, &print_arr[idx].length, &print_arr[idx].flags);
  
  if (*fmt == '.')
  {
    fmt++;
    /* Get print width */
    if (*fmt == '*')
    {
      fmt++;
      fmt= get_width(fmt, &print_arr[idx].width);
      print_arr[idx].width--;
      DBUG_ASSERT(*fmt == '$' && print_arr[idx].width < MAX_ARGS);
      args_arr[print_arr[idx].width].arg_type= 'd';
      args_arr[print_arr[idx].width].have_longlong= 0;
      print_arr[idx].flags|= WIDTH_ARG;
      arg_count= MY_MAX(arg_count, print_arr[idx].width + 1);
      fmt++;
    }
    else
      fmt= get_width(fmt, &print_arr[idx].width);
  }
  else
    print_arr[idx].width= SIZE_T_MAX;

  fmt= check_longlong(fmt, &args_arr[arg_index].have_longlong);
  if (*fmt == 'p')
    args_arr[arg_index].have_longlong= (sizeof(void *) == sizeof(longlong));
  args_arr[arg_index].arg_type= print_arr[idx].arg_type= *fmt;
  
  print_arr[idx].arg_idx= arg_index;
  print_arr[idx].begin= ++fmt;

  while (*fmt && *fmt != '%')
    fmt++;

  if (!*fmt)                                  /* End of format string */
  {
    uint i;
    print_arr[idx].end= fmt;
    /* Obtain parameters from the list */
    for (i= 0 ; i < arg_count; i++)
    {
      switch (args_arr[i].arg_type) {
      case 's':
      case 'b':
        args_arr[i].str_arg= va_arg(ap, char *);
        break;
      case 'f':
      case 'g':
        args_arr[i].double_arg= va_arg(ap, double);
        break;
      case 'd':
      case 'i':
      case 'u':
      case 'x':
      case 'X':
      case 'o':
      case 'p':
        if (args_arr[i].have_longlong)
          args_arr[i].longlong_arg= va_arg(ap,longlong);
        else if (args_arr[i].arg_type == 'd' || args_arr[i].arg_type == 'i')
          args_arr[i].longlong_arg= va_arg(ap, int);
        else
          args_arr[i].longlong_arg= va_arg(ap, uint);
        break;
      case 'c':
        args_arr[i].longlong_arg= va_arg(ap, int);
        break;
      default:
        DBUG_ASSERT(0);
      }
    }
Exemplo n.º 25
0
void
LocalDictCache::drop(const char * name){
  Ndb_local_table_info *info= m_tableHash.deleteKey(name, strlen(name));
  DBUG_ASSERT(info != 0);
  Ndb_local_table_info::destroy(info);
}
Exemplo n.º 26
0
void add_compiled_collation(CHARSET_INFO *cs)
{
  DBUG_ASSERT(cs->number < array_elements(all_charsets));
  all_charsets[cs->number]= cs;
  cs->state|= MY_CS_AVAILABLE;
}
Exemplo n.º 27
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 */
}
Exemplo n.º 28
0
int maria_extra(MARIA_HA *info, enum ha_extra_function function,
                void *extra_arg)
{
  int error= 0;
  ulong cache_size;
  MARIA_SHARE *share= info->s;
  my_bool block_records= share->data_file_type == BLOCK_RECORD;
  DBUG_ENTER("maria_extra");
  DBUG_PRINT("enter",("function: %d",(int) function));

  switch (function) {
  case HA_EXTRA_RESET_STATE:		/* Reset state (don't free buffers) */
    info->lastinx= ~0;			/* Detect index changes */
    info->last_search_keypage= info->cur_row.lastpos= HA_OFFSET_ERROR;
    info->page_changed= 1;
					/* Next/prev gives first/last */
    if (info->opt_flag & READ_CACHE_USED)
    {
      reinit_io_cache(&info->rec_cache,READ_CACHE,0,
		      (pbool) (info->lock_type != F_UNLCK),
                      (pbool) MY_TEST(info->update & HA_STATE_ROW_CHANGED)
		      );
    }
    info->update= ((info->update & HA_STATE_CHANGED) | HA_STATE_NEXT_FOUND |
		   HA_STATE_PREV_FOUND);
    break;
  case HA_EXTRA_CACHE:
    if (block_records)
      break;                                    /* Not supported */

    if (info->lock_type == F_UNLCK &&
	(share->options & HA_OPTION_PACK_RECORD))
    {
      error= 1;			/* Not possibly if not locked */
      my_errno= EACCES;
      break;
    }
    if (info->s->file_map) /* Don't use cache if mmap */
      break;
#if defined(HAVE_MMAP) && defined(HAVE_MADVISE)
    if ((share->options & HA_OPTION_COMPRESS_RECORD))
    {
      mysql_mutex_lock(&share->intern_lock);
      if (_ma_memmap_file(info))
      {
	/* We don't nead MADV_SEQUENTIAL if small file */
	madvise((char*) share->file_map, share->state.state.data_file_length,
		share->state.state.data_file_length <= RECORD_CACHE_SIZE*16 ?
		MADV_RANDOM : MADV_SEQUENTIAL);
	mysql_mutex_unlock(&share->intern_lock);
	break;
      }
      mysql_mutex_unlock(&share->intern_lock);
    }
#endif
    if (info->opt_flag & WRITE_CACHE_USED)
    {
      info->opt_flag&= ~WRITE_CACHE_USED;
      if ((error= end_io_cache(&info->rec_cache)))
	break;
    }
    if (!(info->opt_flag &
	  (READ_CACHE_USED | WRITE_CACHE_USED | MEMMAP_USED)))
    {
      cache_size= (extra_arg ? *(ulong*) extra_arg :
		   my_default_record_cache_size);
      if (!(init_io_cache(&info->rec_cache, info->dfile.file,
			 (uint) MY_MIN(share->state.state.data_file_length+1,
				    cache_size),
			  READ_CACHE,0L,(pbool) (info->lock_type != F_UNLCK),
			  MYF(share->write_flag & MY_WAIT_IF_FULL))))
      {
	info->opt_flag|= READ_CACHE_USED;
	info->update&=   ~HA_STATE_ROW_CHANGED;
      }
      if (share->non_transactional_concurrent_insert)
	info->rec_cache.end_of_file= info->state->data_file_length;
    }
    break;
  case HA_EXTRA_REINIT_CACHE:
    if (info->opt_flag & READ_CACHE_USED)
    {
      reinit_io_cache(&info->rec_cache, READ_CACHE, info->cur_row.nextpos,
		      (pbool) (info->lock_type != F_UNLCK),
                      (pbool) MY_TEST(info->update & HA_STATE_ROW_CHANGED));
      info->update&= ~HA_STATE_ROW_CHANGED;
      if (share->non_transactional_concurrent_insert)
	info->rec_cache.end_of_file= info->state->data_file_length;
    }
    break;
  case HA_EXTRA_WRITE_CACHE:
    if (info->lock_type == F_UNLCK)
    {
      error= 1;                        	/* Not possibly if not locked */
      break;
    }
    if (block_records)
      break;                            /* Not supported */

    cache_size= (extra_arg ? *(ulong*) extra_arg :
		 my_default_record_cache_size);
    if (!(info->opt_flag &
	  (READ_CACHE_USED | WRITE_CACHE_USED | OPT_NO_ROWS)) &&
	!share->state.header.uniques)
      if (!(init_io_cache(&info->rec_cache, info->dfile.file, cache_size,
                          WRITE_CACHE, info->state->data_file_length,
			  (pbool) (info->lock_type != F_UNLCK),
			  MYF(share->write_flag & MY_WAIT_IF_FULL))))
      {
	info->opt_flag|= WRITE_CACHE_USED;
	info->update&=   ~(HA_STATE_ROW_CHANGED |
                           HA_STATE_WRITE_AT_END |
                           HA_STATE_EXTEND_BLOCK);
      }
    break;
  case HA_EXTRA_PREPARE_FOR_UPDATE:
    if (info->s->data_file_type != DYNAMIC_RECORD)
      break;
    /* Remove read/write cache if dynamic rows */
  case HA_EXTRA_NO_CACHE:
    if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
    {
      info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
      error= end_io_cache(&info->rec_cache);
      /* Sergei will insert full text index caching here */
    }
#if defined(HAVE_MMAP) && defined(HAVE_MADVISE)
    if (info->opt_flag & MEMMAP_USED)
      madvise((char*) share->file_map, share->state.state.data_file_length,
              MADV_RANDOM);
#endif
    break;
  case HA_EXTRA_FLUSH_CACHE:
    if (info->opt_flag & WRITE_CACHE_USED)
    {
      if ((error= flush_io_cache(&info->rec_cache)))
      {
        /* Fatal error found */
        _ma_set_fatal_error(share, HA_ERR_CRASHED);
      }
    }
    break;
  case HA_EXTRA_NO_READCHECK:
    info->opt_flag&= ~READ_CHECK_USED;		/* No readcheck */
    break;
  case HA_EXTRA_READCHECK:
    info->opt_flag|= READ_CHECK_USED;
    break;
  case HA_EXTRA_KEYREAD:			/* Read only keys to record */
  case HA_EXTRA_REMEMBER_POS:
    info->opt_flag|= REMEMBER_OLD_POS;
    bmove(info->last_key.data + share->base.max_key_length*2,
	  info->last_key.data,
          info->last_key.data_length + info->last_key.ref_length);
    info->save_update=	info->update;
    info->save_lastinx= info->lastinx;
    info->save_lastpos= info->cur_row.lastpos;
    info->save_lastkey_data_length= info->last_key.data_length;
    info->save_lastkey_ref_length= info->last_key.ref_length;
    if (function == HA_EXTRA_REMEMBER_POS)
      break;
    /* fall through */
  case HA_EXTRA_KEYREAD_CHANGE_POS:
    info->opt_flag|= KEY_READ_USED;
    info->read_record= _ma_read_key_record;
    break;
  case HA_EXTRA_NO_KEYREAD:
  case HA_EXTRA_RESTORE_POS:
    if (info->opt_flag & REMEMBER_OLD_POS)
    {
      bmove(info->last_key.data,
	    info->last_key.data + share->base.max_key_length*2,
	    info->save_lastkey_data_length + info->save_lastkey_ref_length);
      info->update=	info->save_update | HA_STATE_WRITTEN;
      info->lastinx=	info->save_lastinx;
      info->cur_row.lastpos= info->save_lastpos;
      info->last_key.data_length= info->save_lastkey_data_length;
      info->last_key.ref_length= info->save_lastkey_ref_length;
      info->last_key.flag= 0;
    }
    info->read_record=	share->read_record;
    info->opt_flag&= ~(KEY_READ_USED | REMEMBER_OLD_POS);
    break;
  case HA_EXTRA_NO_USER_CHANGE: /* Database is somehow locked agains changes */
    info->lock_type= F_EXTRA_LCK; /* Simulate as locked */
    break;
  case HA_EXTRA_WAIT_LOCK:
    info->lock_wait= 0;
    break;
  case HA_EXTRA_NO_WAIT_LOCK:
    info->lock_wait= MY_SHORT_WAIT;
    break;
  case HA_EXTRA_NO_KEYS:
    /* we're going to modify pieces of the state, stall Checkpoint */
    mysql_mutex_lock(&share->intern_lock);
    if (info->lock_type == F_UNLCK)
    {
      mysql_mutex_unlock(&share->intern_lock);
      error= 1;					/* Not possibly if not lock */
      break;
    }
    if (maria_is_any_key_active(share->state.key_map))
    {
      MARIA_KEYDEF *key= share->keyinfo;
      uint i;
      for (i =0 ; i < share->base.keys ; i++,key++)
      {
        if (!(key->flag & HA_NOSAME) && info->s->base.auto_key != i+1)
        {
          maria_clear_key_active(share->state.key_map, i);
          info->update|= HA_STATE_CHANGED;
        }
      }

      if (!share->changed)
      {
	share->changed= 1;			/* Update on close */
	share->state.changed|= STATE_CHANGED | STATE_NOT_ANALYZED;
	if (!share->global_changed)
	{
	  share->global_changed= 1;
	  share->state.open_count++;
	}
      }
      if (!share->now_transactional)
        share->state.state= *info->state;
      /*
        That state write to disk must be done, even for transactional tables;
        indeed the table's share is going to be lost (there was a
        HA_EXTRA_FORCE_REOPEN before, which set share->last_version to
        0), and so the only way it leaves information (share->state.key_map)
        for the posterity is by writing it to disk.
      */
      DBUG_ASSERT(!maria_in_recovery);
      error= _ma_state_info_write(share,
                                  MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET |
                                  MA_STATE_INFO_WRITE_FULL_INFO);
    }
    mysql_mutex_unlock(&share->intern_lock);
    break;
  case HA_EXTRA_FORCE_REOPEN:
    /*
      MySQL uses this case after it has closed all other instances
      of this table.
      We however do a flush here for additional safety.
    */
    /** @todo consider porting these flush-es to MyISAM */
    DBUG_ASSERT(share->reopen == 1);
    error= _ma_flush_table_files(info, MARIA_FLUSH_DATA | MARIA_FLUSH_INDEX,
                                 FLUSH_FORCE_WRITE, FLUSH_FORCE_WRITE);
    if (!error && share->changed)
    {
      mysql_mutex_lock(&share->intern_lock);
      error= _ma_state_info_write(share,
                                  MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET|
                                  MA_STATE_INFO_WRITE_FULL_INFO);
      mysql_mutex_unlock(&share->intern_lock);
    }
    mysql_mutex_lock(&THR_LOCK_maria);
    mysql_mutex_lock(&share->intern_lock); /* protect against Checkpoint */
    /* Safety against assert in checkpoint */
    share->bitmap.changed_not_flushed= 0;
    /* this makes the share not be re-used next time the table is opened */
    share->last_version= 0L;			/* Impossible version */
    mysql_mutex_unlock(&share->intern_lock);
    mysql_mutex_unlock(&THR_LOCK_maria);
    break;
  case HA_EXTRA_PREPARE_FOR_DROP:
    /* Signals about intent to delete this table */
    share->deleting= TRUE;
    share->global_changed= FALSE;     /* force writing changed flag */
    /* To force repair if reopened */
    share->state.open_count= 1;
    share->changed= 1;
    _ma_mark_file_changed_now(share);
    /* Fall trough */
  case HA_EXTRA_PREPARE_FOR_RENAME:
  {
    my_bool do_flush= MY_TEST(function != HA_EXTRA_PREPARE_FOR_DROP);
    my_bool save_global_changed;
    enum flush_type type;
    /*
      This share, to have last_version=0, needs to save all its data/index
      blocks to disk if this is not for a DROP TABLE. Otherwise they would be
      invisible to future openers; and they could even go to disk late and
      cancel the work of future openers.
    */
    if (info->lock_type != F_UNLCK && !info->was_locked)
    {
      info->was_locked= info->lock_type;
      if (maria_lock_database(info, F_UNLCK))
        error= my_errno;
      info->lock_type= F_UNLCK;
    }
    /*
      We don't need to call _mi_decrement_open_count() if we are
      dropping the table, as the files will be removed anyway. If we
      are aborted before the files is removed, it's better to not
      call it as in that case the automatic repair on open will add
      the missing index entries
    */
    mysql_mutex_lock(&share->intern_lock);
    if (share->kfile.file >= 0 && function != HA_EXTRA_PREPARE_FOR_DROP)
      _ma_decrement_open_count(info, 0);
    if (info->trn)
    {
      _ma_remove_table_from_trnman(share, info->trn);
      /* Ensure we don't point to the deleted data in trn */
      info->state= info->state_start= &share->state.state;
    }
    /* Remove history for table */
    _ma_reset_state(info);

    type= do_flush ? FLUSH_RELEASE : FLUSH_IGNORE_CHANGED;
    save_global_changed= share->global_changed;
    share->global_changed= 1;                 /* Don't increment open count */
    mysql_mutex_unlock(&share->intern_lock);
    if (_ma_flush_table_files(info, MARIA_FLUSH_DATA | MARIA_FLUSH_INDEX,
                              type, type))
    {
      error=my_errno;
      share->changed= 1;
    }
    mysql_mutex_lock(&share->intern_lock);
    share->global_changed= save_global_changed;
    if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
    {
      info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
      if (end_io_cache(&info->rec_cache))
        error= 1;
    }
    if (share->kfile.file >= 0)
    {
      if (do_flush)
      {
        /* Save the state so that others can find it from disk. */
        if ((share->changed &&
             _ma_state_info_write(share,
                                  MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET |
                                  MA_STATE_INFO_WRITE_FULL_INFO)) ||
            mysql_file_sync(share->kfile.file, MYF(0)))
          error= my_errno;
      }
      else
      {
        /* be sure that state is not tried for write as file may be closed */
        share->changed= 0;
        share->global_changed= 0;
        share->state.open_count= 0;
      }
    }
    if (share->data_file_type == BLOCK_RECORD &&
        share->bitmap.file.file >= 0)
    {
      DBUG_ASSERT(share->bitmap.non_flushable == 0 &&
                  share->bitmap.changed == 0);
      if (do_flush && my_sync(share->bitmap.file.file, MYF(0)))
        error= my_errno;
      share->bitmap.changed_not_flushed= 0;
    }
    /* last_version must be protected by intern_lock; See collect_tables() */
    share->last_version= 0L;			/* Impossible version */
    mysql_mutex_unlock(&share->intern_lock);
    break;
  }
  case HA_EXTRA_PREPARE_FOR_FORCED_CLOSE:
    if (info->trn)
    {
      mysql_mutex_lock(&share->intern_lock);
      _ma_remove_table_from_trnman(share, info->trn);
      /* Ensure we don't point to the deleted data in trn */
      info->state= info->state_start= &share->state.state;
      mysql_mutex_unlock(&share->intern_lock);    
    }
    break;
  case HA_EXTRA_FLUSH:
    if (!share->temporary)
      error= _ma_flush_table_files(info, MARIA_FLUSH_DATA | MARIA_FLUSH_INDEX,
                                   FLUSH_KEEP, FLUSH_KEEP);

    _ma_decrement_open_count(info, 1);
    if (share->not_flushed)
    {
      share->not_flushed= 0;
      if (_ma_sync_table_files(info))
	error= my_errno;
      if (error)
      {
	/* Fatal error found */
	share->changed= 1;
        _ma_set_fatal_error(share, HA_ERR_CRASHED);
      }
    }
    break;
  case HA_EXTRA_NORMAL:				/* Theese isn't in use */
    info->quick_mode= 0;
    break;
  case HA_EXTRA_QUICK:
    info->quick_mode= 1;
    break;
  case HA_EXTRA_NO_ROWS:
    if (!share->state.header.uniques)
      info->opt_flag|= OPT_NO_ROWS;
    break;
  case HA_EXTRA_PRELOAD_BUFFER_SIZE:
    info->preload_buff_size= *((ulong *) extra_arg);
    break;
  case HA_EXTRA_CHANGE_KEY_TO_UNIQUE:
  case HA_EXTRA_CHANGE_KEY_TO_DUP:
    maria_extra_keyflag(info, function);
    break;
  case HA_EXTRA_MMAP:
#ifdef HAVE_MMAP
    if (block_records)
      break;                                    /* Not supported */
    mysql_mutex_lock(&share->intern_lock);
    /*
      Memory map the data file if it is not already mapped. It is safe
      to memory map a file while other threads are using file I/O on it.
      Assigning a new address to a function pointer is an atomic
      operation. intern_lock prevents that two or more mappings are done
      at the same time.
    */
    if (!share->file_map)
    {
      if (_ma_dynmap_file(info, share->state.state.data_file_length))
      {
        DBUG_PRINT("warning",("mmap failed: errno: %d",errno));
        error= my_errno= errno;
      }
      else
      {
        share->file_read=  _ma_mmap_pread;
        share->file_write= _ma_mmap_pwrite;
      }
    }
    mysql_mutex_unlock(&share->intern_lock);
#endif
    break;
  case HA_EXTRA_MARK_AS_LOG_TABLE:
    mysql_mutex_lock(&share->intern_lock);
    share->is_log_table= TRUE;
    mysql_mutex_unlock(&share->intern_lock);
    break;
  case HA_EXTRA_KEY_CACHE:
  case HA_EXTRA_NO_KEY_CACHE:
  default:
    break;
  }
  DBUG_RETURN(error);
} /* maria_extra */
Exemplo n.º 29
0
static void check_locks(THR_LOCK *lock, const char *where,
			my_bool allow_no_locks)
{
  uint old_found_errors=found_errors;
  DBUG_ENTER("check_locks");

  if (found_errors < MAX_FOUND_ERRORS)
  {
    if (check_lock(&lock->write,"write",where,1,1) |
	check_lock(&lock->write_wait,"write_wait",where,0,0) |
	check_lock(&lock->read,"read",where,0,1) |
	check_lock(&lock->read_wait,"read_wait",where,0,0))
      found_errors++;

    if (found_errors < MAX_FOUND_ERRORS)
    {
      uint count=0;
      THR_LOCK_DATA *data;
      for (data=lock->read.data ; data ; data=data->next)
      {
	if ((int) data->type == (int) TL_READ_NO_INSERT)
	  count++;
        /* Protect against infinite loop. */
        DBUG_ASSERT(count <= lock->read_no_write_count);
      }
      if (count != lock->read_no_write_count)
      {
	found_errors++;
	fprintf(stderr,
		"Warning at '%s': Locks read_no_write_count was %u when it should have been %u\n", where, lock->read_no_write_count,count);
      }      

      if (!lock->write.data)
      {
	if (!allow_no_locks && !lock->read.data &&
	    (lock->write_wait.data || lock->read_wait.data))
	{
	  found_errors++;
	  fprintf(stderr,
		  "Warning at '%s': No locks in use but locks are in wait queue\n",
		  where);
	}
	if (!lock->write_wait.data)
	{
	  if (!allow_no_locks && lock->read_wait.data)
	  {
	    found_errors++;
	    fprintf(stderr,
		    "Warning at '%s': No write locks and waiting read locks\n",
		    where);
	  }
	}
	else
	{
	  if (!allow_no_locks &&
	      (((lock->write_wait.data->type == TL_WRITE_CONCURRENT_INSERT ||
		 lock->write_wait.data->type == TL_WRITE_ALLOW_WRITE) &&
		!lock->read_no_write_count) ||
	       lock->write_wait.data->type == TL_WRITE_ALLOW_READ ||
	       (lock->write_wait.data->type == TL_WRITE_DELAYED &&
		!lock->read.data)))
	  {
	    found_errors++;
	    fprintf(stderr,
		    "Warning at '%s': Write lock %d waiting while no exclusive read locks\n",where,(int) lock->write_wait.data->type);
	  }
	}	      
      }
      else
      {						/* Have write lock */
	if (lock->write_wait.data)
	{
	  if (!allow_no_locks && 
	      lock->write.data->type == TL_WRITE_ALLOW_WRITE &&
	      lock->write_wait.data->type == TL_WRITE_ALLOW_WRITE)
	  {
	    found_errors++;
	    fprintf(stderr,
		    "Warning at '%s': Found WRITE_ALLOW_WRITE lock waiting for WRITE_ALLOW_WRITE lock\n",
		    where);
	  }
	}
	if (lock->read.data)
	{
          if (!thr_lock_owner_equal(lock->write.data->owner,
                                    lock->read.data->owner) &&
	      ((lock->write.data->type > TL_WRITE_DELAYED &&
		lock->write.data->type != TL_WRITE_ONLY) ||
	       ((lock->write.data->type == TL_WRITE_CONCURRENT_INSERT ||
		 lock->write.data->type == TL_WRITE_ALLOW_WRITE) &&
		lock->read_no_write_count)))
	  {
	    found_errors++;
	    fprintf(stderr,
		    "Warning at '%s': Found lock of type %d that is write and read locked\n",
		    where, lock->write.data->type);
	    DBUG_PRINT("warning",("At '%s': Found lock of type %d that is write and read locked\n",
		    where, lock->write.data->type));

	  }
	}
	if (lock->read_wait.data)
	{
	  if (!allow_no_locks && lock->write.data->type <= TL_WRITE_DELAYED &&
	      lock->read_wait.data->type <= TL_READ_HIGH_PRIORITY)
	  {
	    found_errors++;
	    fprintf(stderr,
		    "Warning at '%s': Found read lock of type %d waiting for write lock of type %d\n",
		    where,
		    (int) lock->read_wait.data->type,
		    (int) lock->write.data->type);
	  }
	}
      }
    }
    if (found_errors != old_found_errors)
    {
      DBUG_PRINT("error",("Found wrong lock"));
    }
  }
  DBUG_VOID_RETURN;
}
Exemplo n.º 30
0
int my_copy(const char *from, const char *to, myf MyFlags)
{
  size_t Count;
  my_bool new_file_stat= 0; /* 1 if we could stat "to" */
  int create_flag;
  File from_file,to_file;
  uchar buff[IO_SIZE];
  MY_STAT stat_buff,new_stat_buff;
  gid_t gid;
  DBUG_ENTER("my_copy");
  DBUG_PRINT("my",("from %s to %s MyFlags %d", from, to, MyFlags));

  from_file=to_file= -1;
  DBUG_ASSERT(!(MyFlags & (MY_FNABP | MY_NABP))); /* for my_read/my_write */
  if (MyFlags & MY_HOLD_ORIGINAL_MODES)		/* Copy stat if possible */
    new_file_stat= test(my_stat((char*) to, &new_stat_buff, MYF(0)));

  if ((from_file=my_open(from,O_RDONLY | O_SHARE,MyFlags)) >= 0)
  {
    if (!my_stat(from, &stat_buff, MyFlags))
    {
      my_errno=errno;
      goto err;
    }
    if (MyFlags & MY_HOLD_ORIGINAL_MODES && new_file_stat)
      stat_buff=new_stat_buff;
    create_flag= (MyFlags & MY_DONT_OVERWRITE_FILE) ? O_EXCL : O_TRUNC;

    if ((to_file=  my_create(to,(int) stat_buff.st_mode,
			     O_WRONLY | create_flag | O_BINARY | O_SHARE,
			     MyFlags)) < 0)
      goto err;

    while ((Count=my_read(from_file, buff, sizeof(buff), MyFlags)) != 0)
    {
	if (Count == (uint) -1 ||
	    my_write(to_file,buff,Count,MYF(MyFlags | MY_NABP)))
	goto err;
    }

    /* sync the destination file */
    if (MyFlags & MY_SYNC)
    {
      if (my_sync(to_file, MyFlags))
        goto err;
    }

    if (my_close(from_file,MyFlags) | my_close(to_file,MyFlags))
      DBUG_RETURN(-1);				/* Error on close */

    /* Copy modes if possible */

    if (MyFlags & MY_HOLD_ORIGINAL_MODES && !new_file_stat)
	DBUG_RETURN(0);			/* File copyed but not stat */

#if !defined(__WIN__) && !defined(__NETWARE__)
    /* Refresh the new_stat_buff */
    if (!my_stat((char*) to, &new_stat_buff, MYF(0)))
    {
      my_errno= errno;
      goto err;
    }

    /* Copy modes */
    if ((stat_buff.st_mode & 07777) != (new_stat_buff.st_mode & 07777) &&
        chmod(to, stat_buff.st_mode & 07777))
    {
      my_errno= errno;
      if (MyFlags & (MY_FAE+MY_WME))
        my_error(EE_CHANGE_PERMISSIONS, MYF(ME_BELL+ME_WAITTANG), from, errno);
      goto err;
    }

    /* Copy ownership */
    if (stat_buff.st_gid == new_stat_buff.st_gid)
      gid= -1;
    else
      gid= stat_buff.st_gid;
    if ((gid != (gid_t) -1 || stat_buff.st_uid != new_stat_buff.st_uid) &&
        chown(to, stat_buff.st_uid, gid))
    {
      my_errno= errno;
      if (MyFlags & (MY_FAE+MY_WME))
        my_error(EE_CHANGE_OWNERSHIP, MYF(ME_BELL+ME_WAITTANG), from, errno);
      goto err;
    }
#endif
#if !defined(VMS) && !defined(__ZTC__)
    if (MyFlags & MY_COPYTIME)
    {
      struct utimbuf timep;
      timep.actime  = stat_buff.st_atime;
      timep.modtime = stat_buff.st_mtime;
      VOID(utime((char*) to, &timep)); /* last accessed and modified times */
    }
#endif
    DBUG_RETURN(0);
  }

err:
  if (from_file >= 0) VOID(my_close(from_file,MyFlags));
  if (to_file >= 0)
  {
    VOID(my_close(to_file, MyFlags));
    /* attempt to delete the to-file we've partially written */
    VOID(my_delete(to, MyFlags));
  }
  DBUG_RETURN(-1);
} /* my_copy */