~drizzle-trunk/drizzle/development

575.1.5 by Monty Taylor
Moved stuff to handlerton.cc
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
 *
4
 *  Copyright (C) 2008 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; version 2 of the License.
9
 *
10
 *  This program is distributed in the hope that it will be useful,
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 *  GNU General Public License for more details.
14
 *
15
 *  You should have received a copy of the GNU General Public License
16
 *  along with this program; if not, write to the Free Software
17
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
 */
19
1241.9.36 by Monty Taylor
ZOMG. I deleted drizzled/server_includes.h.
20
#include "config.h"
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
21
1241.9.1 by Monty Taylor
Removed global.h. Fixed all the headers.
22
#include <fcntl.h>
23
#include <unistd.h>
24
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
25
#include <string>
26
#include <vector>
1183.1.5 by Brian Aker
Reworked getTableNames() interface. Way simpler, less mallocs....
27
#include <set>
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
28
#include <algorithm>
29
#include <functional>
30
31
#include <google/protobuf/io/zero_copy_stream.h>
32
#include <google/protobuf/io/zero_copy_stream_impl.h>
33
1241.9.64 by Monty Taylor
Moved remaining non-public portions of mysys and mystrings to drizzled/internal.
34
#include "drizzled/internal/my_dir.h"
1241.9.57 by Monty Taylor
Oy. Bigger change than I normally like - but this stuff is all intertwined.
35
#include "drizzled/my_hash.h"
1241.9.44 by Monty Taylor
Made magic with cached_directory.
36
#include "drizzled/cached_directory.h"
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
37
575.1.5 by Monty Taylor
Moved stuff to handlerton.cc
38
#include <drizzled/definitions.h>
39
#include <drizzled/base.h>
1183.1.2 by Brian Aker
Rename of handler to Cursor. You would not believe how long I have wanted
40
#include <drizzled/cursor.h>
960.2.23 by Monty Taylor
Moved handlerton to plugin/storage_engine.h.
41
#include <drizzled/plugin/storage_engine.h>
584.1.15 by Monty Taylor
The mega-patch from hell. Renamed sql_class to session (since that's what it is) and removed it and field and table from common_includes.
42
#include <drizzled/session.h>
575.1.5 by Monty Taylor
Moved stuff to handlerton.cc
43
#include <drizzled/error.h>
44
#include <drizzled/gettext.h>
971.1.37 by Monty Taylor
Another one bites the dust.
45
#include <drizzled/unireg.h>
971.1.38 by Monty Taylor
Moved delete table.
46
#include <drizzled/data_home.h>
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
47
#include "drizzled/errmsg_print.h"
48
#include "drizzled/xid.h"
1241.9.23 by Monty Taylor
Removed sql_table.h from server_includes.h.
49
#include "drizzled/sql_table.h"
1241.9.28 by Monty Taylor
Removed global_charset_info.h from server_includes.h
50
#include "drizzled/global_charset_info.h"
1241.9.64 by Monty Taylor
Moved remaining non-public portions of mysys and mystrings to drizzled/internal.
51
#include "drizzled/internal/my_sys.h"
1241.9.28 by Monty Taylor
Removed global_charset_info.h from server_includes.h
52
575.1.5 by Monty Taylor
Moved stuff to handlerton.cc
53
1095.3.3 by Stewart Smith
move drizzle_proto_exists and drizzle_read_table_proto out of unireg.h and into table_proto.h
54
#include <drizzled/table_proto.h>
55
1228.3.1 by Monty Taylor
Removed NameMap. Also remove the aliases from the plugin, since we can just
56
#include "drizzled/hash.h"
1217.1.3 by Brian Aker
Remove NameMap from Storage Engine. Modified the cleanup code to just do a
57
58
static bool shutdown_has_begun= false; // Once we put in the container for the vector/etc for engines this will go away.
59
960.2.44 by Monty Taylor
Removed legacy_db_type.
60
using namespace std;
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
61
62
namespace drizzled
63
{
64
1217.1.3 by Brian Aker
Remove NameMap from Storage Engine. Modified the cleanup code to just do a
65
typedef hash_map<std::string, plugin::StorageEngine *> EngineMap;
66
typedef std::vector<plugin::StorageEngine *> EngineVector;
67
68
static EngineVector vector_of_engines;
69
static EngineVector vector_of_transactional_engines;
70
1228.1.3 by Monty Taylor
All of the outstanding plugin loader system cleanups:
71
const std::string plugin::UNKNOWN_STRING("UNKNOWN");
72
const std::string plugin::DEFAULT_DEFINITION_FILE_EXT(".dfe");
73
1183.1.27 by Brian Aker
Fix issue where there are too many files in data directory. We now only
74
static std::set<std::string> set_of_table_definition_ext;
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
75
76
plugin::StorageEngine::StorageEngine(const string name_arg,
77
                                     const bitset<HTON_BIT_SIZE> &flags_arg,
78
                                     size_t savepoint_offset_arg,
79
                                     bool support_2pc)
1192.2.5 by Monty Taylor
Replaced overridable virtual methods with passing name to constructor. Now individual plugins will not be allowed to set their own plugin type name. :)
80
    : Plugin(name_arg, "StorageEngine"),
1130.2.16 by Monty Taylor
Cleaned up the constructor initializer lists per Brian.
81
      two_phase_commit(support_2pc),
82
      enabled(true),
964.1.6 by Monty Taylor
Moved savepoint stuff to protected virtual methods, moved the offset to private, and moved the logic about adding the offset to the passed-in pointer and adding the offset to the global offset inside of the class.
83
      flags(flags_arg),
84
      savepoint_offset(savepoint_alloc_size),
85
      orig_savepoint_offset(savepoint_offset_arg),
86
      slot(0)
87
{
88
  if (enabled)
89
  {
90
    savepoint_alloc_size+= orig_savepoint_offset;
91
    slot= total_ha++;
92
    if (two_phase_commit)
93
        total_ha_2pc++;
968.2.29 by Monty Taylor
First steps towards new plugin reg.
94
  }
1183.1.30 by Brian Aker
Added engine internal locks (instead of the session based....)
95
  pthread_mutex_init(&proto_cache_mutex, NULL);
964.1.6 by Monty Taylor
Moved savepoint stuff to protected virtual methods, moved the offset to private, and moved the logic about adding the offset to the passed-in pointer and adding the offset to the global offset inside of the class.
96
}
97
98
1130.1.4 by Monty Taylor
Moved StorageEngine into plugin namespace.
99
plugin::StorageEngine::~StorageEngine()
964.1.6 by Monty Taylor
Moved savepoint stuff to protected virtual methods, moved the offset to private, and moved the logic about adding the offset to the passed-in pointer and adding the offset to the global offset inside of the class.
100
{
101
  savepoint_alloc_size-= orig_savepoint_offset;
1183.1.30 by Brian Aker
Added engine internal locks (instead of the session based....)
102
  pthread_mutex_destroy(&proto_cache_mutex);
964.1.6 by Monty Taylor
Moved savepoint stuff to protected virtual methods, moved the offset to private, and moved the logic about adding the offset to the passed-in pointer and adding the offset to the global offset inside of the class.
103
}
104
1183.1.29 by Brian Aker
Clean up interface so that Truncate sets the propper engine when
105
void plugin::StorageEngine::setTransactionReadWrite(Session& session)
1039.3.8 by Stewart Smith
Re-introduce marking transaction as read-write for engine on create_table:
106
{
1240.9.6 by Monty Taylor
Removed some casts- also removed a few c-interface functions and made them actual methods on session. Also made the ha_data private. (fancy that)
107
  Ha_trx_info *ha_info= session.getEngineInfo(this);
108
1039.3.8 by Stewart Smith
Re-introduce marking transaction as read-write for engine on create_table:
109
  /*
110
    When a storage engine method is called, the transaction must
111
    have been started, unless it's a DDL call, for which the
112
    storage engine starts the transaction internally, and commits
113
    it internally, without registering in the ha_list.
114
    Unfortunately here we can't know know for sure if the engine
115
    has registered the transaction or not, so we must check.
116
  */
117
  if (ha_info->is_started())
118
  {
119
    /*
1183.1.22 by Brian Aker
Merge Name changes
120
     * table_share can be NULL in plugin::StorageEngine::dropTable().
1152.1.2 by Brian Aker
First pass through Monty's engine patch for removing dead abstraction
121
     */
1109.1.1 by Brian Aker
Applying refactor of tmp table bits back to session. (this all needs to be
122
    ha_info->set_trx_read_write();
1039.3.8 by Stewart Smith
Re-introduce marking transaction as read-write for engine on create_table:
123
  }
124
}
125
575.1.5 by Monty Taylor
Moved stuff to handlerton.cc
126
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
127
1183.1.7 by Brian Aker
Fix name conventions for rename table
128
int plugin::StorageEngine::doRenameTable(Session *,
129
                                         const char *from,
130
                                         const char *to)
1039.3.5 by Stewart Smith
move handler::rename_table to StorageEngine
131
{
132
  int error= 0;
133
  for (const char **ext= bas_ext(); *ext ; ext++)
134
  {
135
    if (rename_file_ext(from, to, *ext))
136
    {
1241.9.57 by Monty Taylor
Oy. Bigger change than I normally like - but this stuff is all intertwined.
137
      if ((error=errno) != ENOENT)
1039.3.5 by Stewart Smith
move handler::rename_table to StorageEngine
138
	break;
139
      error= 0;
140
    }
141
  }
142
  return error;
143
}
144
145
1039.3.2 by Stewart Smith
move delete_table out of handler and up into StorageEngine where it belongs.
146
/**
147
  Delete all files with extension from bas_ext().
148
149
  @param name		Base name of table
150
151
  @note
1183.1.2 by Brian Aker
Rename of handler to Cursor. You would not believe how long I have wanted
152
    We assume that the Cursor may return more extensions than
1039.3.2 by Stewart Smith
move delete_table out of handler and up into StorageEngine where it belongs.
153
    was actually used for the file.
154
155
  @retval
156
    0   If we successfully deleted at least one file from base_ext and
157
    didn't get any other errors than ENOENT
158
  @retval
159
    !0  Error
160
*/
1183.1.29 by Brian Aker
Clean up interface so that Truncate sets the propper engine when
161
int plugin::StorageEngine::doDropTable(Session&,
162
                                       const string table_path)
1039.3.2 by Stewart Smith
move delete_table out of handler and up into StorageEngine where it belongs.
163
{
164
  int error= 0;
165
  int enoent_or_zero= ENOENT;                   // Error if no file was deleted
166
  char buff[FN_REFLEN];
167
1183.1.21 by Brian Aker
Fixed temp engines to no longer write out DFE. I have two designs right now
168
  for (const char **ext= bas_ext(); *ext ; ext++)
1039.3.2 by Stewart Smith
move delete_table out of handler and up into StorageEngine where it belongs.
169
  {
170
    fn_format(buff, table_path.c_str(), "", *ext,
171
              MY_UNPACK_FILENAME|MY_APPEND_EXT);
172
    if (my_delete_with_symlink(buff, MYF(0)))
173
    {
1241.9.57 by Monty Taylor
Oy. Bigger change than I normally like - but this stuff is all intertwined.
174
      if ((error= errno) != ENOENT)
1039.3.2 by Stewart Smith
move delete_table out of handler and up into StorageEngine where it belongs.
175
	break;
176
    }
177
    else
178
      enoent_or_zero= 0;                        // No error for ENOENT
179
    error= enoent_or_zero;
180
  }
181
  return error;
182
}
971.1.38 by Monty Taylor
Moved delete table.
183
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
184
const char *plugin::StorageEngine::checkLowercaseNames(const char *path,
185
                                                       char *tmp_path)
186
{
187
  if (flags.test(HTON_BIT_FILE_BASED))
188
    return path;
189
1183.1.2 by Brian Aker
Rename of handler to Cursor. You would not believe how long I have wanted
190
  /* Ensure that table Cursor get path in lower case */
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
191
  if (tmp_path != path)
192
    strcpy(tmp_path, path);
193
194
  /*
195
    we only should turn into lowercase database/table part
196
    so start the process after homedirectory
197
  */
198
  if (strstr(tmp_path, drizzle_tmpdir) == tmp_path)
199
    my_casedn_str(files_charset_info, tmp_path + strlen(drizzle_tmpdir));
200
  else
201
    my_casedn_str(files_charset_info, tmp_path + drizzle_data_home_len);
202
203
  return tmp_path;
204
}
205
206
1130.1.19 by Monty Taylor
Added error reporting to plugin registration.
207
bool plugin::StorageEngine::addPlugin(plugin::StorageEngine *engine)
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
208
{
1217.1.3 by Brian Aker
Remove NameMap from Storage Engine. Modified the cleanup code to just do a
209
1183.1.5 by Brian Aker
Reworked getTableNames() interface. Way simpler, less mallocs....
210
  vector_of_engines.push_back(engine);
211
1183.1.17 by Brian Aker
Added Innodb specific vector (well... for any engine)
212
  if (engine->check_flag(HTON_BIT_DOES_TRANSACTIONS))
213
    vector_of_transactional_engines.push_back(engine);
214
1213 by Brian Aker
Fixes startup failures when temporary tables were left behind in a crash.
215
  if (engine->getTableDefinitionFileExtension().length())
1183.1.27 by Brian Aker
Fix issue where there are too many files in data directory. We now only
216
  {
1213 by Brian Aker
Fixes startup failures when temporary tables were left behind in a crash.
217
    assert(engine->getTableDefinitionFileExtension().length() == DEFAULT_DEFINITION_FILE_EXT.length());
218
    set_of_table_definition_ext.insert(engine->getTableDefinitionFileExtension());
1183.1.27 by Brian Aker
Fix issue where there are too many files in data directory. We now only
219
  }
220
1130.1.19 by Monty Taylor
Added error reporting to plugin registration.
221
  return false;
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
222
}
223
1217.1.3 by Brian Aker
Remove NameMap from Storage Engine. Modified the cleanup code to just do a
224
void plugin::StorageEngine::removePlugin(plugin::StorageEngine *)
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
225
{
1217.1.3 by Brian Aker
Remove NameMap from Storage Engine. Modified the cleanup code to just do a
226
  if (shutdown_has_begun == false)
227
  {
228
    vector_of_engines.clear();
229
    vector_of_transactional_engines.clear();
230
231
    shutdown_has_begun= true;
232
  }
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
233
}
234
1228.3.2 by Monty Taylor
Removed engine_map - just use vector_of_engines.
235
class FindEngineByName
236
  : public unary_function<plugin::StorageEngine *, bool>
237
{
238
  const string target;
239
public:
240
  explicit FindEngineByName(const string target_arg)
241
    : target(target_arg)
242
  {}
243
  result_type operator() (argument_type engine)
244
  {
245
    string engine_name(engine->getName());
246
247
    transform(engine_name.begin(), engine_name.end(),
248
              engine_name.begin(), ::tolower);
249
    return engine_name == target;
250
  }
251
};
252
1183.1.29 by Brian Aker
Clean up interface so that Truncate sets the propper engine when
253
plugin::StorageEngine *plugin::StorageEngine::findByName(string find_str)
254
{
255
  transform(find_str.begin(), find_str.end(),
256
            find_str.begin(), ::tolower);
257
1228.3.2 by Monty Taylor
Removed engine_map - just use vector_of_engines.
258
  
259
  EngineVector::iterator iter= find_if(vector_of_engines.begin(),
260
                                       vector_of_engines.end(),
261
                                       FindEngineByName(find_str));
262
  if (iter != vector_of_engines.end())
1217.1.3 by Brian Aker
Remove NameMap from Storage Engine. Modified the cleanup code to just do a
263
  {
1228.3.2 by Monty Taylor
Removed engine_map - just use vector_of_engines.
264
    StorageEngine *engine= *iter;
1217.1.3 by Brian Aker
Remove NameMap from Storage Engine. Modified the cleanup code to just do a
265
    if (engine->is_user_selectable())
266
      return engine;
267
  }
1183.1.29 by Brian Aker
Clean up interface so that Truncate sets the propper engine when
268
269
  return NULL;
270
}
271
272
plugin::StorageEngine *plugin::StorageEngine::findByName(Session& session,
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
273
                                                         string find_str)
274
{
275
  
276
  transform(find_str.begin(), find_str.end(),
277
            find_str.begin(), ::tolower);
1183.1.5 by Brian Aker
Reworked getTableNames() interface. Way simpler, less mallocs....
278
279
  if (find_str.compare("default") == 0)
1183.1.29 by Brian Aker
Clean up interface so that Truncate sets the propper engine when
280
    return session.getDefaultStorageEngine();
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
281
1228.3.2 by Monty Taylor
Removed engine_map - just use vector_of_engines.
282
  EngineVector::iterator iter= find_if(vector_of_engines.begin(),
283
                                       vector_of_engines.end(),
284
                                       FindEngineByName(find_str));
285
  if (iter != vector_of_engines.end())
1217.1.3 by Brian Aker
Remove NameMap from Storage Engine. Modified the cleanup code to just do a
286
  {
1228.3.2 by Monty Taylor
Removed engine_map - just use vector_of_engines.
287
    StorageEngine *engine= *iter;
1217.1.3 by Brian Aker
Remove NameMap from Storage Engine. Modified the cleanup code to just do a
288
    if (engine->is_user_selectable())
289
      return engine;
290
  }
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
291
292
  return NULL;
293
}
294
295
class StorageEngineCloseConnection
1217.1.3 by Brian Aker
Remove NameMap from Storage Engine. Modified the cleanup code to just do a
296
: public unary_function<plugin::StorageEngine *, void>
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
297
{
298
  Session *session;
299
public:
300
  StorageEngineCloseConnection(Session *session_arg) : session(session_arg) {}
301
  /*
302
    there's no need to rollback here as all transactions must
303
    be rolled back already
304
  */
305
  inline result_type operator() (argument_type engine)
306
  {
1240.9.6 by Monty Taylor
Removed some casts- also removed a few c-interface functions and made them actual methods on session. Also made the ha_data private. (fancy that)
307
    if (engine->is_enabled() && (*session->getEngineData(engine)))
308
      engine->close_connection(session);
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
309
  }
310
};
311
312
/**
313
  @note
314
    don't bother to rollback here, it's done already
315
*/
316
void plugin::StorageEngine::closeConnection(Session* session)
317
{
1183.1.16 by Brian Aker
Switch to using vector over Registry
318
  for_each(vector_of_engines.begin(), vector_of_engines.end(),
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
319
           StorageEngineCloseConnection(session));
320
}
321
322
void plugin::StorageEngine::dropDatabase(char* path)
323
{
1183.1.16 by Brian Aker
Switch to using vector over Registry
324
  for_each(vector_of_engines.begin(), vector_of_engines.end(),
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
325
           bind2nd(mem_fun(&plugin::StorageEngine::drop_database),path));
326
}
327
328
int plugin::StorageEngine::commitOrRollbackByXID(XID *xid, bool commit)
329
{
330
  vector<int> results;
331
  
332
  if (commit)
1217.1.3 by Brian Aker
Remove NameMap from Storage Engine. Modified the cleanup code to just do a
333
    transform(vector_of_engines.begin(), vector_of_engines.end(), results.begin(),
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
334
              bind2nd(mem_fun(&plugin::StorageEngine::commit_by_xid),xid));
335
  else
1217.1.3 by Brian Aker
Remove NameMap from Storage Engine. Modified the cleanup code to just do a
336
    transform(vector_of_engines.begin(), vector_of_engines.end(), results.begin(),
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
337
              bind2nd(mem_fun(&plugin::StorageEngine::rollback_by_xid),xid));
338
339
  if (find_if(results.begin(), results.end(), bind2nd(equal_to<int>(),0))
340
         == results.end())
341
    return 1;
342
  return 0;
343
}
344
345
/**
346
  @details
347
  This function should be called when MySQL sends rows of a SELECT result set
348
  or the EOF mark to the client. It releases a possible adaptive hash index
349
  S-latch held by session in InnoDB and also releases a possible InnoDB query
350
  FIFO ticket to enter InnoDB. To save CPU time, InnoDB allows a session to
1183.1.2 by Brian Aker
Rename of handler to Cursor. You would not believe how long I have wanted
351
  keep them over several calls of the InnoDB Cursor interface when a join
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
352
  is executed. But when we let the control to pass to the client they have
353
  to be released because if the application program uses mysql_use_result(),
354
  it may deadlock on the S-latch if the application on another connection
355
  performs another SQL query. In MySQL-4.1 this is even more important because
356
  there a connection can have several SELECT queries open at the same time.
357
358
  @param session           the thread handle of the current connection
359
360
  @return
361
    always 0
362
*/
363
int plugin::StorageEngine::releaseTemporaryLatches(Session *session)
364
{
1183.1.17 by Brian Aker
Added Innodb specific vector (well... for any engine)
365
  for_each(vector_of_transactional_engines.begin(), vector_of_transactional_engines.end(),
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
366
           bind2nd(mem_fun(&plugin::StorageEngine::release_temporary_latches),session));
367
  return 0;
368
}
369
370
bool plugin::StorageEngine::flushLogs(plugin::StorageEngine *engine)
371
{
372
  if (engine == NULL)
373
  {
1217.1.3 by Brian Aker
Remove NameMap from Storage Engine. Modified the cleanup code to just do a
374
    if (find_if(vector_of_engines.begin(), vector_of_engines.end(),
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
375
            mem_fun(&plugin::StorageEngine::flush_logs))
1217.1.3 by Brian Aker
Remove NameMap from Storage Engine. Modified the cleanup code to just do a
376
          != vector_of_engines.begin())
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
377
      return true;
378
  }
379
  else
380
  {
381
    if ((!engine->is_enabled()) ||
382
        (engine->flush_logs()))
383
      return true;
384
  }
385
  return false;
386
}
387
388
/**
389
  recover() step of xa.
390
391
  @note
392
    there are three modes of operation:
393
    - automatic recover after a crash
394
    in this case commit_list != 0, tc_heuristic_recover==0
395
    all xids from commit_list are committed, others are rolled back
396
    - manual (heuristic) recover
397
    in this case commit_list==0, tc_heuristic_recover != 0
398
    DBA has explicitly specified that all prepared transactions should
399
    be committed (or rolled back).
400
    - no recovery (MySQL did not detect a crash)
401
    in this case commit_list==0, tc_heuristic_recover == 0
402
    there should be no prepared transactions in this case.
403
*/
404
class XARecover : unary_function<plugin::StorageEngine *, void>
405
{
406
  int trans_len, found_foreign_xids, found_my_xids;
407
  bool result;
408
  XID *trans_list;
409
  HASH *commit_list;
410
  bool dry_run;
411
public:
412
  XARecover(XID *trans_list_arg, int trans_len_arg,
413
            HASH *commit_list_arg, bool dry_run_arg) 
414
    : trans_len(trans_len_arg), found_foreign_xids(0), found_my_xids(0),
415
      result(false),
416
      trans_list(trans_list_arg), commit_list(commit_list_arg),
417
      dry_run(dry_run_arg)
418
  {}
419
  
420
  int getForeignXIDs()
421
  {
422
    return found_foreign_xids; 
423
  }
424
425
  int getMyXIDs()
426
  {
427
    return found_my_xids; 
428
  }
429
430
  result_type operator() (argument_type engine)
431
  {
432
  
433
    int got;
434
  
435
    if (engine->is_enabled())
436
    {
437
      while ((got= engine->recover(trans_list, trans_len)) > 0 )
438
      {
439
        errmsg_printf(ERRMSG_LVL_INFO,
440
                      _("Found %d prepared transaction(s) in %s"),
441
                      got, engine->getName().c_str());
442
        for (int i=0; i < got; i ++)
443
        {
444
          my_xid x=trans_list[i].get_my_xid();
445
          if (!x) // not "mine" - that is generated by external TM
446
          {
447
            xid_cache_insert(trans_list+i, XA_PREPARED);
448
            found_foreign_xids++;
449
            continue;
450
          }
451
          if (dry_run)
452
          {
453
            found_my_xids++;
454
            continue;
455
          }
456
          // recovery mode
457
          if (commit_list ?
458
              hash_search(commit_list, (unsigned char *)&x, sizeof(x)) != 0 :
459
              tc_heuristic_recover == TC_HEURISTIC_RECOVER_COMMIT)
460
          {
461
            engine->commit_by_xid(trans_list+i);
462
          }
463
          else
464
          {
465
            engine->rollback_by_xid(trans_list+i);
466
          }
467
        }
468
        if (got < trans_len)
469
          break;
470
      }
471
    }
472
  }
473
};
474
475
int plugin::StorageEngine::recover(HASH *commit_list)
476
{
477
  XID *trans_list= NULL;
478
  int trans_len= 0;
479
480
  bool dry_run= (commit_list==0 && tc_heuristic_recover==0);
481
482
  /* commit_list and tc_heuristic_recover cannot be set both */
483
  assert(commit_list==0 || tc_heuristic_recover==0);
484
485
  /* if either is set, total_ha_2pc must be set too */
486
  if (total_ha_2pc <= 1)
487
    return 0;
488
489
490
#ifndef WILL_BE_DELETED_LATER
491
492
  /*
493
    for now, only InnoDB supports 2pc. It means we can always safely
494
    rollback all pending transactions, without risking inconsistent data
495
  */
496
497
  assert(total_ha_2pc == 2); // only InnoDB and binlog
498
  tc_heuristic_recover= TC_HEURISTIC_RECOVER_ROLLBACK; // forcing ROLLBACK
499
  dry_run=false;
500
#endif
501
  for (trans_len= MAX_XID_LIST_SIZE ;
502
       trans_list==0 && trans_len > MIN_XID_LIST_SIZE; trans_len/=2)
503
  {
504
    trans_list=(XID *)malloc(trans_len*sizeof(XID));
505
  }
506
  if (!trans_list)
507
  {
508
    errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_OUTOFMEMORY), trans_len*sizeof(XID));
509
    return(1);
510
  }
511
512
  if (commit_list)
513
    errmsg_printf(ERRMSG_LVL_INFO, _("Starting crash recovery..."));
514
515
516
  XARecover recover_func(trans_list, trans_len, commit_list, dry_run);
1183.1.17 by Brian Aker
Added Innodb specific vector (well... for any engine)
517
  for_each(vector_of_transactional_engines.begin(), vector_of_transactional_engines.end(),
1183.1.16 by Brian Aker
Switch to using vector over Registry
518
           recover_func);
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
519
  free(trans_list);
520
 
521
  if (recover_func.getForeignXIDs())
522
    errmsg_printf(ERRMSG_LVL_WARN,
523
                  _("Found %d prepared XA transactions"),
524
                  recover_func.getForeignXIDs());
525
  if (dry_run && recover_func.getMyXIDs())
526
  {
527
    errmsg_printf(ERRMSG_LVL_ERROR,
528
                  _("Found %d prepared transactions! It means that drizzled "
529
                    "was not shut down properly last time and critical "
530
                    "recovery information (last binlog or %s file) was "
531
                    "manually deleted after a crash. You have to start "
532
                    "drizzled with the --tc-heuristic-recover switch to "
533
                    "commit or rollback pending transactions."),
534
                    recover_func.getMyXIDs(), opt_tc_log_file);
535
    return(1);
536
  }
537
  if (commit_list)
538
    errmsg_printf(ERRMSG_LVL_INFO, _("Crash recovery finished."));
539
  return(0);
540
}
541
542
int plugin::StorageEngine::startConsistentSnapshot(Session *session)
543
{
1183.1.16 by Brian Aker
Switch to using vector over Registry
544
  for_each(vector_of_engines.begin(), vector_of_engines.end(),
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
545
           bind2nd(mem_fun(&plugin::StorageEngine::start_consistent_snapshot),
546
                   session));
547
  return 0;
548
}
549
1200 by Brian Aker
Clean up some mispellings
550
class StorageEngineGetTableDefinition: public unary_function<plugin::StorageEngine *,bool>
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
551
{
1183.1.29 by Brian Aker
Clean up interface so that Truncate sets the propper engine when
552
  Session& session;
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
553
  const char* path;
1183.5.1 by Brian Aker
Extended definition interface (filename building should now be moved
554
  const char *db;
555
  const char *table_name;
556
  const bool is_tmp;
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
557
  message::Table *table_proto;
558
  int *err;
1183.5.1 by Brian Aker
Extended definition interface (filename building should now be moved
559
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
560
public:
1200 by Brian Aker
Clean up some mispellings
561
  StorageEngineGetTableDefinition(Session& session_arg,
562
                                  const char* path_arg,
563
                                  const char *db_arg,
564
                                  const char *table_name_arg,
565
                                  const bool is_tmp_arg,
566
                                  message::Table *table_proto_arg,
567
                                  int *err_arg) :
1183.1.29 by Brian Aker
Clean up interface so that Truncate sets the propper engine when
568
    session(session_arg), 
569
    path(path_arg), 
1183.5.1 by Brian Aker
Extended definition interface (filename building should now be moved
570
    db(db_arg),
571
    table_name(table_name_arg),
572
    is_tmp(is_tmp_arg),
573
    table_proto(table_proto_arg), 
574
    err(err_arg) {}
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
575
576
  result_type operator() (argument_type engine)
577
  {
1183.1.29 by Brian Aker
Clean up interface so that Truncate sets the propper engine when
578
    int ret= engine->doGetTableDefinition(session,
579
                                          path, 
1183.5.1 by Brian Aker
Extended definition interface (filename building should now be moved
580
                                          db,
581
                                          table_name,
582
                                          is_tmp,
583
                                          table_proto);
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
584
585
    if (ret != ENOENT)
586
      *err= ret;
587
588
    return *err == EEXIST;
589
  }
590
};
591
592
static int drizzle_read_table_proto(const char* path, message::Table* table)
593
{
594
  int fd= open(path, O_RDONLY);
595
596
  if (fd == -1)
597
    return errno;
598
599
  google::protobuf::io::ZeroCopyInputStream* input=
600
    new google::protobuf::io::FileInputStream(fd);
601
602
  if (table->ParseFromZeroCopyStream(input) == false)
603
  {
604
    delete input;
605
    close(fd);
606
    return -1;
607
  }
608
609
  delete input;
610
  close(fd);
611
  return 0;
612
}
613
614
/**
1183.1.2 by Brian Aker
Rename of handler to Cursor. You would not believe how long I have wanted
615
  Call this function in order to give the Cursor the possiblity
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
616
  to ask engine if there are any new tables that should be written to disk
617
  or any dropped tables that need to be removed from disk
618
*/
1183.1.29 by Brian Aker
Clean up interface so that Truncate sets the propper engine when
619
int plugin::StorageEngine::getTableDefinition(Session& session,
1223.4.17 by Brian Aker
Added a form of getTableDefinition() that uses TableIdentifiers
620
                                              TableIdentifier &identifier,
621
                                              message::Table *table_proto)
622
{
623
  return getTableDefinition(session,
624
                            identifier.getPath(), identifier.getDBName(), identifier.getTableName(), identifier.isTmp(),
625
                            table_proto);
626
}
627
628
int plugin::StorageEngine::getTableDefinition(Session& session,
1183.1.29 by Brian Aker
Clean up interface so that Truncate sets the propper engine when
629
                                              const char* path,
1183.5.1 by Brian Aker
Extended definition interface (filename building should now be moved
630
                                              const char *,
631
                                              const char *,
632
                                              const bool,
633
                                              message::Table *table_proto)
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
634
{
635
  int err= ENOENT;
636
1183.1.16 by Brian Aker
Switch to using vector over Registry
637
  vector<plugin::StorageEngine *>::iterator iter=
638
    find_if(vector_of_engines.begin(), vector_of_engines.end(),
1200 by Brian Aker
Clean up some mispellings
639
            StorageEngineGetTableDefinition(session, path, NULL, NULL, true, table_proto, &err));
1183.1.16 by Brian Aker
Switch to using vector over Registry
640
641
  if (iter == vector_of_engines.end())
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
642
  {
643
    string proto_path(path);
644
    string file_ext(".dfe");
645
    proto_path.append(file_ext);
646
647
    int error= access(proto_path.c_str(), F_OK);
648
649
    if (error == 0)
650
      err= EEXIST;
651
    else
652
      err= errno;
653
654
    if (table_proto)
655
    {
656
      int read_proto_err= drizzle_read_table_proto(proto_path.c_str(),
657
                                                   table_proto);
658
659
      if (read_proto_err)
660
        err= read_proto_err;
661
    }
662
  }
663
664
  return err;
665
}
666
667
/**
668
  An interceptor to hijack the text of the error message without
669
  setting an error in the thread. We need the text to present it
670
  in the form of a warning to the user.
671
*/
672
673
class Ha_delete_table_error_handler: public Internal_error_handler
674
{
675
public:
676
  Ha_delete_table_error_handler() : Internal_error_handler() {}
677
  virtual bool handle_error(uint32_t sql_errno,
678
                            const char *message,
679
                            DRIZZLE_ERROR::enum_warning_level level,
680
                            Session *session);
681
  char buff[DRIZZLE_ERRMSG_SIZE];
682
};
683
684
685
bool
686
Ha_delete_table_error_handler::
687
handle_error(uint32_t ,
688
             const char *message,
689
             DRIZZLE_ERROR::enum_warning_level ,
690
             Session *)
691
{
692
  /* Grab the error message */
693
  strncpy(buff, message, sizeof(buff)-1);
694
  return true;
695
}
696
697
698
/**
699
  This should return ENOENT if the file doesn't exists.
700
  The .frm file will be deleted only if we return 0 or ENOENT
701
*/
1223.4.16 by Brian Aker
Drop Table now uses identifier.
702
int plugin::StorageEngine::dropTable(Session& session,
703
                                     TableIdentifier &identifier,
1183.1.22 by Brian Aker
Merge Name changes
704
                                     bool generate_warning)
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
705
{
1183.1.8 by Brian Aker
Reworked delete table code (thank god... or... whatever... how about my dog?
706
  int error= 0;
707
  int error_proto;
708
  message::Table src_proto;
709
  plugin::StorageEngine* engine;
710
1183.1.29 by Brian Aker
Clean up interface so that Truncate sets the propper engine when
711
  error_proto= plugin::StorageEngine::getTableDefinition(session,
1223.4.17 by Brian Aker
Added a form of getTableDefinition() that uses TableIdentifiers
712
                                                         identifier,
1183.5.1 by Brian Aker
Extended definition interface (filename building should now be moved
713
                                                         &src_proto);
1183.1.8 by Brian Aker
Reworked delete table code (thank god... or... whatever... how about my dog?
714
715
  engine= plugin::StorageEngine::findByName(session,
716
                                            src_proto.engine().name());
717
718
  if (engine)
1183.1.9 by Brian Aker
Rename deleteTableImpl -> doDeleteTable()
719
  {
720
    engine->setTransactionReadWrite(session);
1223.4.16 by Brian Aker
Drop Table now uses identifier.
721
    error= engine->doDropTable(session, identifier.getPath());
1183.1.9 by Brian Aker
Rename deleteTableImpl -> doDeleteTable()
722
  }
1183.1.8 by Brian Aker
Reworked delete table code (thank god... or... whatever... how about my dog?
723
724
  if (error != ENOENT)
725
  {
726
    if (error == 0)
727
    {
728
      if (engine && engine->check_flag(HTON_BIT_HAS_DATA_DICTIONARY))
1237.6.12 by Brian Aker
Adding patch for engine methods for definition files.
729
      {
730
        deleteDefinitionFromPath(identifier);
731
      }
1183.1.8 by Brian Aker
Reworked delete table code (thank god... or... whatever... how about my dog?
732
      else
1237.6.12 by Brian Aker
Adding patch for engine methods for definition files.
733
      {
734
        error= deleteDefinitionFromPath(identifier);
735
      }
1183.1.8 by Brian Aker
Reworked delete table code (thank god... or... whatever... how about my dog?
736
    }
737
  }
738
739
  if (error_proto && error == 0)
740
    return 0;
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
741
742
  if (error && generate_warning)
743
  {
744
    /*
1216.1.1 by Brian Aker
Move print_error up to Engine.
745
      Because engine->print_error() use my_error() to generate the error message
1183.1.2 by Brian Aker
Rename of handler to Cursor. You would not believe how long I have wanted
746
      we use an internal error Cursor to intercept it and store the text
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
747
      in a temporary buffer. Later the message will be presented to user
748
      as a warning.
749
    */
750
    Ha_delete_table_error_handler ha_delete_table_error_handler;
751
1216.1.1 by Brian Aker
Move print_error up to Engine.
752
    session.push_internal_handler(&ha_delete_table_error_handler);
753
    engine->print_error(error, 0);
754
755
    session.pop_internal_handler();
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
756
757
    /*
758
      XXX: should we convert *all* errors to warnings here?
759
      What if the error is fatal?
760
    */
1183.1.29 by Brian Aker
Clean up interface so that Truncate sets the propper engine when
761
    push_warning(&session, DRIZZLE_ERROR::WARN_LEVEL_ERROR, error,
1130.1.12 by Monty Taylor
Moved service stuff into plugin/
762
                 ha_delete_table_error_handler.buff);
763
  }
764
765
  return error;
766
}
767
971.1.38 by Monty Taylor
Moved delete table.
768
/**
769
  Initiates table-file and calls appropriate database-creator.
770
771
  @retval
772
   0  ok
773
  @retval
774
   1  error
1220.1.14 by Brian Aker
Updated fix for create table like.
775
1222.1.8 by Brian Aker
Remove check_table()
776
   @todo refactor to remove goto
971.1.38 by Monty Taylor
Moved delete table.
777
*/
1223.4.15 by Brian Aker
Final step to make createTable() use the TableIdentifier.
778
int plugin::StorageEngine::createTable(Session& session,
779
                                       TableIdentifier &identifier,
1160.1.1 by Brian Aker
Refactor SE createTable back to engine class.
780
                                       bool update_create_info,
1183.1.18 by Brian Aker
Fixed references to doCreateTable()
781
                                       drizzled::message::Table& table_proto, bool proto_used)
971.1.38 by Monty Taylor
Moved delete table.
782
{
783
  int error= 1;
784
  Table table;
1223.4.15 by Brian Aker
Final step to make createTable() use the TableIdentifier.
785
  TableShare share(identifier.getDBName(), 0, identifier.getTableName(), identifier.getPath());
1130.3.16 by Monty Taylor
Moved the last three methods from plugin/storage_engine.cc to be static methods on StorageEngine.
786
  message::Table tmp_proto;
971.1.38 by Monty Taylor
Moved delete table.
787
1183.1.18 by Brian Aker
Fixed references to doCreateTable()
788
  if (proto_used)
1095.3.16 by Stewart Smith
Remove requirement of having to re-read table proto on CREATE TABLE. Now we only have to do it if we didn't have a table_proto passed to ha_create_table.
789
  {
1183.1.18 by Brian Aker
Fixed references to doCreateTable()
790
    if (parse_table_proto(session, table_proto, &share))
1095.3.16 by Stewart Smith
Remove requirement of having to re-read table proto on CREATE TABLE. Now we only have to do it if we didn't have a table_proto passed to ha_create_table.
791
      goto err;
792
  }
793
  else
794
  {
795
    if (open_table_def(session, &share))
796
      goto err;
797
  }
798
1183.1.29 by Brian Aker
Clean up interface so that Truncate sets the propper engine when
799
  if (open_table_from_share(&session, &share, "", 0, (uint32_t) READ_ALL, 0,
1217.1.1 by Brian Aker
Remove open_table_mode (no longer in use).
800
                            &table))
971.1.38 by Monty Taylor
Moved delete table.
801
    goto err;
802
803
  if (update_create_info)
1222.1.7 by Brian Aker
Remove HA_CREATE_INFO from createTable()
804
    table.updateCreateInfo(&table_proto);
971.1.38 by Monty Taylor
Moved delete table.
805
1220.1.14 by Brian Aker
Updated fix for create table like.
806
  /* Check for legal operations against the Engine using the proto (if used) */
807
  if (proto_used)
808
  {
1235.1.11 by Brian Aker
Small cleanups, did in MERGE table only engine flag.
809
    if (table_proto.type() == message::Table::TEMPORARY &&
1220.1.14 by Brian Aker
Updated fix for create table like.
810
        share.storage_engine->check_flag(HTON_BIT_TEMPORARY_NOT_SUPPORTED) == true)
811
    {
812
      error= HA_ERR_UNSUPPORTED;
813
      goto err2;
814
    }
1235.1.11 by Brian Aker
Small cleanups, did in MERGE table only engine flag.
815
    else if (table_proto.type() != message::Table::TEMPORARY &&
1220.1.14 by Brian Aker
Updated fix for create table like.
816
             share.storage_engine->check_flag(HTON_BIT_TEMPORARY_ONLY) == true)
817
    {
818
      error= HA_ERR_UNSUPPORTED;
819
      goto err2;
820
    }
821
  }
822
1222.1.8 by Brian Aker
Remove check_table()
823
  if (! share.storage_engine->is_enabled())
824
  {
825
    error= HA_ERR_UNSUPPORTED;
826
    goto err2;
827
  }
828
1220.1.14 by Brian Aker
Updated fix for create table like.
829
1183.1.6 by Brian Aker
Simplify createTable()
830
  {
831
    char name_buff[FN_REFLEN];
832
    const char *table_name_arg;
833
1223.4.15 by Brian Aker
Final step to make createTable() use the TableIdentifier.
834
    table_name_arg= share.storage_engine->checkLowercaseNames(identifier.getPath(), name_buff);
1183.1.6 by Brian Aker
Simplify createTable()
835
836
    share.storage_engine->setTransactionReadWrite(session);
837
1235.1.11 by Brian Aker
Small cleanups, did in MERGE table only engine flag.
838
    error= share.storage_engine->doCreateTable(&session,
1222.1.7 by Brian Aker
Remove HA_CREATE_INFO from createTable()
839
                                               table_name_arg,
840
                                               table,
841
                                               table_proto);
1183.1.6 by Brian Aker
Simplify createTable()
842
  }
843
1220.1.14 by Brian Aker
Updated fix for create table like.
844
err2:
971.1.38 by Monty Taylor
Moved delete table.
845
  table.closefrm(false);
1220.1.14 by Brian Aker
Updated fix for create table like.
846
971.1.38 by Monty Taylor
Moved delete table.
847
  if (error)
848
  {
1095.3.14 by Brian Aker
Moved file based flag up to engine (from handler). checkLowercaseNames() is now a ember of StorageEngine.
849
    char name_buff[FN_REFLEN];
1223.4.15 by Brian Aker
Final step to make createTable() use the TableIdentifier.
850
    sprintf(name_buff,"%s.%s", identifier.getDBName(), identifier.getTableName());
971.1.38 by Monty Taylor
Moved delete table.
851
    my_error(ER_CANT_CREATE_TABLE, MYF(ME_BELL+ME_WAITTANG), name_buff, error);
852
  }
853
err:
1000.1.5 by Brian Aker
More refactoring back to TableShare object.
854
  share.free_table_share();
971.1.38 by Monty Taylor
Moved delete table.
855
  return(error != 0);
856
}
857
1253.1.3 by Monty Taylor
MEM_ROOT == memory::Root
858
Cursor *plugin::StorageEngine::getCursor(TableShare &share, memory::Root *alloc)
1183.1.1 by Brian Aker
Rework interface pieces on SE (sort of... dumb ones...)
859
{
860
  assert(enabled);
1220.1.4 by Brian Aker
Merge Brian (first pass of this cleanup)
861
  return create(share, alloc);
1183.1.1 by Brian Aker
Rework interface pieces on SE (sort of... dumb ones...)
862
}
1160.1.1 by Brian Aker
Refactor SE createTable back to engine class.
863
1198 by Brian Aker
Merge Brian
864
/**
865
  TODO -> Remove this to force all engines to implement their own file. Solves the "we only looked at dfe" problem.
866
*/
1183.1.13 by Brian Aker
Fix pass by reference for directory object
867
void plugin::StorageEngine::doGetTableNames(CachedDirectory &directory, string&, set<string>& set_of_names)
1183.1.5 by Brian Aker
Reworked getTableNames() interface. Way simpler, less mallocs....
868
{
869
  CachedDirectory::Entries entries= directory.getEntries();
870
871
  for (CachedDirectory::Entries::iterator entry_iter= entries.begin(); 
872
       entry_iter != entries.end(); ++entry_iter)
873
  {
874
    CachedDirectory::Entry *entry= *entry_iter;
875
    string *filename= &entry->filename;
876
877
    assert(filename->size());
878
879
    const char *ext= strchr(filename->c_str(), '.');
880
1198 by Brian Aker
Merge Brian
881
    if (ext == NULL || my_strcasecmp(system_charset_info, ext, DEFAULT_DEFINITION_FILE_EXT.c_str()) ||
1241.9.12 by Monty Taylor
Trims more out of server_includes.h.
882
        (filename->compare(0, strlen(TMP_FILE_PREFIX), TMP_FILE_PREFIX) == 0))
1183.1.5 by Brian Aker
Reworked getTableNames() interface. Way simpler, less mallocs....
883
    { }
884
    else
885
    {
886
      char uname[NAME_LEN + 1];
887
      uint32_t file_name_len;
888
889
      file_name_len= filename_to_tablename(filename->c_str(), uname, sizeof(uname));
890
      // TODO: Remove need for memory copy here
891
      uname[file_name_len - sizeof(".dfe") + 1]= '\0'; // Subtract ending, place NULL 
1183.1.13 by Brian Aker
Fix pass by reference for directory object
892
      set_of_names.insert(uname);
1183.1.5 by Brian Aker
Reworked getTableNames() interface. Way simpler, less mallocs....
893
    }
894
  }
895
}
896
1183.1.14 by Brian Aker
Style cleanup
897
class AddTableName : 
898
  public unary_function<plugin::StorageEngine *, void>
1183.1.5 by Brian Aker
Reworked getTableNames() interface. Way simpler, less mallocs....
899
{
900
  string db;
901
  CachedDirectory& directory;
1183.1.13 by Brian Aker
Fix pass by reference for directory object
902
  set<string>& set_of_names;
1183.1.5 by Brian Aker
Reworked getTableNames() interface. Way simpler, less mallocs....
903
904
public:
905
906
  AddTableName(CachedDirectory& directory_arg, string& database_name, set<string>& of_names) :
1183.1.13 by Brian Aker
Fix pass by reference for directory object
907
    directory(directory_arg),
908
    set_of_names(of_names)
1183.1.5 by Brian Aker
Reworked getTableNames() interface. Way simpler, less mallocs....
909
  {
910
    db= database_name;
911
  }
912
913
  result_type operator() (argument_type engine)
914
  {
915
    engine->doGetTableNames(directory, db, set_of_names);
916
  }
917
};
918
919
void plugin::StorageEngine::getTableNames(string& db, set<string>& set_of_names)
920
{
921
  char tmp_path[FN_REFLEN];
922
923
  build_table_filename(tmp_path, sizeof(tmp_path), db.c_str(), "", false);
924
1183.1.27 by Brian Aker
Fix issue where there are too many files in data directory. We now only
925
  CachedDirectory directory(tmp_path, set_of_table_definition_ext);
1183.1.5 by Brian Aker
Reworked getTableNames() interface. Way simpler, less mallocs....
926
1183.1.15 by Brian Aker
I_S now provides its own tables via the SE interface
927
  if (db.compare("information_schema"))
1183.1.12 by Brian Aker
Slight cleanup of the interface (no need to keep checking CachedDirectory
928
  {
1183.1.15 by Brian Aker
I_S now provides its own tables via the SE interface
929
    if (directory.fail())
930
    {
1241.9.57 by Monty Taylor
Oy. Bigger change than I normally like - but this stuff is all intertwined.
931
      errno= directory.getError();
932
      if (errno == ENOENT)
1183.1.15 by Brian Aker
I_S now provides its own tables via the SE interface
933
        my_error(ER_BAD_DB_ERROR, MYF(ME_BELL+ME_WAITTANG), db.c_str());
934
      else
1241.9.57 by Monty Taylor
Oy. Bigger change than I normally like - but this stuff is all intertwined.
935
        my_error(ER_CANT_READ_DIR, MYF(ME_BELL+ME_WAITTANG), directory.getPath(), errno);
1183.1.15 by Brian Aker
I_S now provides its own tables via the SE interface
936
      return;
937
    }
1183.1.12 by Brian Aker
Slight cleanup of the interface (no need to keep checking CachedDirectory
938
  }
939
1183.1.5 by Brian Aker
Reworked getTableNames() interface. Way simpler, less mallocs....
940
  for_each(vector_of_engines.begin(), vector_of_engines.end(),
941
           AddTableName(directory, db, set_of_names));
942
}
943
1213 by Brian Aker
Fixes startup failures when temporary tables were left behind in a crash.
944
/* This will later be converted to TableIdentifiers */
945
class DropTables: public unary_function<plugin::StorageEngine *, void>
946
{
947
  Session &session;
948
  set<string>& set_of_names;
949
950
public:
951
952
  DropTables(Session &session_arg, set<string>& of_names) :
953
    session(session_arg),
954
    set_of_names(of_names)
955
  { }
956
957
  result_type operator() (argument_type engine)
958
  {
959
960
    for (set<string>::iterator iter= set_of_names.begin();
961
         iter != set_of_names.end();
962
         iter++)
963
    {
964
      int error= engine->doDropTable(session, *iter);
965
966
      // On a return of zero we know we found and deleted the table. So we
967
      // remove it from our search.
968
      if (! error)
969
        set_of_names.erase(iter);
970
    }
971
  }
972
};
973
974
/*
975
  This only works for engines which use file based DFE.
976
977
  Note-> Unlike MySQL, we do not, on purpose, delete files that do not match any engines. 
978
*/
979
void plugin::StorageEngine::removeLostTemporaryTables(Session &session, const char *directory)
980
{
981
  CachedDirectory dir(directory, set_of_table_definition_ext);
982
  set<string> set_of_table_names;
983
984
  if (dir.fail())
985
  {
1241.9.57 by Monty Taylor
Oy. Bigger change than I normally like - but this stuff is all intertwined.
986
    errno= dir.getError();
987
    my_error(ER_CANT_READ_DIR, MYF(0), directory, errno);
1213 by Brian Aker
Fixes startup failures when temporary tables were left behind in a crash.
988
989
    return;
990
  }
991
992
  CachedDirectory::Entries files= dir.getEntries();
993
994
  for (CachedDirectory::Entries::iterator fileIter= files.begin();
995
       fileIter != files.end(); fileIter++)
996
  {
997
    size_t length;
998
    string path;
999
    CachedDirectory::Entry *entry= *fileIter;
1000
1001
    /* We remove the file extension. */
1002
    length= entry->filename.length();
1003
    entry->filename.resize(length - DEFAULT_DEFINITION_FILE_EXT.length());
1004
1005
    path+= directory;
1006
    path+= FN_LIBCHAR;
1007
    path+= entry->filename;
1008
    set_of_table_names.insert(path);
1009
  }
1010
1011
  for_each(vector_of_engines.begin(), vector_of_engines.end(),
1012
           DropTables(session, set_of_table_names));
1013
  
1014
  /*
1015
    Now we just clean up anything that might left over.
1016
1017
    We rescan because some of what might have been there should
1018
    now be all nice and cleaned up.
1019
  */
1020
  set<string> all_exts= set_of_table_definition_ext;
1021
1022
  for (vector<plugin::StorageEngine *>::iterator iter= vector_of_engines.begin();
1023
       iter != vector_of_engines.end() ; iter++)
1024
  {
1025
    for (const char **ext= (*iter)->bas_ext(); *ext ; ext++)
1026
      all_exts.insert(*ext);
1027
  }
1028
1029
  CachedDirectory rescan(directory, all_exts);
1030
1031
  files= rescan.getEntries();
1032
  for (CachedDirectory::Entries::iterator fileIter= files.begin();
1033
       fileIter != files.end(); fileIter++)
1034
  {
1035
    string path;
1036
    CachedDirectory::Entry *entry= *fileIter;
1037
1038
    path+= directory;
1039
    path+= FN_LIBCHAR;
1040
    path+= entry->filename;
1041
1042
    unlink(path.c_str());
1043
  }
1044
}
1045
1160.1.1 by Brian Aker
Refactor SE createTable back to engine class.
1046
1216.1.1 by Brian Aker
Move print_error up to Engine.
1047
/**
1048
  Print error that we got from Cursor function.
1049
1050
  @note
1051
    In case of delete table it's only safe to use the following parts of
1052
    the 'table' structure:
1053
    - table->s->path
1054
    - table->alias
1055
*/
1056
void plugin::StorageEngine::print_error(int error, myf errflag, Table &table)
1057
{
1058
  print_error(error, errflag, &table);
1059
}
1060
1061
void plugin::StorageEngine::print_error(int error, myf errflag, Table *table)
1062
{
1063
  int textno= ER_GET_ERRNO;
1064
  switch (error) {
1065
  case EACCES:
1066
    textno=ER_OPEN_AS_READONLY;
1067
    break;
1068
  case EAGAIN:
1069
    textno=ER_FILE_USED;
1070
    break;
1071
  case ENOENT:
1072
    textno=ER_FILE_NOT_FOUND;
1073
    break;
1074
  case HA_ERR_KEY_NOT_FOUND:
1075
  case HA_ERR_NO_ACTIVE_RECORD:
1076
  case HA_ERR_END_OF_FILE:
1077
    textno=ER_KEY_NOT_FOUND;
1078
    break;
1079
  case HA_ERR_WRONG_MRG_TABLE_DEF:
1080
    textno=ER_WRONG_MRG_TABLE;
1081
    break;
1082
  case HA_ERR_FOUND_DUPP_KEY:
1083
  {
1084
    assert(table);
1085
    uint32_t key_nr= table->get_dup_key(error);
1086
    if ((int) key_nr >= 0)
1087
    {
1088
      const char *err_msg= ER(ER_DUP_ENTRY_WITH_KEY_NAME);
1089
1090
      if (key_nr == 0 &&
1091
          (table->key_info[0].key_part[0].field->flags &
1092
           AUTO_INCREMENT_FLAG)
1093
          && (current_session)->lex->sql_command == SQLCOM_ALTER_TABLE)
1094
      {
1095
        err_msg= ER(ER_DUP_ENTRY_AUTOINCREMENT_CASE);
1096
      }
1097
1098
      print_keydup_error(key_nr, err_msg, *table);
1099
      return;
1100
    }
1101
    textno=ER_DUP_KEY;
1102
    break;
1103
  }
1104
  case HA_ERR_FOREIGN_DUPLICATE_KEY:
1105
  {
1106
    assert(table);
1107
    uint32_t key_nr= table->get_dup_key(error);
1108
    if ((int) key_nr >= 0)
1109
    {
1110
      uint32_t max_length;
1111
1112
      /* Write the key in the error message */
1113
      char key[MAX_KEY_LENGTH];
1114
      String str(key,sizeof(key),system_charset_info);
1115
1116
      /* Table is opened and defined at this point */
1117
      key_unpack(&str,table,(uint32_t) key_nr);
1118
      max_length= (DRIZZLE_ERRMSG_SIZE-
1119
                   (uint32_t) strlen(ER(ER_FOREIGN_DUPLICATE_KEY)));
1120
      if (str.length() >= max_length)
1121
      {
1122
        str.length(max_length-4);
1123
        str.append(STRING_WITH_LEN("..."));
1124
      }
1125
      my_error(ER_FOREIGN_DUPLICATE_KEY, MYF(0), table->s->table_name.str,
1126
        str.c_ptr(), key_nr+1);
1127
      return;
1128
    }
1129
    textno= ER_DUP_KEY;
1130
    break;
1131
  }
1132
  case HA_ERR_FOUND_DUPP_UNIQUE:
1133
    textno=ER_DUP_UNIQUE;
1134
    break;
1135
  case HA_ERR_RECORD_CHANGED:
1136
    textno=ER_CHECKREAD;
1137
    break;
1138
  case HA_ERR_CRASHED:
1139
    textno=ER_NOT_KEYFILE;
1140
    break;
1141
  case HA_ERR_WRONG_IN_RECORD:
1142
    textno= ER_CRASHED_ON_USAGE;
1143
    break;
1144
  case HA_ERR_CRASHED_ON_USAGE:
1145
    textno=ER_CRASHED_ON_USAGE;
1146
    break;
1147
  case HA_ERR_NOT_A_TABLE:
1148
    textno= error;
1149
    break;
1150
  case HA_ERR_CRASHED_ON_REPAIR:
1151
    textno=ER_CRASHED_ON_REPAIR;
1152
    break;
1153
  case HA_ERR_OUT_OF_MEM:
1154
    textno=ER_OUT_OF_RESOURCES;
1155
    break;
1156
  case HA_ERR_WRONG_COMMAND:
1157
    textno=ER_ILLEGAL_HA;
1158
    break;
1159
  case HA_ERR_OLD_FILE:
1160
    textno=ER_OLD_KEYFILE;
1161
    break;
1162
  case HA_ERR_UNSUPPORTED:
1163
    textno=ER_UNSUPPORTED_EXTENSION;
1164
    break;
1165
  case HA_ERR_RECORD_FILE_FULL:
1166
  case HA_ERR_INDEX_FILE_FULL:
1167
    textno=ER_RECORD_FILE_FULL;
1168
    break;
1169
  case HA_ERR_LOCK_WAIT_TIMEOUT:
1170
    textno=ER_LOCK_WAIT_TIMEOUT;
1171
    break;
1172
  case HA_ERR_LOCK_TABLE_FULL:
1173
    textno=ER_LOCK_TABLE_FULL;
1174
    break;
1175
  case HA_ERR_LOCK_DEADLOCK:
1176
    textno=ER_LOCK_DEADLOCK;
1177
    break;
1178
  case HA_ERR_READ_ONLY_TRANSACTION:
1179
    textno=ER_READ_ONLY_TRANSACTION;
1180
    break;
1181
  case HA_ERR_CANNOT_ADD_FOREIGN:
1182
    textno=ER_CANNOT_ADD_FOREIGN;
1183
    break;
1184
  case HA_ERR_ROW_IS_REFERENCED:
1185
  {
1186
    String str;
1187
    get_error_message(error, &str);
1188
    my_error(ER_ROW_IS_REFERENCED_2, MYF(0), str.c_ptr_safe());
1189
    return;
1190
  }
1191
  case HA_ERR_NO_REFERENCED_ROW:
1192
  {
1193
    String str;
1194
    get_error_message(error, &str);
1195
    my_error(ER_NO_REFERENCED_ROW_2, MYF(0), str.c_ptr_safe());
1196
    return;
1197
  }
1198
  case HA_ERR_TABLE_DEF_CHANGED:
1199
    textno=ER_TABLE_DEF_CHANGED;
1200
    break;
1201
  case HA_ERR_NO_SUCH_TABLE:
1202
    assert(table);
1203
    my_error(ER_NO_SUCH_TABLE, MYF(0), table->s->db.str,
1204
             table->s->table_name.str);
1205
    return;
1206
  case HA_ERR_RBR_LOGGING_FAILED:
1207
    textno= ER_BINLOG_ROW_LOGGING_FAILED;
1208
    break;
1209
  case HA_ERR_DROP_INDEX_FK:
1210
  {
1211
    assert(table);
1212
    const char *ptr= "???";
1213
    uint32_t key_nr= table->get_dup_key(error);
1214
    if ((int) key_nr >= 0)
1215
      ptr= table->key_info[key_nr].name;
1216
    my_error(ER_DROP_INDEX_FK, MYF(0), ptr);
1217
    return;
1218
  }
1219
  case HA_ERR_TABLE_NEEDS_UPGRADE:
1220
    textno=ER_TABLE_NEEDS_UPGRADE;
1221
    break;
1222
  case HA_ERR_TABLE_READONLY:
1223
    textno= ER_OPEN_AS_READONLY;
1224
    break;
1225
  case HA_ERR_AUTOINC_READ_FAILED:
1226
    textno= ER_AUTOINC_READ_FAILED;
1227
    break;
1228
  case HA_ERR_AUTOINC_ERANGE:
1229
    textno= ER_WARN_DATA_OUT_OF_RANGE;
1230
    break;
1231
  case HA_ERR_LOCK_OR_ACTIVE_TRANSACTION:
1232
    my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
1233
               ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
1234
    return;
1235
  default:
1236
    {
1237
      /* 
1238
        The error was "unknown" to this function.
1239
        Ask Cursor if it has got a message for this error 
1240
      */
1241
      bool temporary= false;
1242
      String str;
1243
      temporary= get_error_message(error, &str);
1244
      if (!str.is_empty())
1245
      {
1246
        const char* engine_name= getName().c_str();
1247
        if (temporary)
1248
          my_error(ER_GET_TEMPORARY_ERRMSG, MYF(0), error, str.ptr(),
1249
                   engine_name);
1250
        else
1251
          my_error(ER_GET_ERRMSG, MYF(0), error, str.ptr(), engine_name);
1252
      }
1253
      else
1254
      {
1255
	      my_error(ER_GET_ERRNO,errflag,error);
1256
      }
1257
      return;
1258
    }
1259
  }
1260
  my_error(textno, errflag, table->s->table_name.str, error);
1261
}
1262
1263
1264
/**
1265
  Return an error message specific to this Cursor.
1266
1267
  @param error  error code previously returned by Cursor
1268
  @param buf    pointer to String where to add error message
1269
1270
  @return
1271
    Returns true if this is a temporary error
1272
*/
1273
bool plugin::StorageEngine::get_error_message(int , String* )
1274
{
1275
  return false;
1276
}
1277
1278
1279
void plugin::StorageEngine::print_keydup_error(uint32_t key_nr, const char *msg, Table &table)
1280
{
1281
  /* Write the duplicated key in the error message */
1282
  char key[MAX_KEY_LENGTH];
1283
  String str(key,sizeof(key),system_charset_info);
1284
1285
  if (key_nr == MAX_KEY)
1286
  {
1287
    /* Key is unknown */
1288
    str.copy("", 0, system_charset_info);
1289
    my_printf_error(ER_DUP_ENTRY, msg, MYF(0), str.c_ptr(), "*UNKNOWN*");
1290
  }
1291
  else
1292
  {
1293
    /* Table is opened and defined at this point */
1294
    key_unpack(&str, &table, (uint32_t) key_nr);
1295
    uint32_t max_length=DRIZZLE_ERRMSG_SIZE-(uint32_t) strlen(msg);
1296
    if (str.length() >= max_length)
1297
    {
1298
      str.length(max_length-4);
1299
      str.append(STRING_WITH_LEN("..."));
1300
    }
1301
    my_printf_error(ER_DUP_ENTRY, msg,
1302
		    MYF(0), str.c_ptr(), table.key_info[key_nr].name);
1303
  }
1304
}
1305
1237.6.12 by Brian Aker
Adding patch for engine methods for definition files.
1306
1307
int plugin::StorageEngine::deleteDefinitionFromPath(TableIdentifier &identifier)
1308
{
1309
  string path(identifier.getPath());
1310
1311
  path.append(DEFAULT_DEFINITION_FILE_EXT);
1312
1313
  return my_delete(path.c_str(), MYF(0));
1314
}
1315
1316
int plugin::StorageEngine::renameDefinitionFromPath(TableIdentifier &dest, TableIdentifier &src)
1317
{
1318
  string src_path(src.getPath());
1319
  string dest_path(dest.getPath());
1320
1321
  src_path.append(DEFAULT_DEFINITION_FILE_EXT);
1322
  dest_path.append(DEFAULT_DEFINITION_FILE_EXT);
1323
1324
  return my_rename(src_path.c_str(), dest_path.c_str(), MYF(MY_WME));
1325
}
1326
1327
int plugin::StorageEngine::writeDefinitionFromPath(TableIdentifier &identifier, message::Table &table_proto)
1328
{
1329
  string file_name(identifier.getPath());
1330
1331
  file_name.append(DEFAULT_DEFINITION_FILE_EXT);
1332
1333
  int fd= open(file_name.c_str(), O_RDWR|O_CREAT|O_TRUNC, my_umask);
1334
1335
  if (fd == -1)
1336
    return errno;
1337
1338
  google::protobuf::io::ZeroCopyOutputStream* output=
1339
    new google::protobuf::io::FileOutputStream(fd);
1340
1341
  if (table_proto.SerializeToZeroCopyStream(output) == false)
1342
  {
1343
    delete output;
1344
    close(fd);
1345
    return errno;
1346
  }
1347
1348
  delete output;
1349
  close(fd);
1350
  return 0;
1351
}
1352
1353
1160.1.1 by Brian Aker
Refactor SE createTable back to engine class.
1354
} /* namespace drizzled */