~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/identifier/table.cc

  • Committer: Monty Taylor
  • Date: 2009-03-04 02:48:12 UTC
  • mto: (917.1.2 mordred)
  • mto: This revision was merged to the branch mainline in revision 918.
  • Revision ID: mordred@inaugust.com-20090304024812-5wb6wpye5c1iitbq
Applied atomic patch to current tree.

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