List:Commits« Previous MessageNext Message »
From:Dmitry Lenev Date:April 4 2011 5:38pm
Subject:bzr commit into mysql-trunk branch (Dmitry.Lenev:3536) Bug#11746602
View as plain text  
#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
Thread
bzr commit into mysql-trunk branch (Dmitry.Lenev:3536) Bug#11746602Dmitry Lenev4 Apr
  • Re: bzr commit into mysql-trunk branch (Dmitry.Lenev:3536) Bug#11746602Alexander Nozdrin5 Apr