~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/schema_engine/schema.cc

  • Committer: Jay Pipes
  • Date: 2009-01-30 04:01:12 UTC
  • mto: This revision was merged to the branch mainline in revision 830.
  • Revision ID: jpipes@serialcoder-20090130040112-svbn774guj98pwi4
To remain in compatibility with MySQL, added ability to interpret
decimal arguments as datetime strings for temporal functions.

Fixed YEAR(), MONTH(), DAYOFMONTH(), DAYOFYEAR(), HOUR(), MINUTE(), SECOND(), and MICROSECOND()
to accept decimal parameters and interpret them the same way as MySQL.

Fixed an issue with the TemporalFormat::matches() method which was 
incorrectly assuming all microsecond arguments were specified as 6 digits.
Added power of 10 multiplier to usecond calculation. This fixes issues with
failures in type_date and func_sapdb test cases.

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) 2010 Brian Aker
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 "plugin/schema_engine/schema.h"
24
 
#include "drizzled/db.h"
25
 
#include "drizzled/sql_table.h"
26
 
#include "drizzled/global_charset_info.h"
27
 
#include "drizzled/charset.h"
28
 
#include "drizzled/charset_info.h"
29
 
#include "drizzled/cursor.h"
30
 
#include "drizzled/data_home.h"
31
 
 
32
 
#include "drizzled/internal/my_sys.h"
33
 
 
34
 
#include <fcntl.h>
35
 
#include <sys/stat.h>
36
 
#include <sys/types.h>
37
 
 
38
 
#include <google/protobuf/io/zero_copy_stream.h>
39
 
#include <google/protobuf/io/zero_copy_stream_impl.h>
40
 
 
41
 
#include <iostream>
42
 
#include <fstream>
43
 
#include <string>
44
 
 
45
 
using namespace std;
46
 
using namespace drizzled;
47
 
 
48
 
 
49
 
#define MY_DB_OPT_FILE "db.opt"
50
 
#define DEFAULT_FILE_EXTENSION ".dfe" // Deep Fried Elephant
51
 
 
52
 
Schema::Schema():
53
 
  drizzled::plugin::StorageEngine("schema",
54
 
                                  HTON_ALTER_NOT_SUPPORTED |
55
 
                                  HTON_HAS_SCHEMA_DICTIONARY |
56
 
                                  HTON_SKIP_STORE_LOCK |
57
 
                                  HTON_TEMPORARY_NOT_SUPPORTED),
58
 
  schema_cache_filled(false)
59
 
{
60
 
  table_definition_ext= DEFAULT_FILE_EXTENSION;
61
 
}
62
 
 
63
 
Schema::~Schema()
64
 
{
65
 
}
66
 
 
67
 
void Schema::prime()
68
 
{
69
 
  CachedDirectory directory(getDataHomeCatalog().file_string(), CachedDirectory::DIRECTORY);
70
 
  CachedDirectory::Entries files= directory.getEntries();
71
 
 
72
 
  mutex.lock();
73
 
 
74
 
  for (CachedDirectory::Entries::iterator fileIter= files.begin();
75
 
       fileIter != files.end(); fileIter++)
76
 
  {
77
 
    CachedDirectory::Entry *entry= *fileIter;
78
 
    message::Schema schema_message;
79
 
 
80
 
    if (not entry->filename.compare(GLOBAL_TEMPORARY_EXT))
81
 
      continue;
82
 
 
83
 
    SchemaIdentifier filename(entry->filename);
84
 
    if (readSchemaFile(filename, schema_message))
85
 
    {
86
 
      SchemaIdentifier schema_identifier(schema_message.name());
87
 
 
88
 
      pair<SchemaCache::iterator, bool> ret=
89
 
        schema_cache.insert(make_pair(schema_identifier.getPath(), new message::Schema(schema_message)));
90
 
 
91
 
      if (ret.second == false)
92
 
     {
93
 
        abort(); // If this has happened, something really bad is going down.
94
 
      }
95
 
    }
96
 
  }
97
 
  mutex.unlock();
98
 
}
99
 
 
100
 
void Schema::doGetSchemaIdentifiers(SchemaIdentifier::vector &set_of_names)
101
 
