~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/csv/ha_tina.cc

  • Committer: Stewart Smith
  • Date: 2010-03-02 06:41:59 UTC
  • mto: (1309.2.13 build)
  • mto: This revision was merged to the branch mainline in revision 1318.
  • Revision ID: stewart@flamingspork.com-20100302064159-gktw6hcbs3u0fflm
move Item_result out to its own header file and out of common.h

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
 
12
12
  You should have received a copy of the GNU General Public License
13
13
  along with this program; if not, write to the Free Software
14
 
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
 
14
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
15
 
16
16
/*
17
17
  Make sure to look at ha_tina.h for more details.
53
53
 
54
54
#include <fcntl.h>
55
55
 
56
 
#include <algorithm>
57
 
#include <vector>
58
56
#include <string>
59
57
#include <map>
60
58
 
78
76
static int read_meta_file(int meta_file, ha_rows *rows);
79
77
static int write_meta_file(int meta_file, ha_rows rows, bool dirty);
80
78
 
 
79
void tina_get_status(void* param, int concurrent_insert);
 
80
void tina_update_status(void* param);
 
81
bool tina_check_status(void* param);
 
82
 
81
83
/* Stuff for shares */
82
84
pthread_mutex_t tina_mutex;
83
85
 
86
88
 *****************************************************************************/
87
89
 
88
90
/*
 
91
  Used for sorting chains with qsort().
 
92
*/
 
93
static int sort_set (tina_set *a, tina_set *b)
 
94
{
 
95
  /*
 
96
    We assume that intervals do not intersect. So, it is enought to compare
 
97
    any two points. Here we take start of intervals for comparison.
 
98
  */
 
99
  return ( a->begin > b->begin ? 1 : ( a->begin < b->begin ? -1 : 0 ) );
 
100
}
 
101
 
 
102
 
 
103
/*
89
104
  If frm_error() is called in table.cc this is called to find out what file
90
105
  extensions exist for this Cursor.
91
106
*/
104
119
   : drizzled::plugin::StorageEngine(name_arg,
105
120
                                     HTON_TEMPORARY_ONLY |
106
121
                                     HTON_NO_AUTO_INCREMENT |
107
 
                                     HTON_SKIP_STORE_LOCK),
 
122
                                     HTON_HAS_DATA_DICTIONARY |
 
123
                                     HTON_SKIP_STORE_LOCK |
 
124
                                     HTON_FILE_BASED),
108
125
    tina_open_tables()
109
126
  {}
110
 
  virtual ~Tina()
111
 
  {
112
 
    pthread_mutex_destroy(&tina_mutex);
113
 
  }
114
 
 
115
 
  virtual Cursor *create(Table &table)
116
 
  {
117
 
    return new ha_tina(*this, table);
 
127
  virtual Cursor *create(TableShare &table,
 
128
                         drizzled::memory::Root *mem_root)
 
129
  {
 
130
    return new (mem_root) ha_tina(*this, table);
118
131
  }
119
132
 
120
133
  const char **bas_ext() const {
121
134
    return ha_tina_exts;
122
135
  }
123
136
 
124
 
  int doCreateTable(Session &,
125
 
                    Table &table_arg,
126
 
                    const drizzled::TableIdentifier &identifier,
 
137
  int doCreateTable(Session *,
 
138
                    const char *table_name,
 
139
                    Table& table_arg,
127
140
                    drizzled::message::Table&);
128
141
 
129
142
  int doGetTableDefinition(Session& session,
130
 
                           const drizzled::TableIdentifier &identifier,
131
 
                           drizzled::message::Table &table_message);
132
 
 
133
 
  int doDropTable(Session&, const drizzled::TableIdentifier &identifier);
 
143
                           const char* path,
 
144
                           const char *db,
 
145
                           const char *table_name,
 
146
                           const bool is_tmp,
 
147
                           drizzled::message::Table *table_proto);
 
148
 
 
149
  /* Temp only engine, so do not return values. */
 
150
  void doGetTableNames(drizzled::CachedDirectory &, string& , set<string>&) { };
 
151
 
 
152
  int doDropTable(Session&, const string table_path);
134
153
  TinaShare *findOpenTable(const string table_name);
135
154
  void addOpenTable(const string &table_name, TinaShare *);
136
155
  void deleteOpenTable(const string &table_name);
139
158
  uint32_t max_keys()          const { return 0; }
140
159
  uint32_t max_key_parts()     const { return 0; }
141
160
  uint32_t max_key_length()    const { return 0; }
142
 
  bool doDoesTableExist(Session& session, const drizzled::TableIdentifier &identifier);
143
 
  int doRenameTable(Session&, const drizzled::TableIdentifier &from, const drizzled::TableIdentifier &to);
144
 
 
145
 
  void doGetTableIdentifiers(drizzled::CachedDirectory &directory,
146
 
                             const drizzled::SchemaIdentifier &schema_identifier,
147
 
                             drizzled::TableIdentifier::vector &set_of_identifiers);
148
161
};
149
162
 
