Drizzled Public API Documentation

singular.cc
1 /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3  *
4  * Copyright (C) 2010 Brian Aker
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #include <config.h>
22 
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 
27 #include <drizzled/session.h>
28 #include <plugin/myisam/myisam.h>
29 #include <drizzled/plugin/transactional_storage_engine.h>
30 #include <drizzled/statistics_variables.h>
31 #include <drizzled/table.h>
32 #include <drizzled/create_field.h>
33 
34 namespace drizzled {
35 namespace table {
36 
37 Singular::Singular(Session *session, std::list<CreateField>& field_list) :
38  _share(message::Table::INTERNAL),
39  _has_variable_width(false)
40 {
41  uint32_t field_count= field_list.size();
42  uint32_t blob_count= 0;
43  uint32_t record_length= 0;
44  uint32_t null_count= 0; /* number of columns which may be null */
45  uint32_t null_pack_length; /* NULL representation array length */
46 
47  getMutableShare()->setFields(field_count + 1);
48  setFields(getMutableShare()->getFields(true));
49  Field** field_arg= getMutableShare()->getFields(true);
50  getMutableShare()->blob_field.resize(field_count+1);
51  getMutableShare()->setFieldSize(field_count);
52  getMutableShare()->blob_ptr_size= portable_sizeof_char_ptr;
53  setup_tmp_table_column_bitmaps();
54 
55  in_use= session; /* field_arg->reset() may access in_use */
56 
57  /* Create all fields and calculate the total length of record */
58  message::Table::Field null_field;
59  BOOST_FOREACH(CreateField& it, field_list)
60  {
61  *field_arg= getMutableShare()->make_field(null_field,
62  NULL,
63  it.length,
64  (it.flags & NOT_NULL_FLAG) ? false : true,
65  (unsigned char *) ((it.flags & NOT_NULL_FLAG) ? 0 : ""),
66  (it.flags & NOT_NULL_FLAG) ? 0 : 1,
67  it.decimals,
68  it.sql_type,
69  it.charset,
70  it.unireg_check,
71  it.interval,
72  it.field_name,
73  it.flags & UNSIGNED_FLAG ? true : false);
74  (*field_arg)->init(this);
75  record_length+= (*field_arg)->pack_length();
76  if (! ((*field_arg)->flags & NOT_NULL_FLAG))
77  null_count++;
78 
79  if ((*field_arg)->flags & BLOB_FLAG)
80  getMutableShare()->blob_field[blob_count++]= (uint32_t) (field_arg - getFields());
81 
82  field_arg++;
83  }
84  *field_arg= NULL; /* mark the end of the list */
85  getMutableShare()->blob_field[blob_count]= 0; /* mark the end of the list */
86  getMutableShare()->blob_fields= blob_count;
87 
88  null_pack_length= (null_count + 7)/8;
89  getMutableShare()->setRecordLength(record_length + null_pack_length);
90  getMutableShare()->rec_buff_length= ALIGN_SIZE(getMutableShare()->getRecordLength() + 1);
91  record[0]= session->mem.alloc(getMutableShare()->rec_buff_length);
92 
93  if (null_pack_length)
94  {
95  null_flags= getInsertRecord();
96  getMutableShare()->null_fields= null_count;
97  getMutableShare()->null_bytes= null_pack_length;
98  }
99  {
100  /* Set up field pointers */
101  unsigned char *null_pos= getInsertRecord();
102  unsigned char *field_pos= null_pos + getMutableShare()->null_bytes;
103  uint32_t null_bit= 1;
104 
105  for (field_arg= getFields(); *field_arg; ++field_arg)
106  {
107  Field *cur_field= *field_arg;
108  if ((cur_field->flags & NOT_NULL_FLAG))
109  cur_field->move_field(field_pos);
110  else
111  {
112  cur_field->move_field(field_pos, (unsigned char*) null_pos, null_bit);
113  null_bit<<= 1;
114  if (null_bit == (1 << 8))
115  {
116  ++null_pos;
117  null_bit= 1;
118  }
119  }
120  cur_field->reset();
121 
122  field_pos+= cur_field->pack_length();
123  }
124  }
125 }
126 
127 bool Singular::open_tmp_table()
128 {
129  identifier::Table identifier(getShare()->getSchemaName(), getShare()->getTableName(), getShare()->getPath());
130  if (int error= cursor->ha_open(identifier, O_RDWR, HA_OPEN_TMP_TABLE | HA_OPEN_INTERNAL_TABLE))
131  {
132  print_error(error, MYF(0));
133  db_stat= 0;
134  return true;
135  }
136  (void) cursor->extra(HA_EXTRA_QUICK); /* Faster */
137  return false;
138 }
139 
140 
141 /*
142  Create MyISAM temporary table
143 
144  SYNOPSIS
145  create_myisam_tmp_table()
146  keyinfo Description of the index (there is always one index)
147  start_recinfo MyISAM's column descriptions
148  recinfo INOUT End of MyISAM's column descriptions
149  options Option bits
150 
151  DESCRIPTION
152  Create a MyISAM temporary table according to passed description. The is
153  assumed to have one unique index or constraint.
154 
155  The passed array or MI_COLUMNDEF structures must have this form:
156 
157  1. 1-byte column (afaiu for 'deleted' flag) (note maybe not 1-byte
158  when there are many nullable columns)
159  2. Table columns
160  3. One free MI_COLUMNDEF element (*recinfo points here)
161 
162  This function may use the free element to create hash column for unique
163  constraint.
164 
165  RETURN
166  false - OK
167  true - Error
168 */
169 
170 bool Singular::create_myisam_tmp_table(KeyInfo *keyinfo,
171  MI_COLUMNDEF *start_recinfo,
172  MI_COLUMNDEF **recinfo,
173  uint64_t options)
174 {
175  int error;
176  MI_KEYDEF keydef;
177  MI_UNIQUEDEF uniquedef;
178 
179  if (getShare()->sizeKeys())
180  { // Get keys for ni_create
181  bool using_unique_constraint= false;
182  HA_KEYSEG *seg= new (mem()) HA_KEYSEG[keyinfo->key_parts];
183 
184  memset(seg, 0, sizeof(*seg) * keyinfo->key_parts);
185  if (keyinfo->key_length >= cursor->getEngine()->max_key_length() ||
186  keyinfo->key_parts > cursor->getEngine()->max_key_parts() ||
187  getShare()->uniques)
188  {
189  /* Can't create a key; Make a unique constraint instead of a key */
190  getMutableShare()->keys= 0;
191  getMutableShare()->uniques= 1;
192  using_unique_constraint= true;
193  memset(&uniquedef, 0, sizeof(uniquedef));
194  uniquedef.keysegs=keyinfo->key_parts;
195  uniquedef.seg=seg;
196  uniquedef.null_are_equal=1;
197 
198  /* Create extra column for hash value */
199  memset(*recinfo, 0, sizeof(**recinfo));
200  (*recinfo)->type= FIELD_CHECK;
201  (*recinfo)->length=MI_UNIQUE_HASH_LENGTH;
202  (*recinfo)++;
203  getMutableShare()->setRecordLength(getShare()->getRecordLength() + MI_UNIQUE_HASH_LENGTH);
204  }
205  else
206  {
207  /* Create an unique key */
208  memset(&keydef, 0, sizeof(keydef));
209  keydef.flag=HA_NOSAME | HA_BINARY_PACK_KEY | HA_PACK_KEY;
210  keydef.keysegs= keyinfo->key_parts;
211  keydef.seg= seg;
212  }
213  for (uint32_t i= 0; i < keyinfo->key_parts ; i++,seg++)
214  {
215  Field *key_field=keyinfo->key_part[i].field;
216  seg->flag= 0;
217  seg->language= key_field->charset()->number;
218  seg->length= keyinfo->key_part[i].length;
219  seg->start= keyinfo->key_part[i].offset;
220  if (key_field->flags & BLOB_FLAG)
221  {
222  seg->type= ((keyinfo->key_part[i].key_type & 1 /* binary */) ?
223  HA_KEYTYPE_VARBINARY2 : HA_KEYTYPE_VARTEXT2);
224  seg->bit_start= (uint8_t)(key_field->pack_length() - getShare()->blob_ptr_size);
225  seg->flag= HA_BLOB_PART;
226  seg->length= 0; // Whole blob in unique constraint
227  }
228  else
229  {
230  seg->type= keyinfo->key_part[i].type;
231  }
232  if (!(key_field->flags & NOT_NULL_FLAG))
233  {
234  seg->null_bit= key_field->null_bit;
235  seg->null_pos= (uint32_t) (key_field->null_ptr - getInsertRecord());
236  /*
237  We are using a GROUP BY on something that contains NULL
238  In this case we have to tell MyISAM that two NULL should
239  on INSERT be regarded at the same value
240  */
241  if (! using_unique_constraint)
242  keydef.flag|= HA_NULL_ARE_EQUAL;
243  }
244  }
245  }
246  MI_CREATE_INFO create_info;
247 
248  if ((options & (OPTION_BIG_TABLES | SELECT_SMALL_RESULT)) ==
249  OPTION_BIG_TABLES)
250  create_info.data_file_length= ~(uint64_t) 0;
251 
252  if ((error= mi_create(getShare()->getTableName(), getShare()->sizeKeys(), &keydef,
253  (uint32_t) (*recinfo-start_recinfo),
254  start_recinfo,
255  getShare()->uniques, &uniquedef,
256  &create_info,
257  HA_CREATE_TMP_TABLE)))
258  {
259  print_error(error, MYF(0));
260  db_stat= 0;
261 
262  return true;
263  }
264  in_use->status_var.created_tmp_disk_tables++;
265  getMutableShare()->db_record_offset= 1;
266  return false;
267 }
268 
269 /*
270  Set up column usage bitmaps for a temporary table
271 
272  IMPLEMENTATION
273  For temporary tables, we need one bitmap with all columns set and
274  a tmp_set bitmap to be used by things like filesort.
275 */
276 
277 void Singular::setup_tmp_table_column_bitmaps()
278 {
279  uint32_t field_count= getShare()->sizeFields();
280 
281  def_read_set.resize(field_count);
282  def_write_set.resize(field_count);
283  tmp_set.resize(field_count);
284  getMutableShare()->all_set.resize(field_count);
285  getMutableShare()->all_set.set();
286  def_write_set.set();
287  def_read_set.set();
288  default_column_bitmaps();
289 }
290 
291 Singular::~Singular()
292 {
293  const char* save_proc_info= in_use->get_proc_info();
294  in_use->set_proc_info("removing tmp table");
295 
296  // Release latches since this can take a long time
298 
299  if (cursor)
300  {
301  if (db_stat)
302  cursor->closeMarkForDelete();
303 
304  identifier::Table identifier(getShare()->getSchemaName(), getShare()->getTableName(), getShare()->getTableName());
305  drizzled::error_t ignored;
306  plugin::StorageEngine::dropTable(*in_use, *getShare()->getEngine(), identifier, ignored);
307  delete cursor;
308  }
309 
310  /* free blobs */
311  for (Field **ptr= getFields(); *ptr; ptr++)
312  {
313  (*ptr)->free();
314  }
315  free_io_cache();
316 
317  mem().free_root(MYF(0));
318  in_use->set_proc_info(save_proc_info);
319 }
320 
321 } /* namespace table */
322 } /* namespace drizzled */