~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/identifier/table.cc

  • Committer: Monty Taylor
  • Date: 2010-08-03 18:21:58 UTC
  • mto: (1680.2.6 build)
  • mto: This revision was merged to the branch mainline in revision 1683.
  • Revision ID: mordred@inaugust.com-20100803182158-nkmgnlohodud4290
Made existence of intltool and gettext optional.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
3
 *
4
 
 *  Copyright (C) 2009 Sun Microsystems, Inc.
 
4
 *  Copyright (C) 2009 Sun Microsystems
5
5
 *
6
6
 *  This program is free software; you can redistribute it and/or modify
7
7
 *  it under the terms of the GNU General Public License as published by
18
18
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19
19
 */
20
20
 
21
 
#include <config.h>
 
21
#include "config.h"
22
22
 
23
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>
 
24
 
 
25
#include "drizzled/identifier.h"
 
26
#include "drizzled/session.h"
 
27
#include "drizzled/internal/my_sys.h"
 
28
#include "drizzled/data_home.h"
 
29
 
 
30
#include "drizzled/table.h"
 
31
 
 
32
#include "drizzled/util/string.h"
36
33
 
37
34
#include <algorithm>
38
35
#include <sstream>
45
42
namespace drizzled
46
43
{
47
44
 
48
 
class Table;
49
 
 
50
45
extern std::string drizzle_tmpdir;
51
46
extern pid_t current_pid;
52
47
 
53
 
namespace identifier {
54
 
class Schema;
55
 
 
56
48
static const char hexchars[]= "0123456789abcdef";
57
49
 
 
50
static bool tablename_to_filename(const char *from, char *to, size_t to_length);
 
51
 
58
52
/*
59
53
  Translate a cursor name to a table name (WL #1324).
60
54
 
67
61
  RETURN
68
62
    Table name length.
69
63
*/
70
 
uint32_t Table::filename_to_tablename(const char *from, char *to, uint32_t to_length)
 
64
uint32_t TableIdentifier::filename_to_tablename(const char *from, char *to, uint32_t to_length)
71
65
{
72
66
  uint32_t length= 0;
73
67
 
145
139
 
146
140
#endif
147
141
 
148
 
size_t Table::build_tmptable_filename(std::string &buffer)
 
142
size_t TableIdentifier::build_tmptable_filename(std::string &buffer)
149
143
{
150
144
  size_t tmpdir_length;
151
145
  ostringstream post_tmpdir_str;
163
157
  return buffer.length();
164
158
}
165
159
 
166
 
size_t Table::build_tmptable_filename(std::vector<char> &buffer)
 
160
size_t TableIdentifier::build_tmptable_filename(std::vector<char> &buffer)
167
161
{
168
162
  ostringstream post_tmpdir_str;
169
163
 
210
204
    path length on success, 0 on failure
211
205
*/
212
206
 
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)
 
207
size_t TableIdentifier::build_table_filename(std::string &path, const char *db, const char *table_name, bool is_tmp)
214
208
{
 
209
  char dbbuff[FN_REFLEN];
 
210
  char tbbuff[FN_REFLEN];
215
211
  bool conversion_error= false;
216
212
 
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
 
 
 
213
  memset(tbbuff, 0, sizeof(tbbuff));
228
214
  if (is_tmp) // It a conversion tmp
229
215
  {
230
 
    in_path.append(in_table_name);
 
216
    strncpy(tbbuff, table_name, sizeof(tbbuff));
231
217
  }
232
218
  else
233
219
  {
234
 
    conversion_error= util::tablename_to_filename(in_table_name, in_path);
 
220
    conversion_error= tablename_to_filename(table_name, tbbuff, sizeof(tbbuff));
235
221
    if (conversion_error)
236
222
    {
237
 
      errmsg_printf(error::ERROR,
 
223
      errmsg_printf(ERRMSG_LVL_ERROR,
238
224
                    _("Table name cannot be encoded and fit within filesystem "
239
225
                      "name length restrictions."));
240
226
      return 0;
241
227
    }
242
228
  }
243
 
   
244
 
  return in_path.length();
245
 
}
246
 
 
247
 
Table::Table(const drizzled::Table &table) :
248
 
  identifier::Schema(table.getShare()->getSchemaName()),
 
229
  memset(dbbuff, 0, sizeof(dbbuff));
 
230
  conversion_error= tablename_to_filename(db, dbbuff, sizeof(dbbuff));
 
231
  if (conversion_error)
 
232
  {
 
233
    errmsg_printf(ERRMSG_LVL_ERROR,
 
234
                  _("Schema name cannot be encoded and fit within filesystem "
 
235
                    "name length restrictions."));
 
236
    return 0;
 
237
  }
 
238
   
 
239
 
 
240
  int rootdir_len= strlen(FN_ROOTDIR);
 
241
  path.append(data_home);
 
242
  ssize_t without_rootdir= path.length() - rootdir_len;
 
243
 
 
244
  /* Don't add FN_ROOTDIR if dirzzle_data_home already includes it */
 
245
  if (without_rootdir >= 0)
 
246
  {
 
247
    const char *tmp= path.c_str() + without_rootdir;
 
248
 
 
249
    if (memcmp(tmp, FN_ROOTDIR, rootdir_len) != 0)
 
250
      path.append(FN_ROOTDIR);
 
251
  }
 
252
 
 
253
  path.append(dbbuff);
 
254
  path.append(FN_ROOTDIR);
 
255
  path.append(tbbuff);
 
256
 
 
257
  return path.length();
 
258
}
 
259
 
 
260
 
 
261
/*
 
262
  Translate a table name to a cursor name (WL #1324).
 
263
 
 
264
  SYNOPSIS
 
265
    tablename_to_filename()
 
266
      from                      The table name
 
267
      to                OUT     The cursor name
 
268
      to_length                 The size of the cursor name buffer.
 
269
 
 
270
  RETURN
 
271
    true if errors happen. false on success.
 
272
*/
 
273
static bool tablename_to_filename(const char *from, char *to, size_t to_length)
 
274
{
 
275
  
 
276
  size_t length= 0;
 
277
  for (; *from  && length < to_length; length++, from++)
 
278
  {
 
279
    if ((*from >= '0' && *from <= '9') ||
 
280
        (*from >= 'A' && *from <= 'Z') ||
 
281
        (*from >= 'a' && *from <= 'z') ||
 
282
/* OSX defines an extra set of high-bit and multi-byte characters
 
283
   that cannot be used on the filesystem. Instead of trying to sort
 
284
   those out, we'll just escape encode all high-bit-set chars on OSX.
 
285
   It won't really hurt anything - it'll just make some filenames ugly. */
 
286
#if !defined(TARGET_OS_OSX)
 
287
        ((unsigned char)*from >= 128) ||
 
288
#endif
 
289
        (*from == '_') ||
 
290
        (*from == ' ') ||
 
291
        (*from == '-'))
 
292
    {
 
293
      to[length]= tolower(*from);
 
294
      continue;
 
295
    }
 
296
   
 
297
    if (length + 3 >= to_length)
 
298
      return true;
 
299
 
 
300
    /* We need to escape this char in a way that can be reversed */
 
301
    to[length++]= '@';
 
302
    to[length++]= hexchars[(*from >> 4) & 15];
 
303
    to[length]= hexchars[(*from) & 15];
 
304
  }
 
305
 
 
306
  if (internal::check_if_legal_tablename(to) &&
 
307
      length + 4 < to_length)
 
308
  {
 
309
    memcpy(to + length, "@@@", 4);
 
310
    length+= 3;
 
311
  }
 
312
  return false;
 
313
}
 
314
 
 
315
TableIdentifier::TableIdentifier(const drizzled::Table &table) :
 
316
  SchemaIdentifier(table.getShare()->getSchemaName()),
249
317
  type(table.getShare()->getTableType()),
250
318
  table_name(table.getShare()->getTableName())
251
319
{
255
323
  init();
256
324
}
257
325
 
258
 
void Table::init()
 
326
void TableIdentifier::init()
259
327
{
 
328
  std::string lower_table_name(table_name);
 
329
  std::transform(lower_table_name.begin(), lower_table_name.end(),
 
330
                 lower_table_name.begin(), ::tolower);
 
331
 
260
332
  switch (type) {
261
333
  case message::Table::FUNCTION:
262
334
  case message::Table::STANDARD:
263
335
    assert(path.size() == 0);
264
 
    build_table_filename(path, getSchemaName(), table_name, false);
 
336
    build_table_filename(path, getLower().c_str(), lower_table_name.c_str(), false);
265
337
    break;
266
338
  case message::Table::INTERNAL:
267
339
    assert(path.size() == 0);
268
 
    build_table_filename(path, getSchemaName(), table_name, true);
 
340
    build_table_filename(path, getLower().c_str(), lower_table_name.c_str(), true);
269
341
    break;
270
342
  case message::Table::TEMPORARY:
271
343
    if (path.empty())
275
347
    break;
276
348
  }
277
349
 
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
350
  util::insensitive_hash hasher;
297
351
  hash_value= hasher(path);
298
352
 
299
 
  std::string tb_name(getTableName());
300
 
  std::transform(tb_name.begin(), tb_name.end(), tb_name.begin(), ::tolower);
 
353
  key.resize(getKeySize());
 
354
  size_t key_length= TableIdentifier::createKey(&key[0], *this);
301
355
 
302
 
  key.set(getKeySize(), getSchemaName(), tb_name);
 
356
  assert(key_length == getKeySize()); // If this is off, then we have a memory issue.
303
357
}
304
358
 
305
359
 
306
 
const std::string &Table::getPath() const
 
360
const std::string &TableIdentifier::getPath() const
307
361
{
308
362
  return path;
309
363
}
310
364
 
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
 
365
const std::string &TableIdentifier::getSQLPath()
 
366
{
 
367
  if (sql_path.empty())
 
368
  {
 
369
    switch (type) {
 
370
    case message::Table::FUNCTION:
 
371
    case message::Table::STANDARD:
 
372
      sql_path.append(getLower());
 
373
      sql_path.append(".");
 
374
      sql_path.append(table_name);
 
375
      break;
 
376
    case message::Table::INTERNAL:
 
377
      sql_path.append("temporary.");
 
378
      sql_path.append(table_name);
 
379
      break;
 
380
    case message::Table::TEMPORARY:
 
381
      sql_path.append(getLower());
 
382
      sql_path.append(".#");
 
383
      sql_path.append(table_name);
 
384
      break;
 
385
    }
 
386
  }
 
387
 
 
388
  return sql_path;
 
389
}
 
390
 
 
391
 
 
392
void TableIdentifier::copyToTableMessage(message::Table &message) const
401
393
{
402
394
  message.set_name(table_name);
403
395
  message.set_schema(getSchemaName());
404
396
}
405
397
 
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 */
 
398
std::size_t hash_value(TableIdentifier const& b)
 
399
{
 
400
  return b.getHashValue();
 
401
}
 
402
 
446
403
} /* namespace drizzled */