~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/csv/ha_tina.cc

  • Committer: Monty Taylor
  • Date: 2008-11-16 23:47:43 UTC
  • mto: (584.1.10 devel)
  • mto: This revision was merged to the branch mainline in revision 589.
  • Revision ID: monty@inaugust.com-20081116234743-c38gmv0pa2kdefaj
BrokeĀ outĀ cached_item.

Show diffs side-by-side

added added

removed removed

Lines of Context:
40
40
 
41
41
 -Brian
42
42
*/
43
 
#include "config.h"
44
 
#include <drizzled/field.h>
45
 
#include <drizzled/field/blob.h>
46
 
#include <drizzled/field/timestamp.h>
 
43
#include <drizzled/common_includes.h>
 
44
#include "ha_tina.h"
47
45
#include <drizzled/error.h>
48
 
#include <drizzled/table.h>
49
 
#include <drizzled/session.h>
50
 
#include "drizzled/internal/my_sys.h"
51
 
 
52
 
#include "ha_tina.h"
53
 
 
54
 
#include <fcntl.h>
55
 
 
56
 
#include <string>
57
 
#include <map>
58
 
 
59
 
using namespace std;
60
 
using namespace drizzled;
 
46
 
61
47
 
62
48
/*
63
49
  unsigned char + unsigned char + uint64_t + uint64_t + uint64_t + uint64_t + unsigned char
73
59
#define CSM_EXT ".CSM"               // Meta file
74
60
 
75
61
 
76
 
static int read_meta_file(int meta_file, ha_rows *rows);
77
 
static int write_meta_file(int meta_file, ha_rows rows, bool dirty);
 
62
static TINA_SHARE *get_share(const char *table_name, Table *table);
 
63
static int free_share(TINA_SHARE *share);
 
64
static int read_meta_file(File meta_file, ha_rows *rows);
 
65
static int write_meta_file(File meta_file, ha_rows rows, bool dirty);
78
66
 
79
 
void tina_get_status(void* param, int concurrent_insert);
80
 
void tina_update_status(void* param);
81
 
bool tina_check_status(void* param);
 
67
extern "C" void tina_get_status(void* param, int concurrent_insert);
 
68
extern "C" void tina_update_status(void* param);
 
69
extern "C" bool tina_check_status(void* param);
82
70
 
83
71
/* Stuff for shares */
84
72
pthread_mutex_t tina_mutex;
 
73
static HASH tina_open_tables;
 
74
static handler *tina_create_handler(handlerton *hton,
 
75
                                    TABLE_SHARE *table, 
 
76
                                    MEM_ROOT *mem_root);
 
77
 
85
78
 
86
79
/*****************************************************************************
87
80
 ** TINA tables
90
83
/*
91
84
  Used for sorting chains with qsort().
92
85
*/
93
 
static int sort_set (tina_set *a, tina_set *b)
 
86
int sort_set (tina_set *a, tina_set *b)
94
87
{
95
88
  /*
96
89
    We assume that intervals do not intersect. So, it is enought to compare
99
92
  return ( a->begin > b->begin ? 1 : ( a->begin < b->begin ? -1 : 0 ) );
100
93
}
101
94
 
102
 
 
103
 
/*
104
 
  If frm_error() is called in table.cc this is called to find out what file
105
 
  extensions exist for this Cursor.
106
 
*/
107
 
static const char *ha_tina_exts[] = {
108
 
  CSV_EXT,
109
 
  CSM_EXT,
110
 
  NULL
111
 
};
112
 
 
113
 
class Tina : public drizzled::plugin::StorageEngine
114
 
{
115
 
  typedef std::map<string, TinaShare*> TinaMap;
116
 
  TinaMap tina_open_tables;
117
 
public:
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 |
123
 
                                     HTON_FILE_BASED),
124
 
    tina_open_tables()
125
 
  {}
126
 
  virtual ~Tina()
127
 
  {
128
 
    pthread_mutex_destroy(&tina_mutex);
129
 
  }
130
 
 
131
 
  virtual Cursor *create(TableShare &table,
132
 
                         drizzled::memory::Root *mem_root)
133
 
  {
134
 
    return new (mem_root) ha_tina(*this, table);
135
 
  }
136
 
 
137
 
  const char **bas_ext() const {
138
 
    return ha_tina_exts;
139
 
  }
140
 
 
141
 
  int doCreateTable(Session &,
142
 
                    Table &table_arg,
143
 
                    drizzled::TableIdentifier &identifier,
144
 
                    drizzled::message::Table&);
145
 
 
146
 
  int doGetTableDefinition(Session& session,
147
 
                           TableIdentifier &identifier,
148
 
                           drizzled::message::Table &table_message);
149
 
 
150
 
  /* Temp only engine, so do not return values. */
151
 
  void doGetTableNames(drizzled::CachedDirectory &, SchemaIdentifier&, set<string>&) { };
152
 
 
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);
157
 
 
158
 
 
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);
164
 
 
165
 
  void doGetTableIdentifiers(drizzled::CachedDirectory &directory,
166
 
                             drizzled::SchemaIdentifier &schema_identifier,
167
 
                             drizzled::TableIdentifiers &set_of_identifiers);
168
 
};
169
 
 
170
 
void Tina::doGetTableIdentifiers(drizzled::CachedDirectory&,
171
 
                                 drizzled::SchemaIdentifier&,
172
 
                                 drizzled::TableIdentifiers&)
173
 
{
174
 
}
175
 
 
176
 
int Tina::doRenameTable(Session &session,
177
 
                        TableIdentifier &from, TableIdentifier &to)
178
 
{
179
 
  int error= 0;
180
 
  for (const char **ext= bas_ext(); *ext ; ext++)
181
 
  {
182
 
    if (rename_file_ext(from.getPath().c_str(), to.getPath().c_str(), *ext))
183
 
    {
184
 
      if ((error=errno) != ENOENT)
185
 
        break;
186
 
      error= 0;
187
 
    }
188
 
  }
189
 
 
190
 
  session.renameTableMessage(from, to);
191
 
 
192
 
  return error;
193
 
}
194
 
 
195
 
bool Tina::doDoesTableExist(Session &session, TableIdentifier &identifier)
196
 
{
197
 
  return session.doesTableMessageExist(identifier);
198
 
}
199
 
 
200
 
 
201
 
int Tina::doDropTable(Session &session,
202
 
                      TableIdentifier &identifier)
