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