~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/identifier/table.cc

  • Committer: Brian Aker
  • Date: 2011-02-22 06:12:02 UTC
  • mfrom: (2190.1.6 drizzle-build)
  • Revision ID: brian@tangent.org-20110222061202-k03czxykqy4x9hjs
List update, header fixes, multiple symbols, and David deletes some code.

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