203
 
{
204
 
  int error= 0;
205
 
  int enoent_or_zero= ENOENT;                   // Error if no file was deleted
206
 
  char buff[FN_REFLEN];
207
 
 
208
 
  for (const char **ext= bas_ext(); *ext ; ext++)
209
 
  {
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)))
213
 
    {
214
 
      if ((error= errno) != ENOENT)
215
 
        break;
216
 
    }
217
 
    else
218
 
      enoent_or_zero= 0;                        // No error for ENOENT
219
 
    error= enoent_or_zero;
220
 
  }
221
 
 
222
 
  session.removeTableMessage(identifier);
223
 
 
224
 
  return error;
225
 
}
226
 
 
227
 
TinaShare *Tina::findOpenTable(const string table_name)
228
 
{
229
 
  TinaMap::iterator find_iter=
230
 
    tina_open_tables.find(table_name);
231
 
 
232
 
  if (find_iter != tina_open_tables.end())
233
 
    return (*find_iter).second;
234
 
  else
235
 
    return NULL;
236
 
}
237
 
 
238
 
void Tina::addOpenTable(const string &table_name, TinaShare *share)
239
 
{
240
 
  tina_open_tables[table_name]= share;
241
 
}
242
 
 
243
 
void Tina::deleteOpenTable(const string &table_name)
244
 
{
245
 
  tina_open_tables.erase(table_name);
246
 
}
247
 
 
248
 
 
249
 
int Tina::doGetTableDefinition(Session &session,
250
 
                               drizzled::TableIdentifier &identifier,
251
 
                               drizzled::message::Table &table_message)
252
 
{
253
 
  if (session.getTableMessage(identifier, table_message))
254
 
    return EEXIST;
255
 
 
256
 
  return ENOENT;
257
 
}
258
 
 
259
 
 
260
 
static Tina *tina_engine= NULL;
261
 
 
262
 
static int tina_init_func(drizzled::plugin::Context &context)
263
 
{
264
 
 
265
 
  tina_engine= new Tina("CSV");
266
 
  context.add(tina_engine);
267
 
 
 
95
static unsigned char* tina_get_key(TINA_SHARE *share, size_t *length,
 
96
                          bool not_used __attribute__((unused)))
 
97
{
 
98
  *length=share->table_name_length;
 
99
  return (unsigned char*) share->table_name;
 
100
}
 
101
 
 
102
static int tina_init_func(void *p)
 
103
{
 
104
  handlerton *tina_hton;
 
105
 
 
106
  tina_hton= (handlerton *)p;
268
107
  pthread_mutex_init(&tina_mutex,MY_MUTEX_INIT_FAST);
269
 
  return 0;
270
 
}
271
 
 
272
 
 
273
 
 
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)
278
 
{
279
 
  thr_lock_init(&lock);
280
 
  internal::fn_format(data_file_name, table_name_arg, "", CSV_EXT,
281
 
            MY_REPLACE_EXT|MY_UNPACK_FILENAME);
282
 
}
283
 
 
284
 
TinaShare::~TinaShare()
285
 
{
286
 
  thr_lock_delete(&lock);
287
 
  pthread_mutex_destroy(&mutex);
288
 
}
 
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 | 
 
113
                     HTON_NO_PARTITION);
 
114
  return 0;
 
115
}
 
116
 
 
117
static int tina_done_func(void *p __attribute__((unused)))
 
118
{
 
119
  hash_free(&tina_open_tables);
 
120
  pthread_mutex_destroy(&tina_mutex);
 
121
 
 
122
  return 0;
 
123
}
 
124
 
289
125
 
