#At file:///home/dlenev/src/bzr/mysql-trunk-bug27480/ based on revid:dmitry.lenev@stripped
3536 Dmitry Lenev 2011-04-04
Another follow-up for the patch for Bug#11746602
27480: Extend CREATE TEMPORARY TABLES privilege to
allow temp table operations).
Got rid of extra call to open_temporary_tables() during
HANDLER OPEN introduced by one of previous patches.
This call to open_temporary_tables() was necessary for
privilege checking. It became possible to remove it by
moving privilege check inside of mysql_ha_open() call
Also all HANDLER commands were converted to using Sql_cmd
infrastructure.
@ mysql-test/include/handler.inc
Adjusted test case to the fact that now HANDLER OPEN pre-opens
temporary tables only after it checks if it is called under
LOCK TABLES.
@ mysql-test/r/handler_innodb.result
Adjusted test case to the fact that now HANDLER OPEN pre-opens
temporary tables only after it checks if it is called under
LOCK TABLES.
@ mysql-test/r/handler_myisam.result
Adjusted test case to the fact that now HANDLER OPEN pre-opens
temporary tables only after it checks if it is called under
LOCK TABLES.
@ sql/sql_handler.cc
Got rid of extra call to open_temporary_tables() during
HANDLER OPEN. This call to open_temporary_tables() was
necessary for privilege checking. It became possible to
remove it by moving privilege check inside of mysql_ha_open()
call. To support this change mysql_ha_open() was split in
two parts one specific for HANDLER OPEN and one common for
HANDLER OPEN and re-open of table for HANDLER READ.
Also all HANDLER commands were converted to using Sql_cmd
infrastructure.
@ sql/sql_handler.h
Now all HANDLER commands use Sql_cmd infrastructure.
@ sql/sql_lex.h
Since HANDLER READ command is now respresented by
class inhereted from Sql_cmd there is no need in
LEX::ha_read_mode/ha_rkey_mode members.
Since we still need to keep value for ha_rkey_mode
during statement parsing, until the moment when
Sql_cmd_handler_read instance is constructed, a
corresponding member was added to Yacc_state.
@ sql/sql_parse.cc
All HANDLER commands were moved to Sql_cmd infrastructure.
Also got rid of extra call to open_temporary_tables()
for HANDLER OPEN statement. Now instead of pre-opening
temporary tables separately, for privilege checking, we do
privilege checking after main call to open_temporary_tables(),
inside of Sql_cmd_handler_open::execute() method.
@ sql/sql_yacc.yy
Changed part of grammar for HANDLER statements to use
Sql_cmd infrastructure.
modified:
mysql-test/include/handler.inc
mysql-test/r/handler_innodb.result
mysql-test/r/handler_myisam.result
sql/sql_handler.cc
sql/sql_handler.h
sql/sql_lex.h
sql/sql_parse.cc
sql/sql_yacc.yy
=== modified file 'mysql-test/include/handler.inc'
--- a/mysql-test/include/handler.inc 2011-03-26 10:56:27 +0000
+++ b/mysql-test/include/handler.inc 2011-04-04 17:38:43 +0000
@@ -819,7 +819,7 @@ handler t1 open;
handler t1 read next;
--error ER_LOCK_OR_ACTIVE_TRANSACTION
handler t2 close;
---error ER_CANT_REOPEN_TABLE
+--error ER_LOCK_OR_ACTIVE_TRANSACTION
handler t3 open;
--error ER_LOCK_OR_ACTIVE_TRANSACTION
handler t4 open;
=== modified file 'mysql-test/r/handler_innodb.result'
--- a/mysql-test/r/handler_innodb.result 2011-03-26 10:56:27 +0000
+++ b/mysql-test/r/handler_innodb.result 2011-04-04 17:38:43 +0000
@@ -800,7 +800,7 @@ ERROR HY000: Can't execute the given com
handler t2 close;
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
handler t3 open;
-ERROR HY000: Can't reopen table: 't3'
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
handler t4 open;
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
# After UNLOCK TABLES handlers should be around and
=== modified file 'mysql-test/r/handler_myisam.result'
--- a/mysql-test/r/handler_myisam.result 2011-03-26 10:56:27 +0000
+++ b/mysql-test/r/handler_myisam.result 2011-04-04 17:38:43 +0000
@@ -798,7 +798,7 @@ ERROR HY000: Can't execute the given com
handler t2 close;
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
handler t3 open;
-ERROR HY000: Can't reopen table: 't3'
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
handler t4 open;
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
# After UNLOCK TABLES handlers should be around and
=== modified file 'sql/sql_handler.cc'
--- a/sql/sql_handler.cc 2011-03-26 10:56:27 +0000
+++ b/sql/sql_handler.cc 2011-04-04 17:38:43 +0000
@@ -60,12 +60,15 @@
#include "sql_base.h" // insert_fields
#include "sql_select.h"
#include "transaction.h"
+#include "sql_parse.h" // check_table_access
#define HANDLER_TABLES_HASH_SIZE 120
static enum enum_ha_read_modes rkey_to_rnext[]=
{ RNEXT_SAME, RNEXT, RPREV, RNEXT, RPREV, RNEXT, RPREV, RPREV };
+static bool mysql_ha_open_table(THD *thd, TABLE_LIST *table);
+
/*
Get hash key and hash key length.
@@ -150,40 +153,25 @@ static void mysql_ha_close_table(THD *th
tables->mdl_request.ticket= NULL;
}
-/*
- Open a HANDLER table.
- SYNOPSIS
- mysql_ha_open()
- thd Thread identifier.
- tables A list of tables with the first entry to open.
- reopen Re-open a previously opened handler table.
+/**
+ Execute a HANDLER OPEN statement.
- DESCRIPTION
- Though this function takes a list of tables, only the first list entry
- will be opened.
- 'reopen' is set when a handler table is to be re-opened. In this case,
- 'tables' is the pointer to the hashed TABLE_LIST object which has been
- saved on the original open.
- 'reopen' is also used to suppress the sending of an 'ok' message.
+ @param thd The current thread.
- RETURN
- FALSE OK
- TRUE Error
+ @retval FALSE on success.
+ @retval TRUE on failure.
*/
-bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
+bool Sql_cmd_handler_open::execute(THD *thd)
{
TABLE_LIST *hash_tables = NULL;
char *db, *name, *alias;
- uint dblen, namelen, aliaslen, counter;
- bool error;
- TABLE *backup_open_tables;
- MDL_savepoint mdl_savepoint;
- DBUG_ENTER("mysql_ha_open");
- DBUG_PRINT("enter",("'%s'.'%s' as '%s' reopen: %d",
- tables->db, tables->table_name, tables->alias,
- (int) reopen));
+ uint dblen, namelen, aliaslen;
+ TABLE_LIST *tables= (TABLE_LIST*) thd->lex->select_lex.table_list.first;
+ DBUG_ENTER("Sql_cmd_handler_open::execute");
+ DBUG_PRINT("enter",("'%s'.'%s' as '%s'",
+ tables->db, tables->table_name, tables->alias));
if (thd->locked_tables_mode)
{
@@ -212,8 +200,15 @@ bool mysql_ha_open(THD *thd, TABLE_LIST
DBUG_RETURN(TRUE);
}
}
- else if (! reopen) /* Otherwise we have 'tables' already. */
+ else
{
+ /*
+ Otherwise we might have handler with the same name already.
+
+ Note that it is safe to disclose this information before doing privilege
+ check. Current user can always find out that handler is open by using
+ HANDLER ... READ command, which doesn't requires any privileges.
+ */
if (my_hash_search(&thd->handler_tables_hash, (uchar*) tables->alias,
strlen(tables->alias) + 1))
{
@@ -224,50 +219,84 @@ bool mysql_ha_open(THD *thd, TABLE_LIST
}
}
- if (! reopen)
+ /* copy the TABLE_LIST struct */
+ dblen= strlen(tables->db) + 1;
+ namelen= strlen(tables->table_name) + 1;
+ aliaslen= strlen(tables->alias) + 1;
+ if (!(my_multi_malloc(MYF(MY_WME),
+ &hash_tables, (uint) sizeof(*hash_tables),
+ &db, (uint) dblen,
+ &name, (uint) namelen,
+ &alias, (uint) aliaslen,
+ NullS)))
{
- /* copy the TABLE_LIST struct */
- dblen= strlen(tables->db) + 1;
- namelen= strlen(tables->table_name) + 1;
- aliaslen= strlen(tables->alias) + 1;
- if (!(my_multi_malloc(MYF(MY_WME),
- &hash_tables, (uint) sizeof(*hash_tables),
- &db, (uint) dblen,
- &name, (uint) namelen,
- &alias, (uint) aliaslen,
- NullS)))
- {
- DBUG_PRINT("exit",("ERROR"));
- DBUG_RETURN(TRUE);
- }
- /* structure copy */
- *hash_tables= *tables;
- hash_tables->db= db;
- hash_tables->table_name= name;
- hash_tables->alias= alias;
- memcpy(hash_tables->db, tables->db, dblen);
- memcpy(hash_tables->table_name, tables->table_name, namelen);
- memcpy(hash_tables->alias, tables->alias, aliaslen);
- /*
- We can't request lock with explicit duration for this table
- right from the start as open_tables() can't handle properly
- back-off for such locks.
- */
- hash_tables->mdl_request.init(MDL_key::TABLE, db, name, MDL_SHARED,
- MDL_TRANSACTION);
- /* for now HANDLER can be used only for real TABLES */
- hash_tables->required_type= FRMTYPE_TABLE;
+ DBUG_PRINT("exit",("ERROR"));
+ DBUG_RETURN(TRUE);
+ }
+ /* structure copy */
+ *hash_tables= *tables;
+ hash_tables->db= db;
+ hash_tables->table_name= name;
+ hash_tables->alias= alias;
+ memcpy(hash_tables->db, tables->db, dblen);
+ memcpy(hash_tables->table_name, tables->table_name, namelen);
+ memcpy(hash_tables->alias, tables->alias, aliaslen);
+ /*
+ We can't request lock with explicit duration for this table
+ right from the start as open_tables() can't handle properly
+ back-off for such locks.
+ */
+ hash_tables->mdl_request.init(MDL_key::TABLE, db, name, MDL_SHARED,
+ MDL_TRANSACTION);
+ /* for now HANDLER can be used only for real TABLES */
+ hash_tables->required_type= FRMTYPE_TABLE;
- /* add to hash */
- if (my_hash_insert(&thd->handler_tables_hash, (uchar*) hash_tables))
- {
- my_free(hash_tables);
- DBUG_PRINT("exit",("ERROR"));
- DBUG_RETURN(TRUE);
- }
+ /* add to hash */
+ if (my_hash_insert(&thd->handler_tables_hash, (uchar*) hash_tables))
+ {
+ my_free(hash_tables);
+ DBUG_PRINT("exit",("ERROR"));
+ DBUG_RETURN(TRUE);
}
- else
- hash_tables= tables;
+
+ if (open_temporary_tables(thd, hash_tables) ||
+ check_table_access(thd, SELECT_ACL, hash_tables, FALSE, UINT_MAX,
+ FALSE) ||
+ mysql_ha_open_table(thd, hash_tables))
+
+ {
+ my_hash_delete(&thd->handler_tables_hash, (uchar*) hash_tables);
+ DBUG_PRINT("exit",("ERROR"));
+ DBUG_RETURN(TRUE);
+ }
+
+ my_ok(thd);
+
+ DBUG_PRINT("exit",("OK"));
+ DBUG_RETURN(FALSE);
+}
+
+
+/**
+ Auxiliary function which opens or re-opens table for HANDLER statements.
+
+ @param thd Thread context..
+ @param hash_tables Table list element for table to open.
+
+ @retval FALSE - Success.
+ @retval TRUE - Failure.
+*/
+
+static bool mysql_ha_open_table(THD *thd, TABLE_LIST *hash_tables)
+{
+ TABLE *backup_open_tables;
+ MDL_savepoint mdl_savepoint;
+ uint counter;
+ bool error;
+
+ DBUG_ENTER("mysql_ha_open_table");
+
+ DBUG_ASSERT(!thd->locked_tables_mode);
/*
Save and reset the open_tables list so that open_tables() won't
@@ -282,20 +311,17 @@ bool mysql_ha_open(THD *thd, TABLE_LIST
mdl_savepoint= thd->mdl_context.mdl_savepoint();
/*
- open_tables() will set 'hash_tables->table' if successful.
- It must be NULL for a real open when calling open_tables().
+ 'hash_tables->table' must be NULL, unless there is pre-opened
+ temporary table. open_tables() will set it if successful.
*/
- DBUG_ASSERT(! hash_tables->table);
-
- error= open_temporary_tables(thd, hash_tables);
+ DBUG_ASSERT(! hash_tables->table || is_temporary_table(hash_tables));
- if (!error)
- error= open_tables(thd, &hash_tables, &counter, 0);
+ error= open_tables(thd, &hash_tables, &counter, 0);
if (! error &&
! (hash_tables->table->file->ha_table_flags() & HA_CAN_SQL_HANDLER))
{
- my_error(ER_ILLEGAL_HA, MYF(0), tables->alias);
+ my_error(ER_ILLEGAL_HA, MYF(0), hash_tables->alias);
error= TRUE;
}
if (!error &&
@@ -311,21 +337,16 @@ bool mysql_ha_open(THD *thd, TABLE_LIST
{
/*
No need to rollback statement transaction, it's not started.
- If called with reopen flag, no need to rollback either,
+ If called for re-open, no need to rollback either,
it will be done at statement end.
*/
DBUG_ASSERT(thd->transaction.stmt.is_empty());
close_thread_tables(thd);
thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
thd->set_open_tables(backup_open_tables);
- if (!reopen)
- my_hash_delete(&thd->handler_tables_hash, (uchar*) hash_tables);
- else
- {
- hash_tables->table= NULL;
- /* Safety, cleanup the pointer to satisfy MDL assertions. */
- hash_tables->mdl_request.ticket= NULL;
- }
+ hash_tables->table= NULL;
+ /* Safety, cleanup the pointer to satisfy MDL assertions. */
+ hash_tables->mdl_request.ticket= NULL;
DBUG_PRINT("exit",("ERROR"));
DBUG_RETURN(TRUE);
}
@@ -352,34 +373,28 @@ bool mysql_ha_open(THD *thd, TABLE_LIST
*/
hash_tables->table->open_by_handler= 1;
- if (! reopen)
- my_ok(thd);
DBUG_PRINT("exit",("OK"));
DBUG_RETURN(FALSE);
}
-/*
- Close a HANDLER table by alias or table name
+/**
+ Execute a HANDLER CLOSE statement.
- SYNOPSIS
- mysql_ha_close()
- thd Thread identifier.
- tables A list of tables with the first entry to close.
+ @param thd The current thread.
- DESCRIPTION
- Closes the table that is associated (on the handler tables hash) with the
- name (table->alias) of the specified table.
+ @note Closes the table that is associated (on the handler tables hash)
+ with the name (TABLE_LIST::alias) of the specified table.
- RETURN
- FALSE ok
- TRUE error
+ @retval FALSE on success.
+ @retval TRUE on failure.
*/
-bool mysql_ha_close(THD *thd, TABLE_LIST *tables)
+bool Sql_cmd_handler_close::execute(THD *thd)
{
+ TABLE_LIST *tables= (TABLE_LIST*) thd->lex->select_lex.table_list.first;
TABLE_LIST *hash_tables;
- DBUG_ENTER("mysql_ha_close");
+ DBUG_ENTER("Sql_cmd_handler_close::execute");
DBUG_PRINT("enter",("'%s'.'%s' as '%s'",
tables->db, tables->table_name, tables->alias));
@@ -465,31 +480,19 @@ handle_condition(THD *thd,
}
-/*
- Read from a HANDLER table.
+/**
+ Execute a HANDLER READ statement.
- SYNOPSIS
- mysql_ha_read()
- thd Thread identifier.
- tables A list of tables with the first entry to read.
- mode
- keyname
- key_expr
- ha_rkey_mode
- cond
- select_limit_cnt
- offset_limit_cnt
+ @param thd The current thread.
- RETURN
- FALSE ok
- TRUE error
+ @note Closes the table that is associated (on the handler tables hash)
+ with the name (TABLE_LIST::alias) of the specified table.
+
+ @retval FALSE on success.
+ @retval TRUE on failure.
*/
-
-bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
- enum enum_ha_read_modes mode, char *keyname,
- List<Item> *key_expr,
- enum ha_rkey_function ha_rkey_mode, Item *cond,
- ha_rows select_limit_cnt, ha_rows offset_limit_cnt)
+
+bool Sql_cmd_handler_read::execute(THD *thd)
{
TABLE_LIST *hash_tables;
TABLE *table, *backup_open_tables;
@@ -503,7 +506,14 @@ bool mysql_ha_read(THD *thd, TABLE_LIST
uchar *UNINIT_VAR(key);
uint UNINIT_VAR(key_len);
Sql_handler_lock_error_handler sql_handler_lock_error;
- DBUG_ENTER("mysql_ha_read");
+ LEX *lex= thd->lex;
+ SELECT_LEX *select_lex= &lex->select_lex;
+ SELECT_LEX_UNIT *unit= &lex->unit;
+ TABLE_LIST *tables= select_lex->table_list.first;
+ enum enum_ha_read_modes mode= m_read_mode;
+ Item *cond= select_lex->where;
+ ha_rows select_limit_cnt, offset_limit_cnt;
+ DBUG_ENTER("Sql_cmd_handler_read::execute");
DBUG_PRINT("enter",("'%s'.'%s' as '%s'",
tables->db, tables->table_name, tables->alias));
@@ -513,8 +523,19 @@ bool mysql_ha_read(THD *thd, TABLE_LIST
DBUG_RETURN(TRUE);
}
- thd->lex->select_lex.context.resolve_in_table_list_only(tables);
- list.push_front(new Item_field(&thd->lex->select_lex.context,
+ /*
+ There is no need to check for table permissions here, because
+ if a user has no permissions to read a table, he won't be
+ able to open it (with SQLCOM_HA_OPEN) in the first place.
+ */
+
+ /* Get limit counters from SELECT_LEX. */
+ unit->set_limit(select_lex);
+ select_limit_cnt= unit->select_limit_cnt;
+ offset_limit_cnt= unit->offset_limit_cnt;
+
+ select_lex->context.resolve_in_table_list_only(tables);
+ list.push_front(new Item_field(&select_lex->context,
NULL, NULL, "*"));
List_iterator<Item> it(list);
it++;
@@ -533,7 +554,7 @@ retry:
/*
The handler table has been closed. Re-open it.
*/
- if (mysql_ha_open(thd, hash_tables, 1))
+ if (mysql_ha_open_table(thd, hash_tables))
{
DBUG_PRINT("exit",("reopen failed"));
goto err0;
@@ -609,11 +630,11 @@ retry:
goto err;
}
- if (keyname)
+ if (m_key_name)
{
- if ((keyno=find_type(keyname, &table->s->keynames, 1+2)-1)<0)
+ if ((keyno=find_type((char*)m_key_name, &table->s->keynames, 1+2)-1)<0)
{
- my_error(ER_KEY_DOES_NOT_EXITS, MYF(0), keyname, tables->alias);
+ my_error(ER_KEY_DOES_NOT_EXITS, MYF(0), m_key_name, tables->alias);
goto err;
}
/* Check if the same index involved. */
@@ -626,7 +647,7 @@ retry:
}
}
- if (insert_fields(thd, &thd->lex->select_lex.context,
+ if (insert_fields(thd, &select_lex->context,
tables->db, tables->alias, &it, 0))
goto err;
@@ -646,7 +667,7 @@ retry:
case RNEXT:
if (table->file->inited != handler::NONE)
{
- if (keyname)
+ if (m_key_name)
{
/* Check if we read from the same index. */
DBUG_ASSERT((uint) keyno == table->file->get_index());
@@ -660,7 +681,7 @@ retry:
}
/* else fall through */
case RFIRST:
- if (keyname)
+ if (m_key_name)
{
table->file->ha_index_or_rnd_end();
table->file->ha_index_init(keyno, 1);
@@ -675,7 +696,7 @@ retry:
mode=RNEXT;
break;
case RPREV:
- DBUG_ASSERT(keyname != 0);
+ DBUG_ASSERT(m_key_name != 0);
/* Check if we read from the same index. */
DBUG_ASSERT((uint) keyno == table->file->get_index());
if (table->file->inited != handler::NONE)
@@ -685,7 +706,7 @@ retry:
}
/* else fall through */
case RLAST:
- DBUG_ASSERT(keyname != 0);
+ DBUG_ASSERT(m_key_name != 0);
table->file->ha_index_or_rnd_end();
table->file->ha_index_init(keyno, 1);
error= table->file->ha_index_last(table->record[0]);
@@ -693,20 +714,20 @@ retry:
break;
case RNEXT_SAME:
/* Continue scan on "(keypart1,keypart2,...)=(c1, c2, ...) */
- DBUG_ASSERT(keyname != 0);
+ DBUG_ASSERT(m_key_name != 0);
error= table->file->ha_index_next_same(table->record[0], key, key_len);
break;
case RKEY:
{
- DBUG_ASSERT(keyname != 0);
+ DBUG_ASSERT(m_key_name != 0);
KEY *keyinfo=table->key_info+keyno;
KEY_PART_INFO *key_part=keyinfo->key_part;
- if (key_expr->elements > keyinfo->key_parts)
+ if (m_key_expr->elements > keyinfo->key_parts)
{
my_error(ER_TOO_MANY_KEY_PARTS, MYF(0), keyinfo->key_parts);
goto err;
}
- List_iterator<Item> it_ke(*key_expr);
+ List_iterator<Item> it_ke(*m_key_expr);
Item *item;
key_part_map keypart_map;
for (keypart_map= key_len=0 ; (item=it_ke++) ; key_part++)
@@ -735,8 +756,8 @@ retry:
table->file->ha_index_init(keyno, 1);
key_copy(key, table->record[0], table->key_info + keyno, key_len);
error= table->file->ha_index_read_map(table->record[0],
- key, keypart_map, ha_rkey_mode);
- mode=rkey_to_rnext[(int)ha_rkey_mode];
+ key, keypart_map, m_rkey_mode);
+ mode=rkey_to_rnext[(int)m_rkey_mode];
break;
}
default:
=== modified file 'sql/sql_handler.h'
--- a/sql/sql_handler.h 2010-11-18 16:34:56 +0000
+++ b/sql/sql_handler.h 2011-04-04 17:38:43 +0000
@@ -23,10 +23,100 @@
class THD;
struct TABLE_LIST;
-bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen);
-bool mysql_ha_close(THD *thd, TABLE_LIST *tables);
-bool mysql_ha_read(THD *, TABLE_LIST *,enum enum_ha_read_modes,char *,
- List<Item> *,enum ha_rkey_function,Item *,ha_rows,ha_rows);
+/**
+ Sql_cmd_handler_open represents HANDLER OPEN statement.
+
+ @note Some information about this statement, for example, table to be
+ opened is still kept in LEX class.
+*/
+
+class Sql_cmd_handler_open : public Sql_cmd
+{
+public:
+ Sql_cmd_handler_open()
+ {}
+
+ virtual ~Sql_cmd_handler_open()
+ {}
+
+ virtual enum_sql_command sql_command_code() const
+ {
+ return SQLCOM_HA_OPEN;
+ }
+
+ bool execute(THD *thd);
+};
+
+
+/**
+ Sql_cmd_handler_read represents HANDLER READ statement.
+
+ @note Some information about this statement, for example, table
+ list element which identifies HANDLER to be read from,
+ WHERE and LIMIT clauses is still kept in LEX class.
+*/
+
+class Sql_cmd_handler_read : public Sql_cmd
+{
+public:
+ Sql_cmd_handler_read(enum_ha_read_modes read_mode,
+ const char *key_name,
+ List<Item> *key_expr,
+ ha_rkey_function rkey_mode)
+ : m_read_mode(read_mode), m_key_name(key_name), m_key_expr(key_expr),
+ m_rkey_mode(rkey_mode)
+ {}
+
+ virtual ~Sql_cmd_handler_read()
+ {}
+
+ virtual enum_sql_command sql_command_code() const
+ {
+ return SQLCOM_HA_READ;
+ }
+
+ bool execute(THD *thd);
+
+private:
+ /** Read mode for HANDLER READ: FIRST, NEXT, LAST, ... */
+ enum enum_ha_read_modes m_read_mode;
+ /**
+ Name of key to be used for reading,
+ NULL in cases when natural row-order is to be used.
+ */
+ const char *m_key_name;
+ /** Key values to be satisfied. */
+ List<Item> *m_key_expr;
+ /** Type of condition for key values to be satisfied. */
+ enum ha_rkey_function m_rkey_mode;
+};
+
+
+/**
+ Sql_cmd_handler_close represents HANDLER CLOSE statement.
+
+ @note Table list element which identifies HANDLER to be closed
+ still resides in LEX class.
+*/
+
+class Sql_cmd_handler_close : public Sql_cmd
+{
+public:
+ Sql_cmd_handler_close()
+ {}
+
+ virtual ~Sql_cmd_handler_close()
+ {}
+
+ virtual enum_sql_command sql_command_code() const
+ {
+ return SQLCOM_HA_CLOSE;
+ }
+
+ bool execute(THD *thd);
+};
+
+
void mysql_ha_flush(THD *thd);
void mysql_ha_flush_tables(THD *thd, TABLE_LIST *all_tables);
void mysql_ha_rm_tables(THD *thd, TABLE_LIST *tables);
=== modified file 'sql/sql_lex.h'
--- a/sql/sql_lex.h 2011-03-08 09:21:39 +0000
+++ b/sql/sql_lex.h 2011-04-04 17:38:43 +0000
@@ -2149,11 +2149,7 @@ struct LEX: public Query_tables_list
enum SSL_type ssl_type; /* defined in violite.h */
enum enum_duplicates duplicates;
enum enum_tx_isolation tx_isolation;
- enum enum_ha_read_modes ha_read_mode;
- union {
- enum ha_rkey_function ha_rkey_mode;
- enum xa_option_words xa_opt;
- };
+ enum xa_option_words xa_opt;
enum enum_var_type option_type;
enum enum_view_create_mode create_view_mode;
enum enum_drop_mode drop_mode;
@@ -2459,6 +2455,7 @@ public:
m_set_signal_info.clear();
m_lock_type= TL_READ_DEFAULT;
m_mdl_type= MDL_SHARED_READ;
+ m_ha_rkey_mode= HA_READ_KEY_EXACT;
}
~Yacc_state();
@@ -2471,6 +2468,7 @@ public:
{
m_lock_type= TL_READ_DEFAULT;
m_mdl_type= MDL_SHARED_READ;
+ m_ha_rkey_mode= HA_READ_KEY_EXACT; /* Let us be future-proof. */
}
/**
@@ -2516,6 +2514,9 @@ public:
*/
enum_mdl_type m_mdl_type;
+ /** Type of condition for key in HANDLER READ statement. */
+ enum ha_rkey_function m_ha_rkey_mode;
+
/*
TODO: move more attributes from the LEX structure here.
*/
=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc 2011-04-01 18:08:48 +0000
+++ b/sql/sql_parse.cc 2011-04-04 17:38:43 +0000
@@ -475,7 +475,6 @@ void init_update_queries(void)
sql_command_flags[SQLCOM_SELECT]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_SET_OPTION]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_DO]|= CF_PREOPEN_TMP_TABLES;
- sql_command_flags[SQLCOM_HA_OPEN]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_CALL]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_CHECKSUM]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_ANALYZE]|= CF_PREOPEN_TMP_TABLES;
@@ -3726,32 +3725,6 @@ end_with_restore_list:
break;
}
#endif
- case SQLCOM_HA_OPEN:
- DBUG_ASSERT(first_table == all_tables && first_table != 0);
- if (check_table_access(thd, SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE))
- goto error;
- /* Close temporary tables which were pre-opened for privilege checking. */
- close_thread_tables(thd);
- all_tables->table= NULL;
- res= mysql_ha_open(thd, first_table, 0);
- break;
- case SQLCOM_HA_CLOSE:
- DBUG_ASSERT(first_table == all_tables && first_table != 0);
- res= mysql_ha_close(thd, first_table);
- break;
- case SQLCOM_HA_READ:
- DBUG_ASSERT(first_table == all_tables && first_table != 0);
- /*
- There is no need to check for table permissions here, because
- if a user has no permissions to read a table, he won't be
- able to open it (with SQLCOM_HA_OPEN) in the first place.
- */
- unit->set_limit(select_lex);
- res= mysql_ha_read(thd, first_table, lex->ha_read_mode, lex->ident.str,
- lex->insert_list, lex->ha_rkey_mode, select_lex->where,
- unit->select_limit_cnt, unit->offset_limit_cnt);
- break;
-
case SQLCOM_BEGIN:
if (trans_begin(thd, lex->start_transaction_opt))
goto error;
@@ -4438,6 +4411,9 @@ create_sp_error:
case SQLCOM_REPAIR:
case SQLCOM_TRUNCATE:
case SQLCOM_ALTER_TABLE:
+ case SQLCOM_HA_OPEN:
+ case SQLCOM_HA_READ:
+ case SQLCOM_HA_CLOSE:
DBUG_ASSERT(first_table == all_tables && first_table != 0);
/* fall through */
case SQLCOM_SIGNAL:
=== modified file 'sql/sql_yacc.yy'
--- a/sql/sql_yacc.yy 2011-03-08 09:21:39 +0000
+++ b/sql/sql_yacc.yy 2011-04-04 17:38:43 +0000
@@ -56,6 +56,7 @@
#include "sql_truncate.h" // Sql_cmd_truncate_table
#include "sql_admin.h" // Sql_cmd_analyze/Check..._table
#include "sql_partition_admin.h" // Sql_cmd_alter_table_*_part.
+#include "sql_handler.h" // Sql_cmd_handler_*
#include "sql_signal.h"
#include "event_parse_data.h"
#include <myisam.h>
@@ -753,6 +754,7 @@ static bool add_create_index (LEX *lex,
handlerton *db_type;
enum row_type row_type;
enum ha_rkey_function ha_rkey_mode;
+ enum enum_ha_read_modes ha_read_mode;
enum enum_tx_isolation tx_isolation;
enum Cast_target cast_type;
enum Item_udftype udf_type;
@@ -1531,6 +1533,9 @@ bool my_yyoverflow(short **a, YYSTYPE **
%type <tx_isolation> isolation_types
%type <ha_rkey_mode> handler_rkey_mode
+
+%type <ha_read_mode> handler_read_or_scan handler_scan_function
+ handler_rkey_function
%type <cast_type> cast_type
@@ -1587,7 +1592,6 @@ bool my_yyoverflow(short **a, YYSTYPE **
equal optional_braces
opt_mi_check_type opt_to mi_check_types normal_join
table_to_table_list table_to_table opt_table_list opt_as
- handler_rkey_function handler_read_or_scan
single_multi table_wild_list table_wild_one opt_wild
union_clause union_list
precision subselect_start opt_and charset
@@ -13376,6 +13380,7 @@ unlock:
handler:
HANDLER_SYM table_ident OPEN_SYM opt_table_alias
{
+ THD *thd= YYTHD;
LEX *lex= Lex;
if (lex->sphead)
{
@@ -13383,11 +13388,15 @@ handler:
MYSQL_YYABORT;
}
lex->sql_command = SQLCOM_HA_OPEN;
- if (!lex->current_select->add_table_to_list(lex->thd, $2, $4, 0))
+ if (!lex->current_select->add_table_to_list(thd, $2, $4, 0))
+ MYSQL_YYABORT;
+ lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_handler_open();
+ if (lex->m_sql_cmd == NULL)
MYSQL_YYABORT;
}
| HANDLER_SYM table_ident_nodb CLOSE_SYM
{
+ THD *thd= YYTHD;
LEX *lex= Lex;
if (lex->sphead)
{
@@ -13395,7 +13404,10 @@ handler:
MYSQL_YYABORT;
}
lex->sql_command = SQLCOM_HA_CLOSE;
- if (!lex->current_select->add_table_to_list(lex->thd, $2, 0, 0))
+ if (!lex->current_select->add_table_to_list(thd, $2, 0, 0))
+ MYSQL_YYABORT;
+ lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_handler_close();
+ if (lex->m_sql_cmd == NULL)
MYSQL_YYABORT;
}
| HANDLER_SYM table_ident_nodb READ_SYM
@@ -13408,7 +13420,6 @@ handler:
}
lex->expr_allows_subselect= FALSE;
lex->sql_command = SQLCOM_HA_READ;
- lex->ha_rkey_mode= HA_READ_KEY_EXACT; /* Avoid purify warnings */
Item *one= new (YYTHD->mem_root) Item_int((int32) 1);
if (one == NULL)
MYSQL_YYABORT;
@@ -13419,42 +13430,49 @@ handler:
}
handler_read_or_scan where_clause opt_limit_clause
{
+ THD *thd= YYTHD;
+ LEX *lex= Lex;
Lex->expr_allows_subselect= TRUE;
/* Stored functions are not supported for HANDLER READ. */
- if (Lex->uses_stored_routines())
+ if (lex->uses_stored_routines())
{
my_error(ER_NOT_SUPPORTED_YET, MYF(0),
"stored functions in HANDLER ... READ");
MYSQL_YYABORT;
}
+ lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_handler_read($5,
+ lex->ident.str, lex->insert_list,
+ thd->m_parser_state->m_yacc.m_ha_rkey_mode);
+ if (lex->m_sql_cmd == NULL)
+ MYSQL_YYABORT;
}
;
handler_read_or_scan:
- handler_scan_function { Lex->ident= null_lex_str; }
- | ident handler_rkey_function { Lex->ident= $1; }
+ handler_scan_function { Lex->ident= null_lex_str; $$=$1; }
+ | ident handler_rkey_function { Lex->ident= $1; $$=$2; }
;
handler_scan_function:
- FIRST_SYM { Lex->ha_read_mode = RFIRST; }
- | NEXT_SYM { Lex->ha_read_mode = RNEXT; }
+ FIRST_SYM { $$= RFIRST; }
+ | NEXT_SYM { $$= RNEXT; }
;
handler_rkey_function:
- FIRST_SYM { Lex->ha_read_mode = RFIRST; }
- | NEXT_SYM { Lex->ha_read_mode = RNEXT; }
- | PREV_SYM { Lex->ha_read_mode = RPREV; }
- | LAST_SYM { Lex->ha_read_mode = RLAST; }
+ FIRST_SYM { $$= RFIRST; }
+ | NEXT_SYM { $$= RNEXT; }
+ | PREV_SYM { $$= RPREV; }
+ | LAST_SYM { $$= RLAST; }
| handler_rkey_mode
{
- LEX *lex=Lex;
- lex->ha_read_mode = RKEY;
- lex->ha_rkey_mode=$1;
- if (!(lex->insert_list = new List_item))
+ YYTHD->m_parser_state->m_yacc.m_ha_rkey_mode= $1;
+ if (!(Lex->insert_list = new List_item))
MYSQL_YYABORT;
}
'(' values ')'
- {}
+ {
+ $$= RKEY;
+ }
;
handler_rkey_mode:
Attachment: [text/bzr-bundle] bzr/dmitry.lenev@oracle.com-20110404173843-9k4is5kb01re2xci.bundle