Drizzled Public API Documentation

table.cc
00001 /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
00002  *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
00003  *
00004  *  Copyright (C) 2009 Sun Microsystems, Inc.
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; either version 2 of the License, or
00009  *  (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00019  */
00020 
00021 #include <config.h>
00022 
00023 #include <assert.h>
00024 #include <boost/lexical_cast.hpp>
00025 #include <drizzled/identifier.h>
00026 #include <drizzled/internal/my_sys.h>
00027 
00028 #include <drizzled/error.h>
00029 #include <drizzled/errmsg_print.h>
00030 #include <drizzled/gettext.h>
00031 
00032 #include <drizzled/table.h>
00033 
00034 #include <drizzled/util/string.h>
00035 #include <drizzled/util/tablename_to_filename.h>
00036 
00037 #include <algorithm>
00038 #include <sstream>
00039 #include <cstdio>
00040 
00041 #include <boost/thread.hpp>
00042 
00043 using namespace std;
00044 
00045 namespace drizzled {
00046 
00047 extern std::string drizzle_tmpdir;
00048 extern pid_t current_pid;
00049 
00050 namespace identifier {
00051 
00052 static const char hexchars[]= "0123456789abcdef";
00053 
00054 /*
00055   Translate a cursor name to a table name (WL #1324).
00056 
00057   SYNOPSIS
00058     filename_to_tablename()
00059       from                      The cursor name
00060       to                OUT     The table name
00061       to_length                 The size of the table name buffer.
00062 
00063   RETURN
00064     Table name length.
00065 */
00066 uint32_t Table::filename_to_tablename(const char *from, char *to, uint32_t to_length)
00067 {
00068   uint32_t length= 0;
00069 
00070   if (!memcmp(from, TMP_FILE_PREFIX, TMP_FILE_PREFIX_LENGTH))
00071   {
00072     /* Temporary table name. */
00073     length= strlen(strncpy(to, from, to_length));
00074   }
00075   else
00076   {
00077     for (; *from  && length < to_length; length++, from++)
00078     {
00079       if (*from != '@')
00080       {
00081         to[length]= *from;
00082         continue;
00083       }
00084       /* We've found an escaped char - skip the @ */
00085       from++;
00086       to[length]= 0;
00087       /* There will be a two-position hex-char version of the char */
00088       for (int x=1; x >= 0; x--)
00089       {
00090         if (*from >= '0' && *from <= '9')
00091           to[length] += ((*from++ - '0') << (4 * x));
00092         else if (*from >= 'a' && *from <= 'f')
00093           to[length] += ((*from++ - 'a' + 10) << (4 * x));
00094       }
00095       /* Backup because we advanced extra in the inner loop */
00096       from--;
00097     } 
00098   }
00099 
00100   return length;
00101 }
00102 
00103 /*
00104   Creates path to a cursor: drizzle_tmpdir/#sql1234_12_1.ext
00105 
00106   SYNOPSIS
00107    build_tmptable_filename()
00108      session                    The thread handle.
00109      buff                       Where to write result
00110      bufflen                    buff size
00111 
00112   NOTES
00113 
00114     Uses current_pid, thread_id, and tmp_table counter to create
00115     a cursor name in drizzle_tmpdir.
00116 
00117   RETURN
00118     path length on success, 0 on failure
00119 */
00120 
00121 #ifdef _GLIBCXX_HAVE_TLS 
00122 __thread uint32_t counter= 0;
00123 
00124 static uint32_t get_counter()
00125 {
00126   return ++counter;
00127 }
00128 
00129 #else
00130 boost::mutex counter_mutex;
00131 static uint32_t counter= 1;
00132 
00133 static uint32_t get_counter()
00134 {
00135   boost::mutex::scoped_lock lock(counter_mutex);
00136   return ++counter;
00137 }
00138 
00139 #endif
00140 
00141 std::string Table::build_tmptable_filename()
00142 {
00143   ostringstream os;
00144   os << "/" << TMP_FILE_PREFIX << current_pid << pthread_self() << "-" << get_counter();
00145   return drizzle_tmpdir + boost::to_lower_copy(os.str());
00146 }
00147 
00148 /*
00149   Creates path to a cursor: drizzle_data_dir/db/table.ext
00150 
00151   SYNOPSIS
00152    build_table_filename()
00153      buff                       Where to write result
00154                                 This may be the same as table_name.
00155      bufflen                    buff size
00156      db                         Database name
00157      table_name                 Table name
00158      ext                        File extension.
00159      flags                      table_name is temporary, do not change.
00160 
00161   NOTES
00162 
00163     Uses database and table name, and extension to create
00164     a cursor name in drizzle_data_dir. Database and table
00165     names are converted from system_charset_info into "fscs".
00166     Unless flags indicate a temporary table name.
00167     'db' is always converted.
00168     'ext' is not converted.
00169 
00170     The conversion suppression is required for ALTER Table. This
00171     statement creates intermediate tables. These are regular
00172     (non-temporary) tables with a temporary name. Their path names must
00173     be derivable from the table name. So we cannot use
00174     build_tmptable_filename() for them.
00175 
00176   RETURN
00177     path length on success, 0 on failure
00178 */
00179 
00180 std::string Table::build_table_filename(const std::string &in_db, const std::string &in_table_name, bool is_tmp)
00181 {
00182   string in_path= util::tablename_to_filename(in_db) + FN_LIBCHAR;
00183   return in_path + (is_tmp ? in_table_name : util::tablename_to_filename(in_table_name));
00184 }
00185 
00186 Table::Table(const drizzled::Table &table) :
00187   identifier::Schema(str_ref(table.getShare()->getSchemaName())),
00188   type(table.getShare()->getTableType()),
00189   table_name(table.getShare()->getTableName())
00190 {
00191   if (type == message::Table::TEMPORARY)
00192     path= table.getShare()->getPath();
00193 
00194   init();
00195 }
00196 
00197 void Table::init()
00198 {
00199   switch (type) 
00200   {
00201   case message::Table::FUNCTION:
00202   case message::Table::STANDARD:
00203     assert(path.empty());
00204     path= build_table_filename(getSchemaName(), table_name, false);
00205     break;
00206   case message::Table::INTERNAL:
00207     assert(path.empty());
00208     path= build_table_filename(getSchemaName(), table_name, true);
00209     break;
00210   case message::Table::TEMPORARY:
00211     if (path.empty())
00212       path= build_tmptable_filename();
00213     break;
00214   }
00215 
00216   if (type == message::Table::TEMPORARY)
00217   {
00218     size_t pos= path.find("tmp/#sql");
00219     if (pos != std::string::npos) 
00220       key_path= path.substr(pos);
00221   }
00222 
00223   hash_value= util::insensitive_hash()(path);
00224   key.set(getKeySize(), getCatalogName(), getSchemaName(), boost::to_lower_copy(std::string(getTableName())));
00225 }
00226 
00227 
00228 const std::string &Table::getPath() const
00229 {
00230   return path;
00231 }
00232 
00233 const std::string &Table::getKeyPath() const
00234 {
00235   return key_path.empty() ? path : key_path;
00236 }
00237 
00238 std::string Table::getSQLPath() const  // @todo this is just used for errors, we should find a way to optimize it
00239 {
00240   switch (type) 
00241   {
00242   case message::Table::FUNCTION:
00243   case message::Table::STANDARD:
00244     return getSchemaName() + "." + table_name;
00245   case message::Table::INTERNAL:
00246     return "temporary." + table_name;
00247   case message::Table::TEMPORARY:
00248     return getSchemaName() + ".#" + table_name;
00249   }
00250   assert(false);
00251   return "<no table>";
00252 }
00253 
00254 bool Table::isValid() const
00255 {
00256   if (not identifier::Schema::isValid())
00257     return false;
00258 
00259   bool error= false;
00260   if (table_name.empty()
00261     || table_name.size() > NAME_LEN
00262     || table_name[table_name.length() - 1] == ' '
00263     || table_name[0] == '.')
00264   {
00265     error= true;
00266   }
00267   else
00268   {
00269     const charset_info_st& cs= my_charset_utf8mb4_general_ci;
00270     int well_formed_error;
00271     uint32_t res= cs.cset->well_formed_len(cs, table_name, NAME_CHAR_LEN, &well_formed_error);
00272     if (well_formed_error or table_name.length() != res)
00273       error= true;
00274   }
00275   if (not error)
00276     return true;
00277   my_error(ER_WRONG_TABLE_NAME, MYF(0), getSQLPath().c_str());
00278   return false;
00279 }
00280 
00281 void Table::copyToTableMessage(message::Table &message) const
00282 {
00283   message.set_name(table_name);
00284   message.set_schema(getSchemaName());
00285 }
00286 
00287   void Table::Key::set(size_t resize_arg, const std::string &a, const std::string &b, const std::string &c)
00288 {
00289   key_buffer.resize(resize_arg);
00290 
00291   std::copy(a.begin(), a.end(), key_buffer.begin());
00292   std::copy(b.begin(), b.end(), key_buffer.begin() + a.length() + 1);
00293   std::copy(c.begin(), c.end(),
00294             key_buffer.begin() + a.length() + 1 + b.length() + 1);
00295 
00296   util::sensitive_hash hasher;
00297   hash_value= hasher(key_buffer);
00298 }
00299 
00300 std::size_t hash_value(Table const& b)
00301 {
00302   return b.getHashValue();
00303 }
00304 
00305 std::size_t hash_value(Table::Key const& b)
00306 {
00307   return b.getHashValue();
00308 }
00309 
00310 std::ostream& operator<<(std::ostream& output, const Table& identifier)
00311 {
00312   return output << "Table:(" <<  identifier.getSchemaName() << ", " << identifier.getTableName() << ", " << message::type(identifier.getType()) << ", " << identifier.getPath() << ", " << identifier.getHashValue() << ")";
00313 }
00314 
00315 } /* namespace identifier */
00316 } /* namespace drizzled */