~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/identifier/table.cc

Reverted 1103

Show diffs side-by-side

added added

removed removed

Lines of Context:
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 <assert.h>
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
 
 
37
 
#include <algorithm>
38
 
#include <sstream>
39
 
#include <cstdio>
40
 
 
41
 
#include <boost/thread.hpp>
42
 
 
43
 
using namespace std;
44
 
 
45
 
namespace drizzled
46
 
{
47
 
 
48
 
class Table;
49
 
 
50
 
extern std::string drizzle_tmpdir;
51
 
extern pid_t current_pid;
52
 
 
53
 
namespace identifier {
54
 
class Schema;
55
 
 
56
 
static const char hexchars[]= "0123456789abcdef";
57
 
 
58
 
/*
59
 
  Translate a cursor name to a table name (WL #1324).
60
 
 
61
 
  SYNOPSIS
62
 
    filename_to_tablename()
63
 
      from                      The cursor name
64
 
      to                OUT     The table name
65
 
      to_length                 The size of the table name buffer.
66
 
 
67
 
  RETURN
68
 
    Table name length.
69
 
*/
70
 
uint32_t Table::filename_to_tablename(const char *from, char *to, uint32_t to_length)
71
 
{
72
 
  uint32_t length= 0;
73
 
 
74
 
  if (!memcmp(from, TMP_FILE_PREFIX, TMP_FILE_PREFIX_LENGTH))
75
 
  {
76
 
    /* Temporary table name. */
77
 
    length= strlen(strncpy(to, from, to_length));
78
 
  }
79
 
  else
80
 
  {
81
 
    for (; *from  && length < to_length; length++, from++)
82
 
    {
83
 
      if (*from != '@')
84
 
      {
85
 
        to[length]= *from;
86
 
        continue;
87
 
      }
88
 
      /* We've found an escaped char - skip the @ */
89
 
      from++;
90
 
      to[length]= 0;
91
 
      /* There will be a two-position hex-char version of the char */
92
 
      for (int x=1; x >= 0; x--)
93
 
      {
94
 
        if (*from >= '0' && *from <= '9')
95
 
          to[length] += ((*from++ - '0') << (4 * x));
96
 
        else if (*from >= 'a' && *from <= 'f')
97
 
          to[length] += ((*from++ - 'a' + 10) << (4 * x));
98
 
      }
99
 
      /* Backup because we advanced extra in the inner loop */
100
 
      from--;
101
 
    } 
102
 
  }
103
 
 
104
 
  return length;
105
 
}
106
 
 
107
 
/*
108
 
  Creates path to a cursor: drizzle_tmpdir/#sql1234_12_1.ext
109
 
 
110
 
  SYNOPSIS
111
 
   build_tmptable_filename()
112
 
     session                    The thread handle.
113
 
     buff                       Where to write result
114
 
     bufflen                    buff size
115
 
 
116
 
  NOTES
117
 
 
118
 
    Uses current_pid, thread_id, and tmp_table counter to create
119
 
    a cursor name in drizzle_tmpdir.
120
 
 
121
 
  RETURN
122
 
    path length on success, 0 on failure
123
 
*/
124
 
 
125
 
#ifdef _GLIBCXX_HAVE_TLS 
126
 
__thread uint32_t counter= 0;
127
 
 
128
 
static uint32_t get_counter()
129
 
{
130
 
  return ++counter;
131
 
}
132
 
 
133
 
#else
134
 
boost::mutex counter_mutex;
135
 
static uint32_t counter= 1;
136
 
 
137
 
static uint32_t get_counter()
138
 
{
139
 
  boost::mutex::scoped_lock lock(counter_mutex);
140
 
  uint32_t x;
141
 
  x= ++counter;
142
 
 
143
 
  return x;
144
 
}
145
 
 
146
 
#endif
147
 
 
148
 
size_t Table::build_tmptable_filename(std::string &buffer)
149
 
{
150
 
  size_t tmpdir_length;
151
 
  ostringstream post_tmpdir_str;
152
 
 
153
 
  buffer.append(drizzle_tmpdir);
154
 
  tmpdir_length= buffer.length();
155
 
 
156
 
  post_tmpdir_str << "/" << TMP_FILE_PREFIX << current_pid;
157
 
  post_tmpdir_str << pthread_self() << "-" << get_counter();
158
 
 
159
 
  buffer.append(post_tmpdir_str.str());
160
 
 
161
 
  transform(buffer.begin() + tmpdir_length, buffer.end(), buffer.begin() + tmpdir_length, ::tolower);
162
 
 
163
 
  return buffer.length();
164
 
}
165
 
 
166
 
size_t Table::build_tmptable_filename(std::vector<char> &buffer)
167
 
{
168
 
  ostringstream post_tmpdir_str;
169
 
 
170
 
  post_tmpdir_str << drizzle_tmpdir << "/" << TMP_FILE_PREFIX << current_pid;
171
 
  post_tmpdir_str << pthread_self() << "-" << get_counter();
172
 
 
173
 
  buffer.resize(post_tmpdir_str.str().length() + 1);
174
 
  memcpy(&buffer[0], post_tmpdir_str.str().c_str(), post_tmpdir_str.str().size());
175
 
  buffer[post_tmpdir_str.str().size()]= 0;
176
 
 
177
 
  return buffer.size();
178
 
}
179
 
 
180
 
 
181
 
/*
182
 
  Creates path to a cursor: drizzle_data_dir/db/table.ext
183
 
 
184
 
  SYNOPSIS
185
 
   build_table_filename()
186
 
     buff                       Where to write result
187
 
                                This may be the same as table_name.
188
 
     bufflen                    buff size
189
 
     db                         Database name
190
 
     table_name                 Table name
191
 
     ext                        File extension.
192
 
     flags                      table_name is temporary, do not change.
193
 
 
194
 
  NOTES
195
 
 
196
 
    Uses database and table name, and extension to create
197
 
    a cursor name in drizzle_data_dir. Database and table
198
 
    names are converted from system_charset_info into "fscs".
199
 
    Unless flags indicate a temporary table name.
200
 
    'db' is always converted.
201
 
    'ext' is not converted.
202
 
 
203
 
    The conversion suppression is required for ALTER Table. This
204
 
    statement creates intermediate tables. These are regular
205
 
    (non-temporary) tables with a temporary name. Their path names must
206
 
    be derivable from the table name. So we cannot use
207
 
    build_tmptable_filename() for them.
208
 
 
209
 
  RETURN
210
 
    path length on success, 0 on failure
211
 
*/
212
 
 
213
 
size_t Table::build_table_filename(std::string &in_path, const std::string &in_db, const std::string &in_table_name, bool is_tmp)
214
 
{
215
 
  bool conversion_error= false;
216
 
 
217
 
  conversion_error= util::tablename_to_filename(in_db, in_path);
218
 
  if (conversion_error)
219
 
  {
220
 
    errmsg_printf(error::ERROR,
221
 
                  _("Schema name cannot be encoded and fit within filesystem "
222
 
                    "name length restrictions."));
223
 
    return 0;
224
 
  }
225
 
 
226
 
  in_path.append(FN_ROOTDIR);
227
 
 
228
 
  if (is_tmp) // It a conversion tmp
229
 
  {
230
 
    in_path.append(in_table_name);
231
 
  }
232
 
  else
233
 
  {
234
 
    conversion_error= util::tablename_to_filename(in_table_name, in_path);
235
 
    if (conversion_error)
236
 
    {
237
 
      errmsg_printf(error::ERROR,
238
 
                    _("Table name cannot be encoded and fit within filesystem "
239
 
                      "name length restrictions."));
240
 
      return 0;
241
 
    }
242
 
  }
243
 
   
244
 
  return in_path.length();
245
 
}
246
 
 
247
 
Table::Table(const drizzled::Table &table) :
248
 
  identifier::Schema(table.getShare()->getSchemaName()),
249
 
  type(table.getShare()->getTableType()),
250
 
  table_name(table.getShare()->getTableName())
251
 
{
252
 
  if (type == message::Table::TEMPORARY)
253
 
    path= table.getShare()->getPath();
254
 
 
255
 
  init();
256
 
}
257
 
 
258
 
void Table::init()
259
 
{
260
 
  switch (type) {
261
 
  case message::Table::FUNCTION:
262
 
  case message::Table::STANDARD:
263
 
    assert(path.size() == 0);
264
 
    build_table_filename(path, getSchemaName(), table_name, false);
265
 
    break;
266
 
  case message::Table::INTERNAL:
267
 
    assert(path.size() == 0);
268
 
    build_table_filename(path, getSchemaName(), table_name, true);
269
 
    break;
270
 
  case message::Table::TEMPORARY:
271
 
    if (path.empty())
272
 
    {
273
 
      build_tmptable_filename(path);
274
 
    }
275
 
    break;
276
 
  }
277
 
 
278
 
  switch (type) {
279
 
  case message::Table::FUNCTION:
280
 
  case message::Table::STANDARD:
281
 
  case message::Table::INTERNAL:
282
 
    break;
283
 
  case message::Table::TEMPORARY:
284
 
    {
285
 
      size_t pos;
286
 
 
287
 
      pos= path.find("tmp/#sql");
288
 
      if (pos != std::string::npos) 
289
 
      {
290
 
        key_path= path.substr(pos);
291
 
      }
292
 
    }
293
 
    break;
294
 
  }
295
 
 
296
 
  util::insensitive_hash hasher;
297
 
  hash_value= hasher(path);
298
 
 
299
 
  std::string tb_name(getTableName());
300
 
  std::transform(tb_name.begin(), tb_name.end(), tb_name.begin(), ::tolower);
301
 
 
302
 
  key.set(getKeySize(), getSchemaName(), tb_name);
303
 
}
304
 
 
305
 
 
306
 
const std::string &Table::getPath() const
307
 
{
308
 
  return path;
309
 
}
310
 
 
311
 
const std::string &Table::getKeyPath() const
312
 
{
313
 
  if (key_path.empty())
314
 
    return path;
315
 
 
316
 
  return key_path;
317
 
}
318
 
 
319
 
void Table::getSQLPath(std::string &sql_path) const  // @todo this is just used for errors, we should find a way to optimize it
320
 
{
321
 
  switch (type) {
322
 
  case message::Table::FUNCTION:
323
 
  case message::Table::STANDARD:
324
 
    sql_path.append(getSchemaName());
325
 
    sql_path.append(".");
326
 
    sql_path.append(table_name);
327
 
    break;
328
 
  case message::Table::INTERNAL:
329
 
    sql_path.append("temporary.");
330
 
    sql_path.append(table_name);
331
 
    break;
332
 
  case message::Table::TEMPORARY:
333
 
    sql_path.append(getSchemaName());
334
 
    sql_path.append(".#");
335
 
    sql_path.append(table_name);
336
 
    break;
337
 
  }
338
 
}
339
 
 
340
 
bool Table::isValid() const
341
 
{
342
 
  if (not identifier::Schema::isValid())
343
 
    return false;
344
 
 
345
 
  bool error= false;
346
 
  do
347
 
  {
348
 
    if (table_name.empty())
349
 
    {
350
 
      error= true;
351
 
      break;
352
 
    }
353
 
 
354
 
    if (table_name.size() > NAME_LEN)
355
 
    {
356
 
      error= true;
357
 
      break;
358
 
    }
359
 
 
360
 
    if (table_name.at(table_name.length() -1) == ' ')
361
 
    {
362
 
      error= true;
363
 
      break;
364
 
    }
365
 
 
366
 
    if (table_name.at(0) == '.')
367
 
    {
368
 
      error= true;
369
 
      break;
370
 
    }
371
 
 
372
 
    {
373
 
      const CHARSET_INFO * const cs= &my_charset_utf8mb4_general_ci;
374
 
 
375
 
      int well_formed_error;
376
 
      uint32_t res= cs->cset->well_formed_len(cs, table_name.c_str(), table_name.c_str() + table_name.length(),
377
 
                                              NAME_CHAR_LEN, &well_formed_error);
378
 
      if (well_formed_error or table_name.length() != res)
379
 
      {
380
 
        error= true;
381
 
        break;
382
 
      }
383
 
    }
384
 
  } while (0);
385
 
 
386
 
  if (error)
387
 
  {
388
 
    std::string name;
389
 
 
390
 
    getSQLPath(name);
391
 
    my_error(ER_WRONG_TABLE_NAME, MYF(0), name.c_str());
392
 
 
393
 
    return false;
394
 
  }
395
 
 
396
 
  return true;
397
 
}
398
 
 
399
 
 
400
 
void Table::copyToTableMessage(message::Table &message) const
401
 
{
402
 
  message.set_name(table_name);
403
 
  message.set_schema(getSchemaName());
404
 
}
405
 
 
406
 
void Table::Key::set(size_t resize_arg, const std::string &a, const std::string &b)
407
 
{
408
 
  key_buffer.resize(resize_arg);
409
 
 
410
 
  std::copy(a.begin(), a.end(), key_buffer.begin());
411
 
  std::copy(b.begin(), b.end(), key_buffer.begin() + a.length() + 1);
412
 
 
413
 
  util::sensitive_hash hasher;
414
 
  hash_value= hasher(key_buffer);
415
 
}
416
 
 
417
 
std::size_t hash_value(Table const& b)
418
 
{
419
 
  return b.getHashValue();
420
 
}
421
 
 
422
 
std::size_t hash_value(Table::Key const& b)
423
 
{
424
 
  return b.getHashValue();
425
 
}
426
 
 
427
 
 
428
 
std::ostream& operator<<(std::ostream& output, Table::const_reference identifier)
429
 
{
430
 
  output << "Table:(";
431
 
  output <<  identifier.getSchemaName();
432
 
  output << ", ";
433
 
  output << identifier.getTableName();
434
 
  output << ", ";
435
 
  output << message::type(identifier.getType());
436
 
  output << ", ";
437
 
  output << identifier.getPath();
438
 
  output << ", ";
439
 
  output << identifier.getHashValue();
440
 
  output << ")";
441
 
 
442
 
  return output;  // for multiple << operators.
443
 
}
444
 
 
445
 
} /* namespace identifier */
446
 
} /* namespace drizzled */