summaryrefslogtreecommitdiff
path: root/sql/field.h
Commit message (Collapse)AuthorAgeFilesLines
* Backporting 273d8eb12c40a6dcd05a8148bdfba3f1fd96e764 Proper fix for ↵Varun Gupta2019-09-231-5/+1
| | | | disabling warnings in read_statistics_for_table()
* MDEV-20589: Server still crashes in Field::set_warning_truncated_wrong_valueVarun Gupta2019-09-181-1/+0
| | | | | | | The flag is_stat_field is not set for the min_value and max_value of field items inside table share. This is a must requirement as we don't want to throw warnings of truncation when we read values from the statistics table to the column statistics of table share fields.
* MDEV-20403 Assertion `0' or Assertion `btr_validate_index(index, 0)' failed ↵Sergei Golubchik2019-09-041-1/+0
| | | | | | | | | | | | in row_upd_sec_index_entry or error code 126: Index is corrupted upon UPDATE with TIMESTAMP..ON UPDATE remove a special treatment of a bare DEFAULT keyword that made it behave inconsistently and differently from DEFAULT(column). Now all forms of the explicit assignment of a default column value behave identically, and all count as an explicitly assigned value (for the purpose of ON UPDATE NOW). followup for c7c481f4d91
* cleanup: on update default nowSergei Golubchik2019-09-031-22/+0
| | | | | | | | | * remove one level of virtual functions * remove redundant checks * remove an if() as the value is always known at compilation time don't pretend that "DEFAULT expr" and "ON UPDATE DEFAULT NOW" are "basically the same thing"
* Part2: MDEV-18156 Assertion `0' failed or `btr_validate_index(index, 0, ↵Alexander Barkov2019-09-031-2/+3
| | | | | | | | | | | | | | | | | | | | | | | false)' in row_upd_sec_index_entry or error code 126: Index is corrupted upon DELETE with PAD_CHAR_TO_FULL_LENGTH This patch allows the server to open old tables that have "bad" generated columns (i.e. indexed virtual generated columns, persistent generated columns) that depend on sql_mode, for general things like SELECT, INSERT, DROP, etc. Warning are issued in such cases. Only these commands are now disallowed and return an error: - CREATE TABLE introducing a "bad" generated column - ALTER TABLE introducing a "bad" generated column - CREATE INDEX introdicing a "bad" generated column (i.e. adding an index on a virtual generated column that depends on sql_mode). Note, these commands are allowed: - ALTER TABLE removing a "bad" generate column - ALTER TABLE removing an index from a "bad" virtual generated column - DROP INDEX removing an index from a "bad" virtual generated column but only if the table does not have any "bad" columns as a result.
* MDEV-18156 Assertion `0' failed or `btr_validate_index(index, 0, false)' in ↵Alexander Barkov2019-09-031-0/+16
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | row_upd_sec_index_entry or error code 126: Index is corrupted upon DELETE with PAD_CHAR_TO_FULL_LENGTH This change takes into account a column's GENERATED ALWAYS AS expression dependcy on sql_mode's PAD_CHAR_TO_FULL_LENGTH and NO_UNSIGNED_SUBTRACTION flags. Indexed virtual columns as well as persistent generated columns are now not allowed to have such dependencies to avoid inconsistent data or index files on sql_mode changes. So an error is now returned in cases like this: CREATE OR REPLACE TABLE t1 ( a CHAR(5), v VARCHAR(5) AS (a) PERSISTENT -- CHAR->VARCHAR or CHAR->TEXT = ERROR ); Functions RPAD() and RTRIM() can now remove dependency on PAD_CHAR_TO_FULL_LENGTH. So this can be used instead: CREATE OR REPLACE TABLE t1 ( a CHAR(5), v VARCHAR(5) AS (RTRIM(a)) PERSISTENT ); Note, unlike CHAR->VARCHAR and CHAR->TEXT this still works, not RPAD(a) is needed: CREATE OR REPLACE TABLE t1 ( a CHAR(5), v CHAR(5) AS (a) PERSISTENT -- CHAR->CHAR is OK ); More sql_mode flags may affect values of generated columns. They will be addressed separately. See comments in sql_mode.h for implementation details.
* MDEV-16932: ASAN heap-use-after-free in my_charlen_utf8 / ↵Oleksandr Byelkin2019-08-281-1/+2
| | | | | | | | my_well_formed_char_length_utf8 on 2nd execution of SP with ALTER trying to add bad CHECK Make automatic name generation during execution (not prepare). Check result of memory allocation operation.
* MDEV-19925: Column ... cannot be converted from type 'varchar(20)' to type ↵Sujatha2019-08-271-0/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 'varchar(20)' Cherry picking: Bug#25135304: RBR: WRONG FIELD LENGTH IN ERROR MESSAGE commit 47bd3f7cf3c8518f62b1580ec65af2ba7ac13b95 Description: ============ In row based replication, when replicating from a table with a field with character set set to UTF8mb3 to the same table with the same field set to character set UTF8mb4 I get a confusing error message: For VARCHAR: VARCHAR(1) 'utf8mb3' to VARCHAR(1) 'utf8mb4' "Column 0 of table 'test.t1' cannot be converted from type 'varchar(3)' to type 'varchar(1)'" Similar issue with CHAR type as well. Issue with respect to BLOB types: For BLOB: LONGBLOB to TINYBLOB - Error message displays incorrect blob type. "Column 0 of table 'test.t1' cannot be converted from type 'tinyblob' to type 'tinyblob'" For BINARY to BINARY - Error message displays incorrect type for master side field. "Column 0 of table 'test.t' cannot be converted from type 'char(1)' to type 'binary(10)'" Similar issue exists for VARBINARY type. It is displayed as 'VARCHAR'. Analysis: ========= In Row based replication charset information is not sent as part of metadata from master to slave. For VARCHAR field its character length is converted into equivalent octets/bytes and stored internally. At the time of displaying the data to user it is converted back to original character length. For example: VARCHAR(2)- utf8mb3 is stored as:2*3 = VARCHAR(6) At the time of displaying it to user VARCHAR(6)- charset utf8mb3:6/3= VARCHAR(2). At present the internally converted octect length is sent from master to slave with out providing the charset information. On slave side if the type conversion fails 'show_sql_type' function is used to get the type specific information from metadata. Since there is no charset information is available the filed type is displayed as VARCHAR(6). This results in confused error message. For CHAR fields CHAR(1)- utf8mb3 - CHAR(3) CHAR(1)- utf8mb4 - CHAR(4) 'show_sql_type' function which retrieves type information from metadata uses (bytes/local charset length) to get actual character length. If slave's chaset is 'utf8mb4' then CHAR(3/4)-->CHAR(0) CHAR(4/4)-->CHAR(1). This results in confused error message. Analysis for BLOB type issue: BLOB's length is represented in two forms. 1. Actual length i.e (length < 256) type= MYSQL_TYPE_TINY_BLOB; (length < 65536) type= MYSQL_TYPE_BLOB; ... 2. packlength - The number of bytes used to represent the length of the blob 1- tinyblob 2- blob ... In row based replication only the packlength is written in the binary log. On the slave side this packlength is interpreted as actual length of the blob. Hence the length is always < 256 and the type is displayed as tiny blob. Analysis for BINARY to BINARY type issue: The character set information is needed to identify a filed's type as char or binary. Since master side character set information is not available on the slave side both binary and char fields are displayed as char. Fix: === For CHAR and VARCHAR fields display their length in octets for both source and target fields. For target field display the charset information if it is relevant. For blob type changed the code to use the packlength and display appropriate blob type in error message. For binary and varbinary fields use the slave side character set as reference to map them to binary or varbinary fields.
* Merge 10.1 into 10.2Marko Mäkelä2019-05-131-1/+1
|\
| * Merge branch '5.5' into 10.1Vicențiu Ciorbaru2019-05-111-1/+1
| |\
| | * Update FSF AddressVicențiu Ciorbaru2019-05-111-1/+1
| | | | | | | | | | | | * Update wrong zip-code
| * | MDEV-18452 ASAN unknown-crash in Field::set_default upon SET bit_column = ↵Alexander Barkov2019-04-251-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | DEFAULT Field_bit for BIT(20) uses 2 full bytes in the record, with additional 4 uneven bits in the "null bit area". Field::set_default() called from Field_bit::set_default() erroneously copied 3 bytes instead of 2 bytes from the record with default values. Changing Field::set_default() to copy pack_length_in_rec() bytes instead of pack_length() bytes.
| * | MDEV-9519: Data corruption will happen on the Galera cluster size changeJulius Goryavsky2019-02-251-0/+49
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | If we have a 2+ node cluster which is replicating from an async master and the binlog_format is set to STATEMENT and multi-row inserts are executed on a table with an auto_increment column such that values are automatically generated by MySQL, then the server node generates wrong auto_increment values, which are different from what was generated on the async master. In the title of the MDEV-9519 it was proposed to ban start slave on a Galera if master binlog_format = statement and wsrep_auto_increment_control = 1, but the problem can be solved without such a restriction. The causes and fixes: 1. We need to improve processing of changing the auto-increment values after changing the cluster size. 2. If wsrep auto_increment_control switched on during operation of the node, then we should immediately update the auto_increment_increment and auto_increment_offset global variables, without waiting of the next invocation of the wsrep_view_handler_cb() callback. In the current version these variables retain its initial values if wsrep_auto_increment_control is switched on during operation of the node, which leads to inconsistent results on the different nodes in some scenarios. 3. If wsrep auto_increment_control switched off during operation of the node, then we must return the original values of the auto_increment_increment and auto_increment_offset global variables, as the user has set. To make this possible, we need to add a "shadow copies" of these variables (which stores the latest values set by the user). https://jira.mariadb.org/browse/MDEV-9519
* | | MDEV-9519: Data corruption will happen on the Galera cluster size changeJulius Goryavsky2019-02-261-0/+49
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | If we have a 2+ node cluster which is replicating from an async master and the binlog_format is set to STATEMENT and multi-row inserts are executed on a table with an auto_increment column such that values are automatically generated by MySQL, then the server node generates wrong auto_increment values, which are different from what was generated on the async master. In the title of the MDEV-9519 it was proposed to ban start slave on a Galera if master binlog_format = statement and wsrep_auto_increment_control = 1, but the problem can be solved without such a restriction. The causes and fixes: 1. We need to improve processing of changing the auto-increment values after changing the cluster size. 2. If wsrep auto_increment_control switched on during operation of the node, then we should immediately update the auto_increment_increment and auto_increment_offset global variables, without waiting of the next invocation of the wsrep_view_handler_cb() callback. In the current version these variables retain its initial values if wsrep_auto_increment_control is switched on during operation of the node, which leads to inconsistent results on the different nodes in some scenarios. 3. If wsrep auto_increment_control switched off during operation of the node, then we must return the original values of the auto_increment_increment and auto_increment_offset global variables, as the user has set. To make this possible, we need to add a "shadow copies" of these variables (which stores the latest values set by the user). https://jira.mariadb.org/browse/MDEV-9519
* | | Backporting MDEV-15497 Wrong empty value in a GEOMETRY column on LOAD DATAAlexander Barkov2019-02-231-0/+5
| | | | | | | | | | | | This is a part of "MDEV-18045 Backporting the MDEV-15497 changes to 10.2 branch"
* | | Backporting MDEV-14628 Wrong autoinc value assigned by LOAD XML in the ↵Alexander Barkov2019-02-231-0/+4
| | | | | | | | | | | | | | | | | | NO_AUTO_VALUE_ON_ZERO mode This is a part of "MDEV-18045 Backporting the MDEV-15497 changes to 10.2 branch"
* | | MDEV-16217: Assertion `!table || (!table->read_set || ↵bb-10.2-MDEV-16217Oleksandr Byelkin2018-11-141-0/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | bitmap_is_set(table->read_set, field_index))' failed in Field_num::get_date - clean up DEFAULT() to work only with default value and correctly print itself. - fix of DBUG_ASSERT about fields read/write - fix of field marking for write based really on the thd->mark_used_columns flag
* | | Merge 10.1 into 10.2Marko Mäkelä2018-08-311-46/+0
|\ \ \ | |/ /
| * | Revert MDEV-9519 due to regressionsMarko Mäkelä2018-08-311-46/+0
| | | | | | | | | | | | This reverts commit 75dfd4acb995789ca5f86ccbd361fff9d2797e79.
* | | Merge 10.1 into 10.2Marko Mäkelä2018-08-211-0/+46
|\ \ \ | |/ /
| * | This is patch for the https://jira.mariadb.org/browse/MDEV-9519 issue:Julius Goryavsky2018-08-151-0/+46
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | If we have a 2+ node cluster which is replicating from an async master and the binlog_format is set to STATEMENT and multi-row inserts are executed on a table with an auto_increment column such that values are automatically generated by MySQL, then the server node generates wrong auto_increment values, which are different from what was generated on the async master. The causes and fixes: 1. We need to improve processing of changing the auto-increment values after changing the cluster size. 2. If wsrep auto_increment_control switched on during operation of the node, then we should immediately update the auto_increment_increment and auto_increment_offset global variables, without waiting of the next invocation of the wsrep_view_handler_cb() callback. In the current version these variables retain its initial values if wsrep_auto_increment_control is switched on during operation of the node, which leads to inconsistent results on the different nodes in some scenarios. 3. If wsrep auto_increment_control switched off during operation of the node, then we must return the original values of the auto_increment_increment and auto_increment_offset global variables, as the user has set. To make this possible, we need to add a "shadow copies" of these variables (which stores the latest values set by the user).
* | | MDEV-12574 MAX(old_decimal) produces a column of the old DECIMAL typeAlexander Barkov2018-06-251-0/+13
| | |
* | | MDEV-15114 ASAN heap-use-after-free in mem_heap_dup or ↵Monty2018-06-191-0/+4
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | dfield_data_is_binary_equal The bug was that innobase_get_computed_value() trashed record[0] and data in Field_blob::value Fixed by using a record on the heap for innobase_get_computed_value() Reviewer: Marko Mäkelä
* | | MDEV-9334 ALTER from DECIMAL to BIGINT UNSIGNED returns a wrong resultAlexander Barkov2018-06-151-0/+4
| | | | | | | | | | | | | | | | | | When altering from DECIMAL to *INT UNIGNED or to BIT, go through val_decimal(), to avoid truncation to the biggest possible signed integer (0x7FFFFFFFFFFFFFFF / 9223372036854775807).
* | | MDEV-15352 AUTO_INCREMENT breaks after updating a column value to a negative ↵Alexander Barkov2018-06-141-46/+71
| | | | | | | | | | | | number
* | | Fix conversion warnings/errors.Vladislav Vaintroub2018-05-241-1/+1
| | |
* | | Remove most 'register' use in C++Marko Mäkelä2018-04-241-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | Modern compilers (such as GCC 8) emit warnings that the 'register' keyword is deprecated and not valid C++17. Let us remove most use of the 'register' keyword. Code in 'extra/' is not touched.
* | | Merge branch 'github/10.1' into 10.2Sergei Golubchik2018-02-061-1/+1
|\ \ \ | |/ /
| * | Merge branch 'github/10.0' into 10.1Sergei Golubchik2018-02-021-1/+1
| |\ \
| | * \ Merge remote-tracking branch '5.5' into 10.0Vicențiu Ciorbaru2018-01-241-1/+1
| | |\ \ | | | |/
| | | * Correct TRASH() macro usageSergei Golubchik2018-01-221-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | TRASH was mapped to TRASH_FREE and was supposed to be used for memory that should not be accessed anymore, while TRASH_ALLOC() is to be used for uninitialized but to-be-used memory. But sometimes TRASH() was used in the latter sense. Remove TRASH() macro, always use explicit TRASH_ALLOC() or TRASH_FREE().
* | | | Merge 10.1 to 10.2Marko Mäkelä2017-12-191-7/+7
|\ \ \ \ | |/ / / | | | | | | | | | | | | Follow-up fix to MDEV-14008: Let Field_double::val_uint() silently return 0 on error
| * | | Merge 10.0 into 10.1Marko Mäkelä2017-12-181-1/+7
| |\ \ \ | | |/ /
| | * | MDEV-14008 Assertion failing: `!is_set() || (m_status == DA_OK_BULK && ↵Alexander Barkov2017-12-181-1/+7
| | | | | | | | | | | | | | | | is_bulk_op())
| | * | MDEV-13175 Adding a new enum value at the end of a list triggers a table rebuildSergei Golubchik2017-07-201-9/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Backport of 7e29f2d64fb from 10.1. Create_field does not set BINARY_FLAG, so the check didn't work at all. Also, character sets were already compared, so this check would've been redundant (if it would've worked).
| * | | bugfix: copy timestamps correctly in INSERT...SELECTSergei Golubchik2017-09-211-0/+1
| | | | | | | | | | | | | | | | | | | | don't do it via MYSQL_TIME, that conversion is lossy around DST change dates.
* | | | MDEV-14038 ALTER TABLE does not exit on error with InnoDB + bad default functionAlexander Barkov2017-10-111-2/+2
| | | | | | | | | | | | | | | | | | | | | | | | Changing Field::set_default from void to int. It now uses the same return value notation with Field::store*() and Item::save_in_field().
* | | | MDEV-13384 - misc Windows warnings fixedVladislav Vaintroub2017-09-281-2/+2
| | | |
* | | | bugfix: copy timestamps correctly in INSERT...SELECTSergei Golubchik2017-09-221-0/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Implement Field_timestamp::save_in_field(timestamp_field) that stores timestamp values without converting them to MYSQL_TIME and back, because this conversion is lossy around DST change time. This fixes main.old-mode test. This is 10.2 version of f8a800bec81
* | | | bugfix: ALTER TABLE and TIMESTAMPs around DST change timeSergei Golubchik2017-09-221-0/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Implement a special Copy_func function for timestamps, that copies timestamps without converting them to MYSQL_TIME (the conversion is lossy around DST change time). This fixes ALTER TABLE part of main.old-mode test. This is 10.2 version of f4f48e06215
* | | | MDEV-13868 cannot insert 1288481126 in a timestamp column in Europe/MoscowSergei Golubchik2017-09-221-2/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | make insert NULL into a timestamp mark the field as having an explicit value. So that the field won't be assigned the value again in TABLE::update_default_field() make Item_func_now_local::save_in_field(timestamp_field) not to go through MYSQL_TIME - this conversion is lossy around DST change times. This fixes inserting a default value into a timestamp field.
* | | | Field_varstring: Declare get_data() and get_length() as publicMarko Mäkelä2017-09-151-1/+1
| | | | | | | | | | | | | | | | | | | | The underlying data members are declared public, so there is no point in hiding these const accessors.
* | | | cleanup: move Virtual_column_info::print out of Virtual_column_infoSergei Golubchik2017-07-051-1/+1
| | | |
* | | | MDEV-11117 CHECK constraint fails on intermediate step of ALTERbb-10.2-MDEV-11117Jacob Mathew2017-04-171-3/+24
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Fixed the bug by failing the statement with an error message that explains that an auto-increment column may not be used in an expression for a check constraint. Added a test case in check_constraint.test. Updated existing tests and results.
* | | | Merge branch '10.2' of github.com:MariaDB/server into bb-10.2-mariarocksSergei Petrunia2017-03-111-43/+76
|\ \ \ \
| * | | | Fix many -Wconversion warnings.Marko Mäkelä2017-03-071-26/+28
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Define my_thread_id as an unsigned type, to avoid mismatch with ulonglong. Change some parameters to this type. Use size_t in a few more places. Declare many flag constants as unsigned to avoid sign mismatch when shifting bits or applying the unary ~ operator. When applying the unary ~ operator to enum constants, explictly cast the result to an unsigned type, because enum constants can be treated as signed. In InnoDB, change the source code line number parameters from ulint to unsigned type. Also, make some InnoDB functions return a narrower type (unsigned or uint32_t instead of ulint; bool instead of ibool).
| * | | | MDEV-10201 Bad results for CREATE TABLE t1 (a INT DEFAULT b, b INT DEFAULT 4)Sergei Golubchik2017-02-131-6/+6
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Optionally do table->update_default_fields() even for INSERT that supposedly provides values for all column. Because these "values" might be DEFAULT, which would need table->update_default_fields() at the end. Also set Item_default_value::used_tables() from the default expression. Non-zero used_field() means that mysql_insert() will initialize all fields to their default values (with restore_record()) even if all columns are later provided with values. Because default expressions may refer to other columns and they must be initialized.
| * | | | Merge branch '10.1' into 10.2Sergei Golubchik2017-02-101-5/+2
| |\ \ \ \ | | |/ / /
| * | | | MDEV-11598 Assertion `!table || (!table->read_set || ↵Monty2017-01-111-0/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | bitmap_is_set(table->read_set, field_index))' failed Found and fixed 2 problems: - Filesort addon fields didn't mark virtual columns properly - multi-range-read calculated vcol bitmap but was not using it. This caused wrong vcol field to be calculated on read, which caused the assert.
| * | | | New simpler bugfix for UPDATE and virtual BLOBsMonty2017-01-111-3/+37
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | When updating a table with virtual BLOB columns, the following might happen: - an old record is read from the table, it has no virtual blob values - update_virtual_fields() is run, vcol blob gets its value into the record. But only a pointer to the value is in the table->record[0], the value is in Field_blob::value String (but it doesn't have to be! it can be in the record, if the column is just a copy of another columns: ... b VARCHAR, c BLOB AS (b) ...) - store_record(table,record[1]), old record now is in record[1] - fill_record() prepares new values in record[0], vcol blob is updated, new value replaces the old one in the Field_blob::value - now both record[1] and record[0] have a pointer that points to the *new* vcol blob value. Or record[1] has a pointer to nowhere if Field_blob::value had to realloc. To fix this I have introduced a new String object 'read_value' in Field_blob. When updating virtual columns when a row has been read, the allocated value is stored in 'read_value' instead of 'value'. The allocated blobs for the new row is stored in 'value' as before. I also made, as a safety precaution, the insert delayed handling of blobs more general by using value to store strings instead of the record. This ensures that virtual functions on delayed insert should work in as in the case of normal insert. Triggers are now properly updating the read, write and vcol maps for used fields. This means that we don't need VCOL_UPDATE_FOR_READ_WRITE anymore and there is no need for any other special handling of triggers in update_virtual_fields(). To be able to test how many times virtual fields are invoked, I also relaxed rules that one can use local (@) variables in DEFAULT and non persistent virtual field expressions.