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 
00031 #include <drizzled/table.h>
00032 
00033 namespace drizzled
00034 {
00035 
00036 namespace table
00037 {
00038 
00039 Singular::Singular(Session *session, List<CreateField> &field_list) :
00040   _share(message::Table::INTERNAL),
00041   _has_variable_width(false)
00042 {
00043   uint32_t field_count= field_list.size();
00044   uint32_t blob_count= 0;
00045   Field **field_arg;
00046   CreateField *cdef;                           /* column definition */
00047   uint32_t record_length= 0;
00048   uint32_t null_count= 0;                 /* number of columns which may be null */
00049   uint32_t null_pack_length;              /* NULL representation array length */
00050 
00051   getMutableShare()->setFields(field_count + 1);
00052   setFields(getMutableShare()->getFields(true));
00053   field_arg= getMutableShare()->getFields(true);
00054   getMutableShare()->blob_field.resize(field_count+1);
00055   getMutableShare()->setFieldSize(field_count);
00056   getMutableShare()->blob_ptr_size= portable_sizeof_char_ptr;
00057   setup_tmp_table_column_bitmaps();
00058 
00059   in_use= session;           /* field_arg->reset() may access in_use */
00060 
00061   /* Create all fields and calculate the total length of record */
00062   List<CreateField>::iterator it(field_list.begin());
00063   message::Table::Field null_field;
00064   while ((cdef= it++))
00065   {
00066     *field_arg= getMutableShare()->make_field(null_field,
00067                                               NULL,
00068                                               cdef->length,
00069                                               (cdef->flags & NOT_NULL_FLAG) ? false : true,
00070                                               (unsigned char *) ((cdef->flags & NOT_NULL_FLAG) ? 0 : ""),
00071                                               (cdef->flags & NOT_NULL_FLAG) ? 0 : 1,
00072                                               cdef->decimals,
00073                                               cdef->sql_type,
00074                                               cdef->charset,
00075                                               cdef->unireg_check,
00076                                               cdef->interval,
00077                                               cdef->field_name,
00078                                               cdef->flags & UNSIGNED_FLAG ? true : false);
00079     if (!*field_arg)
00080     {
00081       throw "Memory allocation failure";
00082     }
00083 
00084     (*field_arg)->init(this);
00085     record_length+= (*field_arg)->pack_length();
00086     if (! ((*field_arg)->flags & NOT_NULL_FLAG))
00087       null_count++;
00088 
00089     if ((*field_arg)->flags & BLOB_FLAG)
00090       getMutableShare()->blob_field[blob_count++]= (uint32_t) (field_arg - getFields());
00091 
00092     field_arg++;
00093   }
00094   *field_arg= NULL;                             /* mark the end of the list */
00095   getMutableShare()->blob_field[blob_count]= 0;            /* mark the end of the list */
00096   getMutableShare()->blob_fields= blob_count;
00097 
00098   null_pack_length= (null_count + 7)/8;
00099   getMutableShare()->setRecordLength(record_length + null_pack_length);
00100   getMutableShare()->rec_buff_length= ALIGN_SIZE(getMutableShare()->getRecordLength() + 1);
00101   record[0]= (unsigned char*)session->getMemRoot()->allocate(getMutableShare()->rec_buff_length);
00102   if (not getInsertRecord())
00103   {
00104     throw "Memory allocation failure";
00105   }
00106 
00107   if (null_pack_length)
00108   {
00109     null_flags= (unsigned char*) getInsertRecord();
00110     getMutableShare()->null_fields= null_count;
00111     getMutableShare()->null_bytes= null_pack_length;
00112   }
00113   {
00114     /* Set up field pointers */
00115     unsigned char *null_pos= getInsertRecord();
00116     unsigned char *field_pos= null_pos + getMutableShare()->null_bytes;
00117     uint32_t null_bit= 1;
00118 
00119     for (field_arg= getFields(); *field_arg; ++field_arg)
00120     {
00121       Field *cur_field= *field_arg;
00122       if ((cur_field->flags & NOT_NULL_FLAG))
00123         cur_field->move_field(field_pos);
00124       else
00125       {
00126         cur_field->move_field(field_pos, (unsigned char*) null_pos, null_bit);
00127         null_bit<<= 1;
00128         if (null_bit == (1 << 8))
00129         {
00130           ++null_pos;
00131           null_bit= 1;
00132         }
00133       }
00134       cur_field->reset();
00135 
00136       field_pos+= cur_field->pack_length();
00137     }
00138   }
00139 }
00140 
00141 bool Singular::open_tmp_table()
00142 {
00143   int error;
00144   
00145   identifier::Table identifier(getShare()->getSchemaName(), getShare()->getTableName(), getShare()->getPath());
00146   if ((error=cursor->ha_open(identifier,
00147                              O_RDWR,
00148                              HA_OPEN_TMP_TABLE | HA_OPEN_INTERNAL_TABLE)))
00149   {
00150     print_error(error, MYF(0));
00151     db_stat= 0;
00152     return true;
00153   }
00154   (void) cursor->extra(HA_EXTRA_QUICK);   /* Faster */
00155   return false;
00156 }
00157 
00158 
00159 /*
00160   Create MyISAM temporary table
00161 
00162   SYNOPSIS
00163     create_myisam_tmp_table()
00164       keyinfo         Description of the index (there is always one index)
00165       start_recinfo   MyISAM's column descriptions
00166       recinfo INOUT   End of MyISAM's column descriptions
00167       options         Option bits
00168 
00169   DESCRIPTION
00170     Create a MyISAM temporary table according to passed description. The is
00171     assumed to have one unique index or constraint.
00172 
00173     The passed array or MI_COLUMNDEF structures must have this form:
00174 
00175       1. 1-byte column (afaiu for 'deleted' flag) (note maybe not 1-byte
00176          when there are many nullable columns)
00177       2. Table columns
00178       3. One free MI_COLUMNDEF element (*recinfo points here)
00179 
00180     This function may use the free element to create hash column for unique
00181     constraint.
00182 
00183    RETURN
00184      false - OK
00185      true  - Error
00186 */
00187 
00188 bool Singular::create_myisam_tmp_table(KeyInfo *keyinfo,
00189                                                  MI_COLUMNDEF *start_recinfo,
00190                                                  MI_COLUMNDEF **recinfo,
00191                                                  uint64_t options)
00192 {
00193   int error;
00194   MI_KEYDEF keydef;
00195   MI_UNIQUEDEF uniquedef;
00196 
00197   if (getShare()->sizeKeys())
00198   {           // Get keys for ni_create
00199     bool using_unique_constraint= false;
00200     HA_KEYSEG *seg= (HA_KEYSEG*) getMemRoot()->alloc_root(sizeof(*seg) * keyinfo->key_parts);
00201     if (not seg)
00202       return true;
00203 
00204     memset(seg, 0, sizeof(*seg) * keyinfo->key_parts);
00205     if (keyinfo->key_length >= cursor->getEngine()->max_key_length() ||
00206         keyinfo->key_parts > cursor->getEngine()->max_key_parts() ||
00207         getShare()->uniques)
00208     {
00209       /* Can't create a key; Make a unique constraint instead of a key */
00210       getMutableShare()->keys=    0;
00211       getMutableShare()->uniques= 1;
00212       using_unique_constraint= true;
00213       memset(&uniquedef, 0, sizeof(uniquedef));
00214       uniquedef.keysegs=keyinfo->key_parts;
00215       uniquedef.seg=seg;
00216       uniquedef.null_are_equal=1;
00217 
00218       /* Create extra column for hash value */
00219       memset(*recinfo, 0, sizeof(**recinfo));
00220       (*recinfo)->type= FIELD_CHECK;
00221       (*recinfo)->length=MI_UNIQUE_HASH_LENGTH;
00222       (*recinfo)++;
00223       getMutableShare()->setRecordLength(getShare()->getRecordLength() + MI_UNIQUE_HASH_LENGTH);
00224     }
00225     else
00226     {
00227       /* Create an unique key */
00228       memset(&keydef, 0, sizeof(keydef));
00229       keydef.flag=HA_NOSAME | HA_BINARY_PACK_KEY | HA_PACK_KEY;
00230       keydef.keysegs=  keyinfo->key_parts;
00231       keydef.seg= seg;
00232     }
00233     for (uint32_t i= 0; i < keyinfo->key_parts ; i++,seg++)
00234     {
00235       Field *key_field=keyinfo->key_part[i].field;
00236       seg->flag=     0;
00237       seg->language= key_field->charset()->number;
00238       seg->length=   keyinfo->key_part[i].length;
00239       seg->start=    keyinfo->key_part[i].offset;
00240       if (key_field->flags & BLOB_FLAG)
00241       {
00242         seg->type= ((keyinfo->key_part[i].key_type & 1 /* binary */) ?
00243                     HA_KEYTYPE_VARBINARY2 : HA_KEYTYPE_VARTEXT2);
00244         seg->bit_start= (uint8_t)(key_field->pack_length() - getShare()->blob_ptr_size);
00245         seg->flag= HA_BLOB_PART;
00246         seg->length= 0;     // Whole blob in unique constraint
00247       }
00248       else
00249       {
00250         seg->type= keyinfo->key_part[i].type;
00251       }
00252       if (!(key_field->flags & NOT_NULL_FLAG))
00253       {
00254         seg->null_bit= key_field->null_bit;
00255         seg->null_pos= (uint32_t) (key_field->null_ptr - (unsigned char*) getInsertRecord());
00256         /*
00257           We are using a GROUP BY on something that contains NULL
00258           In this case we have to tell MyISAM that two NULL should
00259           on INSERT be regarded at the same value
00260         */
00261         if (! using_unique_constraint)
00262           keydef.flag|= HA_NULL_ARE_EQUAL;
00263       }
00264     }
00265   }
00266   MI_CREATE_INFO create_info;
00267 
00268   if ((options & (OPTION_BIG_TABLES | SELECT_SMALL_RESULT)) ==
00269       OPTION_BIG_TABLES)
00270     create_info.data_file_length= ~(uint64_t) 0;
00271 
00272   if ((error= mi_create(getShare()->getTableName(), getShare()->sizeKeys(), &keydef,
00273                         (uint32_t) (*recinfo-start_recinfo),
00274                         start_recinfo,
00275                         getShare()->uniques, &uniquedef,
00276                         &create_info,
00277                         HA_CREATE_TMP_TABLE)))
00278   {
00279     print_error(error, MYF(0));
00280     db_stat= 0;
00281 
00282     return true;
00283   }
00284   in_use->status_var.created_tmp_disk_tables++;
00285   getMutableShare()->db_record_offset= 1;
00286   return false;
00287 }
00288 
00289 /*
00290   Set up column usage bitmaps for a temporary table
00291 
00292   IMPLEMENTATION
00293     For temporary tables, we need one bitmap with all columns set and
00294     a tmp_set bitmap to be used by things like filesort.
00295 */
00296 
00297 void Singular::setup_tmp_table_column_bitmaps()
00298 {
00299   uint32_t field_count= getShare()->sizeFields();
00300 
00301   def_read_set.resize(field_count);
00302   def_write_set.resize(field_count);
00303   tmp_set.resize(field_count);
00304   getMutableShare()->all_set.resize(field_count);
00305   getMutableShare()->all_set.set();
00306   def_write_set.set();
00307   def_read_set.set();
00308   default_column_bitmaps();
00309 }
00310 
00311 Singular::~Singular()
00312 {
00313   const char *save_proc_info;
00314 
00315   save_proc_info= in_use->get_proc_info();
00316   in_use->set_proc_info("removing tmp table");
00317 
00318   // Release latches since this can take a long time
00319   plugin::TransactionalStorageEngine::releaseTemporaryLatches(in_use);
00320 
00321   if (cursor)
00322   {
00323     if (db_stat)
00324     {
00325       cursor->closeMarkForDelete(getShare()->getTableName());
00326     }
00327 
00328     identifier::Table identifier(getShare()->getSchemaName(), getShare()->getTableName(), getShare()->getTableName());
00329     drizzled::error_t ignored;
00330     plugin::StorageEngine::dropTable(*in_use,
00331                                      *getShare()->getEngine(),
00332                                      identifier,
00333                                      ignored);
00334 
00335     delete cursor;
00336   }
00337 
00338   /* free blobs */
00339   for (Field **ptr= getFields() ; *ptr ; ptr++)
00340   {
00341     (*ptr)->free();
00342   }
00343   free_io_cache();
00344 
00345   getMemRoot()->free_root(MYF(0));
00346   in_use->set_proc_info(save_proc_info);
00347 }
00348 
00349 
00350 } /* namespace table */
00351 } /* namespace drizzled */