From: Dmitry Lenev Date: April 4 2011 5:38pm Subject: bzr commit into mysql-trunk branch (Dmitry.Lenev:3536) Bug#11746602 List-Archive: http://lists.mysql.com/commits/134641 X-Bug: 11746602 Message-Id: <20110404173851.9D04C7404EF@bandersnatch> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============1431359684==" --===============1431359684== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #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 *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 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 it_ke(*key_expr); + List_iterator 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 *,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 *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 *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 @@ -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 isolation_types %type handler_rkey_mode + +%type handler_read_or_scan handler_scan_function + handler_rkey_function %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: --===============1431359684== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/dmitry.lenev@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: dmitry.lenev@stripped # target_branch: file:///home/dlenev/src/bzr/mysql-trunk-bug27480/ # testament_sha1: 32bea0c268a8d51d8cd2747a715d5afd18816e2c # timestamp: 2011-04-04 21:38:51 +0400 # base_revision_id: dmitry.lenev@stripped\ # 6fju0ncpn4l71xl4 # # Begin bundle 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 FCQ5tbKywA== --===============1431359684==--