diff options
Diffstat (limited to 'sql/sql_parse.cc')
-rw-r--r-- | sql/sql_parse.cc | 661 |
1 files changed, 350 insertions, 311 deletions
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index ac742d79681..f9be9019489 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -101,6 +101,7 @@ #include "set_var.h" #include "log_slow.h" #include "sql_bootstrap.h" +#include "sql_sequence.h" #include "my_json_writer.h" @@ -448,14 +449,17 @@ static bool stmt_causes_implicit_commit(THD *thd, uint mask) switch (lex->sql_command) { case SQLCOM_DROP_TABLE: + case SQLCOM_DROP_SEQUENCE: skip= (lex->tmp_table() || (thd->variables.option_bits & OPTION_GTID_BEGIN)); break; case SQLCOM_ALTER_TABLE: + case SQLCOM_ALTER_SEQUENCE: /* If ALTER TABLE of non-temporary table, do implicit commit */ skip= (lex->tmp_table()); break; case SQLCOM_CREATE_TABLE: + case SQLCOM_CREATE_SEQUENCE: /* If CREATE TABLE of non-temporary table and the table is not part if a BEGIN GTID ... COMMIT group, do a implicit commit. @@ -542,19 +546,27 @@ void init_update_queries(void) */ sql_command_flags[SQLCOM_CREATE_TABLE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | CF_AUTO_COMMIT_TRANS | CF_REPORT_PROGRESS | - CF_CAN_GENERATE_ROW_EVENTS; + CF_CAN_GENERATE_ROW_EVENTS | + CF_SCHEMA_CHANGE; + sql_command_flags[SQLCOM_CREATE_SEQUENCE]= (CF_CHANGES_DATA | + CF_REEXECUTION_FRAGILE | + CF_AUTO_COMMIT_TRANS | + CF_SCHEMA_CHANGE); sql_command_flags[SQLCOM_CREATE_INDEX]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_REPORT_PROGRESS; sql_command_flags[SQLCOM_ALTER_TABLE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS | CF_REPORT_PROGRESS | CF_INSERTS_DATA; + sql_command_flags[SQLCOM_ALTER_SEQUENCE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND | + CF_AUTO_COMMIT_TRANS | CF_SCHEMA_CHANGE; sql_command_flags[SQLCOM_TRUNCATE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS; - sql_command_flags[SQLCOM_DROP_TABLE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; + sql_command_flags[SQLCOM_DROP_TABLE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_SCHEMA_CHANGE; + sql_command_flags[SQLCOM_DROP_SEQUENCE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_SCHEMA_CHANGE; sql_command_flags[SQLCOM_LOAD]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | CF_CAN_GENERATE_ROW_EVENTS | CF_REPORT_PROGRESS | CF_INSERTS_DATA; - sql_command_flags[SQLCOM_CREATE_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; - sql_command_flags[SQLCOM_DROP_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; + sql_command_flags[SQLCOM_CREATE_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_DB_CHANGE; + sql_command_flags[SQLCOM_DROP_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_DB_CHANGE; sql_command_flags[SQLCOM_ALTER_DB_UPGRADE]= CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_ALTER_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_RENAME_TABLE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; @@ -721,6 +733,7 @@ void init_update_queries(void) sql_command_flags[SQLCOM_TRUNCATE]|= CF_FORCE_ORIGINAL_BINLOG_FORMAT; /* We don't want to replicate DROP for temp tables in row format */ sql_command_flags[SQLCOM_DROP_TABLE]|= CF_FORCE_ORIGINAL_BINLOG_FORMAT; + sql_command_flags[SQLCOM_DROP_SEQUENCE]|= CF_FORCE_ORIGINAL_BINLOG_FORMAT; /* One can change replication mode with SET */ sql_command_flags[SQLCOM_SET_OPTION]|= CF_FORCE_ORIGINAL_BINLOG_FORMAT; @@ -763,6 +776,7 @@ void init_update_queries(void) */ sql_command_flags[SQLCOM_CREATE_TABLE]|= CF_PREOPEN_TMP_TABLES; sql_command_flags[SQLCOM_DROP_TABLE]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_DROP_SEQUENCE]|= CF_PREOPEN_TMP_TABLES; sql_command_flags[SQLCOM_CREATE_INDEX]|= CF_PREOPEN_TMP_TABLES; sql_command_flags[SQLCOM_ALTER_TABLE]|= CF_PREOPEN_TMP_TABLES; sql_command_flags[SQLCOM_TRUNCATE]|= CF_PREOPEN_TMP_TABLES; @@ -795,7 +809,9 @@ void init_update_queries(void) have to be closed before temporary tables are pre-opened. */ sql_command_flags[SQLCOM_CREATE_TABLE]|= CF_HA_CLOSE; + sql_command_flags[SQLCOM_CREATE_SEQUENCE]|= CF_HA_CLOSE; sql_command_flags[SQLCOM_DROP_TABLE]|= CF_HA_CLOSE; + sql_command_flags[SQLCOM_DROP_SEQUENCE]|= CF_HA_CLOSE; sql_command_flags[SQLCOM_ALTER_TABLE]|= CF_HA_CLOSE; sql_command_flags[SQLCOM_TRUNCATE]|= CF_HA_CLOSE; sql_command_flags[SQLCOM_REPAIR]|= CF_HA_CLOSE; @@ -813,8 +829,10 @@ void init_update_queries(void) even temporary table DDL should be disallowed. */ sql_command_flags[SQLCOM_CREATE_TABLE]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_CREATE_SEQUENCE]|= CF_DISALLOW_IN_RO_TRANS; sql_command_flags[SQLCOM_ALTER_TABLE]|= CF_DISALLOW_IN_RO_TRANS; sql_command_flags[SQLCOM_DROP_TABLE]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_DROP_SEQUENCE]|= CF_DISALLOW_IN_RO_TRANS; sql_command_flags[SQLCOM_RENAME_TABLE]|= CF_DISALLOW_IN_RO_TRANS; sql_command_flags[SQLCOM_CREATE_INDEX]|= CF_DISALLOW_IN_RO_TRANS; sql_command_flags[SQLCOM_DROP_INDEX]|= CF_DISALLOW_IN_RO_TRANS; @@ -1407,7 +1425,7 @@ out: This is a helper function to mysql_execute_command. - @note SQLCOM_MULTI_UPDATE is an exception and delt with elsewhere. + @note SQLCOM_MULTI_UPDATE is an exception and dealt with elsewhere. @see mysql_execute_command @returns Status code @@ -1425,13 +1443,12 @@ static my_bool deny_updates_if_read_only_option(THD *thd, LEX *lex= thd->lex; - const my_bool user_is_super= - ((ulong)(thd->security_ctx->master_access & SUPER_ACL) == - (ulong)SUPER_ACL); - - if (user_is_super) + /* Super user is allowed to do changes */ + if (((ulong)(thd->security_ctx->master_access & SUPER_ACL) == + (ulong)SUPER_ACL)) DBUG_RETURN(FALSE); + /* Check if command doesn't update anything */ if (!(sql_command_flags[lex->sql_command] & CF_CHANGES_DATA)) DBUG_RETURN(FALSE); @@ -1439,29 +1456,17 @@ static my_bool deny_updates_if_read_only_option(THD *thd, if (lex->sql_command == SQLCOM_UPDATE_MULTI) DBUG_RETURN(FALSE); - const my_bool create_temp_tables= - (lex->sql_command == SQLCOM_CREATE_TABLE) && lex->tmp_table(); - - const my_bool drop_temp_tables= - (lex->sql_command == SQLCOM_DROP_TABLE) && lex->tmp_table(); - - const my_bool update_real_tables= - some_non_temp_table_to_be_updated(thd, all_tables) && - !(create_temp_tables || drop_temp_tables); - - - const my_bool create_or_drop_databases= - (lex->sql_command == SQLCOM_CREATE_DB) || - (lex->sql_command == SQLCOM_DROP_DB); + /* Check if we created or dropped temporary tables */ + if ((sql_command_flags[lex->sql_command] & CF_SCHEMA_CHANGE) && + lex->tmp_table()) + DBUG_RETURN(FALSE); - if (update_real_tables || create_or_drop_databases) - { - /* - An attempt was made to modify one or more non-temporary tables. - */ - DBUG_RETURN(TRUE); - } + /* Check if we created or dropped databases */ + if ((sql_command_flags[lex->sql_command] & CF_DB_CHANGE)) + DBUG_RETURN(TRUE); + if (some_non_temp_table_to_be_updated(thd, all_tables)) + DBUG_RETURN(TRUE); /* Assuming that only temporary tables are modified. */ DBUG_RETURN(FALSE); @@ -1574,7 +1579,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if (thd->wsrep_conflict_state == ABORTED && command != COM_STMT_CLOSE && command != COM_QUIT) { - my_error(ER_LOCK_DEADLOCK, MYF(0), "wsrep aborted transaction"); + my_message(ER_LOCK_DEADLOCK, "wsrep aborted transaction", MYF(0)); WSREP_DEBUG("Deadlock error for: %s", thd->query()); mysql_mutex_unlock(&thd->LOCK_wsrep_thd); thd->killed = NOT_KILLED; @@ -1654,9 +1659,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd, switch (command) { case COM_INIT_DB: { - LEX_STRING tmp; + LEX_CSTRING tmp; status_var_increment(thd->status_var.com_stat[SQLCOM_CHANGE_DB]); - if (thd->copy_with_error(system_charset_info, &tmp, + if (thd->copy_with_error(system_charset_info, (LEX_STRING*) &tmp, thd->charset(), packet, packet_length)) break; if (!mysql_change_db(thd, &tmp, FALSE)) @@ -1726,7 +1731,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if (auth_rc) { /* Free user if allocated by acl_authenticate */ - my_free(thd->security_ctx->user); + my_free(const_cast<char*>(thd->security_ctx->user)); *thd->security_ctx= save_security_ctx; if (thd->user_connect) decrease_user_connections(thd->user_connect); @@ -1745,7 +1750,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, decrease_user_connections(save_user_connect); #endif /* NO_EMBEDDED_ACCESS_CHECKS */ my_free(save_db); - my_free(save_security_ctx.user); + my_free(const_cast<char*>(save_security_ctx.user)); } break; } @@ -1922,7 +1927,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, /* Locked closure of all tables */ TABLE_LIST table_list; LEX_STRING table_name; - LEX_STRING db; + LEX_CSTRING db; /* SHOW statements should not add the used tables to the list of tables used in a transaction. @@ -1969,7 +1974,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if (lower_case_table_names) { table_name.length= my_casedn_str(files_charset_info, table_name.str); - db.length= my_casedn_str(files_charset_info, db.str); + db.length= my_casedn_str(files_charset_info, (char*) db.str); } table_list.init_one_table(db.str, db.length, table_name.str, table_name.length, table_name.str, TL_READ); @@ -2110,7 +2115,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, else #endif { - thd->lex->relay_log_connection_name= empty_lex_str; + thd->lex->relay_log_connection_name= empty_clex_str; if (reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, ¬_used)) break; } @@ -2291,7 +2296,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if (server_command_flags[subcommand] & CF_NO_COM_MULTI) { - my_error(ER_BAD_COMMAND_IN_MULTI, MYF(0), command_name[subcommand]); + my_error(ER_BAD_COMMAND_IN_MULTI, MYF(0), + command_name[subcommand].str); goto com_multi_end; } @@ -2533,10 +2539,16 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, DBUG_RETURN(1); } schema_select_lex= new (thd->mem_root) SELECT_LEX(); - db.str= schema_select_lex->db= lex->select_lex.db; schema_select_lex->table_list.first= NULL; + if (lower_case_table_names == 1) + lex->select_lex.db= thd->strdup(lex->select_lex.db); + schema_select_lex->db= lex->select_lex.db; + /* + check_db_name() may change db.str if lower_case_table_names == 1, + but that's ok as the db is allocted above in this case. + */ + db.str= (char*) lex->select_lex.db; db.length= strlen(db.str); - if (check_db_name(&db)) { my_error(ER_WRONG_DB_NAME, MYF(0), db.str); @@ -2698,7 +2710,7 @@ bool sp_process_definer(THD *thd) DBUG_RETURN(TRUE); if (thd->slave_thread && lex->sphead) - lex->sphead->m_chistics->suid= SP_IS_NOT_SUID; + lex->sphead->set_suid(SP_IS_NOT_SUID); } else { @@ -2863,7 +2875,7 @@ static bool do_execute_sp(THD *thd, sp_head *sp) if (!(thd->client_capabilities & CLIENT_MULTI_RESULTS)) { /* The client does not support multiple result sets being sent back */ - my_error(ER_SP_BADSELECT, MYF(0), sp->m_qname.str); + my_error(ER_SP_BADSELECT, MYF(0), ErrConvDQName(sp).ptr()); return 1; } /* @@ -2902,6 +2914,174 @@ static bool do_execute_sp(THD *thd, sp_head *sp) } +static int mysql_create_routine(THD *thd, LEX *lex) +{ + DBUG_ASSERT(lex->sphead != 0); + DBUG_ASSERT(lex->sphead->m_db.str); /* Must be initialized in the parser */ + /* + Verify that the database name is allowed, optionally + lowercase it. + */ + if (check_db_name((LEX_STRING*) &lex->sphead->m_db)) + { + my_error(ER_WRONG_DB_NAME, MYF(0), lex->sphead->m_db.str); + return true; + } + + if (check_access(thd, CREATE_PROC_ACL, lex->sphead->m_db.str, + NULL, NULL, 0, 0)) + return true; + + /* Checking the drop permissions if CREATE OR REPLACE is used */ + if (lex->create_info.or_replace()) + { + if (check_routine_access(thd, ALTER_PROC_ACL, lex->sphead->m_db.str, + lex->sphead->m_name.str, + lex->sql_command == SQLCOM_DROP_PROCEDURE, 0)) + return true; + } + + const LEX_CSTRING *name= lex->sphead->name(); +#ifdef HAVE_DLOPEN + if (lex->sphead->m_type == TYPE_ENUM_FUNCTION) + { + udf_func *udf = find_udf(name->str, name->length); + + if (udf) + { + my_error(ER_UDF_EXISTS, MYF(0), name->str); + return true; + } + } +#endif + + if (sp_process_definer(thd)) + return true; + + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + if (!sp_create_routine(thd, lex->sphead->m_type, lex->sphead)) + { +#ifndef NO_EMBEDDED_ACCESS_CHECKS + /* only add privileges if really neccessary */ + + Security_context security_context; + bool restore_backup_context= false; + Security_context *backup= NULL; + LEX_USER *definer= thd->lex->definer; + /* + We're going to issue an implicit GRANT statement so we close all + open tables. We have to keep metadata locks as this ensures that + this statement is atomic against concurent FLUSH TABLES WITH READ + LOCK. Deadlocks which can arise due to fact that this implicit + statement takes metadata locks should be detected by a deadlock + detector in MDL subsystem and reported as errors. + + No need to commit/rollback statement transaction, it's not started. + + TODO: Long-term we should either ensure that implicit GRANT statement + is written into binary log as a separate statement or make both + creation of routine and implicit GRANT parts of one fully atomic + statement. + */ + DBUG_ASSERT(thd->transaction.stmt.is_empty()); + close_thread_tables(thd); + /* + Check if the definer exists on slave, + then use definer privilege to insert routine privileges to mysql.procs_priv. + + For current user of SQL thread has GLOBAL_ACL privilege, + which doesn't any check routine privileges, + so no routine privilege record will insert into mysql.procs_priv. + */ + if (thd->slave_thread && is_acl_user(definer->host.str, definer->user.str)) + { + security_context.change_security_context(thd, + &thd->lex->definer->user, + &thd->lex->definer->host, + &thd->lex->sphead->m_db, + &backup); + restore_backup_context= true; + } + + if (sp_automatic_privileges && !opt_noacl && + check_routine_access(thd, DEFAULT_CREATE_PROC_ACLS, + lex->sphead->m_db.str, name->str, + lex->sql_command == SQLCOM_CREATE_PROCEDURE, 1)) + { + if (sp_grant_privileges(thd, lex->sphead->m_db.str, name->str, + lex->sql_command == SQLCOM_CREATE_PROCEDURE)) + push_warning(thd, Sql_condition::WARN_LEVEL_WARN, + ER_PROC_AUTO_GRANT_FAIL, ER_THD(thd, ER_PROC_AUTO_GRANT_FAIL)); + thd->clear_error(); + } + + /* + Restore current user with GLOBAL_ACL privilege of SQL thread + */ + if (restore_backup_context) + { + DBUG_ASSERT(thd->slave_thread == 1); + thd->security_ctx->restore_security_context(thd, backup); + } + +#endif + return false; + } +#ifdef WITH_WSREP +error: /* Used by WSREP_TO_ISOLATION_BEGIN */ +#endif + return true; +} + + +/** + Prepare for CREATE DATABASE, ALTER DATABASE, DROP DATABASE. + + @param thd - current THD + @param want_access - access needed + @param dbname - the database name + + @retval false - Ok to proceed with CREATE/ALTER/DROP + @retval true - not OK to proceed (error, or filtered) + + Note, on slave this function returns true if the database + is in the ignore filter. The caller must distinguish this case + from other cases: bad database error, no access error. + This can be done by testing thd->is_error(). +*/ +static bool prepare_db_action(THD *thd, ulong want_access, LEX_CSTRING *dbname) +{ + if (check_db_name((LEX_STRING*)dbname)) + { + my_error(ER_WRONG_DB_NAME, MYF(0), dbname->str); + return true; + } + /* + If in a slave thread : + - CREATE DATABASE DB was certainly not preceded by USE DB. + - ALTER DATABASE DB may not be preceded by USE DB. + - DROP DATABASE DB may not be preceded by USE DB. + For that reason, db_ok() in sql/slave.cc did not check the + do_db/ignore_db. And as this query involves no tables, tables_ok() + was not called. So we have to check rules again here. + */ +#ifdef HAVE_REPLICATION + if (thd->slave_thread) + { + Rpl_filter *rpl_filter; + rpl_filter= thd->system_thread_info.rpl_sql_info->rpl_filter; + if (!rpl_filter->db_ok(dbname->str) || + !rpl_filter->db_ok_with_wild_table(dbname->str)) + { + my_message(ER_SLAVE_IGNORED_TABLE, + ER_THD(thd, ER_SLAVE_IGNORED_TABLE), MYF(0)); + return true; + } + } +#endif + return check_access(thd, want_access, dbname->str, NULL, NULL, 1, 0); +} + /** Execute command saved in thd and lex->sql_command. @@ -3078,7 +3258,8 @@ mysql_execute_command(THD *thd) */ if (!(lex->sql_command == SQLCOM_UPDATE_MULTI) && !(lex->sql_command == SQLCOM_SET_OPTION) && - !(lex->sql_command == SQLCOM_DROP_TABLE && + !((lex->sql_command == SQLCOM_DROP_TABLE || + lex->sql_command == SQLCOM_DROP_SEQUENCE) && lex->tmp_table() && lex->if_exists()) && all_tables_not_ok(thd, all_tables)) { @@ -3704,6 +3885,7 @@ mysql_execute_command(THD *thd) res = ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_MUTEX); break; } + case SQLCOM_CREATE_SEQUENCE: case SQLCOM_CREATE_TABLE: { DBUG_ASSERT(first_table == all_tables && first_table != 0); @@ -3961,6 +4143,7 @@ mysql_execute_command(THD *thd) /* Regular CREATE TABLE */ res= mysql_create_table(thd, create_table, &create_info, &alter_info); } + if (!res) { /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */ @@ -4169,9 +4352,9 @@ end_with_restore_list: */ DBUG_PRINT("debug", ("lex->only_view: %d, table: %s.%s", - lex->only_view, + lex->table_type == TABLE_TYPE_VIEW, first_table->db, first_table->table_name)); - if (lex->only_view) + if (lex->table_type == TABLE_TYPE_VIEW) { if (check_table_access(thd, SELECT_ACL, first_table, FALSE, 1, FALSE)) { @@ -4185,7 +4368,6 @@ end_with_restore_list: /* Ignore temporary tables if this is "SHOW CREATE VIEW" */ first_table->open_type= OT_BASE_ONLY; - } else { @@ -4694,6 +4876,7 @@ end_with_restore_list: } break; } + case SQLCOM_DROP_SEQUENCE: case SQLCOM_DROP_TABLE: { DBUG_ASSERT(first_table == all_tables && first_table != 0); @@ -4704,7 +4887,7 @@ end_with_restore_list: } else { - status_var_decrement(thd->status_var.com_stat[SQLCOM_DROP_TABLE]); + status_var_decrement(thd->status_var.com_stat[lex->sql_command]); status_var_increment(thd->status_var.com_drop_tmp_table); /* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */ @@ -4734,10 +4917,13 @@ end_with_restore_list: lex->create_info.set(DDL_options_st::OPT_IF_EXISTS); /* DDL and binlog write order are protected by metadata locks. */ - res= mysql_rm_table(thd, first_table, lex->if_exists(), lex->tmp_table()); + res= mysql_rm_table(thd, first_table, lex->if_exists(), lex->tmp_table(), + lex->table_type == TABLE_TYPE_SEQUENCE); - /* when dropping temporary tables if @@session_track_state_change is ON then - send the boolean tracker in the OK packet */ + /* + When dropping temporary tables if @@session_track_state_change is ON + then send the boolean tracker in the OK packet + */ if(!res && (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)) { SESSION_TRACKER_CHANGED(thd, SESSION_STATE_CHANGE_TRACKER, NULL); @@ -4778,7 +4964,7 @@ end_with_restore_list: #endif case SQLCOM_CHANGE_DB: { - LEX_STRING db_str= { (char *) select_lex->db, strlen(select_lex->db) }; + LEX_CSTRING db_str= { (char *) select_lex->db, strlen(select_lex->db) }; if (!mysql_change_db(thd, &db_str, FALSE)) my_ok(thd); @@ -4901,33 +5087,9 @@ end_with_restore_list: break; case SQLCOM_CREATE_DB: { - if (check_db_name(&lex->name)) - { - my_error(ER_WRONG_DB_NAME, MYF(0), lex->name.str); - break; - } - /* - If in a slave thread : - CREATE DATABASE DB was certainly not preceded by USE DB. - For that reason, db_ok() in sql/slave.cc did not check the - do_db/ignore_db. And as this query involves no tables, tables_ok() - above was not called. So we have to check rules again here. - */ -#ifdef HAVE_REPLICATION - if (thd->slave_thread) - { - rpl_filter= thd->system_thread_info.rpl_sql_info->rpl_filter; - if (!rpl_filter->db_ok(lex->name.str) || - !rpl_filter->db_ok_with_wild_table(lex->name.str)) - { - my_message(ER_SLAVE_IGNORED_TABLE, ER_THD(thd, ER_SLAVE_IGNORED_TABLE), MYF(0)); - break; - } - } -#endif - if (check_access(thd, lex->create_info.or_replace() ? + if (prepare_db_action(thd, lex->create_info.or_replace() ? (CREATE_ACL | DROP_ACL) : CREATE_ACL, - lex->name.str, NULL, NULL, 1, 0)) + &lex->name)) break; WSREP_TO_ISOLATION_BEGIN(lex->name.str, NULL, NULL) res= mysql_create_db(thd, lex->name.str, @@ -4936,31 +5098,7 @@ end_with_restore_list: } case SQLCOM_DROP_DB: { - if (check_db_name(&lex->name)) - { - my_error(ER_WRONG_DB_NAME, MYF(0), lex->name.str); - break; - } - /* - If in a slave thread : - DROP DATABASE DB may not be preceded by USE DB. - For that reason, maybe db_ok() in sql/slave.cc did not check the - do_db/ignore_db. And as this query involves no tables, tables_ok() - above was not called. So we have to check rules again here. - */ -#ifdef HAVE_REPLICATION - if (thd->slave_thread) - { - rpl_filter= thd->system_thread_info.rpl_sql_info->rpl_filter; - if (!rpl_filter->db_ok(lex->name.str) || - !rpl_filter->db_ok_with_wild_table(lex->name.str)) - { - my_message(ER_SLAVE_IGNORED_TABLE, ER_THD(thd, ER_SLAVE_IGNORED_TABLE), MYF(0)); - break; - } - } -#endif - if (check_access(thd, DROP_ACL, lex->name.str, NULL, NULL, 1, 0)) + if (prepare_db_action(thd, DROP_ACL, &lex->name)) break; WSREP_TO_ISOLATION_BEGIN(lex->name.str, NULL, NULL) res= mysql_rm_db(thd, lex->name.str, lex->if_exists()); @@ -4968,7 +5106,7 @@ end_with_restore_list: } case SQLCOM_ALTER_DB_UPGRADE: { - LEX_STRING *db= & lex->name; + LEX_CSTRING *db= &lex->name; #ifdef HAVE_REPLICATION if (thd->slave_thread) { @@ -4982,7 +5120,7 @@ end_with_restore_list: } } #endif - if (check_db_name(db)) + if (check_db_name((LEX_STRING*) db)) { my_error(ER_WRONG_DB_NAME, MYF(0), db->str); break; @@ -5002,32 +5140,8 @@ end_with_restore_list: } case SQLCOM_ALTER_DB: { - LEX_STRING *db= &lex->name; - if (check_db_name(db)) - { - my_error(ER_WRONG_DB_NAME, MYF(0), db->str); - break; - } - /* - If in a slave thread : - ALTER DATABASE DB may not be preceded by USE DB. - For that reason, maybe db_ok() in sql/slave.cc did not check the - do_db/ignore_db. And as this query involves no tables, tables_ok() - above was not called. So we have to check rules again here. - */ -#ifdef HAVE_REPLICATION - if (thd->slave_thread) - { - rpl_filter= thd->system_thread_info.rpl_sql_info->rpl_filter; - if (!rpl_filter->db_ok(db->str) || - !rpl_filter->db_ok_with_wild_table(db->str)) - { - my_message(ER_SLAVE_IGNORED_TABLE, ER_THD(thd, ER_SLAVE_IGNORED_TABLE), MYF(0)); - break; - } - } -#endif - if (check_access(thd, ALTER_ACL, db->str, NULL, NULL, 1, 0)) + LEX_CSTRING *db= &lex->name; + if (prepare_db_action(thd, ALTER_ACL, db)) break; WSREP_TO_ISOLATION_BEGIN(db->str, NULL, NULL) res= mysql_alter_db(thd, db->str, &lex->create_info); @@ -5036,19 +5150,19 @@ end_with_restore_list: case SQLCOM_SHOW_CREATE_DB: { char db_name_buff[NAME_LEN+1]; - LEX_STRING db_name; + LEX_CSTRING db_name; DBUG_EXECUTE_IF("4x_server_emul", my_error(ER_UNKNOWN_ERROR, MYF(0)); goto error;); db_name.str= db_name_buff; db_name.length= lex->name.length; - strmov(db_name.str, lex->name.str); + strmov(db_name_buff, lex->name.str); #ifdef WITH_WSREP if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error; #endif /* WITH_WSREP */ - if (check_db_name(&db_name)) + if (check_db_name((LEX_STRING*) &db_name)) { my_error(ER_WRONG_DB_NAME, MYF(0), db_name.str); break; @@ -5104,13 +5218,13 @@ end_with_restore_list: #ifdef WITH_WSREP if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error; #endif /* WITH_WSREP */ - res= Events::show_create_event(thd, lex->spname->m_db, - lex->spname->m_name); + res= Events::show_create_event(thd, &lex->spname->m_db, + &lex->spname->m_name); break; case SQLCOM_DROP_EVENT: WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) if (!(res= Events::drop_event(thd, - lex->spname->m_db, lex->spname->m_name, + &lex->spname->m_db, &lex->spname->m_name, lex->if_exists()))) my_ok(thd); break; @@ -5636,120 +5750,7 @@ end_with_restore_list: case SQLCOM_CREATE_PROCEDURE: case SQLCOM_CREATE_SPFUNCTION: { - uint namelen; - char *name; - - DBUG_ASSERT(lex->sphead != 0); - DBUG_ASSERT(lex->sphead->m_db.str); /* Must be initialized in the parser */ - /* - Verify that the database name is allowed, optionally - lowercase it. - */ - if (check_db_name(&lex->sphead->m_db)) - { - my_error(ER_WRONG_DB_NAME, MYF(0), lex->sphead->m_db.str); - goto error; - } - - if (check_access(thd, CREATE_PROC_ACL, lex->sphead->m_db.str, - NULL, NULL, 0, 0)) - goto error; - - /* Checking the drop permissions if CREATE OR REPLACE is used */ - if (lex->create_info.or_replace()) - { - if (check_routine_access(thd, ALTER_PROC_ACL, lex->spname->m_db.str, - lex->spname->m_name.str, - lex->sql_command == SQLCOM_DROP_PROCEDURE, 0)) - goto error; - } - - name= lex->sphead->name(&namelen); -#ifdef HAVE_DLOPEN - if (lex->sphead->m_type == TYPE_ENUM_FUNCTION) - { - udf_func *udf = find_udf(name, namelen); - - if (udf) - { - my_error(ER_UDF_EXISTS, MYF(0), name); - goto error; - } - } -#endif - - if (sp_process_definer(thd)) - goto error; - - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) - if (!sp_create_routine(thd, lex->sphead->m_type, lex->sphead)) - { -#ifndef NO_EMBEDDED_ACCESS_CHECKS - /* only add privileges if really neccessary */ - - Security_context security_context; - bool restore_backup_context= false; - Security_context *backup= NULL; - LEX_USER *definer= thd->lex->definer; - /* - We're going to issue an implicit GRANT statement so we close all - open tables. We have to keep metadata locks as this ensures that - this statement is atomic against concurent FLUSH TABLES WITH READ - LOCK. Deadlocks which can arise due to fact that this implicit - statement takes metadata locks should be detected by a deadlock - detector in MDL subsystem and reported as errors. - - No need to commit/rollback statement transaction, it's not started. - - TODO: Long-term we should either ensure that implicit GRANT statement - is written into binary log as a separate statement or make both - creation of routine and implicit GRANT parts of one fully atomic - statement. - */ - DBUG_ASSERT(thd->transaction.stmt.is_empty()); - close_thread_tables(thd); - /* - Check if the definer exists on slave, - then use definer privilege to insert routine privileges to mysql.procs_priv. - - For current user of SQL thread has GLOBAL_ACL privilege, - which doesn't any check routine privileges, - so no routine privilege record will insert into mysql.procs_priv. - */ - if (thd->slave_thread && is_acl_user(definer->host.str, definer->user.str)) - { - security_context.change_security_context(thd, - &thd->lex->definer->user, - &thd->lex->definer->host, - &thd->lex->sphead->m_db, - &backup); - restore_backup_context= true; - } - - if (sp_automatic_privileges && !opt_noacl && - check_routine_access(thd, DEFAULT_CREATE_PROC_ACLS, - lex->sphead->m_db.str, name, - lex->sql_command == SQLCOM_CREATE_PROCEDURE, 1)) - { - if (sp_grant_privileges(thd, lex->sphead->m_db.str, name, - lex->sql_command == SQLCOM_CREATE_PROCEDURE)) - push_warning(thd, Sql_condition::WARN_LEVEL_WARN, - ER_PROC_AUTO_GRANT_FAIL, ER_THD(thd, ER_PROC_AUTO_GRANT_FAIL)); - thd->clear_error(); - } - - /* - Restore current user with GLOBAL_ACL privilege of SQL thread - */ - if (restore_backup_context) - { - DBUG_ASSERT(thd->slave_thread == 1); - thd->security_ctx->restore_security_context(thd, backup); - } - -#endif - } - else + if (mysql_create_routine(thd, lex)) goto error; my_ok(thd); break; /* break super switch */ @@ -5777,9 +5778,15 @@ end_with_restore_list: if (!(sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname, &thd->sp_proc_cache, TRUE))) { - my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PROCEDURE", - lex->spname->m_qname.str); - goto error; + /* + sp_find_routine can have issued an ER_SP_RECURSION_LIMIT error. + Send message ER_SP_DOES_NOT_EXIST only if procedure is not found in + cache. + */ + if (!sp_cache_lookup(&thd->sp_proc_cache, lex->spname)) + my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PROCEDURE", + ErrConvDQName(lex->spname).ptr()); + goto error; } else { @@ -5838,11 +5845,11 @@ end_with_restore_list: break; case SP_KEY_NOT_FOUND: my_error(ER_SP_DOES_NOT_EXIST, MYF(0), - SP_COM_STRING(lex), lex->spname->m_qname.str); + SP_COM_STRING(lex), ErrConvDQName(lex->spname).ptr()); goto error; default: my_error(ER_SP_CANT_ALTER, MYF(0), - SP_COM_STRING(lex), lex->spname->m_qname.str); + SP_COM_STRING(lex), ErrConvDQName(lex->spname).ptr()); goto error; } break; @@ -5895,8 +5902,8 @@ end_with_restore_list: enum stored_procedure_type type; type= (lex->sql_command == SQLCOM_DROP_PROCEDURE ? TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION); - char *db= lex->spname->m_db.str; - char *name= lex->spname->m_name.str; + const char *db= lex->spname->m_db.str; + const char *name= lex->spname->m_name.str; if (check_routine_access(thd, ALTER_PROC_ACL, db, name, lex->sql_command == SQLCOM_DROP_PROCEDURE, 0)) @@ -5949,17 +5956,18 @@ end_with_restore_list: res= write_bin_log(thd, TRUE, thd->query(), thd->query_length()); push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, ER_SP_DOES_NOT_EXIST, ER_THD(thd, ER_SP_DOES_NOT_EXIST), - SP_COM_STRING(lex), lex->spname->m_qname.str); + SP_COM_STRING(lex), + ErrConvDQName(lex->spname).ptr()); if (!res) my_ok(thd); break; } my_error(ER_SP_DOES_NOT_EXIST, MYF(0), - SP_COM_STRING(lex), lex->spname->m_qname.str); + SP_COM_STRING(lex), ErrConvDQName(lex->spname).ptr()); goto error; default: my_error(ER_SP_DROP_FAILED, MYF(0), - SP_COM_STRING(lex), lex->spname->m_qname.str); + SP_COM_STRING(lex), ErrConvDQName(lex->spname).ptr()); goto error; } break; @@ -6026,10 +6034,10 @@ end_with_restore_list: { /* Note: SQLCOM_CREATE_VIEW also handles 'ALTER VIEW' commands - as specified through the thd->lex->create_view_mode flag. + as specified through the thd->lex->create_view->mode flag. */ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) - res= mysql_create_view(thd, first_table, thd->lex->create_view_mode); + res= mysql_create_view(thd, first_table, thd->lex->create_view->mode); break; } case SQLCOM_DROP_VIEW: @@ -6202,9 +6210,11 @@ end_with_restore_list: case SQLCOM_REPAIR: case SQLCOM_TRUNCATE: case SQLCOM_ALTER_TABLE: - thd->query_plan_flags|= QPLAN_ADMIN; DBUG_ASSERT(first_table == all_tables && first_table != 0); /* fall through */ + case SQLCOM_ALTER_SEQUENCE: + thd->query_plan_flags|= QPLAN_ADMIN; + /* fall through */ case SQLCOM_SIGNAL: case SQLCOM_RESIGNAL: case SQLCOM_GET_DIAGNOSTICS: @@ -7023,6 +7033,15 @@ check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables, thd->security_ctx= sctx; + if (table_ref->sequence) + { + /* We want to have either SELECT or INSERT rights to sequences depending + on how they are accessed + */ + want_access= ((table_ref->lock_type == TL_WRITE_ALLOW_WRITE) ? + INSERT_ACL : SELECT_ACL); + } + if (check_access(thd, want_access, table_ref->get_db_name(), &table_ref->grant.privilege, &table_ref->grant.m_internal, @@ -7040,7 +7059,8 @@ deny: bool -check_routine_access(THD *thd, ulong want_access,char *db, char *name, +check_routine_access(THD *thd, ulong want_access, const char *db, + const char *name, bool is_proc, bool no_errors) { TABLE_LIST tables[1]; @@ -7213,8 +7233,8 @@ bool check_fk_parent_table_access(THD *thd, TABLE_LIST parent_table; bool is_qualified_table_name; Foreign_key *fk_key= (Foreign_key *)key; - LEX_STRING db_name; - LEX_STRING table_name= { fk_key->ref_table.str, + LEX_CSTRING db_name; + LEX_CSTRING table_name= { fk_key->ref_table.str, fk_key->ref_table.length }; const ulong privileges= (SELECT_ACL | INSERT_ACL | UPDATE_ACL | DELETE_ACL | REFERENCES_ACL); @@ -7230,12 +7250,13 @@ bool check_fk_parent_table_access(THD *thd, if (fk_key->ref_db.str) { is_qualified_table_name= true; - db_name.str= (char *) thd->memdup(fk_key->ref_db.str, - fk_key->ref_db.length+1); + if (!(db_name.str= (char *) thd->memdup(fk_key->ref_db.str, + fk_key->ref_db.length+1))) + return true; db_name.length= fk_key->ref_db.length; // Check if database name is valid or not. - if (fk_key->ref_db.str && check_db_name(&db_name)) + if (check_db_name((LEX_STRING*) &db_name)) { my_error(ER_WRONG_DB_NAME, MYF(0), db_name.str); return true; @@ -7245,11 +7266,14 @@ bool check_fk_parent_table_access(THD *thd, { if (!thd->db) { - db_name.str= (char *) thd->memdup(create_db, strlen(create_db)+1); + DBUG_ASSERT(create_db); db_name.length= strlen(create_db); + if (!(db_name.str= (char *) thd->memdup(create_db, + db_name.length+1))) + return true; is_qualified_table_name= true; - if(create_db && check_db_name(&db_name)) + if (check_db_name((LEX_STRING*) &db_name)) { my_error(ER_WRONG_DB_NAME, MYF(0), db_name.str); return true; @@ -7267,10 +7291,11 @@ bool check_fk_parent_table_access(THD *thd, // if lower_case_table_names is set then convert tablename to lower case. if (lower_case_table_names) { - table_name.str= (char *) thd->memdup(fk_key->ref_table.str, - fk_key->ref_table.length+1); - table_name.length= my_casedn_str(files_charset_info, table_name.str); - db_name.length = my_casedn_str(files_charset_info, db_name.str); + char *name; + table_name.str= name= (char *) thd->memdup(fk_key->ref_table.str, + fk_key->ref_table.length+1); + table_name.length= my_casedn_str(files_charset_info, name); + db_name.length= my_casedn_str(files_charset_info, (char*) db_name.str); } parent_table.init_one_table(db_name.str, db_name.length, @@ -7525,18 +7550,21 @@ mysql_init_select(LEX *lex) */ bool -mysql_new_select(LEX *lex, bool move_down) +mysql_new_select(LEX *lex, bool move_down, SELECT_LEX *select_lex) { - SELECT_LEX *select_lex; THD *thd= lex->thd; + bool new_select= select_lex == NULL; DBUG_ENTER("mysql_new_select"); - if (!(select_lex= new (thd->mem_root) SELECT_LEX())) - DBUG_RETURN(1); - select_lex->select_number= ++thd->select_number; - select_lex->parent_lex= lex; /* Used in init_query. */ - select_lex->init_query(); - select_lex->init_select(); + if (new_select) + { + if (!(select_lex= new (thd->mem_root) SELECT_LEX())) + DBUG_RETURN(1); + select_lex->select_number= ++thd->select_number; + select_lex->parent_lex= lex; /* Used in init_query. */ + select_lex->init_query(); + select_lex->init_select(); + } lex->nest_level++; if (lex->nest_level > (int) MAX_SELECT_NESTING) { @@ -7607,7 +7635,8 @@ mysql_new_select(LEX *lex, bool move_down) unit->first_select()->context.outer_context; } - select_lex->include_global((st_select_lex_node**)&lex->all_selects_list); + if (new_select) + select_lex->include_global((st_select_lex_node**)&lex->all_selects_list); lex->current_select= select_lex; /* in subquery is SELECT query and we allow resolution of names in SELECT @@ -7631,7 +7660,7 @@ void create_select_for_variable(const char *var_name) { THD *thd; LEX *lex; - LEX_STRING tmp; + LEX_CSTRING tmp; Item *var; char buff[MAX_SYS_VAR_LENGTH*2+4+8], *end; DBUG_ENTER("create_select_for_variable"); @@ -7640,13 +7669,13 @@ void create_select_for_variable(const char *var_name) lex= thd->lex; mysql_init_select(lex); lex->sql_command= SQLCOM_SELECT; - tmp.str= (char*) var_name; + tmp.str= var_name; tmp.length=strlen(var_name); /* We set the name of Item to @@session.var_name because that then is used as the column name in the output. */ - if ((var= get_system_var(thd, OPT_SESSION, tmp, null_lex_str))) + if ((var= get_system_var(thd, OPT_SESSION, tmp, null_clex_str))) { end= strxmov(buff, "@@session.", var_name, NullS); var->set_name(thd, buff, end-buff, system_charset_info); @@ -7739,7 +7768,7 @@ static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length, (longlong) thd->thread_id, is_autocommit, thd->wsrep_retry_counter, thd->variables.wsrep_retry_autocommit, thd->query()); - my_error(ER_LOCK_DEADLOCK, MYF(0), "wsrep aborted transaction"); + my_message(ER_LOCK_DEADLOCK, "wsrep aborted transaction", MYF(0)); thd->killed= NOT_KILLED; thd->wsrep_conflict_state= NO_CONFLICT; if (thd->wsrep_conflict_state != REPLAYING) @@ -8013,7 +8042,7 @@ bool add_to_list(THD *thd, SQL_I_List<ORDER> &list, Item *item,bool asc) TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, Table_ident *table, - LEX_STRING *alias, + LEX_CSTRING *alias, ulong table_options, thr_lock_type lock_type, enum_mdl_type mdl_type, @@ -8023,7 +8052,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, { register TABLE_LIST *ptr; TABLE_LIST *UNINIT_VAR(previous_table_ref); /* The table preceding the current one. */ - char *alias_str; + const char *alias_str; LEX *lex= thd->lex; DBUG_ENTER("add_table_to_list"); @@ -8038,7 +8067,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, } if (table->is_derived_table() == FALSE && table->db.str && - check_db_name(&table->db)) + check_db_name((LEX_STRING*) &table->db)) { my_error(ER_WRONG_DB_NAME, MYF(0), table->db.str); DBUG_RETURN(0); @@ -8073,9 +8102,10 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, if (lower_case_table_names) { if (table->table.length) - table->table.length= my_casedn_str(files_charset_info, table->table.str); + table->table.length= my_casedn_str(files_charset_info, + (char*) table->table.str); if (ptr->db_length && ptr->db != any_db) - ptr->db_length= my_casedn_str(files_charset_info, ptr->db); + ptr->db_length= my_casedn_str(files_charset_info, (char*) ptr->db); } ptr->table_name=table->table.str; @@ -8085,6 +8115,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, /* TODO: remove TL_OPTION_FORCE_INDEX as it looks like it's not used */ ptr->force_index= MY_TEST(table_options & TL_OPTION_FORCE_INDEX); ptr->ignore_leaves= MY_TEST(table_options & TL_OPTION_IGNORE_LEAVES); + ptr->sequence= MY_TEST(table_options & TL_OPTION_SEQUENCE); ptr->derived= table->sel; if (!ptr->derived && is_infoschema_db(ptr->db, ptr->db_length)) { @@ -8125,8 +8156,8 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, ptr->cacheable_table= !table->is_derived_table(); ptr->index_hints= index_hints_arg; ptr->option= option ? option->str : 0; - /* check that used name is unique */ - if (lock_type != TL_IGNORE) + /* check that used name is unique. Sequences are ignored */ + if (lock_type != TL_IGNORE && !ptr->sequence) { TABLE_LIST *first_table= table_list.first; if (lex->sql_command == SQLCOM_CREATE_VIEW) @@ -8136,7 +8167,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, tables=tables->next_local) { if (!my_strcasecmp(table_alias_charset, alias_str, tables->alias) && - !strcmp(ptr->db, tables->db)) + !strcmp(ptr->db, tables->db) && ! tables->sequence) { my_error(ER_NONUNIQ_TABLE, MYF(0), alias_str); /* purecov: tested */ DBUG_RETURN(0); /* purecov: tested */ @@ -8144,7 +8175,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, } } /* Store the table reference preceding the current one. */ - if (table_list.elements > 0) + if (table_list.elements > 0 && !ptr->sequence) { /* table_list.next points to the last inserted TABLE_LIST->next_local' @@ -8169,8 +8200,11 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, Notice that as a side effect here we set the next_local field of the previous table reference to 'ptr'. Here we also add one element to the list 'table_list'. + We don't store sequences into the local list to hide them from INSERT + and SELECT. */ - table_list.link_in_list(ptr, &ptr->next_local); + if (!ptr->sequence) + table_list.link_in_list(ptr, &ptr->next_local); ptr->next_name_resolution_table= NULL; #ifdef WITH_PARTITION_STORAGE_ENGINE ptr->partition_names= partition_names; @@ -8414,8 +8448,8 @@ void st_select_lex::prepare_add_window_spec(THD *thd) } bool st_select_lex::add_window_def(THD *thd, - LEX_STRING *win_name, - LEX_STRING *win_ref, + LEX_CSTRING *win_name, + LEX_CSTRING *win_ref, SQL_I_List<ORDER> win_partition_list, SQL_I_List<ORDER> win_order_list, Window_frame *win_frame) @@ -8437,7 +8471,7 @@ bool st_select_lex::add_window_def(THD *thd, } bool st_select_lex::add_window_spec(THD *thd, - LEX_STRING *win_ref, + LEX_CSTRING *win_ref, SQL_I_List<ORDER> win_partition_list, SQL_I_List<ORDER> win_order_list, Window_frame *win_frame) @@ -8538,7 +8572,7 @@ bool st_select_lex_unit::add_fake_select_lex(THD *thd_arg) fake_select_lex->nest_level_base= first_select()->nest_level_base; fake_select_lex->nest_level=first_select()->nest_level; - if (!is_union()) + if (!is_unit_op()) { /* This works only for @@ -9566,7 +9600,7 @@ void get_default_definer(THD *thd, LEX_USER *definer, bool role) if (role) { definer->user.str= const_cast<char*>(sctx->priv_role); - definer->host= empty_lex_str; + definer->host= empty_clex_str; } else { @@ -9623,7 +9657,8 @@ LEX_USER *create_default_definer(THD *thd, bool role) - On error, return 0. */ -LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name) +LEX_USER *create_definer(THD *thd, LEX_CSTRING *user_name, + LEX_CSTRING *host_name) { LEX_USER *definer; @@ -9657,7 +9692,7 @@ LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name) The function is not used in existing code but can be useful later? */ -bool check_string_byte_length(LEX_STRING *str, uint err_msg, +bool check_string_byte_length(LEX_CSTRING *str, uint err_msg, uint max_byte_length) { if (str->length <= max_byte_length) @@ -9687,7 +9722,7 @@ bool check_string_byte_length(LEX_STRING *str, uint err_msg, */ -bool check_string_char_length(LEX_STRING *str, uint err_msg, +bool check_string_char_length(LEX_CSTRING *str, uint err_msg, uint max_char_length, CHARSET_INFO *cs, bool no_error) { @@ -9706,7 +9741,7 @@ bool check_string_char_length(LEX_STRING *str, uint err_msg, } -bool check_ident_length(LEX_STRING *ident) +bool check_ident_length(LEX_CSTRING *ident) { if (check_string_char_length(ident, 0, NAME_CHAR_LEN, system_charset_info, 1)) { @@ -9816,7 +9851,7 @@ int error_if_data_home_dir(const char *path, const char *what) has invalid symbols */ -bool check_host_name(LEX_STRING *str) +bool check_host_name(LEX_CSTRING *str) { const char *name= str->str; const char *end= str->str + str->length; @@ -9839,6 +9874,7 @@ bool check_host_name(LEX_STRING *str) extern int MYSQLparse(THD *thd); // from sql_yacc.cc +extern int ORAparse(THD *thd); // from sql_yacc_ora.cc /** @@ -9898,7 +9934,10 @@ bool parse_sql(THD *thd, Parser_state *parser_state, /* Parse the query. */ - bool mysql_parse_status= MYSQLparse(thd) != 0; + bool mysql_parse_status= + ((thd->variables.sql_mode & MODE_ORACLE) ? + ORAparse(thd) : + MYSQLparse(thd)) != 0; /* Check that if MYSQLparse() failed either thd->is_error() is set, or an |