150
 
void Tina::doGetTableIdentifiers(drizzled::CachedDirectory&,
151
 
                                 const drizzled::SchemaIdentifier&,
152
 
                                 drizzled::TableIdentifier::vector&)
153
 
{
154
 
}
155
 
 
156
 
int Tina::doRenameTable(Session &session,
157
 
                        const drizzled::TableIdentifier &from, const drizzled::TableIdentifier &to)
158
 
{
159
 
  int error= 0;
160
 
  for (const char **ext= bas_ext(); *ext ; ext++)
161
 
  {
162
 
    if (rename_file_ext(from.getPath().c_str(), to.getPath().c_str(), *ext))
163
 
    {
164
 
      if ((error=errno) != ENOENT)
165
 
        break;
166
 
      error= 0;
167
 
    }
168
 
  }
169
 
 
170
 
  session.getMessageCache().renameTableMessage(from, to);
171
 
 
172
 
  return error;
173
 
}
174
 
 
175
 
bool Tina::doDoesTableExist(Session &session, const drizzled::TableIdentifier &identifier)
176
 
{
177
 
  return session.getMessageCache().doesTableMessageExist(identifier);
178
 
}
179
 
 
180
 
 
181
 
int Tina::doDropTable(Session &session,
182
 
                      const drizzled::TableIdentifier &identifier)
 
163
int Tina::doDropTable(Session&,
 
164
                        const string table_path)
183
165
{
184
166
  int error= 0;
185
167
  int enoent_or_zero= ENOENT;                   // Error if no file was deleted
 
168
  char buff[FN_REFLEN];
 
169
  ProtoCache::iterator iter;
186
170
 
187
171
  for (const char **ext= bas_ext(); *ext ; ext++)
188
172
  {
189
 
    std::string full_name= identifier.getPath();
190
 
    full_name.append(*ext);
191
 
 
192
 
    if (internal::my_delete_with_symlink(full_name.c_str(), MYF(0)))
 
173
    internal::fn_format(buff, table_path.c_str(), "", *ext,
 
174
              MY_UNPACK_FILENAME|MY_APPEND_EXT);
 
175
    if (internal::my_delete_with_symlink(buff, MYF(0)))
193
176
    {
194
177
      if ((error= errno) != ENOENT)
195
178
        break;
196
179
    }
197
180
    else
198
 
    {
199
181
      enoent_or_zero= 0;                        // No error for ENOENT
200
 
    }
201
182
    error= enoent_or_zero;
202
183
  }
203
184
 
204
 
  session.getMessageCache().removeTableMessage(identifier);
 
185
  pthread_mutex_lock(&proto_cache_mutex);
 
186
  iter= proto_cache.find(table_path.c_str());
 
187
 
 
188
  if (iter!= proto_cache.end())
 
189
    proto_cache.erase(iter);
 
190
  pthread_mutex_unlock(&proto_cache_mutex);
205
191
 
206
192
  return error;
207
193
}
228
214
}
229
215
 
230
216
 
231
 
int Tina::doGetTableDefinition(Session &session,
232
 
                               const drizzled::TableIdentifier &identifier,
233
 
                               drizzled::message::Table &table_message)
 
217
int Tina::doGetTableDefinition(Session&,
 
218
                               const char* path,
 
219
                               const char *,
 
220
                               const char *,
 
221
                               const bool,
 
222
                               drizzled::message::Table *table_proto)
