1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4
* Copyright (C) 2010 Brian Aker
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.
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.
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
23
#include <sys/types.h>
27
#include "drizzled/session.h"
28
#include "plugin/myisam/myisam.h"
29
#include "drizzled/plugin/transactional_storage_engine.h"
31
#include "drizzled/table.h"
39
Singular::Singular(Session *session, List<CreateField> &field_list) :
40
_share(message::Table::INTERNAL),
41
_has_variable_width(false)
43
uint32_t field_count= field_list.elements;
44
uint32_t blob_count= 0;
46
CreateField *cdef; /* column definition */
47
uint32_t record_length= 0;
48
uint32_t null_count= 0; /* number of columns which may be null */
49
uint32_t null_pack_length; /* NULL representation array length */
51
getMutableShare()->setFields(field_count + 1);
52
setFields(getMutableShare()->getFields(true));
53
field_arg= getMutableShare()->getFields(true);
54
getMutableShare()->blob_field.resize(field_count+1);
55
getMutableShare()->setFieldSize(field_count);
56
getMutableShare()->blob_ptr_size= portable_sizeof_char_ptr;
57
setup_tmp_table_column_bitmaps();
59
in_use= session; /* field_arg->reset() may access in_use */
61
/* Create all fields and calculate the total length of record */
62
List_iterator_fast<CreateField> it(field_list);
63
message::Table::Field null_field;
66
*field_arg= getMutableShare()->make_field(null_field,
69
(cdef->flags & NOT_NULL_FLAG) ? false : true,
70
(unsigned char *) ((cdef->flags & NOT_NULL_FLAG) ? 0 : ""),
71
(cdef->flags & NOT_NULL_FLAG) ? 0 : 1,
78
cdef->flags & UNSIGNED_FLAG ? true : false);
81
throw "Memory allocation failure";
84
(*field_arg)->init(this);
85
record_length+= (*field_arg)->pack_length();
86
if (! ((*field_arg)->flags & NOT_NULL_FLAG))
89
if ((*field_arg)->flags & BLOB_FLAG)
90
getMutableShare()->blob_field[blob_count++]= (uint32_t) (field_arg - getFields());
94
*field_arg= NULL; /* mark the end of the list */
95
getMutableShare()->blob_field[blob_count]= 0; /* mark the end of the list */
96
getMutableShare()->blob_fields= blob_count;
98
null_pack_length= (null_count + 7)/8;
99
getMutableShare()->setRecordLength(record_length + null_pack_length);
100
getMutableShare()->rec_buff_length= ALIGN_SIZE(getMutableShare()->getRecordLength() + 1);
101
record[0]= (unsigned char*)session->getMemRoot()->allocate(getMutableShare()->rec_buff_length);
102
if (not getInsertRecord())
104
throw "Memory allocation failure";
107
if (null_pack_length)
109
null_flags= (unsigned char*) getInsertRecord();
110
getMutableShare()->null_fields= null_count;
111
getMutableShare()->null_bytes= null_pack_length;
114
/* Set up field pointers */
115
unsigned char *null_pos= getInsertRecord();
116
unsigned char *field_pos= null_pos + getMutableShare()->null_bytes;
117
uint32_t null_bit= 1;
119
for (field_arg= getFields(); *field_arg; ++field_arg)
121
Field *cur_field= *field_arg;
122
if ((cur_field->flags & NOT_NULL_FLAG))
123
cur_field->move_field(field_pos);
126
cur_field->move_field(field_pos, (unsigned char*) null_pos, null_bit);
128
if (null_bit == (1 << 8))
136
field_pos+= cur_field->pack_length();
141
bool Singular::open_tmp_table()
145
identifier::Table identifier(getShare()->getSchemaName(), getShare()->getTableName(), getShare()->getPath());
146
if ((error=cursor->ha_open(identifier,
148
HA_OPEN_TMP_TABLE | HA_OPEN_INTERNAL_TABLE)))
150
print_error(error, MYF(0));
154
(void) cursor->extra(HA_EXTRA_QUICK); /* Faster */
160
Create MyISAM temporary table
163
create_myisam_tmp_table()
164
keyinfo Description of the index (there is always one index)
165
start_recinfo MyISAM's column descriptions
166
recinfo INOUT End of MyISAM's column descriptions
170
Create a MyISAM temporary table according to passed description. The is
171
assumed to have one unique index or constraint.
173
The passed array or MI_COLUMNDEF structures must have this form:
175
1. 1-byte column (afaiu for 'deleted' flag) (note maybe not 1-byte
176
when there are many nullable columns)
178
3. One free MI_COLUMNDEF element (*recinfo points here)
180
This function may use the free element to create hash column for unique
188
bool Singular::create_myisam_tmp_table(KeyInfo *keyinfo,
189
MI_COLUMNDEF *start_recinfo,
190
MI_COLUMNDEF **recinfo,
195
MI_UNIQUEDEF uniquedef;
197
if (getShare()->sizeKeys())
198
{ // Get keys for ni_create
199
bool using_unique_constraint= false;
200
HA_KEYSEG *seg= (HA_KEYSEG*) getMemRoot()->alloc_root(sizeof(*seg) * keyinfo->key_parts);
204
memset(seg, 0, sizeof(*seg) * keyinfo->key_parts);
205
if (keyinfo->key_length >= cursor->getEngine()->max_key_length() ||
206
keyinfo->key_parts > cursor->getEngine()->max_key_parts() ||
209
/* Can't create a key; Make a unique constraint instead of a key */
210
getMutableShare()->keys= 0;
211
getMutableShare()->uniques= 1;
212
using_unique_constraint= true;
213
memset(&uniquedef, 0, sizeof(uniquedef));
214
uniquedef.keysegs=keyinfo->key_parts;
216
uniquedef.null_are_equal=1;
218
/* Create extra column for hash value */
219
memset(*recinfo, 0, sizeof(**recinfo));
220
(*recinfo)->type= FIELD_CHECK;
221
(*recinfo)->length=MI_UNIQUE_HASH_LENGTH;
223
getMutableShare()->setRecordLength(getShare()->getRecordLength() + MI_UNIQUE_HASH_LENGTH);
227
/* Create an unique key */
228
memset(&keydef, 0, sizeof(keydef));
229
keydef.flag=HA_NOSAME | HA_BINARY_PACK_KEY | HA_PACK_KEY;
230
keydef.keysegs= keyinfo->key_parts;
233
for (uint32_t i= 0; i < keyinfo->key_parts ; i++,seg++)
235
Field *key_field=keyinfo->key_part[i].field;
237
seg->language= key_field->charset()->number;
238
seg->length= keyinfo->key_part[i].length;
239
seg->start= keyinfo->key_part[i].offset;
240
if (key_field->flags & BLOB_FLAG)
242
seg->type= ((keyinfo->key_part[i].key_type & 1 /* binary */) ?
243
HA_KEYTYPE_VARBINARY2 : HA_KEYTYPE_VARTEXT2);
244
seg->bit_start= (uint8_t)(key_field->pack_length() - getShare()->blob_ptr_size);
245
seg->flag= HA_BLOB_PART;
246
seg->length= 0; // Whole blob in unique constraint
250
seg->type= keyinfo->key_part[i].type;
252
if (!(key_field->flags & NOT_NULL_FLAG))
254
seg->null_bit= key_field->null_bit;
255
seg->null_pos= (uint32_t) (key_field->null_ptr - (unsigned char*) getInsertRecord());
257
We are using a GROUP BY on something that contains NULL
258
In this case we have to tell MyISAM that two NULL should
259
on INSERT be regarded at the same value
261
if (! using_unique_constraint)
262
keydef.flag|= HA_NULL_ARE_EQUAL;
266
MI_CREATE_INFO create_info;
268
if ((options & (OPTION_BIG_TABLES | SELECT_SMALL_RESULT)) ==
270
create_info.data_file_length= ~(uint64_t) 0;
272
if ((error= mi_create(getShare()->getTableName(), getShare()->sizeKeys(), &keydef,
273
(uint32_t) (*recinfo-start_recinfo),
275
getShare()->uniques, &uniquedef,
277
HA_CREATE_TMP_TABLE)))
279
print_error(error, MYF(0));
284
in_use->status_var.created_tmp_disk_tables++;
285
getMutableShare()->db_record_offset= 1;
290
Set up column usage bitmaps for a temporary table
293
For temporary tables, we need one bitmap with all columns set and
294
a tmp_set bitmap to be used by things like filesort.
297
void Singular::setup_tmp_table_column_bitmaps()
299
uint32_t field_count= getShare()->sizeFields();
301
def_read_set.resize(field_count);
302
def_write_set.resize(field_count);
303
tmp_set.resize(field_count);
304
getMutableShare()->all_set.resize(field_count);
305
getMutableShare()->all_set.set();
308
default_column_bitmaps();
311
Singular::~Singular()
313
const char *save_proc_info;
315
save_proc_info= in_use->get_proc_info();
316
in_use->set_proc_info("removing tmp table");
318
// Release latches since this can take a long time
319
plugin::TransactionalStorageEngine::releaseTemporaryLatches(in_use);
325
cursor->closeMarkForDelete(getShare()->getTableName());
328
identifier::Table identifier(getShare()->getSchemaName(), getShare()->getTableName(), getShare()->getTableName());
329
drizzled::error_t ignored;
330
plugin::StorageEngine::dropTable(*in_use,
331
*getShare()->getEngine(),
339
for (Field **ptr= getFields() ; *ptr ; ptr++)
345
getMemRoot()->free_root(MYF(0));
346
in_use->set_proc_info(save_proc_info);
350
} /* namespace table */
351
} /* namespace drizzled */