99
92
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;
118
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);
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
static Tina *tina_engine= NULL;
262
static int tina_init_func(drizzled::plugin::Context &context)
265
tina_engine= new Tina("CSV");
266
context.add(tina_engine);
95
static unsigned char* tina_get_key(TINA_SHARE *share, size_t *length,
96
bool not_used __attribute__((unused)))
98
*length=share->table_name_length;
99
return (unsigned char*) share->table_name;
102
static int tina_init_func(void *p)
104
handlerton *tina_hton;
106
tina_hton= (handlerton *)p;
268
107
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);
108
(void) hash_init(&tina_open_tables,system_charset_info,32,0,0,
109
(hash_get_key) tina_get_key,0,0);
110
tina_hton->state= SHOW_OPTION_YES;
111
tina_hton->create= tina_create_handler;
112
tina_hton->flags= (HTON_CAN_RECREATE | HTON_SUPPORT_LOG_TABLES |
117
static int tina_done_func(void *p __attribute__((unused)))
119
hash_free(&tina_open_tables);
120
pthread_mutex_destroy(&tina_mutex);
291
127
Simple lock controls.
293
TinaShare *ha_tina::get_share(const char *table_name)
129
static TINA_SHARE *get_share(const char *table_name,
130
Table *table __attribute__((unused)))
295
pthread_mutex_lock(&tina_mutex);
297
Tina *a_tina= static_cast<Tina *>(engine);
298
share= a_tina->findOpenTable(table_name);
300
133
char meta_file_name[FN_REFLEN];
301
134
struct stat file_stat;
138
pthread_mutex_lock(&tina_mutex);
139
length=(uint) strlen(table_name);
304
142
If share is not present in the hash, create a new share and
305
143
initialize its members.
145
if (!(share=(TINA_SHARE*) hash_search(&tina_open_tables,
146
(unsigned char*) table_name,
309
share= new TinaShare(table_name);
149
if (!my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
150
&share, sizeof(*share),
313
154
pthread_mutex_unlock(&tina_mutex);
317
internal::fn_format(meta_file_name, table_name, "", CSM_EXT,
159
share->table_name_length= length;
160
share->table_name= tmp_name;
161
share->crashed= false;
162
share->rows_recorded= 0;
163
share->update_file_opened= false;
164
share->tina_write_opened= false;
165
share->data_file_version= 0;
166
my_stpcpy(share->table_name, table_name);
167
fn_format(share->data_file_name, table_name, "", CSV_EXT,
168
MY_REPLACE_EXT|MY_UNPACK_FILENAME);
169
fn_format(meta_file_name, table_name, "", CSM_EXT,
318
170
MY_REPLACE_EXT|MY_UNPACK_FILENAME);
320
172
if (stat(share->data_file_name, &file_stat))
322
pthread_mutex_unlock(&tina_mutex);
327
174
share->saved_data_file_length= file_stat.st_size;
329
a_tina->addOpenTable(share->table_name, share);
176
if (my_hash_insert(&tina_open_tables, (unsigned char*) share))
178
thr_lock_init(&share->lock);
331
179
pthread_mutex_init(&share->mutex,MY_MUTEX_INIT_FAST);
1320
1212
Close opened fildes's. Then move updated file in place
1321
1213
of the old datafile.
1323
if (internal::my_close(data_file, MYF(0)) ||
1324
internal::my_rename(internal::fn_format(updated_fname,
1325
share->table_name.c_str(),
1327
MY_REPLACE_EXT | MY_UNPACK_FILENAME),
1328
share->data_file_name, MYF(0)))
1215
if (my_close(data_file, MYF(0)) ||
1216
my_rename(fn_format(updated_fname, share->table_name, "", CSN_EXT,
1217
MY_REPLACE_EXT | MY_UNPACK_FILENAME),
1218
share->data_file_name, MYF(0)))
1331
1221
/* Open the file again */
1332
if (((data_file= internal::my_open(share->data_file_name, O_RDONLY, MYF(0))) == -1))
1222
if (((data_file= my_open(share->data_file_name, O_RDONLY, MYF(0))) == -1))
1335
As we reopened the data file, increase share->data_file_version
1336
in order to force other threads waiting on a table lock and
1225
As we reopened the data file, increase share->data_file_version
1226
in order to force other threads waiting on a table lock and
1337
1227
have already opened the table to reopen the data file.
1338
1228
That makes the latest changes become visible to them.
1339
Update local_data_file_version as no need to reopen it in the
1229
Update local_data_file_version as no need to reopen it in the
1340
1230
current thread.
1342
1232
share->data_file_version++;
1359
internal::my_close(update_temp_file, MYF(0));
1249
my_close(update_temp_file, MYF(0));
1360
1250
share->update_file_opened= false;
1256
Repair CSV table in the case, it is crashed.
1260
session The thread, performing repair
1261
check_opt The options for repair. We do not use it currently.
1264
If the file is empty, change # of rows in the file and complete recovery.
1265
Otherwise, scan the table looking for bad rows. If none were found,
1266
we mark file as a good one and return. If a bad row was encountered,
1267
we truncate the datafile up to the last good row.
1269
TODO: Make repair more clever - it should try to recover subsequent
1270
rows (after the first bad one) as well.
1273
int ha_tina::repair(Session* session,
1274
HA_CHECK_OPT* check_opt __attribute__((unused)))
1276
char repaired_fname[FN_REFLEN];
1280
ha_rows rows_repaired= 0;
1281
off_t write_begin= 0, write_end;
1284
if (!share->saved_data_file_length)
1286
share->rows_recorded= 0;
1290
/* Don't assert in field::val() functions */
1291
table->use_all_columns();
1292
if (!(buf= (unsigned char*) my_malloc(table->s->reclength, MYF(MY_WME))))
1293
return(HA_ERR_OUT_OF_MEM);
1295
/* position buffer to the start of the file */
1296
if (init_data_file())
1297
return(HA_ERR_CRASHED_ON_REPAIR);
1300
Local_saved_data_file_length is initialized during the lock phase.
1301
Sometimes this is not getting executed before ::repair (e.g. for
1302
the log tables). We set it manually here.
1304
local_saved_data_file_length= share->saved_data_file_length;
1305
/* set current position to the beginning of the file */
1306
current_position= next_position= 0;
1308
init_alloc_root(&blobroot, BLOB_MEMROOT_ALLOC_SIZE, 0);
1310
/* Read the file row-by-row. If everything is ok, repair is not needed. */
1311
while (!(rc= find_current_row(buf)))
1313
session_inc_row_count(session);
1315
current_position= next_position;
1318
free_root(&blobroot, MYF(0));
1322
if (rc == HA_ERR_END_OF_FILE)
1325
All rows were read ok until end of file, the file does not need repair.
1326
If rows_recorded != rows_repaired, we should update rows_recorded value
1327
to the current amount of rows.
1329
share->rows_recorded= rows_repaired;
1334
Otherwise we've encountered a bad row => repair is needed.
1335
Let us create a temporary file.
1337
if ((repair_file= my_create(fn_format(repaired_fname, share->table_name,
1339
MY_REPLACE_EXT|MY_UNPACK_FILENAME),
1340
0, O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
1341
return(HA_ERR_CRASHED_ON_REPAIR);
1343
file_buff->init_buff(data_file);
1346
/* we just truncated the file up to the first bad row. update rows count. */
1347
share->rows_recorded= rows_repaired;
1349
/* write repaired file */
1352
write_end= std::min(file_buff->end(), current_position);
1353
if ((write_end - write_begin) &&
1354
(my_write(repair_file, (unsigned char*)file_buff->ptr(),
1355
write_end - write_begin, MYF_RW)))
1358
write_begin= write_end;
1359
if (write_end== current_position)
1362
file_buff->read_next(); /* shift the buffer */
1366
Close the files and rename repaired file to the datafile.
1367
We have to close the files, as on Windows one cannot rename
1368
a file, which descriptor is still open. EACCES will be returned
1369
when trying to delete the "to"-file in my_rename().
1371
if (my_close(data_file,MYF(0)) || my_close(repair_file, MYF(0)) ||
1372
my_rename(repaired_fname, share->data_file_name, MYF(0)))
1375
/* Open the file again, it should now be repaired */
1376
if ((data_file= my_open(share->data_file_name, O_RDWR|O_APPEND,
1380
/* Set new file size. The file size will be updated by ::update_status() */
1381
local_saved_data_file_length= (size_t) current_position;
1384
share->crashed= false;
1385
return(HA_ADMIN_OK);
1366
1389
DELETE without WHERE calls this
1413
1448
return(HA_ERR_UNSUPPORTED);
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)
1453
if ((create_file= my_create(fn_format(name_buff, name, "", CSM_EXT,
1454
MY_REPLACE_EXT|MY_UNPACK_FILENAME), 0,
1455
O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
1423
1458
write_meta_file(create_file, 0, false);
1424
internal::my_close(create_file, MYF(0));
1459
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)
1461
if ((create_file= my_create(fn_format(name_buff, name, "", CSV_EXT,
1462
MY_REPLACE_EXT|MY_UNPACK_FILENAME),0,
1463
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
1466
my_close(create_file, MYF(0));
1471
int ha_tina::check(Session* session,
1472
HA_CHECK_OPT* check_opt __attribute__((unused)))
1476
const char *old_proc_info;
1477
ha_rows count= share->rows_recorded;
1479
old_proc_info= get_session_proc_info(session);
1480
set_session_proc_info(session, "Checking table");
1481
if (!(buf= (unsigned char*) my_malloc(table->s->reclength, MYF(MY_WME))))
1482
return(HA_ERR_OUT_OF_MEM);
1484
/* position buffer to the start of the file */
1485
if (init_data_file())
1486
return(HA_ERR_CRASHED);
1489
Local_saved_data_file_length is initialized during the lock phase.
1490
Check does not use store_lock in certain cases. So, we set it
1493
local_saved_data_file_length= share->saved_data_file_length;
1494
/* set current position to the beginning of the file */
1495
current_position= next_position= 0;
1497
init_alloc_root(&blobroot, BLOB_MEMROOT_ALLOC_SIZE, 0);
1499
/* Read the file row-by-row. If everything is ok, repair is not needed. */
1500
while (!(rc= find_current_row(buf)))
1502
session_inc_row_count(session);
1504
current_position= next_position;
1507
free_root(&blobroot, MYF(0));
1510
set_session_proc_info(session, old_proc_info);
1512
if ((rc != HA_ERR_END_OF_FILE) || count)
1514
share->crashed= true;
1515
return(HA_ADMIN_CORRUPT);
1518
return(HA_ADMIN_OK);
1522
bool ha_tina::check_if_incompatible_data(HA_CREATE_INFO *info __attribute__((unused)),
1523
uint32_t table_changes __attribute__((unused)))
1525
return COMPATIBLE_DATA_YES;
1528
mysql_declare_plugin(csv)
1530
DRIZZLE_STORAGE_ENGINE_PLUGIN,
1444
1533
"Brian Aker, MySQL AB",
1445
1534
"CSV storage engine",
1446
1535
PLUGIN_LICENSE_GPL,
1447
1536
tina_init_func, /* Plugin Init */
1537
tina_done_func, /* Plugin Deinit */
1538
NULL, /* status variables */
1448
1539
NULL, /* system variables */
1449
1540
NULL /* config options */
1451
DRIZZLE_DECLARE_PLUGIN_END;
1542
mysql_declare_plugin_end;