~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/table_identifier.cc

  • Committer: Brian Aker
  • Date: 2010-03-19 01:45:39 UTC
  • mto: This revision was merged to the branch mainline in revision 1362.
  • Revision ID: brian@gaz-20100319014539-jv38vkd8h9a4axzr
Another pass through the interface...

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
#include "config.h"
22
22
 
23
23
#include <assert.h>
24
 
#include <boost/lexical_cast.hpp>
25
 
#include "drizzled/identifier.h"
 
24
 
 
25
#include "drizzled/table_identifier.h"
26
26
#include "drizzled/session.h"
 
27
#include "drizzled/current_session.h"
27
28
#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"
 
29
#include "drizzled/data_home.h"
33
30
 
34
31
#include <algorithm>
35
32
#include <sstream>
36
33
#include <cstdio>
37
34
 
38
 
#include <boost/thread.hpp>
39
 
 
40
35
using namespace std;
41
36
 
42
37
namespace drizzled
43
38
{
44
39
 
45
 
class SchemaIdentifier;
46
 
 
47
 
extern std::string drizzle_tmpdir;
 
40
extern char *drizzle_tmpdir;
48
41
extern pid_t current_pid;
49
42
 
50
43
static const char hexchars[]= "0123456789abcdef";
51
44
 
 
45
static bool tablename_to_filename(const char *from, char *to, size_t to_length);
 
46
static size_t build_tmptable_filename(std::string &path);
 
47
 
52
48
/*
53
49
  Translate a cursor name to a table name (WL #1324).
54
50
 
61
57
  RETURN
62
58
    Table name length.
63
59
*/
64
 
uint32_t TableIdentifier::filename_to_tablename(const char *from, char *to, uint32_t to_length)
 
60
uint32_t filename_to_tablename(const char *from, char *to, uint32_t to_length)
65
61
{
66
62
  uint32_t length= 0;
67
63
 
116
112
    path length on success, 0 on failure
117
113
*/
118
114
 
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)
 
115
static size_t build_tmptable_filename(std::string &buffer)
143
116
{
144
117
  size_t tmpdir_length;
145
118
  ostringstream post_tmpdir_str;
146
119
 
 
120
  Session *session= current_session;
 
121
 
147
122
  buffer.append(drizzle_tmpdir);
148
123
  tmpdir_length= buffer.length();
149
124
 
150
125
  post_tmpdir_str << "/" << TMP_FILE_PREFIX << current_pid;
151
 
  post_tmpdir_str << pthread_self() << "-" << get_counter();
 
126
  post_tmpdir_str << session->thread_id << session->tmp_table++;
152
127
 
153
128
  buffer.append(post_tmpdir_str.str());
154
129
 
157
132
  return buffer.length();
158
133
}
159
134
 
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
135
/*
176
136
  Creates path to a cursor: drizzle_data_dir/db/table.ext
177
137
 
183
143
     db                         Database name
184
144
     table_name                 Table name
185
145
     ext                        File extension.
186
 
     flags                      table_name is temporary, do not change.
 
146
     flags                      FN_FROM_IS_TMP or FN_TO_IS_TMP
 
147
                                table_name is temporary, do not change.
187
148
 
188
149
  NOTES
189
150
 
204
165
    path length on success, 0 on failure
205
166
*/
206
167
 
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)
 
168
size_t build_table_filename(std::string &path, const char *db, const char *table_name, bool is_tmp)
208
169
{
 
170
  char dbbuff[FN_REFLEN];
 
171
  char tbbuff[FN_REFLEN];
209
172
  bool conversion_error= false;
210
173
 
211
 
  conversion_error= util::tablename_to_filename(in_db, in_path);
 
174
  memset(tbbuff, 0, sizeof(tbbuff));
 
175
  if (is_tmp) // FN_FROM_IS_TMP | FN_TO_IS_TMP
 
176
  {
 
177
    strncpy(tbbuff, table_name, sizeof(tbbuff));
 
178
  }
 
179
  else
 
180
  {
 
181
    conversion_error= tablename_to_filename(table_name, tbbuff, sizeof(tbbuff));
 
182
    if (conversion_error)
 
183
    {
 
184
      errmsg_printf(ERRMSG_LVL_ERROR,
 
185
                    _("Table name cannot be encoded and fit within filesystem "
 
186
                      "name length restrictions."));
 
187
      return 0;
 
188
    }
 
189
  }
 
190
  memset(dbbuff, 0, sizeof(dbbuff));
 
191
  conversion_error= tablename_to_filename(db, dbbuff, sizeof(dbbuff));
212
192
  if (conversion_error)
213
193
  {
214
194
    errmsg_printf(ERRMSG_LVL_ERROR,
216
196
                    "name length restrictions."));
217
197
    return 0;
218
198
  }
