1382
1428
/****************************************************************************/
1384
void Table::column_bitmaps_set(boost::dynamic_bitset<>& read_set_arg,
1385
boost::dynamic_bitset<>& write_set_arg)
1387
read_set= &read_set_arg;
1388
write_set= &write_set_arg;
1392
const boost::dynamic_bitset<> Table::use_all_columns(boost::dynamic_bitset<>& in_map)
1394
const boost::dynamic_bitset<> old= in_map;
1395
in_map= getShare()->all_set;
1431
Create a reduced Table object with properly set up Field list from a
1432
list of field definitions.
1434
The created table doesn't have a table Cursor associated with
1435
it, has no keys, no group/distinct, no copy_funcs array.
1436
The sole purpose of this Table object is to use the power of Field
1437
class to read/write data to/from table->getInsertRecord(). Then one can store
1438
the record in any container (RB tree, hash, etc).
1439
The table is created in Session mem_root, so are the table's fields.
1440
Consequently, if you don't BLOB fields, you don't need to free it.
1442
@param session connection handle
1443
@param field_list list of column definitions
1446
0 if out of memory, Table object in case of success
1449
Table *Session::create_virtual_tmp_table(List<CreateField> &field_list)
1451
uint32_t field_count= field_list.elements;
1452
uint32_t blob_count= 0;
1454
CreateField *cdef; /* column definition */
1455
uint32_t record_length= 0;
1456
uint32_t null_count= 0; /* number of columns which may be null */
1457
uint32_t null_pack_length; /* NULL representation array length */
1458
unsigned char *bitmaps;
1461
TableShareInstance *share= getTemporaryShare(message::Table::INTERNAL); // This will not go into the tableshare cache, so no key is used.
1463
if (! share->getMemRoot()->multi_alloc_root(0,
1464
&bitmaps, bitmap_buffer_size(field_count)*2,
1470
table= share->getTable();
1471
share->setFields(field_count + 1);
1472
table->setFields(share->getFields(true));
1473
field= share->getFields(true);
1474
share->blob_field.resize(field_count+1);
1475
share->fields= field_count;
1476
share->blob_ptr_size= portable_sizeof_char_ptr;
1477
table->setup_tmp_table_column_bitmaps(bitmaps);
1479
table->in_use= this; /* field->reset() may access table->in_use */
1481
/* Create all fields and calculate the total length of record */
1482
List_iterator_fast<CreateField> it(field_list);
1483
while ((cdef= it++))
1485
*field= share->make_field(NULL,
1487
(cdef->flags & NOT_NULL_FLAG) ? false : true,
1488
(unsigned char *) ((cdef->flags & NOT_NULL_FLAG) ? 0 : ""),
1489
(cdef->flags & NOT_NULL_FLAG) ? 0 : 1,
1498
(*field)->init(table);
1499
record_length+= (*field)->pack_length();
1500
if (! ((*field)->flags & NOT_NULL_FLAG))
1503
if ((*field)->flags & BLOB_FLAG)
1504
share->blob_field[blob_count++]= (uint32_t) (field - table->getFields());
1508
*field= NULL; /* mark the end of the list */
1509
share->blob_field[blob_count]= 0; /* mark the end of the list */
1510
share->blob_fields= blob_count;
1512
null_pack_length= (null_count + 7)/8;
1513
share->setRecordLength(record_length + null_pack_length);
1514
share->rec_buff_length= ALIGN_SIZE(share->getRecordLength() + 1);
1515
table->record[0]= (unsigned char*)alloc(share->rec_buff_length);
1516
if (not table->getInsertRecord())
1519
if (null_pack_length)
1521
table->null_flags= (unsigned char*) table->getInsertRecord();
1522
share->null_fields= null_count;
1523
share->null_bytes= null_pack_length;
1526
/* Set up field pointers */
1527
unsigned char *null_pos= table->getInsertRecord();
1528
unsigned char *field_pos= null_pos + share->null_bytes;
1529
uint32_t null_bit= 1;
1531
for (field= table->getFields(); *field; ++field)
1533
Field *cur_field= *field;
1534
if ((cur_field->flags & NOT_NULL_FLAG))
1535
cur_field->move_field(field_pos);
1538
cur_field->move_field(field_pos, (unsigned char*) null_pos, null_bit);
1540
if (null_bit == (1 << 8))
1548
field_pos+= cur_field->pack_length();
1555
for (field= table->getFields(); *field; ++field)
1557
delete *field; /* just invokes field destructor */
1562
bool Table::open_tmp_table()
1566
TableIdentifier identifier(s->getSchemaName(), s->getTableName(), s->getPath());
1567
if ((error=cursor->ha_open(identifier,
1571
HA_OPEN_TMP_TABLE | HA_OPEN_INTERNAL_TABLE)))
1573
print_error(error, MYF(0));
1577
(void) cursor->extra(HA_EXTRA_QUICK); /* Faster */
1583
Create MyISAM temporary table
1586
create_myisam_tmp_table()
1587
keyinfo Description of the index (there is always one index)
1588
start_recinfo MyISAM's column descriptions
1589
recinfo INOUT End of MyISAM's column descriptions
1593
Create a MyISAM temporary table according to passed description. The is
1594
assumed to have one unique index or constraint.
1596
The passed array or MI_COLUMNDEF structures must have this form:
1598
1. 1-byte column (afaiu for 'deleted' flag) (note maybe not 1-byte
1599
when there are many nullable columns)
1601
3. One free MI_COLUMNDEF element (*recinfo points here)
1603
This function may use the free element to create hash column for unique
1611
bool Table::create_myisam_tmp_table(KeyInfo *keyinfo,
1612
MI_COLUMNDEF *start_recinfo,
1613
MI_COLUMNDEF **recinfo,
1618
MI_UNIQUEDEF uniquedef;
1619
TableShare *share= s;
1621
if (share->sizeKeys())
1622
{ // Get keys for ni_create
1623
bool using_unique_constraint= false;
1624
HA_KEYSEG *seg= (HA_KEYSEG*) this->mem_root.alloc_root(sizeof(*seg) * keyinfo->key_parts);
1628
memset(seg, 0, sizeof(*seg) * keyinfo->key_parts);
1629
if (keyinfo->key_length >= cursor->getEngine()->max_key_length() ||
1630
keyinfo->key_parts > cursor->getEngine()->max_key_parts() ||
1633
/* Can't create a key; Make a unique constraint instead of a key */
1636
using_unique_constraint= true;
1637
memset(&uniquedef, 0, sizeof(uniquedef));
1638
uniquedef.keysegs=keyinfo->key_parts;
1640
uniquedef.null_are_equal=1;
1642
/* Create extra column for hash value */
1643
memset(*recinfo, 0, sizeof(**recinfo));
1644
(*recinfo)->type= FIELD_CHECK;
1645
(*recinfo)->length=MI_UNIQUE_HASH_LENGTH;
1647
share->setRecordLength(share->getRecordLength() + MI_UNIQUE_HASH_LENGTH);
1651
/* Create an unique key */
1652
memset(&keydef, 0, sizeof(keydef));
1653
keydef.flag=HA_NOSAME | HA_BINARY_PACK_KEY | HA_PACK_KEY;
1654
keydef.keysegs= keyinfo->key_parts;
1657
for (uint32_t i= 0; i < keyinfo->key_parts ; i++,seg++)
1659
Field *key_field=keyinfo->key_part[i].field;
1661
seg->language= key_field->charset()->number;
1662
seg->length= keyinfo->key_part[i].length;
1663
seg->start= keyinfo->key_part[i].offset;
1664
if (key_field->flags & BLOB_FLAG)
1666
seg->type= ((keyinfo->key_part[i].key_type & 1 /* binary */) ?
1667
HA_KEYTYPE_VARBINARY2 : HA_KEYTYPE_VARTEXT2);
1668
seg->bit_start= (uint8_t)(key_field->pack_length()
1669
- share->blob_ptr_size);
1670
seg->flag= HA_BLOB_PART;
1671
seg->length= 0; // Whole blob in unique constraint
1675
seg->type= keyinfo->key_part[i].type;
1677
if (!(key_field->flags & NOT_NULL_FLAG))
1679
seg->null_bit= key_field->null_bit;
1680
seg->null_pos= (uint32_t) (key_field->null_ptr - (unsigned char*) getInsertRecord());
1682
We are using a GROUP BY on something that contains NULL
1683
In this case we have to tell MyISAM that two NULL should
1684
on INSERT be regarded at the same value
1686
if (! using_unique_constraint)
1687
keydef.flag|= HA_NULL_ARE_EQUAL;
1691
MI_CREATE_INFO create_info;
1692
memset(&create_info, 0, sizeof(create_info));
1694
if ((options & (OPTION_BIG_TABLES | SELECT_SMALL_RESULT)) ==
1696
create_info.data_file_length= ~(uint64_t) 0;
1698
if ((error=mi_create(share->getTableName(), share->sizeKeys(), &keydef,
1699
(uint32_t) (*recinfo-start_recinfo),
1701
share->uniques, &uniquedef,
1703
HA_CREATE_TMP_TABLE)))
1705
print_error(error, MYF(0));
1709
status_var_increment(in_use->status_var.created_tmp_disk_tables);
1710
share->db_record_offset= 1;
1717
void Table::free_tmp_table(Session *session)
1719
memory::Root own_root= mem_root;
1720
const char *save_proc_info;
1722
save_proc_info= session->get_proc_info();
1723
session->set_proc_info("removing tmp table");
1725
// Release latches since this can take a long time
1726
plugin::TransactionalStorageEngine::releaseTemporaryLatches(session);
1732
cursor->closeMarkForDelete(s->getTableName());
1735
TableIdentifier identifier(s->getSchemaName(), s->getTableName(), s->getTableName());
1736
s->db_type()->doDropTable(*session, identifier);
1742
for (Field **ptr= field ; *ptr ; ptr++)
1748
own_root.free_root(MYF(0)); /* the table is allocated in its own root */
1749
session->set_proc_info(save_proc_info);
1752
my_bitmap_map *Table::use_all_columns(MyBitmap *bitmap)
1754
my_bitmap_map *old= bitmap->getBitmap();
1755
bitmap->setBitmap(s->all_set.getBitmap());
1399
void Table::restore_column_map(const boost::dynamic_bitset<>& old)
1759
void Table::restore_column_map(my_bitmap_map *old)
1401
for (boost::dynamic_bitset<>::size_type i= 0; i < old.size(); i++)
1761
read_set->setBitmap(old);
1414
1764
uint32_t Table::find_shortest_key(const key_map *usable_keys)
1445
1795
for (; *ptr ; ptr++)
1447
if ((*ptr)->cmp_offset(getShare()->rec_buff_length))
1797
if ((*ptr)->cmp_offset(s->rec_buff_length))
1454
True if the table's input and output record buffers are comparable using
1455
compare_records(TABLE*).
1457
bool Table::records_are_comparable()
1459
return ((getEngine()->check_flag(HTON_BIT_PARTIAL_COLUMN_READ) == 0) ||
1460
write_set->is_subset_of(*read_set));
1464
Compares the input and outbut record buffers of the table to see if a row
1465
has changed. The algorithm iterates over updated columns and if they are
1466
nullable compares NULL bits in the buffer before comparing actual
1467
data. Special care must be taken to compare only the relevant NULL bits and
1468
mask out all others as they may be undefined. The storage engine will not
1469
and should not touch them.
1471
@param table The table to evaluate.
1473
@return true if row has changed.
1474
@return false otherwise.
1476
bool Table::compare_records()
1478
if (getEngine()->check_flag(HTON_BIT_PARTIAL_COLUMN_READ) != 0)
1481
Storage engine may not have read all columns of the record. Fields
1482
(including NULL bits) not in the write_set may not have been read and
1483
can therefore not be compared.
1485
for (Field **ptr= this->field ; *ptr != NULL; ptr++)
1488
if (write_set->test(f->position()))
1490
if (f->real_maybe_null())
1492
unsigned char null_byte_index= f->null_ptr - record[0];
1494
if (((record[0][null_byte_index]) & f->null_bit) !=
1495
((record[1][null_byte_index]) & f->null_bit))
1498
if (f->cmp_binary_offset(getShare()->rec_buff_length))
1506
The storage engine has read all columns, so it's safe to compare all bits
1507
including those not in the write_set. This is cheaper than the
1508
field-by-field comparison done above.
1510
if (not getShare()->blob_fields + getShare()->hasVariableWidth())
1511
// Fixed-size record: do bitwise comparison of the records
1512
return memcmp(this->getInsertRecord(), this->getUpdateRecord(), (size_t) getShare()->getRecordLength());
1803
/* Return false if row hasn't changed */
1805
bool Table::compare_record()
1807
if (s->blob_fields + s->varchar_fields == 0)
1808
return memcmp(this->getInsertRecord(), this->getUpdateRecord(), (size_t) s->getRecordLength());
1514
1810
/* Compare null bits */
1515
if (memcmp(null_flags, null_flags + getShare()->rec_buff_length, getShare()->null_bytes))
1811
if (memcmp(null_flags, null_flags + s->rec_buff_length, s->null_bytes))
1516
1812
return true; /* Diff in NULL value */
1518
1814
/* Compare updated fields */
1519
1815
for (Field **ptr= field ; *ptr ; ptr++)
1521
if (isWriteSet((*ptr)->position()) &&
1522
(*ptr)->cmp_binary_offset(getShare()->rec_buff_length))
1817
if (isWriteSet((*ptr)->field_index) &&
1818
(*ptr)->cmp_binary_offset(s->rec_buff_length))