1404
1429
/****************************************************************************/
1432
Create a reduced Table object with properly set up Field list from a
1433
list of field definitions.
1435
The created table doesn't have a table Cursor associated with
1436
it, has no keys, no group/distinct, no copy_funcs array.
1437
The sole purpose of this Table object is to use the power of Field
1438
class to read/write data to/from table->getInsertRecord(). Then one can store
1439
the record in any container (RB tree, hash, etc).
1440
The table is created in Session mem_root, so are the table's fields.
1441
Consequently, if you don't BLOB fields, you don't need to free it.
1443
@param session connection handle
1444
@param field_list list of column definitions
1447
0 if out of memory, Table object in case of success
1450
Table *Session::create_virtual_tmp_table(List<CreateField> &field_list)
1452
uint32_t field_count= field_list.elements;
1453
uint32_t blob_count= 0;
1455
CreateField *cdef; /* column definition */
1456
uint32_t record_length= 0;
1457
uint32_t null_count= 0; /* number of columns which may be null */
1458
uint32_t null_pack_length; /* NULL representation array length */
1461
TableShareInstance *share= getTemporaryShare(message::Table::INTERNAL); // This will not go into the tableshare cache, so no key is used.
1462
table= share->getTable();
1463
share->setFields(field_count + 1);
1464
table->setFields(share->getFields(true));
1465
field= share->getFields(true);
1466
share->blob_field.resize(field_count+1);
1467
share->fields= field_count;
1468
share->blob_ptr_size= portable_sizeof_char_ptr;
1469
table->setup_tmp_table_column_bitmaps();
1471
table->in_use= this; /* field->reset() may access table->in_use */
1473
/* Create all fields and calculate the total length of record */
1474
List_iterator_fast<CreateField> it(field_list);
1475
while ((cdef= it++))
1477
*field= share->make_field(NULL,
1479
(cdef->flags & NOT_NULL_FLAG) ? false : true,
1480
(unsigned char *) ((cdef->flags & NOT_NULL_FLAG) ? 0 : ""),
1481
(cdef->flags & NOT_NULL_FLAG) ? 0 : 1,
1490
(*field)->init(table);
1491
record_length+= (*field)->pack_length();
1492
if (! ((*field)->flags & NOT_NULL_FLAG))
1495
if ((*field)->flags & BLOB_FLAG)
1496
share->blob_field[blob_count++]= (uint32_t) (field - table->getFields());
1500
*field= NULL; /* mark the end of the list */
1501
share->blob_field[blob_count]= 0; /* mark the end of the list */
1502
share->blob_fields= blob_count;
1504
null_pack_length= (null_count + 7)/8;
1505
share->setRecordLength(record_length + null_pack_length);
1506
share->rec_buff_length= ALIGN_SIZE(share->getRecordLength() + 1);
1507
table->record[0]= (unsigned char*)alloc(share->rec_buff_length);
1508
if (not table->getInsertRecord())
1511
if (null_pack_length)
1513
table->null_flags= (unsigned char*) table->getInsertRecord();
1514
share->null_fields= null_count;
1515
share->null_bytes= null_pack_length;
1518
/* Set up field pointers */
1519
unsigned char *null_pos= table->getInsertRecord();
1520
unsigned char *field_pos= null_pos + share->null_bytes;
1521
uint32_t null_bit= 1;
1523
for (field= table->getFields(); *field; ++field)
1525
Field *cur_field= *field;
1526
if ((cur_field->flags & NOT_NULL_FLAG))
1527
cur_field->move_field(field_pos);
1530
cur_field->move_field(field_pos, (unsigned char*) null_pos, null_bit);
1532
if (null_bit == (1 << 8))
1540
field_pos+= cur_field->pack_length();
1547
for (field= table->getFields(); *field; ++field)
1549
delete *field; /* just invokes field destructor */
1554
bool Table::open_tmp_table()
1558
TableIdentifier identifier(s->getSchemaName(), s->getTableName(), s->getPath());
1559
if ((error=cursor->ha_open(identifier,
1562
HA_OPEN_TMP_TABLE | HA_OPEN_INTERNAL_TABLE)))
1564
print_error(error, MYF(0));
1568
(void) cursor->extra(HA_EXTRA_QUICK); /* Faster */
1574
Create MyISAM temporary table
1577
create_myisam_tmp_table()
1578
keyinfo Description of the index (there is always one index)
1579
start_recinfo MyISAM's column descriptions
1580
recinfo INOUT End of MyISAM's column descriptions
1584
Create a MyISAM temporary table according to passed description. The is
1585
assumed to have one unique index or constraint.
1587
The passed array or MI_COLUMNDEF structures must have this form:
1589
1. 1-byte column (afaiu for 'deleted' flag) (note maybe not 1-byte
1590
when there are many nullable columns)
1592
3. One free MI_COLUMNDEF element (*recinfo points here)
1594
This function may use the free element to create hash column for unique
1602
bool Table::create_myisam_tmp_table(KeyInfo *keyinfo,
1603
MI_COLUMNDEF *start_recinfo,
1604
MI_COLUMNDEF **recinfo,
1609
MI_UNIQUEDEF uniquedef;
1610
TableShare *share= s;
1612
if (share->sizeKeys())
1613
{ // Get keys for ni_create
1614
bool using_unique_constraint= false;
1615
HA_KEYSEG *seg= (HA_KEYSEG*) this->mem_root.alloc_root(sizeof(*seg) * keyinfo->key_parts);
1619
memset(seg, 0, sizeof(*seg) * keyinfo->key_parts);
1620
if (keyinfo->key_length >= cursor->getEngine()->max_key_length() ||
1621
keyinfo->key_parts > cursor->getEngine()->max_key_parts() ||
1624
/* Can't create a key; Make a unique constraint instead of a key */
1627
using_unique_constraint= true;
1628
memset(&uniquedef, 0, sizeof(uniquedef));
1629
uniquedef.keysegs=keyinfo->key_parts;
1631
uniquedef.null_are_equal=1;
1633
/* Create extra column for hash value */
1634
memset(*recinfo, 0, sizeof(**recinfo));
1635
(*recinfo)->type= FIELD_CHECK;
1636
(*recinfo)->length=MI_UNIQUE_HASH_LENGTH;
1638
share->setRecordLength(share->getRecordLength() + MI_UNIQUE_HASH_LENGTH);
1642
/* Create an unique key */
1643
memset(&keydef, 0, sizeof(keydef));
1644
keydef.flag=HA_NOSAME | HA_BINARY_PACK_KEY | HA_PACK_KEY;
1645
keydef.keysegs= keyinfo->key_parts;
1648
for (uint32_t i= 0; i < keyinfo->key_parts ; i++,seg++)
1650
Field *key_field=keyinfo->key_part[i].field;
1652
seg->language= key_field->charset()->number;
1653
seg->length= keyinfo->key_part[i].length;
1654
seg->start= keyinfo->key_part[i].offset;
1655
if (key_field->flags & BLOB_FLAG)
1657
seg->type= ((keyinfo->key_part[i].key_type & 1 /* binary */) ?
1658
HA_KEYTYPE_VARBINARY2 : HA_KEYTYPE_VARTEXT2);
1659
seg->bit_start= (uint8_t)(key_field->pack_length()
1660
- share->blob_ptr_size);
1661
seg->flag= HA_BLOB_PART;
1662
seg->length= 0; // Whole blob in unique constraint
1666
seg->type= keyinfo->key_part[i].type;
1668
if (!(key_field->flags & NOT_NULL_FLAG))
1670
seg->null_bit= key_field->null_bit;
1671
seg->null_pos= (uint32_t) (key_field->null_ptr - (unsigned char*) getInsertRecord());
1673
We are using a GROUP BY on something that contains NULL
1674
In this case we have to tell MyISAM that two NULL should
1675
on INSERT be regarded at the same value
1677
if (! using_unique_constraint)
1678
keydef.flag|= HA_NULL_ARE_EQUAL;
1682
MI_CREATE_INFO create_info;
1684
if ((options & (OPTION_BIG_TABLES | SELECT_SMALL_RESULT)) ==
1686
create_info.data_file_length= ~(uint64_t) 0;
1688
if ((error= mi_create(share->getTableName(), share->sizeKeys(), &keydef,
1689
(uint32_t) (*recinfo-start_recinfo),
1691
share->uniques, &uniquedef,
1693
HA_CREATE_TMP_TABLE)))
1695
print_error(error, MYF(0));
1700
in_use->status_var.created_tmp_disk_tables++;
1701
share->db_record_offset= 1;
1706
void Table::free_tmp_table(Session *session)
1708
memory::Root own_root= mem_root;
1709
const char *save_proc_info;
1711
save_proc_info= session->get_proc_info();
1712
session->set_proc_info("removing tmp table");
1714
// Release latches since this can take a long time
1715
plugin::TransactionalStorageEngine::releaseTemporaryLatches(session);
1721
cursor->closeMarkForDelete(s->getTableName());
1724
TableIdentifier identifier(s->getSchemaName(), s->getTableName(), s->getTableName());
1725
s->db_type()->doDropTable(*session, identifier);
1731
for (Field **ptr= field ; *ptr ; ptr++)
1737
own_root.free_root(MYF(0)); /* the table is allocated in its own root */
1738
session->set_proc_info(save_proc_info);
1406
1741
void Table::column_bitmaps_set(boost::dynamic_bitset<>& read_set_arg,
1407
1742
boost::dynamic_bitset<>& write_set_arg)
1467
1802
for (; *ptr ; ptr++)
1469
if ((*ptr)->cmp_offset(getShare()->rec_buff_length))
1804
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());
1810
/* Return false if row hasn't changed */
1812
bool Table::compare_record()
1814
if (s->blob_fields + s->varchar_fields == 0)
1815
return memcmp(this->getInsertRecord(), this->getUpdateRecord(), (size_t) s->getRecordLength());
1536
1817
/* Compare null bits */
1537
if (memcmp(null_flags, null_flags + getShare()->rec_buff_length, getShare()->null_bytes))
1818
if (memcmp(null_flags, null_flags + s->rec_buff_length, s->null_bytes))
1538
1819
return true; /* Diff in NULL value */
1540
1821
/* Compare updated fields */
1541
1822
for (Field **ptr= field ; *ptr ; ptr++)
1543
if (isWriteSet((*ptr)->position()) &&
1544
(*ptr)->cmp_binary_offset(getShare()->rec_buff_length))
1824
if (isWriteSet((*ptr)->field_index) &&
1825
(*ptr)->cmp_binary_offset(s->rec_buff_length))