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,
1570
HA_OPEN_TMP_TABLE | HA_OPEN_INTERNAL_TABLE)))
1572
print_error(error, MYF(0));
1576
(void) cursor->extra(HA_EXTRA_QUICK); /* Faster */
1582
Create MyISAM temporary table
1585
create_myisam_tmp_table()
1586
keyinfo Description of the index (there is always one index)
1587
start_recinfo MyISAM's column descriptions
1588
recinfo INOUT End of MyISAM's column descriptions
1592
Create a MyISAM temporary table according to passed description. The is
1593
assumed to have one unique index or constraint.
1595
The passed array or MI_COLUMNDEF structures must have this form:
1597
1. 1-byte column (afaiu for 'deleted' flag) (note maybe not 1-byte
1598
when there are many nullable columns)
1600
3. One free MI_COLUMNDEF element (*recinfo points here)
1602
This function may use the free element to create hash column for unique
1610
bool Table::create_myisam_tmp_table(KeyInfo *keyinfo,
1611
MI_COLUMNDEF *start_recinfo,
1612
MI_COLUMNDEF **recinfo,
1617
MI_UNIQUEDEF uniquedef;
1618
TableShare *share= s;
1620
if (share->sizeKeys())
1621
{ // Get keys for ni_create
1622
bool using_unique_constraint= false;
1623
HA_KEYSEG *seg= (HA_KEYSEG*) this->mem_root.alloc_root(sizeof(*seg) * keyinfo->key_parts);
1627
memset(seg, 0, sizeof(*seg) * keyinfo->key_parts);
1628
if (keyinfo->key_length >= cursor->getEngine()->max_key_length() ||
1629
keyinfo->key_parts > cursor->getEngine()->max_key_parts() ||
1632
/* Can't create a key; Make a unique constraint instead of a key */
1635
using_unique_constraint= true;
1636
memset(&uniquedef, 0, sizeof(uniquedef));
1637
uniquedef.keysegs=keyinfo->key_parts;
1639
uniquedef.null_are_equal=1;
1641
/* Create extra column for hash value */
1642
memset(*recinfo, 0, sizeof(**recinfo));
1643
(*recinfo)->type= FIELD_CHECK;
1644
(*recinfo)->length=MI_UNIQUE_HASH_LENGTH;
1646
share->setRecordLength(share->getRecordLength() + MI_UNIQUE_HASH_LENGTH);
1650
/* Create an unique key */
1651
memset(&keydef, 0, sizeof(keydef));
1652
keydef.flag=HA_NOSAME | HA_BINARY_PACK_KEY | HA_PACK_KEY;
1653
keydef.keysegs= keyinfo->key_parts;
1656
for (uint32_t i= 0; i < keyinfo->key_parts ; i++,seg++)
1658
Field *key_field=keyinfo->key_part[i].field;
1660
seg->language= key_field->charset()->number;
1661
seg->length= keyinfo->key_part[i].length;
1662
seg->start= keyinfo->key_part[i].offset;
1663
if (key_field->flags & BLOB_FLAG)
1665
seg->type= ((keyinfo->key_part[i].key_type & 1 /* binary */) ?
1666
HA_KEYTYPE_VARBINARY2 : HA_KEYTYPE_VARTEXT2);
1667
seg->bit_start= (uint8_t)(key_field->pack_length()
1668
- share->blob_ptr_size);
1669
seg->flag= HA_BLOB_PART;
1670
seg->length= 0; // Whole blob in unique constraint
1674
seg->type= keyinfo->key_part[i].type;
1676
if (!(key_field->flags & NOT_NULL_FLAG))
1678
seg->null_bit= key_field->null_bit;
1679
seg->null_pos= (uint32_t) (key_field->null_ptr - (unsigned char*) getInsertRecord());
1681
We are using a GROUP BY on something that contains NULL
1682
In this case we have to tell MyISAM that two NULL should
1683
on INSERT be regarded at the same value
1685
if (! using_unique_constraint)
1686
keydef.flag|= HA_NULL_ARE_EQUAL;
1690
MI_CREATE_INFO create_info;
1692
if ((options & (OPTION_BIG_TABLES | SELECT_SMALL_RESULT)) ==
1694
create_info.data_file_length= ~(uint64_t) 0;
1696
if ((error= mi_create(share->getTableName(), share->sizeKeys(), &keydef,
1697
(uint32_t) (*recinfo-start_recinfo),
1699
share->uniques, &uniquedef,
1701
HA_CREATE_TMP_TABLE)))
1703
print_error(error, MYF(0));
1708
in_use->status_var.created_tmp_disk_tables++;
1709
share->db_record_offset= 1;
1714
void Table::free_tmp_table(Session *session)
1716
memory::Root own_root= mem_root;
1717
const char *save_proc_info;
1719
save_proc_info= session->get_proc_info();
1720
session->set_proc_info("removing tmp table");
1722
// Release latches since this can take a long time
1723
plugin::TransactionalStorageEngine::releaseTemporaryLatches(session);
1729
cursor->closeMarkForDelete(s->getTableName());
1732
TableIdentifier identifier(s->getSchemaName(), s->getTableName(), s->getTableName());
1733
s->db_type()->doDropTable(*session, identifier);
1739
for (Field **ptr= field ; *ptr ; ptr++)
1745
own_root.free_root(MYF(0)); /* the table is allocated in its own root */
1746
session->set_proc_info(save_proc_info);
1749
my_bitmap_map *Table::use_all_columns(MyBitmap *bitmap)
1751
my_bitmap_map *old= bitmap->getBitmap();
1752
bitmap->setBitmap(s->all_set.getBitmap());
1399
void Table::restore_column_map(const boost::dynamic_bitset<>& old)
1756
void Table::restore_column_map(my_bitmap_map *old)
1401
for (boost::dynamic_bitset<>::size_type i= 0; i < old.size(); i++)
1758
read_set->setBitmap(old);
1414
1761
uint32_t Table::find_shortest_key(const key_map *usable_keys)
1445
1792
for (; *ptr ; ptr++)
1447
if ((*ptr)->cmp_offset(getShare()->rec_buff_length))
1794
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());
1800
/* Return false if row hasn't changed */
1802
bool Table::compare_record()
1804
if (s->blob_fields + s->varchar_fields == 0)
1805
return memcmp(this->getInsertRecord(), this->getUpdateRecord(), (size_t) s->getRecordLength());
1514
1807
/* Compare null bits */
1515
if (memcmp(null_flags, null_flags + getShare()->rec_buff_length, getShare()->null_bytes))
1808
if (memcmp(null_flags, null_flags + s->rec_buff_length, s->null_bytes))
1516
1809
return true; /* Diff in NULL value */
1518
1811
/* Compare updated fields */
1519
1812
for (Field **ptr= field ; *ptr ; ptr++)
1521
if (isWriteSet((*ptr)->position()) &&
1522
(*ptr)->cmp_binary_offset(getShare()->rec_buff_length))
1814
if (isWriteSet((*ptr)->field_index) &&
1815
(*ptr)->cmp_binary_offset(s->rec_buff_length))