From: Dmitry Lenev Date: April 5 2011 12:37pm Subject: bzr commit into mysql-trunk branch (Dmitry.Lenev:3536) Bug#11746602 List-Archive: http://lists.mysql.com/commits/134713 X-Bug: 11746602 Message-Id: <20110405123750.18CA7740B3E@bandersnatch> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============1065173437==" --===============1065173437== 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-05 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 represented by class inherited 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-05 12:37:41 +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-05 12:37:41 +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-05 12:37:41 +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-05 12:37:41 +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-05 12:37:41 +0000 @@ -23,10 +23,103 @@ 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; + } + + virtual 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; + } + + virtual 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; + } + + virtual 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-05 12:37:41 +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-05 12:37:41 +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-05 12:37:41 +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,50 @@ 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; + Lex->insert_list= new List_item; + if (! Lex->insert_list) MYSQL_YYABORT; } '(' values ')' - {} + { + $$= RKEY; + } ; handler_rkey_mode: --===============1065173437== 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: f8f05c20be7684012e5ba3946416184af68af343 # timestamp: 2011-04-05 16:37:49 +0400 # base_revision_id: dmitry.lenev@stripped\ # 6fju0ncpn4l71xl4 # # Begin bundle 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 --===============1065173437==--