290
126
/*
291
127
  Simple lock controls.
292
128
*/
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)))
294
131
{
295
 
  pthread_mutex_lock(&tina_mutex);
296
 
 
297
 
  Tina *a_tina= static_cast<Tina *>(engine);
298
 
  share= a_tina->findOpenTable(table_name);
299
 
 
 
132
  TINA_SHARE *share;
300
133
  char meta_file_name[FN_REFLEN];
301
134
  struct stat file_stat;
 
135
  char *tmp_name;
 
136
  uint32_t length;
 
137
 
 
138
  pthread_mutex_lock(&tina_mutex);
 
139
  length=(uint) strlen(table_name);
302
140
 
303
141
  /*
304
142
    If share is not present in the hash, create a new share and
305
143
    initialize its members.
306
144
  */
307
 
  if (! share)
 
145
  if (!(share=(TINA_SHARE*) hash_search(&tina_open_tables,
 
146
                                        (unsigned char*) table_name,
 
147
                                       length)))
308
148
  {
309
 
    share= new TinaShare(table_name);
310
 
 
311
 
    if (share == NULL)
 
149
    if (!my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
 
150
                         &share, sizeof(*share),
 
151
                         &tmp_name, length+1,
 
152
                         NULL))
312
153
    {
313
154
      pthread_mutex_unlock(&tina_mutex);
314
155
      return NULL;
315
156
    }
316
157
 
317
 
    internal::fn_format(meta_file_name, table_name, "", CSM_EXT,
 
158
    share->use_count= 0;
 
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);
319
171
 
320
172
    if (stat(share->data_file_name, &file_stat))
321
 
    {
322
 
      pthread_mutex_unlock(&tina_mutex);
323
 
      delete share;
324
 
      return NULL;
325
 
    }
326
 
  
 
173
      goto error;
327
174
    share->saved_data_file_length= file_stat.st_size;
328
175
 
329
 
    a_tina->addOpenTable(share->table_name, share);
330
 
 
 
176
    if (my_hash_insert(&tina_open_tables, (unsigned char*) share))
 
177
      goto error;
 
178
    thr_lock_init(&share->lock);
331
179
    pthread_mutex_init(&share->mutex,MY_MUTEX_INIT_FAST);
332
180
 
333
181
    /*
336
184
      Usually this will result in auto-repair, and we will get a good
337
185
      meta-file in the end.
338
186
    */
339
 
    if ((share->meta_file= internal::my_open(meta_file_name,
340
 
                                             O_RDWR|O_CREAT, MYF(0))) == -1)
 
187
    if ((share->meta_file= my_open(meta_file_name,
 
188
                                   O_RDWR|O_CREAT, MYF(0))) == -1)
341
189
      share->crashed= true;
342
190
 
343
191
    /*
351
199
  pthread_mutex_unlock(&tina_mutex);
352
200
 
353
201
  return share;
 
202
 
 
203
error:
 
204
  pthread_mutex_unlock(&tina_mutex);
 
205
  free((unsigned char*) share);
 
206
 
 
207
  return NULL;
354
208
}
355
209
 
356
210
 
373
227
    non-zero - error occurred
374
228
*/
375
229
 
376
 
static int read_meta_file(int meta_file, ha_rows *rows)
 
230
static int read_meta_file(File meta_file, ha_rows *rows)
377
231
{
378
232
  unsigned char meta_buffer[META_BUFFER_SIZE];
379
233
  unsigned char *ptr= meta_buffer;
380
234
 
381
 
  lseek(meta_file, 0, SEEK_SET);
382
 
  if (internal::my_read(meta_file, (unsigned char*)meta_buffer, META_BUFFER_SIZE, 0)
 
235
  my_seek(meta_file, 0, MY_SEEK_SET, MYF(0));
 
236
  if (my_read(meta_file, (unsigned char*)meta_buffer, META_BUFFER_SIZE, 0)
383
237
      != META_BUFFER_SIZE)
384
238
    return(HA_ERR_CRASHED_ON_USAGE);
385
239
 
401
255
      ((bool)(*ptr)== true))
402
256
    return(HA_ERR_CRASHED_ON_USAGE);
403
257
 
404
 
  internal::my_sync(meta_file, MYF(MY_WME));
 
258
  my_sync(meta_file, MYF(MY_WME));
405
259
 
406
260
  return(0);
407
261
}
426
280
    non-zero - error occurred
427
281
*/
428
282
 
429
 
static int write_meta_file(int meta_file, ha_rows rows, bool dirty)
 
283
static int write_meta_file(File meta_file, ha_rows rows, bool dirty)
430
284
{
431
285
  unsigned char meta_buffer[META_BUFFER_SIZE];
432
286
  unsigned char *ptr= meta_buffer;
445
299
  ptr+= 3*sizeof(uint64_t);
446
300
  *ptr= (unsigned char)dirty;
447
301
 
448
 
  lseek(meta_file, 0, SEEK_SET);
449
 
  if (internal::my_write(meta_file, (unsigned char *)meta_buffer, META_BUFFER_SIZE, 0)
 
302
  my_seek(meta_file, 0, MY_SEEK_SET, MYF(0));
 
303
  if (my_write(meta_file, (unsigned char *)meta_buffer, META_BUFFER_SIZE, 0)
450
304
      != META_BUFFER_SIZE)
451
305
    return(-1);
452
306
 
453
 
  internal::my_sync(meta_file, MYF(MY_WME));
 
307
  my_sync(meta_file, MYF(MY_WME));
454
308
 
455
309
  return(0);
456
310
}
457
311
 
 
312
bool ha_tina::check_and_repair(Session *session)
 
313
{
 
314
  HA_CHECK_OPT check_opt;
 
315
 
 
316
  check_opt.init();
 
317
 
 
318
  return(repair(session, &check_opt));
 
319
}
 
320
 
 
321
 
458
322
int ha_tina::init_tina_writer()
459
323
{
460
324
  /*
465
329
  (void)write_meta_file(share->meta_file, share->rows_recorded, true);
466
330
 
467
331
  if ((share->tina_write_filedes=
468
 
        internal::my_open(share->data_file_name, O_RDWR|O_APPEND, MYF(0))) == -1)
 
332
        my_open(share->data_file_name, O_RDWR|O_APPEND, MYF(0))) == -1)
469
333
  {
470
334
    share->crashed= true;
471
335
    return(1);
476
340
}
477
341
 
478
342
 
 
343
bool ha_tina::is_crashed() const
 
344
{
 
345
  return(share->crashed);
 
346
}
 
347
 
479
348
/*
480
349
  Free lock controls.
481
350
*/
482
 
int ha_tina::free_share()
 
351
static int free_share(TINA_SHARE *share)
483
352
{
484
353
  pthread_mutex_lock(&tina_mutex);
485
354
  int result_code= 0;
487
356
    /* Write the meta file. Mark it as crashed if needed. */
488
357
    (void)write_meta_file(share->meta_file, share->rows_recorded,
489
358
                          share->crashed ? true :false);
490
 
    if (internal::my_close(share->meta_file, MYF(0)))
 
359
    if (my_close(share->meta_file, MYF(0)))
491
360
      result_code= 1;
492
361
    if (share->tina_write_opened)
493
362
    {
494
 
      if (internal::my_close(share->tina_write_filedes, MYF(0)))
 
363
      if (my_close(share->tina_write_filedes, MYF(0)))
495
364
        result_code= 1;
496
365
      share->tina_write_opened= false;
497
366
    }
498
367
 
499
 
    Tina *a_tina= static_cast<Tina *>(engine);
500
 
    a_tina->deleteOpenTable(share->table_name);
501
 
    delete share;
 
368
    hash_delete(&tina_open_tables, (unsigned char*) share);
 
369
    thr_lock_delete(&share->lock);
 
370
    pthread_mutex_destroy(&share->mutex);
 
371
    free((unsigned char*) share);
502
372
  }
503
373
  pthread_mutex_unlock(&tina_mutex);
504
374
 
516
386
  '\r''\n' --  DOS\Windows line ending
517
387
*/
518
388
 
519
 
static off_t find_eoln_buff(Transparent_file *data_buff, off_t begin,
520
 
                            off_t end, int *eoln_len)
 
389
off_t find_eoln_buff(Transparent_file *data_buff, off_t begin,
 
390
                     off_t end, int *eoln_len)
521
391
{
522
392
  *eoln_len= 0;
523
393
 
544
414
}
545
415
 
546
416
 
547
 
 
548
 
ha_tina::ha_tina(drizzled::plugin::StorageEngine &engine_arg, TableShare &table_arg)
549
 
  :Cursor(engine_arg, table_arg),
 
417
static handler *tina_create_handler(handlerton *hton,
 
418
                                    TABLE_SHARE *table, 
 
419
                                    MEM_ROOT *mem_root)
 
420
{
 
421
  return new (mem_root) ha_tina(hton, table);
 
422
}
 
423
 
 
424
 
 
425
ha_tina::ha_tina(handlerton *hton, TABLE_SHARE *table_arg)
 
426
  :handler(hton, table_arg),
550
427
  /*
551
 
    These definitions are found in Cursor.h
 
428
    These definitions are found in handler.h
552
429
    They are not probably completely right.
553
430
  */
554
431
  current_position(0), next_position(0), local_saved_data_file_length(0),
566
443
  Encode a buffer into the quoted format.
567
444
*/
568
445
 
569
 
int ha_tina::encode_quote(unsigned char *)
 
446
int ha_tina::encode_quote(unsigned char *buf __attribute__((unused)))
570
447
{
571
448
  char attribute_buffer[1024];
572
449
  String attribute(attribute_buffer, sizeof(attribute_buffer),
579
456
    const char *ptr;
580
457
    const char *end_ptr;
581
458
    const bool was_null= (*field)->is_null();
582
 
 
 
459
    
583
460
    /*
584
461
      assistance for backwards compatibility in production builds.
585
462
      note: this will not work for ENUM columns.
590
467
      (*field)->set_notnull();
591
468
    }
592
469
 
593
 
    /* 
594
 
      Since we are needing to "translate" the type into a string we 
595
 
      will need to do a val_str(). This would cause an assert() to
596
 
      normally occur since we are onlying "writing" values.
597
 
    */
598
 
    (*field)->setReadSet();
599
470
    (*field)->val_str(&attribute,&attribute);
600
 
 
 
471
    
601
472
    if (was_null)
602
473
      (*field)->set_null();
603
474
 
608
479
 
609
480
      buffer.append('"');
610
481
 
611
 
      while (ptr < end_ptr)
 
482
      while (ptr < end_ptr) 
612
483
      {
613
484
        if (*ptr == '"')
614
485
        {
673
544
      chain_size += DEFAULT_CHAIN_LENGTH;
674
545
      if (chain_alloced)
675
546
      {
676
 
        if ((chain= (tina_set *) realloc(chain, chain_size)) == NULL)
 
547
        /* Must cast since my_malloc unlike malloc doesn't have a void ptr */
 
548
        if ((chain= (tina_set *) my_realloc((unsigned char*)chain,
 
549
                                            chain_size, MYF(MY_WME))) == NULL)
677
550
          return -1;
678
551
      }
679
552
      else
680
553
      {
681
 
        tina_set *ptr= (tina_set *) malloc(chain_size * sizeof(tina_set));
682
 
        if (ptr == NULL)
683
 
          return -1;
 
554
        tina_set *ptr= (tina_set *) my_malloc(chain_size * sizeof(tina_set),
 
555
                                              MYF(MY_WME));
684
556
        memcpy(ptr, chain, DEFAULT_CHAIN_LENGTH * sizeof(tina_set));
685
557
        chain= ptr;
686
558
        chain_alloced++;
704
576
  off_t end_offset, curr_offset= current_position;
705
577
  int eoln_len;
706
578
  int error;
 
579
  bool read_all;
707
580
 
708
 
  free_root(&blobroot, MYF(drizzled::memory::MARK_BLOCKS_FREE));
 
581
  free_root(&blobroot, MYF(MY_MARK_BLOCKS_FREE));
709
582
 
710
583
  /*
711
584
    We do not read further then local_saved_data_file_length in order
716
589
                       local_saved_data_file_length, &eoln_len)) == 0)
717
590
    return(HA_ERR_END_OF_FILE);
718
591
 
 
592
  /* We must read all columns in case a table is opened for update */
 
593
  read_all= !bitmap_is_clear_all(table->write_set);
719
594
  error= HA_ERR_CRASHED_ON_USAGE;
720
595
 
721
596
  memset(buf, 0, table->s->null_bytes);
723
598
  for (Field **field=table->field ; *field ; field++)
724
599
  {
725
600
    char curr_char;
726
 
 
 
601
    
727
602
    buffer.length(0);
728
603
    if (curr_offset >= end_offset)
729
604
      goto err;
771
646
        }
772
647
      }
773
648
    }
774
 
    else
 
649
    else 
775
650
    {
776
651
      for(; curr_offset < end_offset; curr_offset++)
777
652
      {
785
660
      }
786
661
    }
787
662
 
788
 
    if ((*field)->isReadSet() || (*field)->isWriteSet())
 
663
    if (read_all || bitmap_is_set(table->read_set, (*field)->field_index))
789
664
    {
790
 
      /* This masks a bug in the logic for a SELECT * */
791
 
      (*field)->setWriteSet();
792
665
      if ((*field)->store(buffer.ptr(), buffer.length(), buffer.charset(),
793
666
                          CHECK_FIELD_WARN))
794
667
        goto err;
795
 
 
796
668
      if ((*field)->flags & BLOB_FLAG)
797
669
      {
798
670
        Field_blob *blob= *(Field_blob**) field;
799
671
        unsigned char *src, *tgt;
800
672
        uint32_t length, packlength;
801
 
 
 
673
        
802
674
        packlength= blob->pack_length_no_ptr();
803
675
        length= blob->get_length(blob->ptr);
804
676
        memcpy(&src, blob->ptr + packlength, sizeof(char*));
805
677
        if (src)
806
678
        {
807
679
          tgt= (unsigned char*) alloc_root(&blobroot, length);
808
 
          memmove(tgt, src, length);
 
680
          memcpy(tgt, src, length);
809
681
          memcpy(blob->ptr + packlength, &tgt, sizeof(char*));
810
682
        }
811
683
      }
820
692
}
821
693
 
822
694
/*
 
695
  If frm_error() is called in table.cc this is called to find out what file
 
696
  extensions exist for this handler.
 
697
*/
 
698
static const char *ha_tina_exts[] = {
 
699
  CSV_EXT,
 
700
  CSM_EXT,
 
701
  NULL
 
702
};
 
703
 
 
704
const char **ha_tina::bas_ext() const
 
705
{
 
706
  return ha_tina_exts;
 
707
}
 
708
 
 
709
/*
823
710
  Three functions below are needed to enable concurrent insert functionality
824
711
  for CSV engine. For more details see mysys/thr_lock.c
825
712
*/
826
713
 
827
 
void tina_get_status(void* param, int)
 
714
void tina_get_status(void* param,
 
715
                     int concurrent_insert __attribute__((unused)))
828
716
{
829
717
  ha_tina *tina= (ha_tina*) param;
830
718
  tina->get_status();
837
725
}
838
726
 
839
727
/* this should exist and return 0 for concurrent insert to work */
840
 
bool tina_check_status(void *)
 
728
bool tina_check_status(void* param __attribute__((unused)))
841
729
{
842
730
  return 0;
843
731
}
877
765
    For log tables concurrent insert works different. The reason is that
878
766
    log tables are always opened and locked. And as they do not unlock
879
767
    tables, the file length after writes should be updated in a different
880
 
    way.
 
768
    way. 
881
769
*/
882
770
 
883
771
void ha_tina::update_status()
892
780
  this will not be called for every request. Any sort of positions
893
781
  that need to be reset should be kept in the ::extra() call.
894
782
*/
895
 
int ha_tina::open(const char *name, int, uint32_t)
 
783
int ha_tina::open(const char *name, int mode __attribute__((unused)),
 
784
                  uint32_t open_options)
896
785
{
897
 
  if (!(share= get_share(name)))
898
 
    return(ENOENT);
 
786
  if (!(share= get_share(name, table)))
 
787
    return(HA_ERR_OUT_OF_MEM);
899
788
 
900
 
  if (share->crashed)
 
789
  if (share->crashed && !(open_options & HA_OPEN_FOR_REPAIR))
901
790
  {
902
 
    free_share();
 
791
    free_share(share);
903
792
    return(HA_ERR_CRASHED_ON_USAGE);
904
793
  }
905
794
 
906
795
  local_data_file_version= share->data_file_version;
907
 
  if ((data_file= internal::my_open(share->data_file_name, O_RDONLY, MYF(0))) == -1)
 
796
  if ((data_file= my_open(share->data_file_name, O_RDONLY, MYF(0))) == -1)
908
797
    return(0);
909
798
 
910
799
  /*
911
 
    Init locking. Pass Cursor object to the locking routines,
 
800
    Init locking. Pass handler object to the locking routines,
912
801
    so that they could save/update local_saved_data_file_length value
913
802
    during locking. This is needed to enable concurrent inserts.
914
803
  */
930
819
int ha_tina::close(void)
931
820
{
932
821
  int rc= 0;
933
 
  rc= internal::my_close(data_file, MYF(0));
934
 
  return(free_share() || rc);
 
822
  rc= my_close(data_file, MYF(0));
 
823
  return(free_share(share) || rc);
935
824
}
936
825
 
937
826
/*
938
 
  This is an INSERT. At the moment this Cursor just seeks to the end
 
827
  This is an INSERT. At the moment this handler just seeks to the end
939
828
  of the file and appends the data. In an error case it really should
940
829
  just truncate to the original position (this is not done yet).
941
830
*/
946
835
  if (share->crashed)
947
836
      return(HA_ERR_CRASHED_ON_USAGE);
948
837
 
949
 
  ha_statistic_increment(&system_status_var::ha_write_count);
 
838
  ha_statistic_increment(&SSV::ha_write_count);
 
839
 
 
840
  if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
 
841
    table->timestamp_field->set_time();
950
842
 
951
843
  size= encode_quote(buf);
952
844
 
955
847
      return(-1);
956
848
 
957
849
   /* use pwrite, as concurrent reader could have changed the position */
958
 
  if (internal::my_write(share->tina_write_filedes, (unsigned char*)buffer.ptr(), size,
 
850
  if (my_write(share->tina_write_filedes, (unsigned char*)buffer.ptr(), size,
959
851
               MYF(MY_WME | MY_NABP)))
960
852
    return(-1);
961
853
 
980
872
  if (!share->update_file_opened)
981
873
  {
982
874
    if ((update_temp_file=
983
 
           internal::my_create(internal::fn_format(updated_fname, share->table_name.c_str(),
 
875
           my_create(fn_format(updated_fname, share->table_name,
984
876
                               "", CSN_EXT,
985
877
                               MY_REPLACE_EXT | MY_UNPACK_FILENAME),
986
878
                     0, O_RDWR | O_TRUNC, MYF(MY_WME))) < 0)
995
887
  This is called for an update.
996
888
  Make sure you put in code to increment the auto increment, also
997
889
  update any timestamp data. Currently auto increment is not being
998
 
  fixed since autoincrements have yet to be added to this table Cursor.
 
890
  fixed since autoincrements have yet to be added to this table handler.
999
891
  This will be called in a table scan right before the previous ::rnd_next()
1000
892
  call.
1001
893
*/
1002
 
int ha_tina::update_row(const unsigned char *, unsigned char * new_data)
 
894
int ha_tina::update_row(const unsigned char * old_data __attribute__((unused)),
 
895
                        unsigned char * new_data)
1003
896
{
1004
897
  int size;
1005
898
  int rc= -1;
1006
899
 
1007
 
  ha_statistic_increment(&system_status_var::ha_update_count);
 
900
  ha_statistic_increment(&SSV::ha_update_count);
1008
901
 
1009
902
  if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
1010
903
    table->timestamp_field->set_time();
1012
905
  size= encode_quote(new_data);
1013
906
 
1014
907
  /*
1015
 
    During update we mark each updating record as deleted
1016
 
    (see the chain_append()) then write new one to the temporary data file.
 
908
    During update we mark each updating record as deleted 
 
909
    (see the chain_append()) then write new one to the temporary data file. 
1017
910
    At the end of the sequence in the rnd_end() we append all non-marked
1018
911
    records from the data file to the temporary data file then rename it.
1019
912
    The temp_file_length is used to calculate new data file length.
1024
917
  if (open_update_temp_file_if_needed())
1025
918
    goto err;
1026
919
 
1027
 
  if (internal::my_write(update_temp_file, (unsigned char*)buffer.ptr(), size,
 
920
  if (my_write(update_temp_file, (unsigned char*)buffer.ptr(), size,
1028
921
               MYF(MY_WME | MY_NABP)))
1029
922
    goto err;
1030
923
  temp_file_length+= size;
1039
932
  Deletes a row. First the database will find the row, and then call this
1040
933
  method. In the case of a table scan, the previous call to this will be
1041
934
  the ::rnd_next() that found this row.
1042
 
  The exception to this is an ORDER BY. This will cause the table Cursor
 
935
  The exception to this is an ORDER BY. This will cause the table handler
1043
936
  to walk the table noting the positions of all rows that match a query.
1044
937
  The table will then be deleted/positioned based on the ORDER (so RANDOM,
1045
938
  DESC, ASC).
1046
939
*/
1047
 
int ha_tina::delete_row(const unsigned char *)
 
940
int ha_tina::delete_row(const unsigned char * buf __attribute__((unused)))
1048
941
{
1049
 
  ha_statistic_increment(&system_status_var::ha_delete_count);
 
942
  ha_statistic_increment(&SSV::ha_delete_count);
1050
943
 
1051
944
  if (chain_append())
1052
945
    return(-1);
1064
957
 
1065
958
/**
1066
959
  @brief Initialize the data file.
1067
 
 
 
960
  
1068
961
  @details Compare the local version of the data file with the shared one.
1069
962
  If they differ, there are some changes behind and we have to reopen
1070
963
  the data file to make the changes visible.
1071
 
  Call @c file_buff->init_buff() at the end to read the beginning of the
 
964
  Call @c file_buff->init_buff() at the end to read the beginning of the 
1072
965
  data file into buffer.
1073
 
 
 
966
  
1074
967
  @retval  0  OK.
1075
968
  @retval  1  There was an error.
1076
969
*/
1080
973
  if (local_data_file_version != share->data_file_version)
1081
974
  {
1082
975
    local_data_file_version= share->data_file_version;
1083
 
    if (internal::my_close(data_file, MYF(0)) ||
1084
 
        (data_file= internal::my_open(share->data_file_name, O_RDONLY, MYF(0))) == -1)
 
976
    if (my_close(data_file, MYF(0)) ||
 
977
        (data_file= my_open(share->data_file_name, O_RDONLY, MYF(0))) == -1)
1085
978
      return 1;
1086
979
  }
1087
980
  file_buff->init_buff(data_file);
1093
986
  All table scans call this first.
1094
987
  The order of a table scan is:
1095
988
 
 
989
  ha_tina::store_lock
 
990
  ha_tina::external_lock
1096
991
  ha_tina::info
1097
992
  ha_tina::rnd_init
1098
993
  ha_tina::extra
1108
1003
  ha_tina::rnd_next
1109
1004
  ha_tina::extra
1110
1005
  ENUM HA_EXTRA_NO_CACHE   End cacheing of records (def)
 
1006
  ha_tina::external_lock
1111
1007
  ha_tina::extra
1112
1008
  ENUM HA_EXTRA_RESET   Reset database to after open
1113
1009
 
1117
1013
 
1118
1014
*/
1119
1015
 
1120
 
int ha_tina::rnd_init(bool)
 
1016
int ha_tina::rnd_init(bool scan __attribute__((unused)))
1121
1017
{
1122
1018
  /* set buffer to the beginning of the file */
1123
1019
  if (share->crashed || init_data_file())
1128
1024
  records_is_known= 0;
1129
1025
  chain_ptr= chain;
1130
1026
 
1131
 
  init_alloc_root(&blobroot, BLOB_MEMROOT_ALLOC_SIZE);
 
1027
  init_alloc_root(&blobroot, BLOB_MEMROOT_ALLOC_SIZE, 0);
1132
1028
 
1133
1029
  return(0);
1134
1030
}
1143
1039
  reserved for null count.
1144
1040
  Basically this works as a mask for which rows are nulled (compared to just
1145
1041
  empty).
1146
 
  This table Cursor doesn't do nulls and does not know the difference between
1147
 
  NULL and "". This is ok since this table Cursor is for spreadsheets and
 
1042
  This table handler doesn't do nulls and does not know the difference between
 
1043
  NULL and "". This is ok since this table handler is for spreadsheets and
1148
1044
  they don't know about them either :)
1149
1045
*/
1150
1046
int ha_tina::rnd_next(unsigned char *buf)
1154
1050
  if (share->crashed)
1155
1051
      return(HA_ERR_CRASHED_ON_USAGE);
1156
1052
 
1157
 
  ha_statistic_increment(&system_status_var::ha_read_rnd_next_count);
 
1053
  ha_statistic_increment(&SSV::ha_read_rnd_next_count);
1158
1054
 
1159
1055
  current_position= next_position;
1160
1056
 
1178
1074
  its just a position. Look at the bdb code if you want to see a case
1179
1075
  where something other then a number is stored.
1180
1076
*/
1181
 
void ha_tina::position(const unsigned char *)
 
1077
void ha_tina::position(const unsigned char *record __attribute__((unused)))
1182
1078
{
1183
 
  internal::my_store_ptr(ref, ref_length, current_position);
 
1079
  my_store_ptr(ref, ref_length, current_position);
1184
1080
  return;
1185
1081
}
1186
1082
 
1187
1083
 
1188
1084
/*
1189
1085
  Used to fetch a row from a posiion stored with ::position().
1190
 
  internal::my_get_ptr() retrieves the data for you.
 
1086
  my_get_ptr() retrieves the data for you.
1191
1087
*/
1192
1088
 
1193
1089
int ha_tina::rnd_pos(unsigned char * buf, unsigned char *pos)
1194
1090
{
1195
 
  ha_statistic_increment(&system_status_var::ha_read_rnd_count);
1196
 
  current_position= (off_t)internal::my_get_ptr(pos,ref_length);
 
1091
  ha_statistic_increment(&SSV::ha_read_rnd_count);
 
1092
  current_position= (off_t)my_get_ptr(pos,ref_length);
1197
1093
  return(find_current_row(buf));
1198
1094
}
1199
1095
 
1200
1096
/*
1201
1097
  ::info() is used to return information to the optimizer.
1202
 
  Currently this table Cursor doesn't implement most of the fields
 
1098
  Currently this table handler doesn't implement most of the fields
1203
1099
  really needed. SHOW also makes use of this data
1204
1100
*/
1205
 
int ha_tina::info(uint32_t)
 
1101
int ha_tina::info(uint32_t flag __attribute__((unused)))
1206
1102
{
1207
1103
  /* This is a lie, but you don't want the optimizer to see zero or 1 */
1208
 
  if (!records_is_known && stats.records < 2)
 
1104
  if (!records_is_known && stats.records < 2) 
1209
1105
    stats.records= 2;
1210
1106
  return(0);
1211
1107
}
1254
1150
      The sort is needed when there were updates/deletes with random orders.
1255
1151
      It sorts so that we move the firts blocks to the beginning.
1256
1152
    */
1257
 
    internal::my_qsort(chain, (size_t)(chain_ptr - chain), sizeof(tina_set),
1258
 
                       (qsort_cmp)sort_set);
 
1153
    my_qsort(chain, (size_t)(chain_ptr - chain), sizeof(tina_set),
 
1154
             (qsort_cmp)sort_set);
1259
1155
 
1260
1156
    off_t write_begin= 0, write_end;
1261
1157
 
1268
1164
    {
1269
1165
      bool in_hole= get_write_pos(&write_end, ptr);
1270
1166
      off_t write_length= write_end - write_begin;
1271
 
      if ((uint64_t)write_length > SIZE_MAX)
1272
 
      {
1273
 
        goto error;
1274
 
      }
1275
1167
 
1276
1168
      /* if there is something to write, write it */
1277
1169
      if (write_length)
1278
1170
      {
1279
 
        if (internal::my_write(update_temp_file,
 
1171
        if (my_write(update_temp_file, 
1280
1172
                     (unsigned char*) (file_buff->ptr() +
1281
1173
                               (write_begin - file_buff->start())),
1282
 
                     (size_t)write_length, MYF_RW))
 
1174
                     write_length, MYF_RW))
1283
1175
          goto error;
1284
1176
        temp_file_length+= write_length;
1285
1177
      }
1299
1191
 
1300
1192
    }
1301
1193
 
1302
 
    if (internal::my_sync(update_temp_file, MYF(MY_WME)) ||
1303
 
        internal::my_close(update_temp_file, MYF(0)))
 
1194
    if (my_sync(update_temp_file, MYF(MY_WME)) ||
 
1195
        my_close(update_temp_file, MYF(0)))
1304
1196
      return(-1);
1305
1197
 
1306
1198
    share->update_file_opened= false;
1307
1199
 
1308
1200
    if (share->tina_write_opened)
1309
1201
    {
1310
 
      if (internal::my_close(share->tina_write_filedes, MYF(0)))
 
1202
      if (my_close(share->tina_write_filedes, MYF(0)))
1311
1203
        return(-1);
1312
1204
      /*
1313
1205
        Mark that the writer fd is closed, so that init_tina_writer()
1320
1212
      Close opened fildes's. Then move updated file in place
1321
1213
      of the old datafile.
1322
1214
    */
1323
 
    if (internal::my_close(data_file, MYF(0)) ||
1324
 
        internal::my_rename(internal::fn_format(updated_fname,
1325
 
                                                share->table_name.c_str(),
1326
 
                                                "", CSN_EXT,
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)))
1329
1219
      return(-1);
1330
1220
 
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))
1333
1223
      return(-1);
1334
1224
    /*
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.
1341
1231
    */
1342
1232
    share->data_file_version++;
1347
1237
      Here we record this fact to the meta-file.
1348
1238
    */
1349
1239
    (void)write_meta_file(share->meta_file, share->rows_recorded, false);
1350
 
    /*
1351
 
      Update local_saved_data_file_length with the real length of the
 
1240
    /* 
 
1241
      Update local_saved_data_file_length with the real length of the 
1352
1242
      data file.
1353
1243
    */
1354
1244
    local_saved_data_file_length= temp_file_length;
1356
1246
 
1357
1247
  return(0);
1358
1248
error:
1359
 
  internal::my_close(update_temp_file, MYF(0));
 
1249
  my_close(update_temp_file, MYF(0));
1360
1250
  share->update_file_opened= false;
1361
1251
  return(-1);
1362
1252
}
1363
1253
 
1364
1254
 
1365
1255
/*
 
1256
  Repair CSV table in the case, it is crashed.
 
1257
 
 
1258
  SYNOPSIS
 
1259
    repair()
 
1260
    session         The thread, performing repair
 
1261
    check_opt   The options for repair. We do not use it currently.
 
1262
 
 
1263
  DESCRIPTION
 
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.
 
1268
 
 
1269
   TODO: Make repair more clever - it should try to recover subsequent
 
1270
         rows (after the first bad one) as well.
 
1271
*/
 
1272
 
 
1273
int ha_tina::repair(Session* session,
 
1274
                    HA_CHECK_OPT* check_opt __attribute__((unused)))
 
1275
{
 
1276
  char repaired_fname[FN_REFLEN];
 
1277
  unsigned char *buf;
 
1278
  File repair_file;
 
1279
  int rc;
 
1280
  ha_rows rows_repaired= 0;
 
1281
  off_t write_begin= 0, write_end;
 
1282
 
 
1283
  /* empty file */
 
1284
  if (!share->saved_data_file_length)
 
1285
  {
 
1286
    share->rows_recorded= 0;
 
1287
    goto end;
 
1288
  }
 
1289
 
 
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);
 
1294
 
 
1295
  /* position buffer to the start of the file */
 
1296
  if (init_data_file())
 
1297
    return(HA_ERR_CRASHED_ON_REPAIR);
 
1298
 
 
1299
  /*
 
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.
 
1303
  */
 
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;
 
1307
 
 
1308
  init_alloc_root(&blobroot, BLOB_MEMROOT_ALLOC_SIZE, 0);
 
1309
 
 
1310
  /* Read the file row-by-row. If everything is ok, repair is not needed. */
 
1311
  while (!(rc= find_current_row(buf)))
 
1312
  {
 
1313
    session_inc_row_count(session);
 
1314
    rows_repaired++;
 
1315
    current_position= next_position;
 
1316
  }
 
1317
 
 
1318
  free_root(&blobroot, MYF(0));
 
1319
 
 
1320
  free((char*)buf);
 
1321
 
 
1322
  if (rc == HA_ERR_END_OF_FILE)
 
1323
  {
 
1324
    /*
 
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.
 
1328
    */
 
1329
    share->rows_recorded= rows_repaired;
 
1330
    goto end;
 
1331
  }
 
1332
 
 
1333
  /*
 
1334
    Otherwise we've encountered a bad row => repair is needed.
 
1335
    Let us create a temporary file.
 
1336
  */
 
1337
  if ((repair_file= my_create(fn_format(repaired_fname, share->table_name,
 
1338
                                        "", CSN_EXT,
 
1339
                                        MY_REPLACE_EXT|MY_UNPACK_FILENAME),
 
1340
                           0, O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
 
1341
    return(HA_ERR_CRASHED_ON_REPAIR);
 
1342
 
 
1343
  file_buff->init_buff(data_file);
 
1344
 
 
1345
 
 
1346
  /* we just truncated the file up to the first bad row. update rows count. */
 
1347
  share->rows_recorded= rows_repaired;
 
1348
 
 
1349
  /* write repaired file */
 
1350
  while (1)
 
1351
  {
 
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)))
 
1356
      return(-1);
 
1357
 
 
1358
    write_begin= write_end;
 
1359
    if (write_end== current_position)
 
1360
      break;
 
1361
    else
 
1362
      file_buff->read_next(); /* shift the buffer */
 
1363
  }
 
1364
 
 
1365
  /*
 
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().
 
1370
  */
 
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)))
 
1373
    return(-1);
 
1374
 
 
1375
  /* Open the file again, it should now be repaired */
 
1376
  if ((data_file= my_open(share->data_file_name, O_RDWR|O_APPEND,
 
1377
                          MYF(0))) == -1)
 
1378
     return(-1);
 
1379
 
 
1380
  /* Set new file size. The file size will be updated by ::update_status() */
 
1381
  local_saved_data_file_length= (size_t) current_position;
 
1382
 
 
1383
end:
 
1384
  share->crashed= false;
 
1385
  return(HA_ADMIN_OK);
 
1386
}
 
1387
 
 
1388
/*
1366
1389
  DELETE without WHERE calls this
1367
1390
*/
1368
1391
 
1371
1394
  int rc;
1372
1395
 
1373
1396
  if (!records_is_known)
1374
 
    return(errno=HA_ERR_WRONG_COMMAND);
 
1397
    return(my_errno=HA_ERR_WRONG_COMMAND);
1375
1398
 
1376
1399
  if (!share->tina_write_opened)
1377
1400
    if (init_tina_writer())
1390
1413
}
1391
1414
 
1392
1415
/*
 
1416
  Called by the database to lock the table. Keep in mind that this
 
1417
  is an internal lock.
 
1418
*/
 
1419
THR_LOCK_DATA **ha_tina::store_lock(Session *session __attribute__((unused)),
 
1420
                                    THR_LOCK_DATA **to,
 
1421
                                    enum thr_lock_type lock_type)
 
1422
{
 
1423
  if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK)
 
1424
    lock.type=lock_type;
 
1425
  *to++= &lock;
 
1426
  return to;
 
1427
}
 
1428
 
 
1429
/* 
1393
1430
  Create a table. You do not want to leave the table open after a call to
1394
1431
  this (the database will call ::open() if it needs to).
1395
1432
*/
1396
1433
 
1397
 
int Tina::doCreateTable(Session &session,
1398
 
                        Table& table_arg,
1399
 
                        drizzled::TableIdentifier &identifier,
1400
 
                        drizzled::message::Table &create_proto)
 
1434
int ha_tina::create(const char *name, Table *table_arg,
 
1435
                    HA_CREATE_INFO *create_info __attribute__((unused)))
1401
1436
{
1402
1437
  char name_buff[FN_REFLEN];
1403
 
  int create_file;
 
1438
  File create_file;
1404
1439
 
1405
1440
  /*
1406
1441
    check columns
1407
1442
  */
1408
 
  for (Field **field= table_arg.s->field; *field; field++)
 
1443
  for (Field **field= table_arg->s->field; *field; field++)
1409
1444
  {
1410
1445
    if ((*field)->real_maybe_null())
1411
1446
    {
1413
1448
      return(HA_ERR_UNSUPPORTED);
1414
1449
    }
1415
1450
  }
1416
 
 
1417
 
 
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)
 
1451
  
 
1452
 
 
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)
1421
1456
    return(-1);
1422
1457
 
1423
1458
  write_meta_file(create_file, 0, false);
1424
 
  internal::my_close(create_file, MYF(0));
 
1459
  my_close(create_file, MYF(0));
1425
1460
 
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)
1429
1464
    return(-1);
1430
1465
 
1431
 
  internal::my_close(create_file, MYF(0));
1432
 
 
1433
 
  session.storeTableMessage(identifier, create_proto);
1434
 
 
1435
 
  return 0;
1436
 
}
1437
 
 
1438
 
 
1439
 
DRIZZLE_DECLARE_PLUGIN
1440
 
{
1441
 
  DRIZZLE_VERSION_ID,
 
1466
  my_close(create_file, MYF(0));
 
1467
 
 
1468
  return(0);
 
1469
}
 
1470
 
 
1471
int ha_tina::check(Session* session,
 
1472
                   HA_CHECK_OPT* check_opt __attribute__((unused)))
 
1473
{
 
1474
  int rc= 0;
 
1475
  unsigned char *buf;
 
1476
  const char *old_proc_info;
 
1477
  ha_rows count= share->rows_recorded;
 
1478
 
 
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);
 
1483
 
 
1484
  /* position buffer to the start of the file */
 
1485
   if (init_data_file())
 
1486
     return(HA_ERR_CRASHED);
 
1487
 
 
1488
  /*
 
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
 
1491
    manually here.
 
1492
  */
 
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;
 
1496
 
 
1497
  init_alloc_root(&blobroot, BLOB_MEMROOT_ALLOC_SIZE, 0);
 
1498
 
 
1499
  /* Read the file row-by-row. If everything is ok, repair is not needed. */
 
1500
  while (!(rc= find_current_row(buf)))
 
1501
  {
 
1502
    session_inc_row_count(session);
 
1503
    count--;
 
1504
    current_position= next_position;
 
1505
  }
 
1506
  
 
1507
  free_root(&blobroot, MYF(0));
 
1508
 
 
1509
  free((char*)buf);
 
1510
  set_session_proc_info(session, old_proc_info);
 
1511
 
 
1512
  if ((rc != HA_ERR_END_OF_FILE) || count)
 
1513
  {
 
1514
    share->crashed= true;
 
1515
    return(HA_ADMIN_CORRUPT);
 
1516
  }
 
1517
  else
 
1518
    return(HA_ADMIN_OK);
 
1519
}
 
1520
 
 
1521
 
 
1522
bool ha_tina::check_if_incompatible_data(HA_CREATE_INFO *info __attribute__((unused)),
 
1523
                                         uint32_t table_changes __attribute__((unused)))
 
1524
{
 
1525
  return COMPATIBLE_DATA_YES;
 
1526
}
 
1527
 
 
1528
mysql_declare_plugin(csv)
 
1529
{
 
1530
  DRIZZLE_STORAGE_ENGINE_PLUGIN,
1442
1531
  "CSV",
1443
1532
  "1.0",
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                  */
1450
1541
}
1451
 
DRIZZLE_DECLARE_PLUGIN_END;
 
1542
mysql_declare_plugin_end;
1452
1543