~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/table_identifier.cc

  • Committer: Monty Taylor
  • Date: 2009-04-14 19:16:51 UTC
  • mto: (997.2.5 mordred)
  • mto: This revision was merged to the branch mainline in revision 994.
  • Revision ID: mordred@inaugust.com-20090414191651-ltbww6hpqks8k7qk
Clarified instructions in README.

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
 
 
25
 
#include "drizzled/table_identifier.h"
26
 
#include "drizzled/session.h"
27
 
#include "drizzled/current_session.h"
28
 
#include "drizzled/internal/my_sys.h"
29
 
#include "drizzled/data_home.h"
30
 
 
31
 
#include "drizzled/table.h"
32
 
 
33
 
#include <algorithm>
34
 
#include <sstream>
35
 
#include <cstdio>
36
 
 
37
 
using namespace std;
38
 
 
39
 
namespace drizzled
40
 
{
41
 
 
42
 
extern char *drizzle_tmpdir;
43
 
extern pid_t current_pid;
44
 
 
45
 
static const char hexchars[]= "0123456789abcdef";
46
 
 
47
 
static bool tablename_to_filename(const char *from, char *to, size_t to_length);
48
 
static size_t build_tmptable_filename(std::string &path);
49
 
 
50
 
/*
51
 
  Translate a cursor name to a table name (WL #1324).
52
 
 
53
 
  SYNOPSIS
54
 
    filename_to_tablename()
55
 
      from                      The cursor name
56
 
      to                OUT     The table name
57
 
      to_length                 The size of the table name buffer.
58
 
 
59
 
  RETURN
60
 
    Table name length.
61
 
*/
62
 
uint32_t filename_to_tablename(const char *from, char *to, uint32_t to_length)
63
 
{
64
 
  uint32_t length= 0;
65
 
 
66
 
  if (!memcmp(from, TMP_FILE_PREFIX, TMP_FILE_PREFIX_LENGTH))
67
 
  {
68
 
    /* Temporary table name. */
69
 
    length= strlen(strncpy(to, from, to_length));
70
 
  }
71
 
  else
72
 
  {
73
 
    for (; *from  && length < to_length; length++, from++)
74
 
    {
75
 
      if (*from != '@')
76
 
      {
77
 
        to[length]= *from;
78
 
        continue;
79
 
      }
80
 
      /* We've found an escaped char - skip the @ */
81
 
      from++;
82
 
      to[length]= 0;
83
 
      /* There will be a two-position hex-char version of the char */
84
 
      for (int x=1; x >= 0; x--)
85
 
      {
86
 
        if (*from >= '0' && *from <= '9')
87
 
          to[length] += ((*from++ - '0') << (4 * x));
88
 
        else if (*from >= 'a' && *from <= 'f')
89
 
          to[length] += ((*from++ - 'a' + 10) << (4 * x));
90
 
      }
91
 
      /* Backup because we advanced extra in the inner loop */
92
 
      from--;
93
 
    } 
94
 
  }
95
 
 
96
 
  return length;
97
 
}
98
 
 
99
 
/*
100
 
  Creates path to a cursor: drizzle_tmpdir/#sql1234_12_1.ext
101
 
 
102
 
  SYNOPSIS
103
 
   build_tmptable_filename()
104
 
     session                    The thread handle.
105
 
     buff                       Where to write result
106
 
     bufflen                    buff size
107
 
 
108
 
  NOTES
109
 
 
110
 
    Uses current_pid, thread_id, and tmp_table counter to create
111
 
    a cursor name in drizzle_tmpdir.
112
 
 
113
 
  RETURN
114
 
    path length on success, 0 on failure
115
 
*/
116
 
 
117
 
static size_t build_tmptable_filename(std::string &buffer)
118
 
{
119
 
  size_t tmpdir_length;
120
 
  ostringstream post_tmpdir_str;
121
 
 
122
 
  Session *session= current_session;
123
 
 
124
 
  buffer.append(drizzle_tmpdir);
125
 
  tmpdir_length= buffer.length();
126
 
 
127
 
  post_tmpdir_str << "/" << TMP_FILE_PREFIX << current_pid;
128
 
  post_tmpdir_str << session->thread_id << session->tmp_table++;
129
 
 
130
 
  buffer.append(post_tmpdir_str.str());
131
 
 
132
 
  transform(buffer.begin() + tmpdir_length, buffer.end(), buffer.begin() + tmpdir_length, ::tolower);
133
 
 
134
 
  return buffer.length();
135
 
}
136
 
 
137
 
/*
138
 
  Creates path to a cursor: drizzle_data_dir/db/table.ext
139
 
 
140
 
  SYNOPSIS
141
 
   build_table_filename()
142
 
     buff                       Where to write result
143
 
                                This may be the same as table_name.
144
 
     bufflen                    buff size
145
 
     db                         Database name
146
 
     table_name                 Table name
147
 
     ext                        File extension.
148
 
     flags                      FN_FROM_IS_TMP or FN_TO_IS_TMP
149
 
                                table_name is temporary, do not change.
150
 
 
151
 
  NOTES
152
 
 
153
 
    Uses database and table name, and extension to create
154
 
    a cursor name in drizzle_data_dir. Database and table
155
 
    names are converted from system_charset_info into "fscs".
156
 
    Unless flags indicate a temporary table name.
157
 
    'db' is always converted.
158
 
    'ext' is not converted.
159
 
 
160
 
    The conversion suppression is required for ALTER Table. This
161
 
    statement creates intermediate tables. These are regular
162
 
    (non-temporary) tables with a temporary name. Their path names must
163
 
    be derivable from the table name. So we cannot use
164
 
    build_tmptable_filename() for them.
165
 
 
166
 
  RETURN
167
 
    path length on success, 0 on failure
168
 
*/
169
 
 
170
 
size_t build_table_filename(std::string &path, const char *db, const char *table_name, bool is_tmp)
171
 
{
172
 
  char dbbuff[FN_REFLEN];
173
 
  char tbbuff[FN_REFLEN];
174
 
  bool conversion_error= false;
175
 
 
176
 
  memset(tbbuff, 0, sizeof(tbbuff));
177
 
  if (is_tmp) // FN_FROM_IS_TMP | FN_TO_IS_TMP
178
 
  {
179
 
    strncpy(tbbuff, table_name, sizeof(tbbuff));
180
 
  }
181
 
  else
182
 
  {
183
 
    conversion_error= tablename_to_filename(table_name, tbbuff, sizeof(tbbuff));
184
 
    if (conversion_error)
185
 
    {
186
 
      errmsg_printf(ERRMSG_LVL_ERROR,
187
 
                    _("Table name cannot be encoded and fit within filesystem "
188
 
                      "name length restrictions."));
189
 
      return 0;
190
 
    }
191
 
  }
192
 
  memset(dbbuff, 0, sizeof(dbbuff));
193
 
  conversion_error= tablename_to_filename(db, dbbuff, sizeof(dbbuff));
194
 
  if (conversion_error)
195
 
  {
196
 
    errmsg_printf(ERRMSG_LVL_ERROR,
197
 
                  _("Schema name cannot be encoded and fit within filesystem "
198
 
                    "name length restrictions."));
199
 
    return 0;
200
 
  }
201
 
   
202
 
 
203
 
  int rootdir_len= strlen(FN_ROOTDIR);
204
 
  path.append(drizzle_data_home);
205
 
  ssize_t without_rootdir= path.length() - rootdir_len;
206
 
 
207
 
  /* Don't add FN_ROOTDIR if dirzzle_data_home already includes it */
208
 
  if (without_rootdir >= 0)
209
 
  {
210
 
    const char *tmp= path.c_str() + without_rootdir;
211
 
 
212
 
    if (memcmp(tmp, FN_ROOTDIR, rootdir_len) != 0)
213
 
      path.append(FN_ROOTDIR);
214
 
  }
215
 
 
216
 
  path.append(dbbuff);
217
 
  path.append(FN_ROOTDIR);
218
 
  path.append(tbbuff);
219
 
 
220
 
  return path.length();
221
 
}
222
 
 
223
 
 
224
 
/*
225
 
  Translate a table name to a cursor name (WL #1324).
226
 
 
227
 
  SYNOPSIS
228
 
    tablename_to_filename()
229
 
      from                      The table name
230
 
      to                OUT     The cursor name
231
 
      to_length                 The size of the cursor name buffer.
232
 
 
233
 
  RETURN
234
 
    true if errors happen. false on success.
235
 
*/
236
 
static bool tablename_to_filename(const char *from, char *to, size_t to_length)
237
 
{
238
 
  
239
 
  size_t length= 0;
240
 
  for (; *from  && length < to_length; length++, from++)
241
 
  {
242
 
    if ((*from >= '0' && *from <= '9') ||
243
 
        (*from >= 'A' && *from <= 'Z') ||
244
 
        (*from >= 'a' && *from <= 'z') ||
245
 
/* OSX defines an extra set of high-bit and multi-byte characters
246
 
   that cannot be used on the filesystem. Instead of trying to sort
247
 
   those out, we'll just escape encode all high-bit-set chars on OSX.
248
 
   It won't really hurt anything - it'll just make some filenames ugly. */
249
 
#if !defined(TARGET_OS_OSX)
250
 
        ((unsigned char)*from >= 128) ||
251
 
#endif
252
 
        (*from == '_') ||
253
 
        (*from == ' ') ||
254
 
        (*from == '-'))
255
 
    {
256
 
      to[length]= tolower(*from);
257
 
      continue;
258
 
    }
259
 
   
260
 
    if (length + 3 >= to_length)
261
 
      return true;
262
 
 
263
 
    /* We need to escape this char in a way that can be reversed */
264
 
    to[length++]= '@';
265
 
    to[length++]= hexchars[(*from >> 4) & 15];
266
 
    to[length]= hexchars[(*from) & 15];
267
 
  }
268
 
 
269
 
  if (internal::check_if_legal_tablename(to) &&
270
 
      length + 4 < to_length)
271
 
  {
272
 
    memcpy(to + length, "@@@", 4);
273
 
    length+= 3;
274
 
  }
275
 
  return false;
276
 
}
277
 
 
278
 
TableIdentifier::TableIdentifier(const drizzled::Table &table) :
279
 
  SchemaIdentifier(table.s->getTableProto()->schema()),
280
 
  type(table.s->getTableProto()->type()),
281
 
  table_name(table.s->getTableProto()->name())
282
 
{
283
 
  if (type == message::Table::TEMPORARY)
284
 
    path= table.s->path.str;
285
 
 
286
 
  init();
287
 
}
288
 
 
289
 
void TableIdentifier::init()
290
 
{
291
 
  lower_table_name.append(table_name);
292
 
  std::transform(lower_table_name.begin(), lower_table_name.end(),
293
 
                 lower_table_name.begin(), ::tolower);
294
 
}
295
 
 
296
 
 
297
 
const std::string &TableIdentifier::getPath()
298
 
{
299
 
  assert(not lower_table_name.empty());
300
 
 
301
 
  if (path.empty())
302
 
  {
303
 
    switch (type) {
304
 
    case message::Table::STANDARD:
305
 
      build_table_filename(path, getLower().c_str(), lower_table_name.c_str(), false);
306
 
      break;
307
 
    case message::Table::INTERNAL:
308
 
      build_table_filename(path, getLower().c_str(), lower_table_name.c_str(), true);
309
 
      break;
310
 
    case message::Table::TEMPORARY:
311
 
      build_tmptable_filename(path);
312
 
      break;
313
 
    case message::Table::FUNCTION:
314
 
      path.append(getSchemaName());
315
 
      path.append(".");
316
 
      path.append(table_name);
317
 
      break;
318
 
    }
319
 
    assert(path.length()); // TODO throw exception, this is a possibility
320
 
  }
321
 
 
322
 
  return path;
323
 
}
324
 
 
325
 
bool TableIdentifier::compare(std::string schema_arg, std::string table_arg)
326
 
{
327
 
  std::transform(schema_arg.begin(), schema_arg.end(),
328
 
                 schema_arg.begin(), ::tolower);
329
 
 
330
 
  std::transform(table_arg.begin(), table_arg.end(),
331
 
                 table_arg.begin(), ::tolower);
332
 
 
333
 
  if (schema_arg == getLower() && table_arg == lower_table_name)
334
 
  {
335
 
    return true;
336
 
  }
337
 
 
338
 
  return false;
339
 
}
340
 
 
341
 
const std::string &TableIdentifier::getSQLPath()
342
 
{
343
 
  if (sql_path.empty())
344
 
  {
345
 
    switch (type) {
346
 
    case message::Table::FUNCTION:
347
 
    case message::Table::STANDARD:
348
 
      sql_path.append(getLower());
349
 
      sql_path.append(".");
350
 
      sql_path.append(table_name);
351
 
      break;
352
 
    case message::Table::INTERNAL:
353
 
      sql_path.append("temporary.");
354
 
      sql_path.append(table_name);
355
 
      break;
356
 
    case message::Table::TEMPORARY:
357
 
      sql_path.append(getLower());
358
 
      sql_path.append(".#");
359
 
      sql_path.append(table_name);
360
 
      break;
361
 
    }
362
 
  }
363
 
 
364
 
  return sql_path;
365
 
}
366
 
 
367
 
 
368
 
void TableIdentifier::copyToTableMessage(message::Table &message)
369
 
{
370
 
  message.set_name(table_name);
371
 
  message.set_schema(getSchemaName());
372
 
}
373
 
 
374
 
} /* namespace drizzled */