1382
1427
/****************************************************************************/
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;
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());
1399
void Table::restore_column_map(const boost::dynamic_bitset<>& old)
1755
void Table::restore_column_map(my_bitmap_map *old)
1401
for (boost::dynamic_bitset<>::size_type i= 0; i < old.size(); i++)
1757
read_set->setBitmap(old);
1414
1760
uint32_t Table::find_shortest_key(const key_map *usable_keys)
1445
1791
for (; *ptr ; ptr++)
1447
if ((*ptr)->cmp_offset(getShare()->rec_buff_length))
1793
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());
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());
1514
1806
/* Compare null bits */
1515
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))
1516
1808
return true; /* Diff in NULL value */
1518
1810
/* Compare updated fields */
1519
1811
for (Field **ptr= field ; *ptr ; ptr++)
1521
if (isWriteSet((*ptr)->position()) &&
1522
(*ptr)->cmp_binary_offset(getShare()->rec_buff_length))
1813
if (isWriteSet((*ptr)->field_index) &&
1814
(*ptr)->cmp_binary_offset(s->rec_buff_length))