~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/identifier/table.cc

  • Committer: Andrew Hutchings
  • Date: 2010-10-20 15:31:27 UTC
  • mto: This revision was merged to the branch mainline in revision 1907.
  • Revision ID: andrew@linuxjedi.co.uk-20101020153127-w9djuz9omzezg2kz
Add error message for global sort buffer constraint

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
23
23
#include <assert.h>
24
24
#include <boost/lexical_cast.hpp>
25
25
#include "drizzled/identifier.h"
 
26
#include "drizzled/session.h"
26
27
#include "drizzled/internal/my_sys.h"
27
28
 
28
 
#include <drizzled/error.h>
29
 
#include <drizzled/errmsg_print.h>
30
 
#include <drizzled/gettext.h>
31
 
 
32
 
#include <drizzled/table.h>
 
29
#include "drizzled/table.h"
33
30
 
34
31
#include "drizzled/util/string.h"
35
 
#include "drizzled/util/tablename_to_filename.h"
36
32
 
37
33
#include <algorithm>
38
34
#include <sstream>
45
41
namespace drizzled
46
42
{
47
43
 
48
 
class Table;
49
 
 
50
44
extern std::string drizzle_tmpdir;
51
45
extern pid_t current_pid;
52
46
 
53
 
namespace identifier {
54
 
class Schema;
55
 
 
56
47
static const char hexchars[]= "0123456789abcdef";
57
48
 
 
49
static bool tablename_to_filename(const char *from, char *to, size_t to_length);
 
50
 
58
51
/*
59
52
  Translate a cursor name to a table name (WL #1324).
60
53
 
67
60
  RETURN
68
61
    Table name length.
69
62
*/
70
 
uint32_t Table::filename_to_tablename(const char *from, char *to, uint32_t to_length)
 
63
uint32_t TableIdentifier::filename_to_tablename(const char *from, char *to, uint32_t to_length)
71
64
{
72
65
  uint32_t length= 0;
73
66
 
145
138
 
146
139
#endif
147
140
 
148
 
size_t Table::build_tmptable_filename(std::string &buffer)
 
141
size_t TableIdentifier::build_tmptable_filename(std::string &buffer)
149
142
{
150
143
  size_t tmpdir_length;
151
144
  ostringstream post_tmpdir_str;
163
156
  return buffer.length();
164
157
}
165
158
 
166
 
size_t Table::build_tmptable_filename(std::vector<char> &buffer)
 
159
size_t TableIdentifier::build_tmptable_filename(std::vector<char> &buffer)
167
160
{
168
161
  ostringstream post_tmpdir_str;
169
162
 
210
203
    path length on success, 0 on failure
211
204
*/
212
205
 
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)
 
206
size_t TableIdentifier::build_table_filename(std::string &path, const char *db, const char *table_name, bool is_tmp)
214
207
{
 
208
  char dbbuff[FN_REFLEN];
 
209
  char tbbuff[FN_REFLEN];
215
210
  bool conversion_error= false;
216
211
 
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
 
 
 
212
  memset(tbbuff, 0, sizeof(tbbuff));
228
213
  if (is_tmp) // It a conversion tmp
229
214
  {
230
 
    in_path.append(in_table_name);
 
215
    strncpy(tbbuff, table_name, sizeof(tbbuff));
231
216
  }
232
217
  else
233
218
  {
234
 
    conversion_error= util::tablename_to_filename(in_table_name, in_path);
 
219
    conversion_error= tablename_to_filename(table_name, tbbuff, sizeof(tbbuff));
235
220
    if (conversion_error)
236
221
    {
237
 
      errmsg_printf(error::ERROR,
 
222
      errmsg_printf(ERRMSG_LVL_ERROR,
238
223
                    _("Table name cannot be encoded and fit within filesystem "
239
224
                      "name length restrictions."));
240
225
      return 0;
241
226
    }
242
227
  }
243
 
   
244
 
  return in_path.length();
245
 
}
246
 
 
247
 
Table::Table(const drizzled::Table &table) :
248
 
  identifier::Schema(table.getShare()->getSchemaName()),
 
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()),
249
307
  type(table.getShare()->getTableType()),
250
308
  table_name(table.getShare()->getTableName())
251
309
{
255
313
  init();
256
314
}
257
315
 
258
 
void Table::init()
 
316
void TableIdentifier::init()
259
317
{
260
318
  switch (type) {
261
319
  case message::Table::FUNCTION:
262
320
  case message::Table::STANDARD:
263
321
    assert(path.size() == 0);
264
 
    build_table_filename(path, getSchemaName(), table_name, false);
 
322
    build_table_filename(path, getSchemaName().c_str(), table_name.c_str(), false);
265
323
    break;
266
324
  case message::Table::INTERNAL:
267
325
    assert(path.size() == 0);
268
 
    build_table_filename(path, getSchemaName(), table_name, true);
 
326
    build_table_filename(path, getSchemaName().c_str(), table_name.c_str(), true);
269
327
    break;
270
328
  case message::Table::TEMPORARY:
271
329
    if (path.empty())
275
333
    break;
276
334
  }
277
335
 
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
336
  util::insensitive_hash hasher;
297
337
  hash_value= hasher(path);
298
338
 
299
 
  std::string tb_name(getTableName());
300
 
  std::transform(tb_name.begin(), tb_name.end(), tb_name.begin(), ::tolower);
 
339
  key.resize(getKeySize());
 
340
  size_t key_length= TableIdentifier::createKey(&key[0], *this);
301
341
 
302
 
  key.set(getKeySize(), getSchemaName(), tb_name);
 
342
  assert(key_length == getKeySize()); // If this is off, then we have a memory issue.
303
343
}
304
344
 
305
345
 
306
 
const std::string &Table::getPath() const
 
346
const std::string &TableIdentifier::getPath() const
307
347
{
308
348
  return path;
309
349
}
310
350
 
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
 
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
401
379
{
402
380
  message.set_name(table_name);
403
381
  message.set_schema(getSchemaName());
404
382
}
405
383
 
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 */
 
384
std::size_t hash_value(TableIdentifier const& b)
 
385
{
 
386
  return b.getHashValue();
 
387
}
 
388
 
446
389
} /* namespace drizzled */