To update data you need to first know that it exists. To do this MySQL reads the rows that need to be updated, either by index or scan read. Since we have already spoken on scan reads, we are going to look at updates that occur that need to scan the entire table. MySQL will start up a read and do the folllowing:
rnd_init()
rnd_next()
rnd_next()
rnd_next()
update_row()
rnd_next()
rnd_next()
rnd_end()
In the above example, MySQL find four rows in the table. The third row is matched for an update. The engine writer doesn't have to do to the predicate test themselves (aka ... UPDAT E A SET b=5 WHERE a=3, the engine writer doesn't need to worry about matching the a=3). The update_row() code looks like this:
int ha_skeleton::update_row(const byte * old_data, byte * new_data) { DBUG_ENTER("ha_skeleton::update_row"); char content_buffer[1024]; String content(content_buffer, sizeof(content_buffer), &my_charset_bin); char utf8_buffer[1024]; String utf8(utf8_buffer, sizeof(utf8_buffer), &my_charset_bin); utf8.length(0); content.length(0); ha_statistic_increment(&SSV::ha_read_rnd_next_count); if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE) table->timestamp_field->set_time(); for (Field **field=table->field ; *field ; field++) { if ((*field)->is_null()) { xml_engine_row_add(engine_clone, (char *)(*field)->field_name, NULL, 0, 1); } else { (*field)->val_str(&content); utf8.set(content->ptr(), content->length(), content->charset(), &my_charset_utf8_general_ci, &error_count); xml_engine_row_add(engine_clone, (char *)(*field)->field_name, content.c_ptr_safe(), content.length(), 1); } } xml_engine_update(engine_clone); DBUG_RETURN(0); }
The two arguments passed into update_row is the old image, and the new image of the row. The Field objects points to the data in old row. We loop through the new row and push the data into the storage engine. Notice that we differentiate between NULL and no content. While some engines in MySQL don't store NULL as NULL in MySQL, CSV for example, almost all engines store NULL.
Notice that there is no update_end() call. If you require this sort of call it is best to flag that an update occurred and then use the index_end() or rnd_end() methods to do any cleanup required.
Since the xml database only operates in UTF8, notice that we used the internal mysql String class to convert the content to UTF8 before storage. You can use this to convert character sets MySQL supports.
You can find the code for this in Chapter 4 of:
http://hg.tangent.org/writing_engines_for_mysql
Previous articles in this series:
The previous entries in this series:
Getting The Skeleton to Compile
Reading Data
Writing Data