{
102
 
  mutex.lock_shared();
103
 
  {
104
 
    for (SchemaCache::iterator iter= schema_cache.begin();
105
 
         iter != schema_cache.end();
106
 
         iter++)
107
 
    {
108
 
      set_of_names.push_back(SchemaIdentifier((*iter).second->name()));
109
 
    }
110
 
  }
111
 
  mutex.unlock_shared();
112
 
}
113
 
 
114
 
bool Schema::doGetSchemaDefinition(const SchemaIdentifier &schema_identifier, message::schema::shared_ptr &schema_message)
115
 
{
116
 
  mutex.lock_shared();
117
 
  SchemaCache::iterator iter= schema_cache.find(schema_identifier.getPath());
118
 
 
119
 
  if (iter != schema_cache.end())
120
 
  {
121
 
    schema_message= (*iter).second;
122
 
    mutex.unlock_shared();
123
 
    return true;
124
 
  }
125
 
  mutex.unlock_shared();
126
 
 
127
 
  return false;
128
 
}
129
 
 
130
 
 
131
 
bool Schema::doCreateSchema(const drizzled::message::Schema &schema_message)
132
 
{
133
 
  SchemaIdentifier schema_identifier(schema_message.name());
134
 
 
135
 
  if (mkdir(schema_identifier.getPath().c_str(), 0777) == -1)
136
 
    return false;
137
 
 
138
 
  if (not writeSchemaFile(schema_identifier, schema_message))
139
 
  {
140
 
    rmdir(schema_identifier.getPath().c_str());
141
 
 
142
 
    return false;
143
 
  }
144
 
 
145
 
  mutex.lock();
146
 
  {
147
 
    pair<SchemaCache::iterator, bool> ret=
148
 
      schema_cache.insert(make_pair(schema_identifier.getPath(), new message::Schema(schema_message)));
149
 
 
150
 
 
151
 
    if (ret.second == false)
152
 
    {
153
 
      abort(); // If this has happened, something really bad is going down.
154
 
    }
155
 
  }
156
 
  mutex.unlock();
157
 
 
158
 
  return true;
159
 
}
160
 
 
161
 
bool Schema::doDropSchema(const SchemaIdentifier &schema_identifier)
162
 
{
163
 
  message::schema::shared_ptr schema_message;
164
 
 
165
 
  string schema_file(schema_identifier.getPath());
166
 
  schema_file.append(1, FN_LIBCHAR);
167
 
  schema_file.append(MY_DB_OPT_FILE);
168
 
 
169
 
  if (not doGetSchemaDefinition(schema_identifier, schema_message))
170
 
    return false;
171
 
 
172
 
  // No db.opt file, no love from us.
173
 
  if (access(schema_file.c_str(), F_OK))
174
 
  {
175
 
    perror(schema_file.c_str());
176
 
    return false;
177
 
  }
178
 
 
179
 
  if (unlink(schema_file.c_str()))
180
 
  {
181
 
    perror(schema_file.c_str());
182
 
    return false;
183
 
  }
184
 
 
185
 
  if (rmdir(schema_identifier.getPath().c_str()))
186
 
  {
187
 
    perror(schema_identifier.getPath().c_str());
188
 
    //@todo If this happens, we want a report of it. For the moment I dump
189
 
    //to stderr so I can catch it in Hudson.
190
 
    CachedDirectory dir(schema_identifier.getPath());
191
 
    cerr << dir;
192
 
  }
193
 
 
194
 
  mutex.lock();
195
 
  schema_cache.erase(schema_identifier.getPath());
196
 
  mutex.unlock();
197
 
 
198
 
  return true;
199
 
}
200
 
 
201
 
bool Schema::doAlterSchema(const drizzled::message::Schema &schema_message)
202
 
{
203
 
  SchemaIdentifier schema_identifier(schema_message.name());
204
 
 
205
 
  if (access(schema_identifier.getPath().c_str(), F_OK))
206
 
    return false;
207
 
 
208
 
  if (writeSchemaFile(schema_identifier, schema_message))
209
 
  {
210
 
    mutex.lock();
211
 
    {
212
 
      schema_cache.erase(schema_identifier.getPath());
213
 
 
214
 
      pair<SchemaCache::iterator, bool> ret=
215
 
        schema_cache.insert(make_pair(schema_identifier.getPath(), new message::Schema(schema_message)));
216
 
 
217
 
      if (ret.second == false)
218
 
      {
219
 
        abort(); // If this has happened, something really bad is going down.
220
 
      }
221
 
    }
222
 
    mutex.unlock();
223
 
  }
224
 
 
225
 
  return true;
226
 
}
227
 
 
228
 
