1404
1426
/****************************************************************************/
1429
Create a reduced Table object with properly set up Field list from a
1430
list of field definitions.
1432
The created table doesn't have a table Cursor associated with
1433
it, has no keys, no group/distinct, no copy_funcs array.
1434
The sole purpose of this Table object is to use the power of Field
1435
class to read/write data to/from table->getInsertRecord(). Then one can store
1436
the record in any container (RB tree, hash, etc).
1437
The table is created in Session mem_root, so are the table's fields.
1438
Consequently, if you don't BLOB fields, you don't need to free it.
1440
@param session connection handle
1441
@param field_list list of column definitions
1444
0 if out of memory, Table object in case of success
1447
Table *Session::create_virtual_tmp_table(List<CreateField> &field_list)
1449
uint32_t field_count= field_list.elements;
1450
uint32_t blob_count= 0;
1452
CreateField *cdef; /* column definition */
1453
uint32_t record_length= 0;
1454
uint32_t null_count= 0; /* number of columns which may be null */
1455
uint32_t null_pack_length; /* NULL representation array length */
1457
Table *table= getTemporaryShare(message::Table::INTERNAL); // This will not go into the tableshare cache, so no key is used.
1458
table->getMutableShare()->setFields(field_count + 1);
1459
table->setFields(table->getMutableShare()->getFields(true));
1460
field= table->getMutableShare()->getFields(true);
1461
table->getMutableShare()->blob_field.resize(field_count+1);
1462
table->getMutableShare()->fields= field_count;
1463
table->getMutableShare()->blob_ptr_size= portable_sizeof_char_ptr;
1464
table->setup_tmp_table_column_bitmaps();
1466
table->in_use= this; /* field->reset() may access table->in_use */
1468
/* Create all fields and calculate the total length of record */
1469
List_iterator_fast<CreateField> it(field_list);
1470
while ((cdef= it++))
1472
*field= table->getMutableShare()->make_field(NULL,
1474
(cdef->flags & NOT_NULL_FLAG) ? false : true,
1475
(unsigned char *) ((cdef->flags & NOT_NULL_FLAG) ? 0 : ""),
1476
(cdef->flags & NOT_NULL_FLAG) ? 0 : 1,
1485
(*field)->init(table);
1486
record_length+= (*field)->pack_length();
1487
if (! ((*field)->flags & NOT_NULL_FLAG))
1490
if ((*field)->flags & BLOB_FLAG)
1491
table->getMutableShare()->blob_field[blob_count++]= (uint32_t) (field - table->getFields());
1495
*field= NULL; /* mark the end of the list */
1496
table->getMutableShare()->blob_field[blob_count]= 0; /* mark the end of the list */
1497
table->getMutableShare()->blob_fields= blob_count;
1499
null_pack_length= (null_count + 7)/8;
1500
table->getMutableShare()->setRecordLength(record_length + null_pack_length);
1501
table->getMutableShare()->rec_buff_length= ALIGN_SIZE(table->getMutableShare()->getRecordLength() + 1);
1502
table->record[0]= (unsigned char*)alloc(table->getMutableShare()->rec_buff_length);
1503
if (not table->getInsertRecord())
1506
if (null_pack_length)
1508
table->null_flags= (unsigned char*) table->getInsertRecord();
1509
table->getMutableShare()->null_fields= null_count;
1510
table->getMutableShare()->null_bytes= null_pack_length;
1513
/* Set up field pointers */
1514
unsigned char *null_pos= table->getInsertRecord();
1515
unsigned char *field_pos= null_pos + table->getMutableShare()->null_bytes;
1516
uint32_t null_bit= 1;
1518
for (field= table->getFields(); *field; ++field)
1520
Field *cur_field= *field;
1521
if ((cur_field->flags & NOT_NULL_FLAG))
1522
cur_field->move_field(field_pos);
1525
cur_field->move_field(field_pos, (unsigned char*) null_pos, null_bit);
1527
if (null_bit == (1 << 8))
1535
field_pos+= cur_field->pack_length();
1542
for (field= table->getFields(); *field; ++field)
1544
delete *field; /* just invokes field destructor */
1549
bool Table::open_tmp_table()
1553
TableIdentifier identifier(getShare()->getSchemaName(), getShare()->getTableName(), getShare()->getPath());
1554
if ((error=cursor->ha_open(identifier,
1557
HA_OPEN_TMP_TABLE | HA_OPEN_INTERNAL_TABLE)))
1559
print_error(error, MYF(0));
1563
(void) cursor->extra(HA_EXTRA_QUICK); /* Faster */
1569
Create MyISAM temporary table
1572
create_myisam_tmp_table()
1573
keyinfo Description of the index (there is always one index)
1574
start_recinfo MyISAM's column descriptions
1575
recinfo INOUT End of MyISAM's column descriptions
1579
Create a MyISAM temporary table according to passed description. The is
1580
assumed to have one unique index or constraint.
1582
The passed array or MI_COLUMNDEF structures must have this form:
1584
1. 1-byte column (afaiu for 'deleted' flag) (note maybe not 1-byte
1585
when there are many nullable columns)
1587
3. One free MI_COLUMNDEF element (*recinfo points here)
1589
This function may use the free element to create hash column for unique
1597
bool Table::create_myisam_tmp_table(KeyInfo *keyinfo,
1598
MI_COLUMNDEF *start_recinfo,
1599
MI_COLUMNDEF **recinfo,
1604
MI_UNIQUEDEF uniquedef;
1606
if (getShare()->sizeKeys())
1607
{ // Get keys for ni_create
1608
bool using_unique_constraint= false;
1609
HA_KEYSEG *seg= (HA_KEYSEG*) this->mem_root.alloc_root(sizeof(*seg) * keyinfo->key_parts);
1613
memset(seg, 0, sizeof(*seg) * keyinfo->key_parts);
1614
if (keyinfo->key_length >= cursor->getEngine()->max_key_length() ||
1615
keyinfo->key_parts > cursor->getEngine()->max_key_parts() ||
1616
getShare()->uniques)
1618
/* Can't create a key; Make a unique constraint instead of a key */
1619
getMutableShare()->keys= 0;
1620
getMutableShare()->uniques= 1;
1621
using_unique_constraint= true;
1622
memset(&uniquedef, 0, sizeof(uniquedef));
1623
uniquedef.keysegs=keyinfo->key_parts;
1625
uniquedef.null_are_equal=1;
1627
/* Create extra column for hash value */
1628
memset(*recinfo, 0, sizeof(**recinfo));
1629
(*recinfo)->type= FIELD_CHECK;
1630
(*recinfo)->length=MI_UNIQUE_HASH_LENGTH;
1632
getMutableShare()->setRecordLength(getShare()->getRecordLength() + MI_UNIQUE_HASH_LENGTH);
1636
/* Create an unique key */
1637
memset(&keydef, 0, sizeof(keydef));
1638
keydef.flag=HA_NOSAME | HA_BINARY_PACK_KEY | HA_PACK_KEY;
1639
keydef.keysegs= keyinfo->key_parts;
1642
for (uint32_t i= 0; i < keyinfo->key_parts ; i++,seg++)
1644
Field *key_field=keyinfo->key_part[i].field;
1646
seg->language= key_field->charset()->number;
1647
seg->length= keyinfo->key_part[i].length;
1648
seg->start= keyinfo->key_part[i].offset;
1649
if (key_field->flags & BLOB_FLAG)
1651
seg->type= ((keyinfo->key_part[i].key_type & 1 /* binary */) ?
1652
HA_KEYTYPE_VARBINARY2 : HA_KEYTYPE_VARTEXT2);
1653
seg->bit_start= (uint8_t)(key_field->pack_length() - getShare()->blob_ptr_size);
1654
seg->flag= HA_BLOB_PART;
1655
seg->length= 0; // Whole blob in unique constraint
1659
seg->type= keyinfo->key_part[i].type;
1661
if (!(key_field->flags & NOT_NULL_FLAG))
1663
seg->null_bit= key_field->null_bit;
1664
seg->null_pos= (uint32_t) (key_field->null_ptr - (unsigned char*) getInsertRecord());
1666
We are using a GROUP BY on something that contains NULL
1667
In this case we have to tell MyISAM that two NULL should
1668
on INSERT be regarded at the same value
1670
if (! using_unique_constraint)
1671
keydef.flag|= HA_NULL_ARE_EQUAL;
1675
MI_CREATE_INFO create_info;
1677
if ((options & (OPTION_BIG_TABLES | SELECT_SMALL_RESULT)) ==
1679
create_info.data_file_length= ~(uint64_t) 0;
1681
if ((error= mi_create(getShare()->getTableName(), getShare()->sizeKeys(), &keydef,
1682
(uint32_t) (*recinfo-start_recinfo),
1684
getShare()->uniques, &uniquedef,
1686
HA_CREATE_TMP_TABLE)))
1688
print_error(error, MYF(0));
1693
in_use->status_var.created_tmp_disk_tables++;
1694
getMutableShare()->db_record_offset= 1;
1699
void Table::free_tmp_table(Session *session)
1701
memory::Root own_root= mem_root;
1702
const char *save_proc_info;
1704
save_proc_info= session->get_proc_info();
1705
session->set_proc_info("removing tmp table");
1707
// Release latches since this can take a long time
1708
plugin::TransactionalStorageEngine::releaseTemporaryLatches(session);
1714
cursor->closeMarkForDelete(getShare()->getTableName());
1717
TableIdentifier identifier(getShare()->getSchemaName(), getShare()->getTableName(), getShare()->getTableName());
1718
getMutableShare()->db_type()->doDropTable(*session, identifier);
1724
for (Field **ptr= field ; *ptr ; ptr++)
1730
own_root.free_root(MYF(0)); /* the table is allocated in its own root */
1731
session->set_proc_info(save_proc_info);
1406
1734
void Table::column_bitmaps_set(boost::dynamic_bitset<>& read_set_arg,
1407
1735
boost::dynamic_bitset<>& write_set_arg)
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
1803
/* Return false if row hasn't changed */
1805
bool Table::compare_record()
1807
if (getShare()->blob_fields + getShare()->varchar_fields == 0)
1534
1808
return memcmp(this->getInsertRecord(), this->getUpdateRecord(), (size_t) getShare()->getRecordLength());
1536
1810
/* Compare null bits */
1537
1811
if (memcmp(null_flags, null_flags + getShare()->rec_buff_length, getShare()->null_bytes))
1538
1812
return true; /* Diff in NULL value */