~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_db.cc

  • Committer: Brian Aker
  • Date: 2008-08-01 22:38:22 UTC
  • Revision ID: brian@tangent.org-20080801223822-0hh22boeev5xa8p5
Removed ALTER TABLE UPGRADE.

We have nothing to upgrade from :)

Show diffs side-by-side

added added

removed removed

Lines of Context:
78
78
 
79
79
 
80
80
/*
81
 
  Put a database lock entry into the hash.
82
 
  
83
 
  DESCRIPTION
84
 
    Insert a database lock entry into hash.
85
 
    LOCK_db_lock must be previously locked.
86
 
  
87
 
  RETURN VALUES
88
 
    0 on success.
89
 
    1 on error.
90
 
*/
91
 
 
92
 
static bool lock_db_insert(const char *dbname, uint length)
93
 
{
94
 
  my_dblock_t *opt;
95
 
  bool error= false;
96
 
  
97
 
  safe_mutex_assert_owner(&LOCK_lock_db);
98
 
 
99
 
  if (!(opt= (my_dblock_t*) hash_search(&lock_db_cache,
100
 
                                        (uchar*) dbname, length)))
101
 
  { 
102
 
    /* Db is not in the hash, insert it */
103
 
    char *tmp_name;
104
 
    if (!my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
105
 
                         &opt, (uint) sizeof(*opt), &tmp_name, (uint) length+1,
106
 
                         NullS))
107
 
    {
108
 
      error= true;
109
 
      goto end;
110
 
    }
111
 
    
112
 
    opt->name= tmp_name;
113
 
    strmov(opt->name, dbname);
114
 
    opt->name_length= length;
115
 
    
116
 
    if ((error= my_hash_insert(&lock_db_cache, (uchar*) opt)))
117
 
      my_free(opt, MYF(0));
118
 
  }
119
 
 
120
 
end:
121
 
  return(error);
122
 
}
123
 
 
124
 
 
125
 
/*
126
81
  Delete a database lock entry from hash.
127
82
*/
128
83
 
1494
1449
}
1495
1450
 
1496
1451
 
1497
 
static int
1498
 
lock_databases(THD *thd, const char *db1, uint length1,
1499
 
                         const char *db2, uint length2)
1500
 
{
1501
 
  pthread_mutex_lock(&LOCK_lock_db);
1502
 
  while (!thd->killed &&
1503
 
         (hash_search(&lock_db_cache,(uchar*) db1, length1) ||
1504
 
          hash_search(&lock_db_cache,(uchar*) db2, length2)))
1505
 
  {
1506
 
    wait_for_condition(thd, &LOCK_lock_db, &COND_refresh);
1507
 
    pthread_mutex_lock(&LOCK_lock_db);
1508
 
  }
1509
 
 
1510
 
  if (thd->killed)
1511
 
  {
1512
 
    pthread_mutex_unlock(&LOCK_lock_db);
1513
 
    return 1;
1514
 
  }
1515
 
 
1516
 
  lock_db_insert(db1, length1);
1517
 
  lock_db_insert(db2, length2);
1518
 
  creating_database++;
1519
 
 
1520
 
  /*
1521
 
    Wait if a concurent thread is creating a table at the same time.
1522
 
    The assumption here is that it will not take too long until
1523
 
    there is a point in time when a table is not created.
1524
 
  */
1525
 
 
1526
 
  while (!thd->killed && creating_table)
1527
 
  {
1528
 
    wait_for_condition(thd, &LOCK_lock_db, &COND_refresh);
1529
 
    pthread_mutex_lock(&LOCK_lock_db);
1530
 
  }
1531
 
 
1532
 
  if (thd->killed)
1533
 
  {
1534
 
    lock_db_delete(db1, length1);
1535
 
    lock_db_delete(db2, length2);
1536
 
    creating_database--;
1537
 
    pthread_mutex_unlock(&LOCK_lock_db);
1538
 
    pthread_cond_signal(&COND_refresh);
1539
 
    return(1);
1540
 
  }
1541
 
 
1542
 
  /*
1543
 
    We can unlock now as the hash will protect against anyone creating a table
1544
 
    in the databases we are using
1545
 
  */
1546
 
  pthread_mutex_unlock(&LOCK_lock_db);
1547
 
  return 0;
1548
 
}
1549
 
 
1550
 
 
1551
 
/**
1552
 
  Upgrade a 5.0 database.
1553
 
  This function is invoked whenever an ALTER DATABASE UPGRADE query is executed:
1554
 
    ALTER DATABASE 'olddb' UPGRADE DATA DIRECTORY NAME.
1555
 
 
1556
 
  If we have managed to rename (move) tables to the new database
1557
 
  but something failed on a later step, then we store the
1558
 
  RENAME DATABASE event in the log. mysql_rename_db() is atomic in
1559
 
  the sense that it will rename all or none of the tables.
1560
 
 
1561
 
  @param thd Current thread
1562
 
  @param old_db 5.0 database name, in #mysql50#name format
1563
 
  @return 0 on success, 1 on error
1564
 
*/
1565
 