234
223
{
235
 
  if (session.getMessageCache().getTableMessage(identifier, table_message))
236
 
    return EEXIST;
237
 
 
238
 
  return ENOENT;
 
224
  int error= ENOENT;
 
225
  ProtoCache::iterator iter;
 
226
 
 
227
  pthread_mutex_lock(&proto_cache_mutex);
 
228
  iter= proto_cache.find(path);
 
229
 
 
230
  if (iter!= proto_cache.end())
 
231
  {
 
232
    if (table_proto)
 
233
      table_proto->CopyFrom(((*iter).second));
 
234
    error= EEXIST;
 
235
  }
 
236
  pthread_mutex_unlock(&proto_cache_mutex);
 
237
 
 
238
  return error;
239
239
}
240
240
 
241
241
 
242
242
static Tina *tina_engine= NULL;
243
243
 
244
 
static int tina_init_func(drizzled::module::Context &context)
 
244
static int tina_init_func(drizzled::plugin::Registry &registry)
245
245
{
246
246
 
247
247
  tina_engine= new Tina("CSV");
248
 
  context.add(tina_engine);
 
248
  registry.add(tina_engine);
249
249
 
250
250
  pthread_mutex_init(&tina_mutex,MY_MUTEX_INIT_FAST);
251
251
  return 0;
252
252
}
253
253
 
254
 
 
255
 
 
256
 
TinaShare::TinaShare(const std::string &table_name_arg) : 
257
 
  table_name(table_name_arg),
258
 
  data_file_name(table_name_arg),
259
 
  use_count(0),
260
 
  saved_data_file_length(0),
261
 
  update_file_opened(false),
262
 
  tina_write_opened(false),
263
 
  crashed(false),
264
 
  rows_recorded(0),
265
 
  data_file_version(0)
266
 
