~drizzle-trunk/drizzle/development

1223.4.18 by Brian Aker
More TableIdentifier code.
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
1241.9.1 by Monty Taylor
Removed global.h. Fixed all the headers.
21
#include "config.h"
22
23
#include <assert.h>
24
1309.1.24 by Brian Aker
Moved the build table stuff into table_identifier (all to make it simpler to
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 <algorithm>
32
#include <sstream>
1223.4.18 by Brian Aker
More TableIdentifier code.
33
34
using namespace std;
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
35
36
namespace drizzled
37
{
1223.4.18 by Brian Aker
More TableIdentifier code.
38
1309.1.24 by Brian Aker
Moved the build table stuff into table_identifier (all to make it simpler to
39
extern char *drizzle_tmpdir;
40
extern pid_t current_pid;
41
42
static const char hexchars[]= "0123456789abcdef";
43
44
/*
45
  Translate a cursor name to a table name (WL #1324).
46
47
  SYNOPSIS
48
    filename_to_tablename()
49
      from                      The cursor name
50
      to                OUT     The table name
51
      to_length                 The size of the table name buffer.
52
53
  RETURN
54
    Table name length.
55
*/
56
uint32_t filename_to_tablename(const char *from, char *to, uint32_t to_length)
57
{
58
  uint32_t length= 0;
59
60
  if (!memcmp(from, TMP_FILE_PREFIX, TMP_FILE_PREFIX_LENGTH))
61
  {
62
    /* Temporary table name. */
63
    length= strlen(strncpy(to, from, to_length));
64
  }
65
  else
66
  {
67
    for (; *from  && length < to_length; length++, from++)
68
    {
69
      if (*from != '@')
70
      {
71
        to[length]= *from;
72
        continue;
73
      }
74
      /* We've found an escaped char - skip the @ */
75
      from++;
76
      to[length]= 0;
77
      /* There will be a two-position hex-char version of the char */
78
      for (int x=1; x >= 0; x--)
79
      {
80
        if (*from >= '0' && *from <= '9')
81
          to[length] += ((*from++ - '0') << (4 * x));
82
        else if (*from >= 'a' && *from <= 'f')
83
          to[length] += ((*from++ - 'a' + 10) << (4 * x));
84
      }
85
      /* Backup because we advanced extra in the inner loop */
86
      from--;
87
    } 
88
  }
89
90
  return length;
91
}
92
93
/*
94
  Creates path to a cursor: drizzle_tmpdir/#sql1234_12_1.ext
95
96
  SYNOPSIS
97
   build_tmptable_filename()
98
     session                    The thread handle.
99
     buff                       Where to write result
100
     bufflen                    buff size
101
102
  NOTES
103
104
    Uses current_pid, thread_id, and tmp_table counter to create
105
    a cursor name in drizzle_tmpdir.
106
107
  RETURN
108
    path length on success, 0 on failure
109
*/
110
111
size_t build_tmptable_filename(char *buff, size_t bufflen)
112
{
113
  size_t length;
114
  ostringstream path_str, post_tmpdir_str;
115
  string tmp;
116
117
  Session *session= current_session;
118
119
  path_str << drizzle_tmpdir;
120
  post_tmpdir_str << "/" << TMP_FILE_PREFIX << current_pid;
121
  post_tmpdir_str << session->thread_id << session->tmp_table++;
122
  tmp= post_tmpdir_str.str();
123
124
  transform(tmp.begin(), tmp.end(), tmp.begin(), ::tolower);
125
126
  path_str << tmp;
127
128
  if (bufflen < path_str.str().length())
129
    length= 0;
130
  else
131
    length= internal::unpack_filename(buff, path_str.str().c_str());
132
133
  return length;
134
}
135
136
/*
137
  Creates path to a cursor: drizzle_data_dir/db/table.ext
138
139
  SYNOPSIS
140
   build_table_filename()
141
     buff                       Where to write result
142
                                This may be the same as table_name.
143
     bufflen                    buff size
144
     db                         Database name
145
     table_name                 Table name
146
     ext                        File extension.
147
     flags                      FN_FROM_IS_TMP or FN_TO_IS_TMP
148
                                table_name is temporary, do not change.
149
150
  NOTES
151
152
    Uses database and table name, and extension to create
153
    a cursor name in drizzle_data_dir. Database and table
154
    names are converted from system_charset_info into "fscs".
155
    Unless flags indicate a temporary table name.
156
    'db' is always converted.
157
    'ext' is not converted.
158
159
    The conversion suppression is required for ALTER Table. This
160
    statement creates intermediate tables. These are regular
161
    (non-temporary) tables with a temporary name. Their path names must
162
    be derivable from the table name. So we cannot use
163
    build_tmptable_filename() for them.
164
165
  RETURN
166
    path length on success, 0 on failure
167
*/
168
169
size_t build_table_filename(char *buff, size_t bufflen, const char *db, const char *table_name, bool is_tmp)
170
{
171
  char dbbuff[FN_REFLEN];
172
  char tbbuff[FN_REFLEN];
173
  bool conversion_error= false;
174
175
  memset(tbbuff, 0, sizeof(tbbuff));
176
  if (is_tmp) // FN_FROM_IS_TMP | FN_TO_IS_TMP
177
    strncpy(tbbuff, table_name, sizeof(tbbuff));
178
  else
179
  {
180
    conversion_error= tablename_to_filename(table_name, tbbuff, sizeof(tbbuff));
181
    if (conversion_error)
182
    {
183
      errmsg_printf(ERRMSG_LVL_ERROR,
184
                    _("Table name cannot be encoded and fit within filesystem "
185
                      "name length restrictions."));
186
      return 0;
187
    }
188
  }
189
  memset(dbbuff, 0, sizeof(dbbuff));
190
  conversion_error= tablename_to_filename(db, dbbuff, sizeof(dbbuff));
191
  if (conversion_error)
192
  {
193
    errmsg_printf(ERRMSG_LVL_ERROR,
194
                  _("Schema name cannot be encoded and fit within filesystem "
195
                    "name length restrictions."));
196
    return 0;
197
  }
198
   
199
200
  int rootdir_len= strlen(FN_ROOTDIR);
201
  string table_path(drizzle_data_home);
202
  int without_rootdir= table_path.length()-rootdir_len;
203
204
  /* Don't add FN_ROOTDIR if dirzzle_data_home already includes it */
205
  if (without_rootdir >= 0)
206
  {
207
    const char *tmp= table_path.c_str()+without_rootdir;
208
    if (memcmp(tmp, FN_ROOTDIR, rootdir_len) != 0)
209
      table_path.append(FN_ROOTDIR);
210
  }
211
212
  table_path.append(dbbuff);
213
  table_path.append(FN_ROOTDIR);
214
  table_path.append(tbbuff);
215
216
  if (bufflen < table_path.length())
217
    return 0;
218
219
  strcpy(buff, table_path.c_str());
220
221
  return table_path.length();
222
}
223
224
225
/*
226
  Translate a table name to a cursor name (WL #1324).
227
228
  SYNOPSIS
229
    tablename_to_filename()
230
      from                      The table name
231
      to                OUT     The cursor name
232
      to_length                 The size of the cursor name buffer.
233
234
  RETURN
235
    true if errors happen. false on success.
236
*/
237
bool tablename_to_filename(const char *from, char *to, size_t to_length)
238
{
239
  
240
  size_t length= 0;
241
  for (; *from  && length < to_length; length++, from++)
242
  {
243
    if ((*from >= '0' && *from <= '9') ||
244
        (*from >= 'A' && *from <= 'Z') ||
245
        (*from >= 'a' && *from <= 'z') ||
246
/* OSX defines an extra set of high-bit and multi-byte characters
247
   that cannot be used on the filesystem. Instead of trying to sort
248
   those out, we'll just escape encode all high-bit-set chars on OSX.
249
   It won't really hurt anything - it'll just make some filenames ugly. */
250
#if !defined(TARGET_OS_OSX)
251
        ((unsigned char)*from >= 128) ||
252
#endif
253
        (*from == '_') ||
254
        (*from == ' ') ||
255
        (*from == '-'))
256
    {
257
      to[length]= *from;
258
      continue;
259
    }
260
   
261
    if (length + 3 >= to_length)
262
      return true;
263
264
    /* We need to escape this char in a way that can be reversed */
265
    to[length++]= '@';
266
    to[length++]= hexchars[(*from >> 4) & 15];
267
    to[length]= hexchars[(*from) & 15];
268
  }
269
270
  if (internal::check_if_legal_tablename(to) &&
271
      length + 4 < to_length)
272
  {
273
    memcpy(to + length, "@@@", 4);
274
    length+= 3;
275
  }
276
  return false;
277
}
278
279
1223.4.18 by Brian Aker
More TableIdentifier code.
280
281
const char *TableIdentifier::getPath()
282
{
283
  if (! path_inited)
284
  {
285
    size_t path_length= 0;
286
287
    switch (type) {
1309.2.16 by Brian Aker
Small name change (AKA... I hate reading the NO_**@##@$# logic).
288
    case STANDARD_TABLE:
1223.4.18 by Brian Aker
More TableIdentifier code.
289
      path_length= build_table_filename(path, sizeof(path),
290
                                        db, table_name,
291
                                        false);
292
      break;
293
    case INTERNAL_TMP_TABLE:
294
      path_length= build_table_filename(path, sizeof(path),
295
                                        db, table_name,
296
                                        true);
297
      break;
1235.1.3 by Brian Aker
Remove the need for trans/non-trans temp tables for lock conditions.
298
    case TEMP_TABLE:
1223.4.18 by Brian Aker
More TableIdentifier code.
299
      path_length= build_tmptable_filename(path, sizeof(path));
300
      break;
301
    case SYSTEM_TMP_TABLE:
302
      assert(0);
303
    }
304
    path_inited= true;
305
    assert(path_length); // TODO throw exception, this is a possibility
306
  }
307
308
  return path;
309
}
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
310
311
} /* namespace drizzled */