Drizzled Public API Documentation

singular.cc
00001 /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
00002  *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
00003  *
00004  *  Copyright (C) 2010 Brian Aker
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; either version 2 of the License, or
00009  *  (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00019  */
00020 
00021 #include <config.h>
00022 
00023 #include <sys/types.h>
00024 #include <sys/stat.h>
00025 #include <fcntl.h>
00026 
00027 #include <drizzled/session.h>
00028 #include <plugin/myisam/myisam.h>
00029 #include <drizzled/plugin/transactional_storage_engine.h>
00030 #include <drizzled/statistics_variables.h>
00031 #include <drizzled/table.h>
00032 #include <drizzled/create_field.h>
00033 
00034 namespace drizzled {
00035 namespace table {
00036 
00037 Singular::Singular(Session *session, std::list<CreateField>& field_list) :
00038   _share(message::Table::INTERNAL),
00039   _has_variable_width(false)
00040 {
00041   uint32_t field_count= field_list.size();
00042   uint32_t blob_count= 0;
00043   uint32_t record_length= 0;
00044   uint32_t null_count= 0;                 /* number of columns which may be null */
00045   uint32_t null_pack_length;              /* NULL representation array length */
00046 
00047   getMutableShare()->setFields(field_count + 1);
00048   setFields(getMutableShare()->getFields(true));
00049   Field** field_arg= getMutableShare()->getFields(true);
00050   getMutableShare()->blob_field.resize(field_count+1);
00051   getMutableShare()->setFieldSize(field_count);
00052   getMutableShare()->blob_ptr_size= portable_sizeof_char_ptr;
00053   setup_tmp_table_column_bitmaps();
00054 
00055   in_use= session;           /* field_arg->reset() may access in_use */
00056 
00057   /* Create all fields and calculate the total length of record */
00058   message::Table::Field null_field;
00059   BOOST_FOREACH(CreateField& it, field_list)
00060   {
00061     *field_arg= getMutableShare()->make_field(null_field,
00062                                               NULL,
00063                                               it.length,
00064                                               (it.flags & NOT_NULL_FLAG) ? false : true,
00065                                               (unsigned char *) ((it.flags & NOT_NULL_FLAG) ? 0 : ""),
00066                                               (it.flags & NOT_NULL_FLAG) ? 0 : 1,
00067                                               it.decimals,
00068                                               it.sql_type,
00069                                               it.charset,
00070                                               it.unireg_check,
00071                                               it.interval,
00072                                               it.field_name,
00073                                               it.flags & UNSIGNED_FLAG ? true : false);
00074     (*field_arg)->init(this);
00075     record_length+= (*field_arg)->pack_length();
00076     if (! ((*field_arg)->flags & NOT_NULL_FLAG))
00077       null_count++;
00078 
00079     if ((*field_arg)->flags & BLOB_FLAG)
00080       getMutableShare()->blob_field[blob_count++]= (uint32_t) (field_arg - getFields());
00081 
00082     field_arg++;
00083   }
00084   *field_arg= NULL;                             /* mark the end of the list */
00085   getMutableShare()->blob_field[blob_count]= 0;            /* mark the end of the list */
00086   getMutableShare()->blob_fields= blob_count;
00087 
00088   null_pack_length= (null_count + 7)/8;
00089   getMutableShare()->setRecordLength(record_length + null_pack_length);
00090   getMutableShare()->rec_buff_length= ALIGN_SIZE(getMutableShare()->getRecordLength() + 1);
00091   record[0]= session->mem.alloc(getMutableShare()->rec_buff_length);
00092 
00093   if (null_pack_length)
00094   {
00095     null_flags= getInsertRecord();
00096     getMutableShare()->null_fields= null_count;
00097     getMutableShare()->null_bytes= null_pack_length;
00098   }
00099   {
00100     /* Set up field pointers */
00101     unsigned char *null_pos= getInsertRecord();
00102     unsigned char *field_pos= null_pos + getMutableShare()->null_bytes;
00103     uint32_t null_bit= 1;
00104 
00105     for (field_arg= getFields(); *field_arg; ++field_arg)
00106     {
00107       Field *cur_field= *field_arg;
00108       if ((cur_field->flags & NOT_NULL_FLAG))
00109         cur_field->move_field(field_pos);
00110       else
00111       {
00112         cur_field->move_field(field_pos, (unsigned char*) null_pos, null_bit);
00113         null_bit<<= 1;
00114         if (null_bit == (1 << 8))
00115         {
00116           ++null_pos;
00117           null_bit= 1;
00118         }
00119       }
00120       cur_field->reset();
00121 
00122       field_pos+= cur_field->pack_length();
00123     }
00124   }
00125 }
00126 
00127 bool Singular::open_tmp_table()
00128 {
00129   identifier::Table identifier(getShare()->getSchemaName(), getShare()->getTableName(), getShare()->getPath());
00130   if (int error= cursor->ha_open(identifier, O_RDWR, HA_OPEN_TMP_TABLE | HA_OPEN_INTERNAL_TABLE))
00131   {
00132     print_error(error, MYF(0));
00133     db_stat= 0;
00134     return true;
00135   }
00136   (void) cursor->extra(HA_EXTRA_QUICK);   /* Faster */
00137   return false;
00138 }
00139 
00140 
00141 /*
00142   Create MyISAM temporary table
00143 
00144   SYNOPSIS
00145     create_myisam_tmp_table()
00146       keyinfo         Description of the index (there is always one index)
00147       start_recinfo   MyISAM's column descriptions
00148       recinfo INOUT   End of MyISAM's column descriptions
00149       options         Option bits
00150 
00151   DESCRIPTION
00152     Create a MyISAM temporary table according to passed description. The is
00153     assumed to have one unique index or constraint.
00154 
00155     The passed array or MI_COLUMNDEF structures must have this form:
00156 
00157       1. 1-byte column (afaiu for 'deleted' flag) (note maybe not 1-byte
00158          when there are many nullable columns)
00159       2. Table columns
00160       3. One free MI_COLUMNDEF element (*recinfo points here)
00161 
00162     This function may use the free element to create hash column for unique
00163     constraint.
00164 
00165    RETURN
00166      false - OK
00167      true  - Error
00168 */
00169 
00170 bool Singular::create_myisam_tmp_table(KeyInfo *keyinfo,
00171                                                  MI_COLUMNDEF *start_recinfo,
00172                                                  MI_COLUMNDEF **recinfo,
00173                                                  uint64_t options)
00174 {
00175   int error;
00176   MI_KEYDEF keydef;
00177   MI_UNIQUEDEF uniquedef;
00178 
00179   if (getShare()->sizeKeys())
00180   {           // Get keys for ni_create
00181     bool using_unique_constraint= false;
00182     HA_KEYSEG *seg= new (mem()) HA_KEYSEG[keyinfo->key_parts];
00183 
00184     memset(seg, 0, sizeof(*seg) * keyinfo->key_parts);
00185     if (keyinfo->key_length >= cursor->getEngine()->max_key_length() ||
00186         keyinfo->key_parts > cursor->getEngine()->max_key_parts() ||
00187         getShare()->uniques)
00188     {
00189       /* Can't create a key; Make a unique constraint instead of a key */
00190       getMutableShare()->keys=    0;
00191       getMutableShare()->uniques= 1;
00192       using_unique_constraint= true;
00193       memset(&uniquedef, 0, sizeof(uniquedef));
00194       uniquedef.keysegs=keyinfo->key_parts;
00195       uniquedef.seg=seg;
00196       uniquedef.null_are_equal=1;
00197 
00198       /* Create extra column for hash value */
00199       memset(*recinfo, 0, sizeof(**recinfo));
00200       (*recinfo)->type= FIELD_CHECK;
00201       (*recinfo)->length=MI_UNIQUE_HASH_LENGTH;
00202       (*recinfo)++;
00203       getMutableShare()->setRecordLength(getShare()->getRecordLength() + MI_UNIQUE_HASH_LENGTH);
00204     }
00205     else
00206     {
00207       /* Create an unique key */
00208       memset(&keydef, 0, sizeof(keydef));
00209       keydef.flag=HA_NOSAME | HA_BINARY_PACK_KEY | HA_PACK_KEY;
00210       keydef.keysegs=  keyinfo->key_parts;
00211       keydef.seg= seg;
00212     }
00213     for (uint32_t i= 0; i < keyinfo->key_parts ; i++,seg++)
00214     {
00215       Field *key_field=keyinfo->key_part[i].field;
00216       seg->flag=     0;
00217       seg->language= key_field->charset()->number;
00218       seg->length=   keyinfo->key_part[i].length;
00219       seg->start=    keyinfo->key_part[i].offset;
00220       if (key_field->flags & BLOB_FLAG)
00221       {
00222         seg->type= ((keyinfo->key_part[i].key_type & 1 /* binary */) ?
00223                     HA_KEYTYPE_VARBINARY2 : HA_KEYTYPE_VARTEXT2);
00224         seg->bit_start= (uint8_t)(key_field->pack_length() - getShare()->blob_ptr_size);
00225         seg->flag= HA_BLOB_PART;
00226         seg->length= 0;     // Whole blob in unique constraint
00227       }
00228       else
00229       {
00230         seg->type= keyinfo->key_part[i].type;
00231       }
00232       if (!(key_field->flags & NOT_NULL_FLAG))
00233       {
00234         seg->null_bit= key_field->null_bit;
00235         seg->null_pos= (uint32_t) (key_field->null_ptr - getInsertRecord());
00236         /*
00237           We are using a GROUP BY on something that contains NULL
00238           In this case we have to tell MyISAM that two NULL should
00239           on INSERT be regarded at the same value
00240         */
00241         if (! using_unique_constraint)
00242           keydef.flag|= HA_NULL_ARE_EQUAL;
00243       }
00244     }
00245   }
00246   MI_CREATE_INFO create_info;
00247 
00248   if ((options & (OPTION_BIG_TABLES | SELECT_SMALL_RESULT)) ==
00249       OPTION_BIG_TABLES)
00250     create_info.data_file_length= ~(uint64_t) 0;
00251 
00252   if ((error= mi_create(getShare()->getTableName(), getShare()->sizeKeys(), &keydef,
00253                         (uint32_t) (*recinfo-start_recinfo),
00254                         start_recinfo,
00255                         getShare()->uniques, &uniquedef,
00256                         &create_info,
00257                         HA_CREATE_TMP_TABLE)))
00258   {
00259     print_error(error, MYF(0));
00260     db_stat= 0;
00261 
00262     return true;
00263   }
00264   in_use->status_var.created_tmp_disk_tables++;
00265   getMutableShare()->db_record_offset= 1;
00266   return false;
00267 }
00268 
00269 /*
00270   Set up column usage bitmaps for a temporary table
00271 
00272   IMPLEMENTATION
00273     For temporary tables, we need one bitmap with all columns set and
00274     a tmp_set bitmap to be used by things like filesort.
00275 */
00276 
00277 void Singular::setup_tmp_table_column_bitmaps()
00278 {
00279   uint32_t field_count= getShare()->sizeFields();
00280 
00281   def_read_set.resize(field_count);
00282   def_write_set.resize(field_count);
00283   tmp_set.resize(field_count);
00284   getMutableShare()->all_set.resize(field_count);
00285   getMutableShare()->all_set.set();
00286   def_write_set.set();
00287   def_read_set.set();
00288   default_column_bitmaps();
00289 }
00290 
00291 Singular::~Singular()
00292 {
00293   const char* save_proc_info= in_use->get_proc_info();
00294   in_use->set_proc_info("removing tmp table");
00295 
00296   // Release latches since this can take a long time
00297   plugin::TransactionalStorageEngine::releaseTemporaryLatches(in_use);
00298 
00299   if (cursor)
00300   {
00301     if (db_stat)
00302       cursor->closeMarkForDelete();
00303 
00304     identifier::Table identifier(getShare()->getSchemaName(), getShare()->getTableName(), getShare()->getTableName());
00305     drizzled::error_t ignored;
00306     plugin::StorageEngine::dropTable(*in_use, *getShare()->getEngine(), identifier, ignored);
00307     delete cursor;
00308   }
00309 
00310   /* free blobs */
00311   for (Field **ptr= getFields(); *ptr; ptr++)
00312   {
00313     (*ptr)->free();
00314   }
00315   free_io_cache();
00316 
00317   mem().free_root(MYF(0));
00318   in_use->set_proc_info(save_proc_info);
00319 }
00320 
00321 } /* namespace table */
00322 } /* namespace drizzled */