summaryrefslogtreecommitdiff
path: root/sql/table.h
diff options
context:
space:
mode:
authorkostja@dipika.(none) <>2008-04-08 20:01:20 +0400
committerkostja@dipika.(none) <>2008-04-08 20:01:20 +0400
commitd1f9376229f0a615829a436cf6004840237d1e75 (patch)
tree8ec6e9de86b024933c862dd990eb29572de10727 /sql/table.h
parenta9fff11f49d88e3fec08232b24a721cc515639fc (diff)
downloadmariadb-git-d1f9376229f0a615829a436cf6004840237d1e75.tar.gz
Tentative implementation of
WL#4165 Prepared statements: validation WL#4166 Prepared statements: automatic re-prepare Fixes Bug#27430 Crash in subquery code when in PS and table DDL changed after PREPARE Bug#27690 Re-execution of prepared statement after table was replaced with a view crashes Bug#27420 A combination of PS and view operations cause error + assertion on shutdown The basic idea of the patch is to keep track of table metadata between prepared statement prepare and execute. If some table used in the statement has changed, the prepared statement is re-prepared before execution. See WL#4165 and WL#4166 contents and comments in the code for details of the implementation.
Diffstat (limited to 'sql/table.h')
-rw-r--r--sql/table.h130
1 files changed, 130 insertions, 0 deletions
diff --git a/sql/table.h b/sql/table.h
index d448485a117..2b3c9b8d5b1 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -437,6 +437,105 @@ typedef struct st_table_share
return table_map_id;
}
+ /**
+ Convert unrelated members of TABLE_SHARE to one enum
+ representing its metadata type.
+
+ @todo perhaps we need to have a member instead of a function.
+ */
+ enum enum_metadata_type get_metadata_type() const
+ {
+ if (is_view)
+ return METADATA_VIEW;
+ switch (tmp_table) {
+ case NO_TMP_TABLE:
+ return METADATA_BASE_TABLE;
+ case SYSTEM_TMP_TABLE:
+ return METADATA_I_S_TABLE;
+ default:
+ return METADATA_TMP_TABLE;
+ }
+ }
+ /**
+ Return a table metadata version.
+ * for base tables, we return table_map_id.
+ It is assigned from a global counter incremented for each
+ new table loaded into the table definition cache (TDC).
+ * for temporary tables it's table_map_id again. But for
+ temporary tables table_map_id is assigned from
+ thd->query_id. The latter is assigned from a thread local
+ counter incremented for every new SQL statement. Since
+ temporary tables are thread-local, each temporary table
+ gets a unique id.
+ * for everything else (views, information schema tables),
+ the version id is zero.
+
+ This choice of version id is a large compromise
+ to have a working prepared statement validation in 5.1. In
+ future version ids will be persistent, as described in WL#4180.
+
+ Let's try to explain why and how this limited solution allows
+ to validate prepared statements.
+
+ Firstly, spaces (in mathematical sense) of version numbers
+ never intersect for different metadata types. Therefore,
+ version id of a temporary table is never compared with
+ a version id of a view or a temporary table, and vice versa.
+
+ Secondly, for base tables, we know that each DDL flushes the
+ respective share from the TDC. This ensures that whenever
+ a table is altered or dropped and recreated, it gets a new
+ version id.
+ Unfortunately, since elements of the TDC are also flushed on
+ LRU basis, this choice of version ids leads to false positives.
+ E.g. when the TDC size is too small, we may have a SELECT
+ * FROM INFORMATION_SCHEMA.TABLES flush all its elements, which
+ in turn will lead to a validation error and a subsequent
+ reprepare of all prepared statements. This is
+ considered acceptable, since as long as prepared statements are
+ automatically reprepared, spurious invalidation is only
+ a performance hit. Besides, no better simple solution exists.
+
+ For temporary tables, using thd->query_id ensures that if
+ a temporary table was altered or recreated, a new version id is
+ assigned. This suits validation needs very well and will perhaps
+ never change.
+
+ Metadata of information schema tables never changes.
+ Thus we can safely assume 0 for a good enough version id.
+
+ Views are a special and tricky case. A view is always inlined
+ into the parse tree of a prepared statement at prepare.
+ Thus, when we execute a prepared statement, the parse tree
+ will not get modified even if the view is replaced with another
+ view. Therefore, we can safely choose 0 for version id of
+ views and effectively never invalidate a prepared statement
+ when a view definition is altered. Note, that this leads to
+ wrong binary log in statement-based replication, since we log
+ prepared statement execution in form Query_log_events
+ containing conventional statements. But since there is no
+ metadata locking for views, the very same problem exists for
+ conventional statements alone, as reported in Bug#25144. The only
+ difference between prepared and conventional execution is,
+ effectively, that for prepared statements the race condition
+ window is much wider.
+ In 6.0 we plan to support view metadata locking (WL#3726) and
+ extend table definition cache to cache views (WL#4298).
+ When this is done, views will be handled in the same fashion
+ as the base tables.
+
+ Finally, by taking into account metadata type, we always
+ track that a change has taken place when a view is replaced
+ with a base table, a base table is replaced with a temporary
+ table and so on.
+
+ @sa TABLE_LIST::is_metadata_version_equal()
+ */
+ ulong get_metadata_version() const
+ {
+ return tmp_table == SYSTEM_TMP_TABLE || is_view ? 0 : table_map_id;
+ }
+
} TABLE_SHARE;
@@ -1232,6 +1331,33 @@ struct TABLE_LIST
child_def_version= ~0UL;
}
+ /**
+ Compare the version of metadata from the previous execution
+ (if any) with values obtained from the current table
+ definition cache element.
+
+ @sa check_and_update_metadata_version()
+ */
+ inline
+ bool is_metadata_version_equal(TABLE_SHARE *s) const
+ {
+ return (m_metadata_type == s->get_metadata_type() &&
+ m_metadata_version == s->get_metadata_version());
+ }
+
+ /**
+ Record the value of metadata version of the corresponding
+ table definition cache element in this parse tree node.
+
+ @sa check_and_update_metadata_version()
+ */
+ inline
+ void set_metadata_version(TABLE_SHARE *s)
+ {
+ m_metadata_type= s->get_metadata_type();
+ m_metadata_version= s->get_metadata_version();
+ }
+
private:
bool prep_check_option(THD *thd, uint8 check_opt_type);
bool prep_where(THD *thd, Item **conds, bool no_where_clause);
@@ -1242,6 +1368,10 @@ private:
/* Remembered MERGE child def version. See top comment in ha_myisammrg.cc */
ulong child_def_version;
+ /** See comments for set_metadata_version() */
+ enum enum_metadata_type m_metadata_type;
+ /** See comments for set_metadata_version() */
+ ulong m_metadata_version;
};
class Item;