bool mysql_upgrade_db(THD *thd, LEX_STRING *old_db)
1566
 
{
1567
 
  int error= 0, change_to_newdb= 0;
1568
 
  char path[FN_REFLEN+16];
1569
 
  uint length;
1570
 
  HA_CREATE_INFO create_info;
1571
 
  MY_DIR *dirp;
1572
 
  TABLE_LIST *table_list;
1573
 
  SELECT_LEX *sl= thd->lex->current_select;
1574
 
  LEX_STRING new_db;
1575
 
 
1576
 
  if ((old_db->length <= MYSQL50_TABLE_NAME_PREFIX_LENGTH) ||
1577
 
      (strncmp(old_db->str,
1578
 
              MYSQL50_TABLE_NAME_PREFIX,
1579
 
              MYSQL50_TABLE_NAME_PREFIX_LENGTH) != 0))
1580
 
  {
1581
 
    my_error(ER_WRONG_USAGE, MYF(0),
1582
 
             "ALTER DATABASE UPGRADE DATA DIRECTORY NAME",
1583
 
             "name");
1584
 
    return(1);
1585
 
  }
1586
 
 
1587
 
  /* `#mysql50#<name>` converted to encoded `<name>` */
1588
 
  new_db.str= old_db->str + MYSQL50_TABLE_NAME_PREFIX_LENGTH;
1589
 
  new_db.length= old_db->length - MYSQL50_TABLE_NAME_PREFIX_LENGTH;
1590
 
 
1591
 
  if (lock_databases(thd, old_db->str, old_db->length,
1592
 
                          new_db.str, new_db.length))
1593
 
    return(1);
1594
 
 
1595
 
  /*
1596
 
    Let's remember if we should do "USE newdb" afterwards.
1597
 
    thd->db will be cleared in mysql_rename_db()
1598
 
  */
1599
 
  if (thd->db && !strcmp(thd->db, old_db->str))
1600
 
    change_to_newdb= 1;
1601
 
 
1602
 
  build_table_filename(path, sizeof(path)-1,
1603
 
                       old_db->str, "", MY_DB_OPT_FILE, 0);
1604
 
  if ((load_db_opt(thd, path, &create_info)))
1605
 
    create_info.default_table_charset= thd->variables.collation_server;
1606
 
 
1607
 
  length= build_table_filename(path, sizeof(path)-1, old_db->str, "", "", 0);
1608
 
  if (length && path[length-1] == FN_LIBCHAR)
1609
 
    path[length-1]=0;                            // remove ending '\'
1610
 
  if ((error= my_access(path,F_OK)))
1611
 
  {
1612
 
    my_error(ER_BAD_DB_ERROR, MYF(0), old_db->str);
1613
 
    goto exit;
1614
 
  }
1615
 
 
1616
 
  /* Step1: Create the new database */
1617
 
  if ((error= mysql_create_db(thd, new_db.str, &create_info, 1)))
1618
 
    goto exit;
1619
 
 
1620
 
  /* Step2: Move tables to the new database */
1621
 
  if ((dirp = my_dir(path,MYF(MY_DONT_SORT))))
1622
 
  {
1623
 
    uint nfiles= (uint) dirp->number_off_files;
1624
 
    for (uint idx=0 ; idx < nfiles && !thd->killed ; idx++)
1625
 
    {
1626
 
      FILEINFO *file= dirp->dir_entry + idx;
1627
 
      char *extension, tname[FN_REFLEN];
1628
 
      LEX_STRING table_str;
1629
 
 
1630
 
      /* skiping non-FRM files */
1631
 
      if (my_strcasecmp(files_charset_info,
1632
 
                        (extension= fn_rext(file->name)), reg_ext))
1633
 
        continue;
1634
 
 
1635
 
      /* A frm file found, add the table info rename list */
1636
 
      *extension= '\0';
1637
 
 
1638
 
      table_str.length= filename_to_tablename(file->name,
1639
 
                                              tname, sizeof(tname)-1);
1640
 
      table_str.str= (char*) sql_memdup(tname, table_str.length + 1);
1641
 
      Table_ident *old_ident= new Table_ident(thd, *old_db, table_str, 0);
1642
 
      Table_ident *new_ident= new Table_ident(thd, new_db, table_str, 0);
1643
 
      if (!old_ident || !new_ident ||
1644
 
          !sl->add_table_to_list(thd, old_ident, NULL,
1645
 
                                 TL_OPTION_UPDATING, TL_IGNORE) ||
1646
 
          !sl->add_table_to_list(thd, new_ident, NULL,
1647
 
                                 TL_OPTION_UPDATING, TL_IGNORE))
1648
 
      {
1649
 
        error= true;
1650
 
        my_dirend(dirp);
1651
 
        goto exit;
1652
 
      }
1653
 
    }
1654
 
    my_dirend(dirp);  
1655
 
  }
1656
 
 
1657
 
  if ((table_list= thd->lex->query_tables) &&
1658
 
      (error= mysql_rename_tables(thd, table_list, 1)))
1659
 
  {
1660
 
    /*
1661
 
      Failed to move all tables from the old database to the new one.
1662
 
      In the best case mysql_rename_tables() moved all tables back to the old
1663
 
      database. In the worst case mysql_rename_tables() moved some tables
1664
 
      to the new database, then failed, then started to move the tables back,
1665
 
      and then failed again. In this situation we have some tables in the
1666
 
      old database and some tables in the new database.
1667
 
      Let's delete the option file, and then the new database directory.
1668
 
      If some tables were left in the new directory, rmdir() will fail.
1669
 
      It garantees we never loose any tables.
1670
 
    */
1671
 
    build_table_filename(path, sizeof(path)-1,
1672
 
                         new_db.str,"",MY_DB_OPT_FILE, 0);
1673
 
    my_delete(path, MYF(MY_WME));
1674
 
    length= build_table_filename(path, sizeof(path)-1, new_db.str, "", "", 0);
1675
 
    if (length && path[length-1] == FN_LIBCHAR)
1676
 
      path[length-1]=0;                            // remove ending '\'
1677
 
    rmdir(path);
1678
 
    goto exit;
1679
 
  }
1680
 
 
1681
 
 
1682
 
  if ((dirp = my_dir(path,MYF(MY_DONT_SORT))))
1683
 
  {
1684
 
    uint nfiles= (uint) dirp->number_off_files;
1685
 
    for (uint idx=0 ; idx < nfiles ; idx++)
1686
 
    {
1687
 
      FILEINFO *file= dirp->dir_entry + idx;
1688
 
      char oldname[FN_REFLEN], newname[FN_REFLEN];
1689
 
 
1690
 
      /* skiping . and .. and MY_DB_OPT_FILE */
1691
 
      if ((file->name[0] == '.' &&
1692
 
           (!file->name[1] || (file->name[1] == '.' && !file->name[2]))) ||
1693
 
          !my_strcasecmp(files_charset_info, file->name, MY_DB_OPT_FILE))
1694
 
        continue;
1695
 
 
1696
 
      /* pass empty file name, and file->name as extension to avoid encoding */
1697
 
      build_table_filename(oldname, sizeof(oldname)-1,
1698
 
                           old_db->str, "", file->name, 0);
1699
 
      build_table_filename(newname, sizeof(newname)-1,
1700
 
                           new_db.str, "", file->name, 0);
1701
 
      my_rename(oldname, newname, MYF(MY_WME));
1702
 
    }
1703
 
    my_dirend(dirp);
1704
 
  }
1705
 
 
1706
 
  /*
1707
 
    Step7: drop the old database.
1708
 
    remove_db_from_cache(olddb) and query_cache_invalidate(olddb)
1709
 
    are done inside mysql_rm_db(), no needs to execute them again.
1710
 
    mysql_rm_db() also "unuses" if we drop the current database.
1711
 
  */
1712
 
  error= mysql_rm_db(thd, old_db->str, 0, 1);
1713
 
 
1714
 
  /* Step8: logging */
1715
 
  if (mysql_bin_log.is_open())
1716
 
  {
1717
 
    Query_log_event qinfo(thd, thd->query, thd->query_length, 0, true);
1718
 
    thd->clear_error();
1719
 
    mysql_bin_log.write(&qinfo);
1720
 
  }
1721
 
 
1722
 
  /* Step9: Let's do "use newdb" if we renamed the current database */
1723
 
  if (change_to_newdb)
1724
 
    error|= mysql_change_db(thd, & new_db, false);
1725
 
 
1726
 
exit:
1727
 
  pthread_mutex_lock(&LOCK_lock_db);
1728
 
  /* Remove the databases from db lock cache */
1729
 
  lock_db_delete(old_db->str, old_db->length);
1730
 
  lock_db_delete(new_db.str, new_db.length);
1731
 
  creating_database--;
1732
 
  /* Signal waiting CREATE TABLE's to continue */
1733
 
  pthread_cond_signal(&COND_refresh);
1734
 
  pthread_mutex_unlock(&LOCK_lock_db);
1735
 
 
1736
 
  return(error);
1737
 
}
1738
 
 
1739
 
 
1740
 
 
1741
1452
/*
1742
1453
  Check if there is directory for the database name.
1743
1454