219
 
 
220
 
  in_path.append(FN_ROOTDIR);
221
 
 
222
 
  if (is_tmp) // It a conversion tmp
 
199
   
 
200
 
 
201
  int rootdir_len= strlen(FN_ROOTDIR);
 
202
  path.append(drizzle_data_home);
 
203
  ssize_t without_rootdir= path.length() - rootdir_len;
 
204
 
 
205
  /* Don't add FN_ROOTDIR if dirzzle_data_home already includes it */
 
206
  if (without_rootdir >= 0)
223
207
  {
224
 
    in_path.append(in_table_name);
 
208
    const char *tmp= path.c_str() + without_rootdir;
 
209
 
 
210
    if (memcmp(tmp, FN_ROOTDIR, rootdir_len) != 0)
 
211
      path.append(FN_ROOTDIR);
225
212
  }
226
 
  else
 
213
 
 
214
  path.append(dbbuff);
 
215
  path.append(FN_ROOTDIR);
 
216
  path.append(tbbuff);
 
217
 
 
218
  return path.length();
 
219
}
 
220
 
 
221
 
 
222
/*
 
223
  Translate a table name to a cursor name (WL #1324).
 
224
 
 
225
  SYNOPSIS
 
226
    tablename_to_filename()
 
227
      from                      The table name
 
228
      to                OUT     The cursor name
 
229
      to_length                 The size of the cursor name buffer.
 
230
 
 
231
  RETURN
 
232
    true if errors happen. false on success.
 
233
*/
 
234
static bool tablename_to_filename(const char *from, char *to, size_t to_length)
 
235
{
 
236
  
 
237
  size_t length= 0;
 
238
  for (; *from  && length < to_length; length++, from++)
227
239
  {
228
 
    conversion_error= util::tablename_to_filename(in_table_name, in_path);
229
 
    if (conversion_error)
 
240
    if ((*from >= '0' && *from <= '9') ||
 
241
        (*from >= 'A' && *from <= 'Z') ||
 
242
        (*from >= 'a' && *from <= 'z') ||
 
243
/* OSX defines an extra set of high-bit and multi-byte characters
 
244
   that cannot be used on the filesystem. Instead of trying to sort
 
245
   those out, we'll just escape encode all high-bit-set chars on OSX.
 
246
   It won't really hurt anything - it'll just make some filenames ugly. */
 
247
#if !defined(TARGET_OS_OSX)
 
248
        ((unsigned char)*from >= 128) ||
 
249
#endif
 
250
        (*from == '_') ||
 
251
        (*from == ' ') ||
 
252
        (*from == '-'))
230
253
    {
231
 
      errmsg_printf(ERRMSG_LVL_ERROR,
232
 
                    _("Table name cannot be encoded and fit within filesystem "
233
 
                      "name length restrictions."));
234
 
      return 0;
 
254
      to[length]= *from;
 
255
      continue;
235
256
    }
236
 
  }
237
257
   
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
 
    {
 
258
    if (length + 3 >= to_length)
 
259
      return true;
 
260
 
 
261
    /* We need to escape this char in a way that can be reversed */
 
262
    to[length++]= '@';
 
263
    to[length++]= hexchars[(*from >> 4) & 15];
 
264
    to[length]= hexchars[(*from) & 15];
 
265
  }
 
266
 
 
267
  if (internal::check_if_legal_tablename(to) &&
 
268
      length + 4 < to_length)
 
269
  {
 
270
    memcpy(to + length, "@@@", 4);
 
271
    length+= 3;
 
272
  }
 
273
  return false;
 
274
}
 
275
 
 
276
 
 
277
 
 
278
const char *TableIdentifier::getPath()
 
279
{
 
280
  if (not path_inited)
 
281
  {
 
282
    switch (type) {
 
283
    case STANDARD_TABLE:
 
284
      build_table_filename(path, lower_db.c_str(), lower_table_name.c_str(), false);
 
285
      break;
 
286
    case INTERNAL_TMP_TABLE:
 
287
      build_table_filename(path, lower_db.c_str(), lower_table_name.c_str(), true);
 
288
      break;
 
289
    case TEMP_TABLE:
267
290
      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();
 
291
      break;
 
292
    case SYSTEM_TMP_TABLE:
 
293
      assert(0);
 
294
    }
 
295
    path_inited= true;
 
296
    assert(path.length()); // TODO throw exception, this is a possibility
 
297
  }
 
298
 
 
299
  return path.c_str();
393
300
}
394
301
 
395
302
} /* namespace drizzled */