99
98
return ( a->begin > b->begin ? 1 : ( a->begin < b->begin ? -1 : 0 ) );
104
If frm_error() is called in table.cc this is called to find out what file
105
extensions exist for this Cursor.
107
static const char *ha_tina_exts[] = {
113
class Tina : public drizzled::plugin::StorageEngine
115
typedef std::map<string, TinaShare*> TinaMap;
116
TinaMap tina_open_tables;
101
static unsigned char* tina_get_key(TINA_SHARE *share, size_t *length, bool)
103
*length=share->table_name_length;
104
return (unsigned char*) share->table_name;
107
class Tina : public StorageEngine
118
110
Tina(const string& name_arg)
119
: drizzled::plugin::StorageEngine(name_arg,
120
HTON_TEMPORARY_ONLY |
121
HTON_NO_AUTO_INCREMENT |
122
HTON_SKIP_STORE_LOCK |
128
pthread_mutex_destroy(&tina_mutex);
131
virtual Cursor *create(TableShare &table,
132
drizzled::memory::Root *mem_root)
134
return new (mem_root) ha_tina(*this, table);
137
const char **bas_ext() const {
141
int doCreateTable(Session &,
143
drizzled::TableIdentifier &identifier,
144
drizzled::message::Table&);
146
int doGetTableDefinition(Session& session,
147
TableIdentifier &identifier,
148
drizzled::message::Table &table_message);
150
/* Temp only engine, so do not return values. */
151
void doGetTableNames(drizzled::CachedDirectory &, SchemaIdentifier&, set<string>&) { };
153
int doDropTable(Session&, TableIdentifier &identifier);
154
TinaShare *findOpenTable(const string table_name);
155
void addOpenTable(const string &table_name, TinaShare *);
156
void deleteOpenTable(const string &table_name);
159
uint32_t max_keys() const { return 0; }
160
uint32_t max_key_parts() const { return 0; }
161
uint32_t max_key_length() const { return 0; }
162
bool doDoesTableExist(Session& session, TableIdentifier &identifier);
163
int doRenameTable(Session&, TableIdentifier &from, TableIdentifier &to);
165
void doGetTableIdentifiers(drizzled::CachedDirectory &directory,
166
drizzled::SchemaIdentifier &schema_identifier,
167
drizzled::TableIdentifiers &set_of_identifiers);
111
: StorageEngine(name_arg, HTON_CAN_RECREATE | HTON_SUPPORT_LOG_TABLES |
112
HTON_NO_PARTITION) {}
113
virtual handler *create(TABLE_SHARE *table,
116
return new (mem_root) ha_tina(this, table);
170
void Tina::doGetTableIdentifiers(drizzled::CachedDirectory&,
171
drizzled::SchemaIdentifier&,
172
drizzled::TableIdentifiers&)
176
int Tina::doRenameTable(Session &session,
177
TableIdentifier &from, TableIdentifier &to)
180
for (const char **ext= bas_ext(); *ext ; ext++)
182
if (rename_file_ext(from.getPath().c_str(), to.getPath().c_str(), *ext))
184
if ((error=errno) != ENOENT)
190
session.renameTableMessage(from, to);
195
bool Tina::doDoesTableExist(Session &session, TableIdentifier &identifier)
197
return session.doesTableMessageExist(identifier);
201
int Tina::doDropTable(Session &session,
202
TableIdentifier &identifier)
205
int enoent_or_zero= ENOENT; // Error if no file was deleted
206
char buff[FN_REFLEN];
208
for (const char **ext= bas_ext(); *ext ; ext++)
210
internal::fn_format(buff, identifier.getPath().c_str(), "", *ext,
211
MY_UNPACK_FILENAME|MY_APPEND_EXT);
212
if (internal::my_delete_with_symlink(buff, MYF(0)))
214
if ((error= errno) != ENOENT)
218
enoent_or_zero= 0; // No error for ENOENT
219
error= enoent_or_zero;
222
session.removeTableMessage(identifier);
227
TinaShare *Tina::findOpenTable(const string table_name)
229
TinaMap::iterator find_iter=
230
tina_open_tables.find(table_name);
232
if (find_iter != tina_open_tables.end())
233
return (*find_iter).second;
238
void Tina::addOpenTable(const string &table_name, TinaShare *share)
240
tina_open_tables[table_name]= share;
243
void Tina::deleteOpenTable(const string &table_name)
245
tina_open_tables.erase(table_name);
249
int Tina::doGetTableDefinition(Session &session,
250
drizzled::TableIdentifier &identifier,
251
drizzled::message::Table &table_message)
253
if (session.getTableMessage(identifier, table_message))
260
120
static Tina *tina_engine= NULL;
262
static int tina_init_func(drizzled::plugin::Context &context)
122
static int tina_init_func(PluginRegistry ®istry)
265
tina_engine= new Tina("CSV");
266
context.add(tina_engine);
125
tina_engine= new Tina(engine_name);
126
registry.add(tina_engine);
268
128
pthread_mutex_init(&tina_mutex,MY_MUTEX_INIT_FAST);
274
TinaShare::TinaShare(const char *table_name_arg)
275
: table_name(table_name_arg), use_count(0), saved_data_file_length(0),
276
update_file_opened(false), tina_write_opened(false),
277
crashed(false), rows_recorded(0), data_file_version(0)
279
thr_lock_init(&lock);
280
internal::fn_format(data_file_name, table_name_arg, "", CSV_EXT,
281
MY_REPLACE_EXT|MY_UNPACK_FILENAME);
284
TinaShare::~TinaShare()
286
thr_lock_delete(&lock);
287
pthread_mutex_destroy(&mutex);
129
(void) hash_init(&tina_open_tables,system_charset_info,32,0,0,
130
(hash_get_key) tina_get_key,0,0);
134
static int tina_done_func(PluginRegistry ®istry)
136
registry.remove(tina_engine);
139
hash_free(&tina_open_tables);
140
pthread_mutex_destroy(&tina_mutex);
291
147
Simple lock controls.
293
TinaShare *ha_tina::get_share(const char *table_name)
149
static TINA_SHARE *get_share(const char *table_name, Table *)
295
pthread_mutex_lock(&tina_mutex);
297
Tina *a_tina= static_cast<Tina *>(engine);
298
share= a_tina->findOpenTable(table_name);
300
152
char meta_file_name[FN_REFLEN];
301
153
struct stat file_stat;
157
pthread_mutex_lock(&tina_mutex);
158
length=(uint) strlen(table_name);
304
161
If share is not present in the hash, create a new share and
305
162
initialize its members.
164
if (!(share=(TINA_SHARE*) hash_search(&tina_open_tables,
165
(unsigned char*) table_name,
309
share= new TinaShare(table_name);
168
if (!my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
169
&share, sizeof(*share),
313
173
pthread_mutex_unlock(&tina_mutex);
317
internal::fn_format(meta_file_name, table_name, "", CSM_EXT,
178
share->table_name_length= length;
179
share->table_name= tmp_name;
180
share->crashed= false;
181
share->rows_recorded= 0;
182
share->update_file_opened= false;
183
share->tina_write_opened= false;
184
share->data_file_version= 0;
185
strcpy(share->table_name, table_name);
186
fn_format(share->data_file_name, table_name, "", CSV_EXT,
187
MY_REPLACE_EXT|MY_UNPACK_FILENAME);
188
fn_format(meta_file_name, table_name, "", CSM_EXT,
318
189
MY_REPLACE_EXT|MY_UNPACK_FILENAME);
320
191
if (stat(share->data_file_name, &file_stat))
322
pthread_mutex_unlock(&tina_mutex);
327
193
share->saved_data_file_length= file_stat.st_size;
329
a_tina->addOpenTable(share->table_name, share);
195
if (my_hash_insert(&tina_open_tables, (unsigned char*) share))
197
thr_lock_init(&share->lock);
331
198
pthread_mutex_init(&share->mutex,MY_MUTEX_INIT_FAST);
1359
internal::my_close(update_temp_file, MYF(0));
1258
my_close(update_temp_file, MYF(0));
1360
1259
share->update_file_opened= false;
1265
Repair CSV table in the case, it is crashed.
1269
session The thread, performing repair
1270
check_opt The options for repair. We do not use it currently.
1273
If the file is empty, change # of rows in the file and complete recovery.
1274
Otherwise, scan the table looking for bad rows. If none were found,
1275
we mark file as a good one and return. If a bad row was encountered,
1276
we truncate the datafile up to the last good row.
1278
TODO: Make repair more clever - it should try to recover subsequent
1279
rows (after the first bad one) as well.
1282
int ha_tina::repair(Session* session, HA_CHECK_OPT *)
1284
char repaired_fname[FN_REFLEN];
1288
ha_rows rows_repaired= 0;
1289
off_t write_begin= 0, write_end;
1292
if (!share->saved_data_file_length)
1294
share->rows_recorded= 0;
1298
/* Don't assert in field::val() functions */
1299
table->use_all_columns();
1300
if (!(buf= (unsigned char*) malloc(table->s->reclength)))
1301
return(HA_ERR_OUT_OF_MEM);
1303
/* position buffer to the start of the file */
1304
if (init_data_file())
1305
return(HA_ERR_CRASHED_ON_REPAIR);
1308
Local_saved_data_file_length is initialized during the lock phase.
1309
Sometimes this is not getting executed before ::repair (e.g. for
1310
the log tables). We set it manually here.
1312
local_saved_data_file_length= share->saved_data_file_length;
1313
/* set current position to the beginning of the file */
1314
current_position= next_position= 0;
1316
init_alloc_root(&blobroot, BLOB_MEMROOT_ALLOC_SIZE, 0);
1318
/* Read the file row-by-row. If everything is ok, repair is not needed. */
1319
while (!(rc= find_current_row(buf)))
1321
session_inc_row_count(session);
1323
current_position= next_position;
1326
free_root(&blobroot, MYF(0));
1330
if (rc == HA_ERR_END_OF_FILE)
1333
All rows were read ok until end of file, the file does not need repair.
1334
If rows_recorded != rows_repaired, we should update rows_recorded value
1335
to the current amount of rows.
1337
share->rows_recorded= rows_repaired;
1342
Otherwise we've encountered a bad row => repair is needed.
1343
Let us create a temporary file.
1345
if ((repair_file= my_create(fn_format(repaired_fname, share->table_name,
1347
MY_REPLACE_EXT|MY_UNPACK_FILENAME),
1348
0, O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
1349
return(HA_ERR_CRASHED_ON_REPAIR);
1351
file_buff->init_buff(data_file);
1354
/* we just truncated the file up to the first bad row. update rows count. */
1355
share->rows_recorded= rows_repaired;
1357
/* write repaired file */
1360
write_end= std::min(file_buff->end(), current_position);
1362
off_t write_length= write_end - write_begin;
1363
if ((uint64_t)write_length > SIZE_MAX)
1367
if ((write_length) &&
1368
(my_write(repair_file, (unsigned char*)file_buff->ptr(),
1369
(size_t)write_length, MYF_RW)))
1372
write_begin= write_end;
1373
if (write_end== current_position)
1376
file_buff->read_next(); /* shift the buffer */
1380
Close the files and rename repaired file to the datafile.
1381
We have to close the files, as on Windows one cannot rename
1382
a file, which descriptor is still open. EACCES will be returned
1383
when trying to delete the "to"-file in my_rename().
1385
if (my_close(data_file,MYF(0)) || my_close(repair_file, MYF(0)) ||
1386
my_rename(repaired_fname, share->data_file_name, MYF(0)))
1389
/* Open the file again, it should now be repaired */
1390
if ((data_file= my_open(share->data_file_name, O_RDWR|O_APPEND,
1394
/* Set new file size. The file size will be updated by ::update_status() */
1395
local_saved_data_file_length= (size_t) current_position;
1398
share->crashed= false;
1399
return(HA_ADMIN_OK);
1366
1403
DELETE without WHERE calls this
1418
if ((create_file= internal::my_create(internal::fn_format(name_buff, identifier.getPath().c_str(), "", CSM_EXT,
1419
MY_REPLACE_EXT|MY_UNPACK_FILENAME), 0,
1420
O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
1466
if ((create_file= my_create(fn_format(name_buff, name, "", CSM_EXT,
1467
MY_REPLACE_EXT|MY_UNPACK_FILENAME), 0,
1468
O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
1423
1471
write_meta_file(create_file, 0, false);
1424
internal::my_close(create_file, MYF(0));
1472
my_close(create_file, MYF(0));
1426
if ((create_file= internal::my_create(internal::fn_format(name_buff, identifier.getPath().c_str(), "", CSV_EXT,
1427
MY_REPLACE_EXT|MY_UNPACK_FILENAME),0,
1428
O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
1474
if ((create_file= my_create(fn_format(name_buff, name, "", CSV_EXT,
1475
MY_REPLACE_EXT|MY_UNPACK_FILENAME),0,
1476
O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
1431
internal::my_close(create_file, MYF(0));
1433
session.storeTableMessage(identifier, create_proto);
1439
DRIZZLE_DECLARE_PLUGIN
1479
my_close(create_file, MYF(0));
1484
int ha_tina::check(Session* session, HA_CHECK_OPT *)
1488
const char *old_proc_info;
1489
ha_rows count= share->rows_recorded;
1491
old_proc_info= get_session_proc_info(session);
1492
set_session_proc_info(session, "Checking table");
1493
if (!(buf= (unsigned char*) malloc(table->s->reclength)))
1494
return(HA_ERR_OUT_OF_MEM);
1496
/* position buffer to the start of the file */
1497
if (init_data_file())
1498
return(HA_ERR_CRASHED);
1501
Local_saved_data_file_length is initialized during the lock phase.
1502
Check does not use store_lock in certain cases. So, we set it
1505
local_saved_data_file_length= share->saved_data_file_length;
1506
/* set current position to the beginning of the file */
1507
current_position= next_position= 0;
1509
init_alloc_root(&blobroot, BLOB_MEMROOT_ALLOC_SIZE, 0);
1511
/* Read the file row-by-row. If everything is ok, repair is not needed. */
1512
while (!(rc= find_current_row(buf)))
1514
session_inc_row_count(session);
1516
current_position= next_position;
1519
free_root(&blobroot, MYF(0));
1522
set_session_proc_info(session, old_proc_info);
1524
if ((rc != HA_ERR_END_OF_FILE) || count)
1526
share->crashed= true;
1527
return(HA_ADMIN_CORRUPT);
1530
return(HA_ADMIN_OK);
1534
bool ha_tina::check_if_incompatible_data(HA_CREATE_INFO *, uint32_t)
1536
return COMPATIBLE_DATA_YES;
1539
drizzle_declare_plugin(csv)
1444
1543
"Brian Aker, MySQL AB",
1445
1544
"CSV storage engine",
1446
1545
PLUGIN_LICENSE_GPL,
1447
1546
tina_init_func, /* Plugin Init */
1547
tina_done_func, /* Plugin Deinit */
1548
NULL, /* status variables */
1448
1549
NULL, /* system variables */
1449
1550
NULL /* config options */
1451
DRIZZLE_DECLARE_PLUGIN_END;
1552
drizzle_declare_plugin_end;