1404
1427
/****************************************************************************/
1406
void Table::column_bitmaps_set(boost::dynamic_bitset<>& read_set_arg,
1407
boost::dynamic_bitset<>& write_set_arg)
1409
read_set= &read_set_arg;
1410
write_set= &write_set_arg;
1414
const boost::dynamic_bitset<> Table::use_all_columns(boost::dynamic_bitset<>& in_map)
1416
const boost::dynamic_bitset<> old= in_map;
1417
in_map= getShare()->all_set;
1430
Create a reduced Table object with properly set up Field list from a
1431
list of field definitions.
1433
The created table doesn't have a table Cursor associated with
1434
it, has no keys, no group/distinct, no copy_funcs array.
1435
The sole purpose of this Table object is to use the power of Field
1436
class to read/write data to/from table->getInsertRecord(). Then one can store
1437
the record in any container (RB tree, hash, etc).
1438
The table is created in Session mem_root, so are the table's fields.
1439
Consequently, if you don't BLOB fields, you don't need to free it.
1441
@param session connection handle
1442
@param field_list list of column definitions
1445
0 if out of memory, Table object in case of success
1448
Table *Session::create_virtual_tmp_table(List<CreateField> &field_list)
1450
uint32_t field_count= field_list.elements;
1451
uint32_t blob_count= 0;
1453
CreateField *cdef; /* column definition */
1454
uint32_t record_length= 0;
1455
uint32_t null_count= 0; /* number of columns which may be null */
1456
uint32_t null_pack_length; /* NULL representation array length */
1457
unsigned char *bitmaps;
1460
TableShareInstance *share= getTemporaryShare(message::Table::INTERNAL); // This will not go into the tableshare cache, so no key is used.
1462
if (! share->getMemRoot()->multi_alloc_root(0,
1463
&bitmaps, bitmap_buffer_size(field_count)*2,
1469
table= share->getTable();
1470
share->setFields(field_count + 1);
1471
table->setFields(share->getFields(true));
1472
field= share->getFields(true);
1473
share->blob_field.resize(field_count+1);
1474
share->fields= field_count;
1475
share->blob_ptr_size= portable_sizeof_char_ptr;
1476
table->setup_tmp_table_column_bitmaps(bitmaps);
1478
table->in_use= this; /* field->reset() may access table->in_use */
1480
/* Create all fields and calculate the total length of record */
1481
List_iterator_fast<CreateField> it(field_list);
1482
while ((cdef= it++))
1484
*field= share->make_field(NULL,
1486
(cdef->flags & NOT_NULL_FLAG) ? false : true,
1487
(unsigned char *) ((cdef->flags & NOT_NULL_FLAG) ? 0 : ""),
1488
(cdef->flags & NOT_NULL_FLAG) ? 0 : 1,
1497
(*field)->init(table);
1498
record_length+= (*field)->pack_length();
1499
if (! ((*field)->flags & NOT_NULL_FLAG))
1502
if ((*field)->flags & BLOB_FLAG)
1503
share->blob_field[blob_count++]= (uint32_t) (field - table->getFields());
1507
*field= NULL; /* mark the end of the list */
1508
share->blob_field[blob_count]= 0; /* mark the end of the list */
1509
share->blob_fields= blob_count;
1511
null_pack_length= (null_count + 7)/8;
1512
share->setRecordLength(record_length + null_pack_length);
1513
share->rec_buff_length= ALIGN_SIZE(share->getRecordLength() + 1);
1514
table->record[0]= (unsigned char*)alloc(share->rec_buff_length);
1515
if (not table->getInsertRecord())
1518
if (null_pack_length)
1520
table->null_flags= (unsigned char*) table->getInsertRecord();
1521
share->null_fields= null_count;
1522
share->null_bytes= null_pack_length;
1525
/* Set up field pointers */
1526
unsigned char *null_pos= table->getInsertRecord();
1527
unsigned char *field_pos= null_pos + share->null_bytes;
1528
uint32_t null_bit= 1;
1530
for (field= table->getFields(); *field; ++field)
1532
Field *cur_field= *field;
1533
if ((cur_field->flags & NOT_NULL_FLAG))
1534
cur_field->move_field(field_pos);
1537
cur_field->move_field(field_pos, (unsigned char*) null_pos, null_bit);
1539
if (null_bit == (1 << 8))
1547
field_pos+= cur_field->pack_length();
1554
for (field= table->getFields(); *field; ++field)
1556
delete *field; /* just invokes field destructor */
1561
bool Table::open_tmp_table()
1565
TableIdentifier identifier(s->getSchemaName(), s->getTableName(), s->getPath());
1566
if ((error=cursor->ha_open(identifier,
1569
HA_OPEN_TMP_TABLE | HA_OPEN_INTERNAL_TABLE)))
1571
print_error(error, MYF(0));
1575
(void) cursor->extra(HA_EXTRA_QUICK); /* Faster */
1581
Create MyISAM temporary table
1584
create_myisam_tmp_table()
1585
keyinfo Description of the index (there is always one index)
1586
start_recinfo MyISAM's column descriptions
1587
recinfo INOUT End of MyISAM's column descriptions
1591
Create a MyISAM temporary table according to passed description. The is
1592
assumed to have one unique index or constraint.
1594
The passed array or MI_COLUMNDEF structures must have this form:
1596
1. 1-byte column (afaiu for 'deleted' flag) (note maybe not 1-byte
1597
when there are many nullable columns)
1599
3. One free MI_COLUMNDEF element (*recinfo points here)
1601
This function may use the free element to create hash column for unique
1609
bool Table::create_myisam_tmp_table(KeyInfo *keyinfo,
1610
MI_COLUMNDEF *start_recinfo,
1611
MI_COLUMNDEF **recinfo,
1616
MI_UNIQUEDEF uniquedef;
1617
TableShare *share= s;
1619
if (share->sizeKeys())
1620
{ // Get keys for ni_create
1621
bool using_unique_constraint= false;
1622
HA_KEYSEG *seg= (HA_KEYSEG*) this->mem_root.alloc_root(sizeof(*seg) * keyinfo->key_parts);
1626
memset(seg, 0, sizeof(*seg) * keyinfo->key_parts);
1627
if (keyinfo->key_length >= cursor->getEngine()->max_key_length() ||
1628
keyinfo->key_parts > cursor->getEngine()->max_key_parts() ||
1631
/* Can't create a key; Make a unique constraint instead of a key */
1634
using_unique_constraint= true;
1635
memset(&uniquedef, 0, sizeof(uniquedef));
1636
uniquedef.keysegs=keyinfo->key_parts;
1638
uniquedef.null_are_equal=1;
1640
/* Create extra column for hash value */
1641
memset(*recinfo, 0, sizeof(**recinfo));
1642
(*recinfo)->type= FIELD_CHECK;
1643
(*recinfo)->length=MI_UNIQUE_HASH_LENGTH;
1645
share->setRecordLength(share->getRecordLength() + MI_UNIQUE_HASH_LENGTH);
1649
/* Create an unique key */
1650
memset(&keydef, 0, sizeof(keydef));
1651
keydef.flag=HA_NOSAME | HA_BINARY_PACK_KEY | HA_PACK_KEY;
1652
keydef.keysegs= keyinfo->key_parts;
1655
for (uint32_t i= 0; i < keyinfo->key_parts ; i++,seg++)
1657
Field *key_field=keyinfo->key_part[i].field;
1659
seg->language= key_field->charset()->number;
1660
seg->length= keyinfo->key_part[i].length;
1661
seg->start= keyinfo->key_part[i].offset;
1662
if (key_field->flags & BLOB_FLAG)
1664
seg->type= ((keyinfo->key_part[i].key_type & 1 /* binary */) ?
1665
HA_KEYTYPE_VARBINARY2 : HA_KEYTYPE_VARTEXT2);
1666
seg->bit_start= (uint8_t)(key_field->pack_length()
1667
- share->blob_ptr_size);
1668
seg->flag= HA_BLOB_PART;
1669
seg->length= 0; // Whole blob in unique constraint
1673
seg->type= keyinfo->key_part[i].type;
1675
if (!(key_field->flags & NOT_NULL_FLAG))
1677
seg->null_bit= key_field->null_bit;
1678
seg->null_pos= (uint32_t) (key_field->null_ptr - (unsigned char*) getInsertRecord());
1680
We are using a GROUP BY on something that contains NULL
1681
In this case we have to tell MyISAM that two NULL should
1682
on INSERT be regarded at the same value
1684
if (! using_unique_constraint)
1685
keydef.flag|= HA_NULL_ARE_EQUAL;
1689
MI_CREATE_INFO create_info;
1691
if ((options & (OPTION_BIG_TABLES | SELECT_SMALL_RESULT)) ==
1693
create_info.data_file_length= ~(uint64_t) 0;
1695
if ((error= mi_create(share->getTableName(), share->sizeKeys(), &keydef,
1696
(uint32_t) (*recinfo-start_recinfo),
1698
share->uniques, &uniquedef,
1700
HA_CREATE_TMP_TABLE)))
1702
print_error(error, MYF(0));
1707
in_use->status_var.created_tmp_disk_tables++;
1708
share->db_record_offset= 1;
1713
void Table::free_tmp_table(Session *session)
1715
memory::Root own_root= mem_root;
1716
const char *save_proc_info;
1718
save_proc_info= session->get_proc_info();
1719
session->set_proc_info("removing tmp table");
1721
// Release latches since this can take a long time
1722
plugin::TransactionalStorageEngine::releaseTemporaryLatches(session);
1728
cursor->closeMarkForDelete(s->getTableName());
1731
TableIdentifier identifier(s->getSchemaName(), s->getTableName(), s->getTableName());
1732
s->db_type()->doDropTable(*session, identifier);
1738
for (Field **ptr= field ; *ptr ; ptr++)
1744
own_root.free_root(MYF(0)); /* the table is allocated in its own root */
1745
session->set_proc_info(save_proc_info);
1748
my_bitmap_map *Table::use_all_columns(MyBitmap *bitmap)
1750
my_bitmap_map *old= bitmap->getBitmap();
1751
bitmap->setBitmap(s->all_set.getBitmap());
1421
void Table::restore_column_map(const boost::dynamic_bitset<>& old)
1755
void Table::restore_column_map(my_bitmap_map *old)
1423
for (boost::dynamic_bitset<>::size_type i= 0; i < old.size(); i++)
1757
read_set->setBitmap(old);
1436
1760
uint32_t Table::find_shortest_key(const key_map *usable_keys)
1467
1791
for (; *ptr ; ptr++)
1469
if ((*ptr)->cmp_offset(getShare()->rec_buff_length))
1793
if ((*ptr)->cmp_offset(s->rec_buff_length))
1476
True if the table's input and output record buffers are comparable using
1477
compare_records(TABLE*).
1479
bool Table::records_are_comparable()
1481
return ((getEngine()->check_flag(HTON_BIT_PARTIAL_COLUMN_READ) == 0) ||
1482
write_set->is_subset_of(*read_set));
1486
Compares the input and outbut record buffers of the table to see if a row
1487
has changed. The algorithm iterates over updated columns and if they are
1488
nullable compares NULL bits in the buffer before comparing actual
1489
data. Special care must be taken to compare only the relevant NULL bits and
1490
mask out all others as they may be undefined. The storage engine will not
1491
and should not touch them.
1493
@param table The table to evaluate.
1495
@return true if row has changed.
1496
@return false otherwise.
1498
bool Table::compare_records()
1500
if (getEngine()->check_flag(HTON_BIT_PARTIAL_COLUMN_READ) != 0)
1503
Storage engine may not have read all columns of the record. Fields
1504
(including NULL bits) not in the write_set may not have been read and
1505
can therefore not be compared.
1507
for (Field **ptr= this->field ; *ptr != NULL; ptr++)
1510
if (write_set->test(f->position()))
1512
if (f->real_maybe_null())
1514
unsigned char null_byte_index= f->null_ptr - record[0];
1516
if (((record[0][null_byte_index]) & f->null_bit) !=
1517
((record[1][null_byte_index]) & f->null_bit))
1520
if (f->cmp_binary_offset(getShare()->rec_buff_length))
1528
The storage engine has read all columns, so it's safe to compare all bits
1529
including those not in the write_set. This is cheaper than the
1530
field-by-field comparison done above.
1532
if (not getShare()->blob_fields + getShare()->hasVariableWidth())
1533
// Fixed-size record: do bitwise comparison of the records
1534
return memcmp(this->getInsertRecord(), this->getUpdateRecord(), (size_t) getShare()->getRecordLength());
1799
/* Return false if row hasn't changed */
1801
bool Table::compare_record()
1803
if (s->blob_fields + s->varchar_fields == 0)
1804
return memcmp(this->getInsertRecord(), this->getUpdateRecord(), (size_t) s->getRecordLength());
1536
1806
/* Compare null bits */
1537
if (memcmp(null_flags, null_flags + getShare()->rec_buff_length, getShare()->null_bytes))
1807
if (memcmp(null_flags, null_flags + s->rec_buff_length, s->null_bytes))
1538
1808
return true; /* Diff in NULL value */
1540
1810
/* Compare updated fields */
1541
1811
for (Field **ptr= field ; *ptr ; ptr++)
1543
if (isWriteSet((*ptr)->position()) &&
1544
(*ptr)->cmp_binary_offset(getShare()->rec_buff_length))
1813
if (isWriteSet((*ptr)->field_index) &&
1814
(*ptr)->cmp_binary_offset(s->rec_buff_length))