/**
229
 
  path is path to database, not schema file 
230
 
 
231
 
  @note we do the rename to make it crash safe.
232
 
*/
233
 
bool Schema::writeSchemaFile(const SchemaIdentifier &schema_identifier, const message::Schema &db)
234
 
{
235
 
  char schema_file_tmp[FN_REFLEN];
236
 
  string schema_file(schema_identifier.getPath());
237
 
 
238
 
 
239
 
  schema_file.append(1, FN_LIBCHAR);
240
 
  schema_file.append(MY_DB_OPT_FILE);
241
 
 
242
 
  snprintf(schema_file_tmp, FN_REFLEN, "%sXXXXXX", schema_file.c_str());
243
 
 
244
 
  int fd= mkstemp(schema_file_tmp);
245
 
 
246
 
  if (fd == -1)
247
 
  {
248
 
    perror(schema_file_tmp);
249
 
 
250
 
    return false;
251
 
  }
252
 
 
253
 
  bool success;
254
 
 
255
 
  try {
256
 
    success= db.SerializeToFileDescriptor(fd);
257
 
  }
258
 
  catch (...)
259
 
  {
260
 
    success= false;
261
 
  }
262
 
 
263
 
  if (not success)
264
 
  {
265
 
    my_error(ER_CORRUPT_SCHEMA_DEFINITION, MYF(0), schema_file.c_str(),
266
 
             db.InitializationErrorString().empty() ? "unknown" :  db.InitializationErrorString().c_str());
267
 
 
268
 
    if (close(fd) == -1)
269
 
      perror(schema_file_tmp);
270
 
 
271
 
    if (unlink(schema_file_tmp))
272
 
      perror(schema_file_tmp);
273
 
 
274
 
    return false;
275
 
  }
276
 
 
277
 
  if (close(fd) == -1)
278
 
  {
279
 
    perror(schema_file_tmp);
280
 
 
281
 
    if (unlink(schema_file_tmp))
282
 
      perror(schema_file_tmp);
283
 
 
284
 
    return false;
285
 
  }
286
 
 
287
 
  if (rename(schema_file_tmp, schema_file.c_str()) == -1)
288
 
  {
289
 
    if (unlink(schema_file_tmp))
290
 
      perror(schema_file_tmp);
291
 
 
292
 
    return false;
293
 
  }
294
 
 
295
 
  return true;
296
 
}
297
 
 
298
 
 
299
 
bool Schema::readSchemaFile(const drizzled::SchemaIdentifier &schema_identifier, drizzled::message::Schema &schema)
300
 
{
301
 
  string db_opt_path(schema_identifier.getPath());
302
 
 
303
 
  /*
304
 
    Pass an empty file name, and the database options file name as extension
305
 
    to avoid table name to file name encoding.
306
 
  */
307
 
  db_opt_path.append(1, FN_LIBCHAR);
308
 
  db_opt_path.append(MY_DB_OPT_FILE);
309
 
 
310
 
  fstream input(db_opt_path.c_str(), ios::in | ios::binary);
311
 
 
312
 
  /**
313
 
    @note If parsing fails, either someone has done a "mkdir" or has deleted their opt file.
314
 
    So what do we do? We muddle through the adventure by generating 
315
 
    one with a name in it, and the charset set to the default.
316
 
  */
317
 
  if (input.good())
318
 
  {
319
 
    if (schema.ParseFromIstream(&input))
320
 
    {
321
 
      return true;
322
 
    }
323
 
 
324
 
    my_error(ER_CORRUPT_SCHEMA_DEFINITION, MYF(0), db_opt_path.c_str(),
325
 
             schema.InitializationErrorString().empty() ? "unknown" :  schema.InitializationErrorString().c_str());
326
 
  }
327
 
  else
328
 
  {
329
 
    perror(db_opt_path.c_str());
330
 
  }
331
 
 
332
 
  return false;
333
 
}
334
 
 
335
 
void Schema::doGetTableIdentifiers(drizzled::CachedDirectory&,
336
 
                                   const drizzled::SchemaIdentifier&,
337
 
                                   drizzled::TableIdentifier::vector&)
338
 
{
339
 
}