Drizzled Public API Documentation

table.cc
1 /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3  *
4  * Copyright (C) 2009 Sun Microsystems, Inc.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #include <config.h>
22 
23 #include <cassert>
24 #include <boost/lexical_cast.hpp>
25 #include <drizzled/identifier.h>
26 #include <drizzled/internal/my_sys.h>
27 
28 #include <drizzled/error.h>
29 #include <drizzled/errmsg_print.h>
30 #include <drizzled/gettext.h>
31 
32 #include <drizzled/table.h>
33 
34 #include <drizzled/util/string.h>
35 #include <drizzled/util/tablename_to_filename.h>
36 #include <drizzled/catalog/local.h>
37 
38 #include <algorithm>
39 #include <sstream>
40 #include <cstdio>
41 
42 #include <boost/thread.hpp>
43 
44 using namespace std;
45 
46 namespace drizzled {
47 
48 extern std::string drizzle_tmpdir;
49 extern pid_t current_pid;
50 
51 namespace identifier {
52 
53 static const char hexchars[]= "0123456789abcdef";
54 
55 /*
56  Translate a cursor name to a table name (WL #1324).
57 
58  SYNOPSIS
59  filename_to_tablename()
60  from The cursor name
61  to OUT The table name
62  to_length The size of the table name buffer.
63 
64  RETURN
65  Table name length.
66 */
67 uint32_t Table::filename_to_tablename(const char *from, char *to, uint32_t to_length)
68 {
69  uint32_t length= 0;
70 
71  if (!memcmp(from, TMP_FILE_PREFIX, TMP_FILE_PREFIX_LENGTH))
72  {
73  /* Temporary table name. */
74  length= strlen(strncpy(to, from, to_length));
75  }
76  else
77  {
78  for (; *from && length < to_length; length++, from++)
79  {
80  if (*from != '@')
81  {
82  to[length]= *from;
83  continue;
84  }
85  /* We've found an escaped char - skip the @ */
86  from++;
87  to[length]= 0;
88  /* There will be a two-position hex-char version of the char */
89  for (int x=1; x >= 0; x--)
90  {
91  if (*from >= '0' && *from <= '9')
92  {
93  to[length] += ((*from++ - '0') << (4 * x));
94  }
95  else if (*from >= 'a' && *from <= 'f')
96  {
97  to[length] += ((*from++ - 'a' + 10) << (4 * x));
98  }
99  }
100  /* Backup because we advanced extra in the inner loop */
101  from--;
102  }
103  }
104 
105  return length;
106 }
107 
108 /*
109  Creates path to a cursor: drizzle_tmpdir/#sql1234_12_1.ext
110 
111  SYNOPSIS
112  build_tmptable_filename()
113  session The thread handle.
114  buff Where to write result
115  bufflen buff size
116 
117  NOTES
118 
119  Uses current_pid, thread_id, and tmp_table counter to create
120  a cursor name in drizzle_tmpdir.
121 
122  RETURN
123  path length on success, 0 on failure
124 */
125 
126 #ifdef _GLIBCXX_HAVE_TLS
127 __thread uint32_t counter= 0;
128 
129 static uint32_t get_counter()
130 {
131  return ++counter;
132 }
133 
134 #else
135 boost::mutex counter_mutex;
136 static uint32_t counter= 1;
137 
138 static uint32_t get_counter()
139 {
140  boost::mutex::scoped_lock lock(counter_mutex);
141  return ++counter;
142 }
143 
144 #endif
145 
146 std::string Table::build_tmptable_filename()
147 {
148  ostringstream os;
149  os << "/" << TMP_FILE_PREFIX << current_pid << pthread_self() << "-" << get_counter();
150  return drizzle_tmpdir + boost::to_lower_copy(os.str());
151 }
152 
153 /*
154  Creates path to a cursor: drizzle_data_dir/db/table.ext
155 
156  SYNOPSIS
157  build_table_filename()
158  buff Where to write result
159  This may be the same as table_name.
160  bufflen buff size
161  db Database name
162  table_name Table name
163  ext File extension.
164  flags table_name is temporary, do not change.
165 
166  NOTES
167 
168  Uses database and table name, and extension to create
169  a cursor name in drizzle_data_dir. Database and table
170  names are converted from system_charset_info into "fscs".
171  Unless flags indicate a temporary table name.
172  'db' is always converted.
173  'ext' is not converted.
174 
175  The conversion suppression is required for ALTER Table. This
176  statement creates intermediate tables. These are regular
177  (non-temporary) tables with a temporary name. Their path names must
178  be derivable from the table name. So we cannot use
179  build_tmptable_filename() for them.
180 
181  RETURN
182  path length on success, 0 on failure
183 */
184 
185 std::string Table::build_table_filename(const identifier::Table &table_identifier, bool is_tmp)
186 {
187  string in_path= table_identifier.getCatalog().getPath();
188  in_path+= FN_LIBCHAR + util::tablename_to_filename(table_identifier.getSchemaName()) + FN_LIBCHAR;
189  return in_path + (is_tmp ? table_identifier.getTableName() : util::tablename_to_filename(table_identifier.getTableName()));
190 }
191 
192 Table::Table(const drizzled::Table &table) :
193  identifier::Schema(table.getShare()->getTableIdentifier().getCatalog(),
194  str_ref(table.getShare()->getSchemaName())),
195  type(table.getShare()->getTableType()),
196  table_name(table.getShare()->getTableName())
197 {
198  if (type == message::Table::TEMPORARY)
199  {
200  path= table.getShare()->getPath();
201  }
202 
203  init();
204 }
205 
206 Table::Table(const identifier::Schema &schema,
207  const std::string &table_name_arg,
208  Type tmp_arg) :
209  Schema(schema),
210  type(tmp_arg),
211  table_name(table_name_arg)
212 {
213  init();
214 }
215 
216 Table::Table(const drizzled::identifier::Catalog &catalog,
217  const std::string &db_arg,
218  const std::string &table_name_arg,
219  Type tmp_arg) :
220  Schema(catalog, db_arg),
221  type(tmp_arg),
222  table_name(table_name_arg)
223 {
224  init();
225 }
226 
227 Table::Table(const drizzled::identifier::Catalog &catalog,
228  const std::string &schema_name_arg,
229  const std::string &table_name_arg,
230  const std::string &path_arg ) :
231  Schema(catalog, schema_name_arg),
232  type(message::Table::TEMPORARY),
233  path(path_arg),
234  table_name(table_name_arg)
235 {
236  init();
237 }
238 
239 void Table::init()
240 {
241  switch (type)
242  {
243  case message::Table::FUNCTION:
244  case message::Table::STANDARD:
245  assert(path.empty());
246  path= build_table_filename(*this, false);
247  break;
248 
249  case message::Table::INTERNAL:
250  assert(path.empty());
251  path= build_table_filename(*this, true);
252  break;
253 
254  case message::Table::TEMPORARY:
255  if (path.empty())
256  {
257  path= build_tmptable_filename();
258  }
259  break;
260  }
261 
262  if (type == message::Table::TEMPORARY)
263  {
264  size_t pos= path.find("tmp/#sql");
265  if (pos != std::string::npos)
266  {
267  key_path= path.substr(pos);
268  }
269  }
270 
271  hash_value= util::insensitive_hash()(path);
272  key.set(getKeySize(), getCatalogName(), getCompareWithSchemaName(), boost::to_lower_copy(std::string(getTableName())));
273 }
274 
275 
276 const std::string &Table::getPath() const
277 {
278  return path;
279 }
280 
281 const std::string &Table::getKeyPath() const
282 {
283  return key_path.empty() ? path : key_path;
284 }
285 
286 std::string Table::getSQLPath() const // @todo this is just used for errors, we should find a way to optimize it
287 {
288  switch (type)
289  {
290  case message::Table::FUNCTION:
291  case message::Table::STANDARD:
292  return getSchemaName() + "." + table_name;
293 
294  case message::Table::INTERNAL:
295  return "temporary." + table_name;
296 
297  case message::Table::TEMPORARY:
298  return getSchemaName() + ".#" + table_name;
299  }
300  assert(false);
301  return "<no table>";
302 }
303 
304 bool Table::isValid() const
305 {
306  if (identifier::Schema::isValid() == false)
307  {
308  return false;
309  }
310 
311  bool error= false;
312  if (table_name.empty()
313  || table_name.size() > NAME_LEN
314  || table_name[table_name.length() - 1] == ' '
315  || table_name[0] == '.')
316  {
317  error= true;
318  }
319  else
320  {
321  const charset_info_st& cs= my_charset_utf8mb4_general_ci;
322  int well_formed_error;
323  uint32_t res= cs.cset->well_formed_len(cs, table_name, NAME_CHAR_LEN, &well_formed_error);
324  if (well_formed_error or table_name.length() != res)
325  {
326  error= true;
327  }
328  }
329 
330  if (error == false)
331  {
332  return true;
333  }
334  my_error(ER_WRONG_TABLE_NAME, MYF(0), getSQLPath().c_str());
335 
336  return false;
337 }
338 
339 void Table::copyToTableMessage(message::Table &message) const
340 {
341  message.set_name(table_name);
342  message.set_schema(getSchemaName());
343 }
344 
345 void Table::Key::set(size_t resize_arg, const std::string &catalog_arg, const std::string &schema_arg, const std::string &table_arg)
346 {
347  key_buffer.resize(resize_arg);
348 
349  schema_offset= catalog_arg.length() +1;
350  table_offset= schema_offset +schema_arg.length() +1;
351 
352  std::copy(catalog_arg.begin(), catalog_arg.end(), key_buffer.begin());
353  std::copy(schema_arg.begin(), schema_arg.end(), key_buffer.begin() +schema_offset);
354  std::copy(table_arg.begin(), table_arg.end(), key_buffer.begin() +table_offset);
355 
356  util::sensitive_hash hasher;
357  hash_value= hasher(key_buffer);
358 }
359 
360 std::size_t hash_value(Table const& b)
361 {
362  return b.getHashValue();
363 }
364 
365 std::size_t hash_value(Table::Key const& b)
366 {
367  return b.getHashValue();
368 }
369 
370 std::ostream& operator<<(std::ostream& output, const Table::Key& arg)
371 {
372  return output << "Key:(" << arg.schema_name() << ", " << arg.table_name() << ", " << arg.hash() << std::endl;
373 }
374 
375 std::ostream& operator<<(std::ostream& output, const Table& identifier)
376 {
377  return output << "Table:(" << identifier.getSchemaName() << ", " << identifier.getTableName() << ", " << message::type(identifier.getType()) << ", " << identifier.getPath() << ", " << identifier.getHashValue() << ")";
378 }
379 
380 } /* namespace identifier */
381 } /* namespace drizzled */
#define TMP_FILE_PREFIX
Definition: definitions.h:210
TODO: Rename this file - func.h is stupid.
Definition: schema.h:30