{
267
 
  data_file_name.append(CSV_EXT);
 
254
static int tina_done_func(drizzled::plugin::Registry &registry)
 
255
{
 
256
  registry.remove(tina_engine);
 
257
  delete tina_engine;
 
258
 
 
259
  pthread_mutex_destroy(&tina_mutex);
 
260
 
 
261
  return 0;
 
262
}
 
263
 
 
264
 
 
265
TinaShare::TinaShare(const char *table_name_arg)
 
266
  : table_name(table_name_arg), use_count(0), saved_data_file_length(0),
 
267
    update_file_opened(false), tina_write_opened(false),
 
268
    crashed(false), rows_recorded(0), data_file_version(0)
 
269
{
 
270
  thr_lock_init(&lock);
 
271
  internal::fn_format(data_file_name, table_name_arg, "", CSV_EXT,
 
272
            MY_REPLACE_EXT|MY_UNPACK_FILENAME);
268
273
}
269
274
 
270
275
TinaShare::~TinaShare()
271
276
{
 
277
  thr_lock_delete(&lock);
272
278
  pthread_mutex_destroy(&mutex);
273
279
}
274
280
 
275
281
/*
276
282
  Simple lock controls.
277
283
*/
278
 
TinaShare *ha_tina::get_share(const std::string &table_name)
 
284
TinaShare *ha_tina::get_share(const char *table_name)
279
285
{
280
286
  pthread_mutex_lock(&tina_mutex);
281
287
 
282
 
  Tina *a_tina= static_cast<Tina *>(getEngine());
 
288
  Tina *a_tina= static_cast<Tina *>(engine);
283
289
  share= a_tina->findOpenTable(table_name);
284
290
 
285
 
  std::string meta_file_name;
 
291
  char meta_file_name[FN_REFLEN];
286
292
  struct stat file_stat;
287
293
 
288
294
  /*
299
305
      return NULL;
300
306
    }
301
307
 
302
 
    meta_file_name.assign(table_name);
303
 
    meta_file_name.append(CSM_EXT);
 
308
    internal::fn_format(meta_file_name, table_name, "", CSM_EXT,
 
309
              MY_REPLACE_EXT|MY_UNPACK_FILENAME);
304
310
 
305
 
    if (stat(share->data_file_name.c_str(), &file_stat))
 
311
    if (stat(share->data_file_name, &file_stat))
306
312
    {
307
313
      pthread_mutex_unlock(&tina_mutex);
308
314
      delete share;
321
327
      Usually this will result in auto-repair, and we will get a good
322
328
      meta-file in the end.
323
329
    */
324
 
    if ((share->meta_file= internal::my_open(meta_file_name.c_str(),
 
330
    if ((share->meta_file= internal::my_open(meta_file_name,
325
331
                                             O_RDWR|O_CREAT, MYF(0))) == -1)
326
332
      share->crashed= true;
327
333
 
450
456
  (void)write_meta_file(share->meta_file, share->rows_recorded, true);
451
457
 
452
458
  if ((share->tina_write_filedes=
453
 
        internal::my_open(share->data_file_name.c_str(), O_RDWR|O_APPEND, MYF(0))) == -1)
 
459
        internal::my_open(share->data_file_name, O_RDWR|O_APPEND, MYF(0))) == -1)
454
460
  {
455
461
    share->crashed= true;
456
462
    return(1);
481
487
      share->tina_write_opened= false;
482
488
    }
483
489
 
484
 
    Tina *a_tina= static_cast<Tina *>(getEngine());
 
490
    Tina *a_tina= static_cast<Tina *>(engine);
485
491
    a_tina->deleteOpenTable(share->table_name);
486
492
    delete share;
487
493
  }
530
536
 
531
537
 
532
538
 
533
 
ha_tina::ha_tina(drizzled::plugin::StorageEngine &engine_arg, Table &table_arg)
 
539
ha_tina::ha_tina(drizzled::plugin::StorageEngine &engine_arg, TableShare &table_arg)
534
540
  :Cursor(engine_arg, table_arg),
535
541
  /*
536
542
    These definitions are found in Cursor.h
537
543
    They are not probably completely right.
538
544
  */
539
545
  current_position(0), next_position(0), local_saved_data_file_length(0),
540
 
  file_buff(0), local_data_file_version(0), records_is_known(0)
 
546
  file_buff(0), chain_alloced(0), chain_size(DEFAULT_CHAIN_LENGTH),
 
547
  local_data_file_version(0), records_is_known(0)
541
548
{
542
549
  /* Set our original buffers from pre-allocated memory */
543
550
  buffer.set((char*)byte_buffer, IO_SIZE, &my_charset_bin);
 
551
  chain= chain_buffer;
544
552
  file_buff= new Transparent_file();
545
553
}
546
554
 
557
565
 
558
566
  buffer.length(0);
559
567
 
560
 
  for (Field **field= getTable()->getFields() ; *field ; field++)
 
568
  for (Field **field=table->field ; *field ; field++)
561
569
  {
562
570
    const char *ptr;
563
571
    const char *end_ptr;
597
605
        {
598
606
          buffer.append('\\');
599
607
          buffer.append('"');
600
 
          (void) *ptr++;
 
608
          *ptr++;
601
609
        }
602
610
        else if (*ptr == '\r')
603
611
        {
604
612
          buffer.append('\\');
605
613
          buffer.append('r');
606
 
          (void) *ptr++;
 
614
          *ptr++;
607
615
        }
608
616
        else if (*ptr == '\\')
609
617
        {
610
618
          buffer.append('\\');
611
619
          buffer.append('\\');
612
 
          (void) *ptr++;
 
620
          *ptr++;
613
621
        }
614
622
        else if (*ptr == '\n')
615
623
        {
616
624
          buffer.append('\\');
617
625
          buffer.append('n');
618
 
          (void) *ptr++;
 
626
          *ptr++;
619
627
        }
620
628
        else
621
629
          buffer.append(*ptr++);
645
653
*/
646
654
int ha_tina::chain_append()
647
655
{
648
 
  if (chain.size() > 0 && chain.back().second == current_position)
649
 
    chain.back().second= next_position;
 
656
  if ( chain_ptr != chain && (chain_ptr -1)->end == current_position)
 
657
    (chain_ptr -1)->end= next_position;
650
658
  else
651
 
    chain.push_back(make_pair(current_position, next_position));
 
659
  {
 
660
    /* We set up for the next position */
 
661
    if ((off_t)(chain_ptr - chain) == (chain_size -1))
 
662
    {
 
663
      off_t location= chain_ptr - chain;
 
664
      chain_size += DEFAULT_CHAIN_LENGTH;
 
665
      if (chain_alloced)
 
666
      {
 
667
        if ((chain= (tina_set *) realloc(chain, chain_size)) == NULL)
 
668
          return -1;
 
669
      }
 
670
      else
 
671
      {
 
672
        tina_set *ptr= (tina_set *) malloc(chain_size * sizeof(tina_set));
 
673
        if (ptr == NULL)
 
674
          return -1;
 
675
        memcpy(ptr, chain, DEFAULT_CHAIN_LENGTH * sizeof(tina_set));
 
676
        chain= ptr;
 
677
        chain_alloced++;
 
678
      }
 
679
      chain_ptr= chain + location;
 
680
    }
 
681
    chain_ptr->begin= current_position;
 
682
    chain_ptr->end= next_position;
 
683
    chain_ptr++;
 
684
  }
 
685
 
652
686
  return 0;
653
687
}
654
688
 
662
696
  int eoln_len;
663
697
  int error;
664
698
 
665
 
  blobroot.free_root(MYF(drizzled::memory::MARK_BLOCKS_FREE));
 
699
  free_root(&blobroot, MYF(drizzled::memory::MARK_BLOCKS_FREE));
666
700
 
667
701
  /*
668
702
    We do not read further then local_saved_data_file_length in order
675
709
 
676
710
  error= HA_ERR_CRASHED_ON_USAGE;
677
711
 
678
 
  memset(buf, 0, getTable()->getShare()->null_bytes);
 
712
  memset(buf, 0, table->s->null_bytes);
679
713
 
680
 
  for (Field **field= getTable()->getFields() ; *field ; field++)
 
714
  for (Field **field=table->field ; *field ; field++)
681
715
  {
682
716
    char curr_char;
683
717
 
746
780
    {
747
781
      /* This masks a bug in the logic for a SELECT * */
748
782
      (*field)->setWriteSet();
749
 
      if ((*field)->store_and_check(CHECK_FIELD_WARN, buffer.c_ptr(), buffer.length(), buffer.charset()))
750
 
      {
 
783
      if ((*field)->store(buffer.ptr(), buffer.length(), buffer.charset(),
 
784
                          CHECK_FIELD_WARN))
751
785
        goto err;
752
 
      }
753
786
 
754
787
      if ((*field)->flags & BLOB_FLAG)
755
788
      {
762
795
        memcpy(&src, blob->ptr + packlength, sizeof(char*));
763
796
        if (src)
764
797
        {
765
 
          tgt= (unsigned char*) blobroot.alloc_root(length);
 
798
          tgt= (unsigned char*) alloc_root(&blobroot, length);
766
799
          memmove(tgt, src, length);
767
800
          memcpy(blob->ptr + packlength, &tgt, sizeof(char*));
768
801
        }
778
811
}
779
812
 
780
813
/*
 
814
  Three functions below are needed to enable concurrent insert functionality
 
815
  for CSV engine. For more details see mysys/thr_lock.c
 
816
*/
 
817
 
 
818
void tina_get_status(void* param, int)
 
819
{
 
820
  ha_tina *tina= (ha_tina*) param;
 
821
  tina->get_status();
 
822
}
 
823
 
 
824
void tina_update_status(void* param)
 
825
{
 
826
  ha_tina *tina= (ha_tina*) param;
 
827
  tina->update_status();
 
828
}
 
829
 
 
830
/* this should exist and return 0 for concurrent insert to work */
 
831
bool tina_check_status(void *)
 
832
{
 
833
  return 0;
 
834
}
 
835
 
 
836
/*
 
837
  Save the state of the table
 
838
 
 
839
  SYNOPSIS
 
840
    get_status()
 
841
 
 
842
  DESCRIPTION
 
843
    This function is used to retrieve the file length. During the lock
 
844
    phase of concurrent insert. For more details see comment to
 
845
    ha_tina::update_status below.
 
846
*/
 
847
 
 
848
void ha_tina::get_status()
 
849
{
 
850
  local_saved_data_file_length= share->saved_data_file_length;
 
851
}
 
852
 
 
853
 
 
854
/*
 
855
  Correct the state of the table. Called by unlock routines
 
856
  before the write lock is released.
 
857
 
 
858
  SYNOPSIS
 
859
    update_status()
 
860
 
 
861
  DESCRIPTION
 
862
    When we employ concurrent insert lock, we save current length of the file
 
863
    during the lock phase. We do not read further saved value, as we don't
 
864
    want to interfere with undergoing concurrent insert. Writers update file
 
865
    length info during unlock with update_status().
 
866
 
 
867
  NOTE
 
868
    For log tables concurrent insert works different. The reason is that
 
869
    log tables are always opened and locked. And as they do not unlock
 
870
    tables, the file length after writes should be updated in a different
 
871
    way.
 
872
*/
 
873
 
 
874
void ha_tina::update_status()
 
875
{
 
876
  /* correct local_saved_data_file_length for writers */
 
877
  share->saved_data_file_length= local_saved_data_file_length;
 
878
}
 
879
 
 
880
 
 
881
/*
781
882
  Open a database file. Keep in mind that tables are caches, so
782
883
  this will not be called for every request. Any sort of positions
783
884
  that need to be reset should be kept in the ::extra() call.
784
885
*/
785
 
int ha_tina::doOpen(const TableIdentifier &identifier, int , uint32_t )
 
886
int ha_tina::open(const char *name, int, uint32_t)
786
887
{
787
 
  if (not (share= get_share(identifier.getPath().c_str())))
 
888
  if (!(share= get_share(name)))
788
889
    return(ENOENT);
789
890
 
790
891
  if (share->crashed)
794
895
  }
795
896
 
796
897
  local_data_file_version= share->data_file_version;
797
 
  if ((data_file= internal::my_open(share->data_file_name.c_str(), O_RDONLY, MYF(0))) == -1)
 
898
  if ((data_file= internal::my_open(share->data_file_name, O_RDONLY, MYF(0))) == -1)
798
899
    return(0);
799
900
 
800
901
  /*
802
903
    so that they could save/update local_saved_data_file_length value
803
904
    during locking. This is needed to enable concurrent inserts.
804
905
  */
 
906
  thr_lock_data_init(&share->lock, &lock, (void*) this);
805
907
  ref_length=sizeof(off_t);
806
908
 
 
909
  share->lock.get_status= tina_get_status;
 
910
  share->lock.update_status= tina_update_status;
 
911
  share->lock.check_status= tina_check_status;
 
912
 
807
913
  return(0);
808
914
}
809
915
 
 
916
 
810
917
/*
811
918
  Close a database file. We remove ourselves from the shared strucutre.
812
919
  If it is empty we destroy it.
823
930
  of the file and appends the data. In an error case it really should
824
931
  just truncate to the original position (this is not done yet).
825
932
*/
826
 
int ha_tina::doInsertRecord(unsigned char * buf)
 
933
int ha_tina::write_row(unsigned char * buf)
827
934
{
828
935
  int size;
829
936
 
830
937
  if (share->crashed)
831
938
      return(HA_ERR_CRASHED_ON_USAGE);
832
939
 
 
940
  ha_statistic_increment(&system_status_var::ha_write_count);
 
941
 
833
942
  size= encode_quote(buf);
834
943
 
835
944
  if (!share->tina_write_opened)
881
990
  This will be called in a table scan right before the previous ::rnd_next()
882
991
  call.
883
992
*/
884
 
int ha_tina::doUpdateRecord(const unsigned char *, unsigned char * new_data)
 
993
int ha_tina::update_row(const unsigned char *, unsigned char * new_data)
885
994
{
886
995
  int size;
887
996
  int rc= -1;
888
997
 
 
998
  ha_statistic_increment(&system_status_var::ha_update_count);
 
999
 
 
1000
  if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
 
1001
    table->timestamp_field->set_time();
 
1002
 
889
1003
  size= encode_quote(new_data);
890
1004
 
891
1005
  /*
892
1006
    During update we mark each updating record as deleted
893
1007
    (see the chain_append()) then write new one to the temporary data file.
894
 
    At the end of the sequence in the doEndTableScan() we append all non-marked
 
1008
    At the end of the sequence in the rnd_end() we append all non-marked
895
1009
    records from the data file to the temporary data file then rename it.
896
1010
    The temp_file_length is used to calculate new data file length.
897
1011
  */
921
1035
  The table will then be deleted/positioned based on the ORDER (so RANDOM,
922
1036
  DESC, ASC).
923
1037
*/
924
 
int ha_tina::doDeleteRecord(const unsigned char *)
 
1038
int ha_tina::delete_row(const unsigned char *)
925
1039
{
 
1040
  ha_statistic_increment(&system_status_var::ha_delete_count);
926
1041
 
927
1042
  if (chain_append())
928
1043
    return(-1);
957
1072
  {
958
1073
    local_data_file_version= share->data_file_version;
959
1074
    if (internal::my_close(data_file, MYF(0)) ||
960
 
        (data_file= internal::my_open(share->data_file_name.c_str(), O_RDONLY, MYF(0))) == -1)
 
1075
        (data_file= internal::my_open(share->data_file_name, O_RDONLY, MYF(0))) == -1)
961
1076
      return 1;
962
1077
  }
963
1078
  file_buff->init_buff(data_file);
993
1108
 
994
1109
*/
995
1110
 
996
 
int ha_tina::doStartTableScan(bool)
 
1111
int ha_tina::rnd_init(bool)
997
1112
{
998
1113
  /* set buffer to the beginning of the file */
999
1114
  if (share->crashed || init_data_file())
1002
1117
  current_position= next_position= 0;
1003
1118
  stats.records= 0;
1004
1119
  records_is_known= 0;
1005
 
  chain.clear();
 
1120
  chain_ptr= chain;
1006
1121
 
1007
 
  blobroot.init_alloc_root(BLOB_MEMROOT_ALLOC_SIZE);
 
1122
  init_alloc_root(&blobroot, BLOB_MEMROOT_ALLOC_SIZE);
1008
1123
 
1009
1124
  return(0);
1010
1125
}
1091
1206
  to the given "hole", stored in the buffer. "Valid" here means,
1092
1207
  not listed in the chain of deleted records ("holes").
1093
1208
*/
1094
 
bool ha_tina::get_write_pos(off_t *end_pos, vector< pair<off_t, off_t> >::iterator &closest_hole)
 
1209
bool ha_tina::get_write_pos(off_t *end_pos, tina_set *closest_hole)
1095
1210
{
1096
 
  if (closest_hole == chain.end()) /* no more chains */
 
1211
  if (closest_hole == chain_ptr) /* no more chains */
1097
1212
    *end_pos= file_buff->end();
1098
1213
  else
1099
1214
    *end_pos= std::min(file_buff->end(),
1100
 
                       closest_hole->first);
1101
 
  return (closest_hole != chain.end()) && (*end_pos == closest_hole->first);
 
1215
                       closest_hole->begin);
 
1216
  return (closest_hole != chain_ptr) && (*end_pos == closest_hole->begin);
1102
1217
}
1103
1218
 
1104
1219
 
1108
1223
  slots to clean up all of the dead space we have collected while
1109
1224
  performing deletes/updates.
1110
1225
*/
1111
 
int ha_tina::doEndTableScan()
 
1226
int ha_tina::rnd_end()
1112
1227
{
 
1228
  char updated_fname[FN_REFLEN];
1113
1229
  off_t file_buffer_start= 0;
1114
1230
 
1115
 
  blobroot.free_root(MYF(0));
 
1231
  free_root(&blobroot, MYF(0));
1116
1232
  records_is_known= 1;
1117
1233
 
1118
 
  if (chain.size() > 0)
 
1234
  if ((chain_ptr - chain)  > 0)
1119
1235
  {
1120
 
    vector< pair<off_t, off_t> >::iterator ptr= chain.begin();
 
1236
    tina_set *ptr= chain;
1121
1237
 
1122
1238
    /*
1123
1239
      Re-read the beginning of a file (as the buffer should point to the
1129
1245
      The sort is needed when there were updates/deletes with random orders.
1130
1246
      It sorts so that we move the firts blocks to the beginning.
1131
1247
    */
1132
 
    sort(chain.begin(), chain.end());
 
1248
    internal::my_qsort(chain, (size_t)(chain_ptr - chain), sizeof(tina_set),
 
1249
                       (qsort_cmp)sort_set);
1133
1250
 
1134
1251
    off_t write_begin= 0, write_end;
1135
1252
 
1160
1277
      if (in_hole)
1161
1278
      {
1162
1279
        /* skip hole */
1163
 
        while (file_buff->end() <= ptr->second && file_buffer_start != -1)
 
1280
        while (file_buff->end() <= ptr->end && file_buffer_start != -1)
1164
1281
          file_buffer_start= file_buff->read_next();
1165
 
        write_begin= ptr->second;
1166
 
        ++ptr;
 
1282
        write_begin= ptr->end;
 
1283
        ptr++;
1167
1284
      }
1168
1285
      else
1169
1286
        write_begin= write_end;
1194
1311
      Close opened fildes's. Then move updated file in place
1195
1312
      of the old datafile.
1196
1313
    */
1197
 
    std::string rename_file= share->table_name;
1198
 
    rename_file.append(CSN_EXT);
1199
1314
    if (internal::my_close(data_file, MYF(0)) ||
1200
 
        internal::my_rename(rename_file.c_str(),
1201
 
                            share->data_file_name.c_str(), MYF(0)))
 
1315
        internal::my_rename(internal::fn_format(updated_fname,
 
1316
                                                share->table_name.c_str(),
 
1317
                                                "", CSN_EXT,
 
1318
                                                MY_REPLACE_EXT | MY_UNPACK_FILENAME),
 
1319
                            share->data_file_name, MYF(0)))
1202
1320
      return(-1);
1203
1321
 
1204
1322
    /* Open the file again */
1205
 
    if (((data_file= internal::my_open(share->data_file_name.c_str(), O_RDONLY, MYF(0))) == -1))
 
1323
    if (((data_file= internal::my_open(share->data_file_name, O_RDONLY, MYF(0))) == -1))
1206
1324
      return(-1);
1207
1325
    /*
1208
1326
      As we reopened the data file, increase share->data_file_version
1267
1385
  this (the database will call ::open() if it needs to).
1268
1386
*/
1269
1387
 
1270
 
int Tina::doCreateTable(Session &session,
 
1388
int Tina::doCreateTable(Session *, const char *table_name,
1271
1389
                        Table& table_arg,
1272
 
                        const drizzled::TableIdentifier &identifier,
1273
 
                        drizzled::message::Table &create_proto)
 
1390
                        drizzled::message::Table& create_proto)
1274
1391
{
1275
1392
  char name_buff[FN_REFLEN];
1276
1393
  int create_file;
1278
1395
  /*
1279
1396
    check columns
1280
1397
  */
1281
 
  const drizzled::TableShare::Fields fields(table_arg.getShare()->getFields());
1282
 
  for (drizzled::TableShare::Fields::const_iterator iter= fields.begin();
1283
 
       iter != fields.end();
1284
 
       iter++)
 
1398
  for (Field **field= table_arg.s->field; *field; field++)
1285
1399
  {
1286
 
    if (not *iter) // Historical legacy for NULL array end.
1287
 
      continue;
1288
 
 
1289
 
    if ((*iter)->real_maybe_null())
 
1400
    if ((*field)->real_maybe_null())
1290
1401
    {
1291
1402
      my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "nullable columns");
1292
1403
      return(HA_ERR_UNSUPPORTED);
1294
1405
  }
1295
1406
 
1296
1407
 
1297
 
  if ((create_file= internal::my_create(internal::fn_format(name_buff, identifier.getPath().c_str(), "", CSM_EXT,
1298
 
                                                            MY_REPLACE_EXT|MY_UNPACK_FILENAME), 0,
1299
 
                                        O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
 
1408
  if ((create_file= internal::my_create(internal::fn_format(name_buff, table_name, "", CSM_EXT,
 
1409
                                        MY_REPLACE_EXT|MY_UNPACK_FILENAME), 0,
 
1410
                              O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
1300
1411
    return(-1);
1301
1412
 
1302
1413
  write_meta_file(create_file, 0, false);
1303
1414
  internal::my_close(create_file, MYF(0));
1304
1415
 
1305
 
  if ((create_file= internal::my_create(internal::fn_format(name_buff, identifier.getPath().c_str(), "", CSV_EXT,
1306
 
                                                            MY_REPLACE_EXT|MY_UNPACK_FILENAME),0,
1307
 
                                        O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
 
1416
  if ((create_file= internal::my_create(internal::fn_format(name_buff, table_name, "", CSV_EXT,
 
1417
                                        MY_REPLACE_EXT|MY_UNPACK_FILENAME),0,
 
1418
                              O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
1308
1419
    return(-1);
1309
1420
 
1310
1421
  internal::my_close(create_file, MYF(0));
1311
1422
 
1312
 
  session.getMessageCache().storeTableMessage(identifier, create_proto);
 
1423
  pthread_mutex_lock(&proto_cache_mutex);
 
1424
  proto_cache.insert(make_pair(table_name, create_proto));
 
1425
  pthread_mutex_unlock(&proto_cache_mutex);
1313
1426
 
1314
1427
  return 0;
1315
1428
}
1324
1437
  "CSV storage engine",
1325
1438
  PLUGIN_LICENSE_GPL,
1326
1439
  tina_init_func, /* Plugin Init */
 
1440
  tina_done_func, /* Plugin Deinit */
1327
1441
  NULL,                       /* system variables                */
1328
1442
  NULL                        /* config options                  */
1329
1443
}