diff options
author | unknown <pem@mysql.com> | 2004-04-07 19:07:44 +0200 |
---|---|---|
committer | unknown <pem@mysql.com> | 2004-04-07 19:07:44 +0200 |
commit | c635d37479fbf8aa0da03d47f264ab9907cfe72b (patch) | |
tree | e5ac1517ff3dccc42352b7bac39ecd1c093d0ae6 /sql/sql_parse.cc | |
parent | 8468cde4f1e028b380c24d0bac28402678568d81 (diff) | |
parent | 0948f9769b3e3da2e064e65015b86644af4acd78 (diff) | |
download | mariadb-git-c635d37479fbf8aa0da03d47f264ab9907cfe72b.tar.gz |
Merge 4.1 -> 5.0.
BitKeeper/etc/ignore:
auto-union
BitKeeper/etc/logging_ok:
auto-union
VC++Files/sql/mysqld.dsp:
Auto merged
client/Makefile.am:
Auto merged
client/mysql.cc:
Auto merged
client/mysqltest.c:
Auto merged
configure.in:
Auto merged
include/my_global.h:
Auto merged
include/my_pthread.h:
Auto merged
include/my_sys.h:
Auto merged
include/mysql_com.h:
Auto merged
libmysqld/Makefile.am:
Auto merged
libmysqld/lib_sql.cc:
Auto merged
myisam/mi_check.c:
Auto merged
myisam/myisamchk.c:
Auto merged
myisam/myisamdef.h:
Auto merged
mysql-test/install_test_db.sh:
Auto merged
mysql-test/r/insert_select.result:
Auto merged
mysql-test/r/join_outer.result:
Auto merged
mysql-test/r/null.result:
Auto merged
mysql-test/r/connect.result:
Auto merged
mysql-test/r/func_sapdb.result:
Auto merged
mysql-test/r/mix_innodb_myisam_binlog.result:
Auto merged
mysql-test/r/mysqldump.result:
Auto merged
mysql-test/r/rpl_change_master.result:
Auto merged
mysql-test/r/rpl_log.result:
Auto merged
mysql-test/r/show_check.result:
Auto merged
mysql-test/r/symlink.result:
Auto merged
mysql-test/r/rpl_flush_log_loop.result:
Auto merged
mysql-test/r/rpl_flush_tables.result:
Auto merged
mysql-test/r/rpl_loaddata.result:
Auto merged
mysql-test/r/rpl_loaddata_rule_m.result:
Auto merged
mysql-test/r/rpl_loaddata_rule_s.result:
Auto merged
mysql-test/r/rpl_max_relay_size.result:
Auto merged
mysql-test/r/rpl_reset_slave.result:
Auto merged
mysql-test/r/rpl_temporary.result:
Auto merged
mysql-test/r/rpl_until.result:
Auto merged
mysql-test/r/rpl_user_variables.result:
Auto merged
mysql-test/r/subselect.result:
Auto merged
mysql-test/r/union.result:
Auto merged
mysql-test/r/variables.result:
Auto merged
mysql-test/t/func_sapdb.test:
Auto merged
mysql-test/t/mix_innodb_myisam_binlog.test:
Auto merged
mysql-test/t/mysqlbinlog.test:
Auto merged
mysql-test/t/rpl_change_master.test:
Auto merged
mysql-test/t/rpl_log.test:
Auto merged
mysql-test/t/variables.test:
Auto merged
netware/BUILD/compile-linux-tools:
Auto merged
netware/BUILD/compile-netware-END:
Auto merged
netware/BUILD/compile-netware-all:
Auto merged
netware/BUILD/compile-netware-standard:
Auto merged
mysql-test/t/rpl_empty_master_crash.test:
Auto merged
mysql-test/t/rpl_error_ignored_table.test:
Auto merged
mysql-test/t/rpl_flush_log_loop.test:
Auto merged
mysql-test/t/rpl_loaddata.test:
Auto merged
mysql-test/t/rpl_loaddata_rule_m.test:
Auto merged
mysql-test/t/rpl_loaddata_rule_s.test:
Auto merged
mysql-test/t/rpl_max_relay_size.test:
Auto merged
mysql-test/t/rpl_openssl.test:
Auto merged
mysql-test/t/rpl_relayrotate-slave.opt:
Auto merged
mysql-test/t/rpl_reset_slave.test:
Auto merged
mysql-test/t/rpl_trunc_binlog.test:
Auto merged
mysql-test/t/rpl_until.test:
Auto merged
mysql-test/t/rpl_user_variables.test:
Auto merged
mysql-test/t/subselect.test:
Auto merged
scripts/make_binary_distribution.sh:
Auto merged
scripts/mysql_create_system_tables.sh:
Auto merged
scripts/mysql_fix_privilege_tables.sql:
Auto merged
scripts/mysql_install_db.sh:
Auto merged
sql/filesort.cc:
Auto merged
sql/ha_berkeley.cc:
Auto merged
sql/ha_berkeley.h:
Auto merged
sql/ha_innodb.h:
Auto merged
sql/ha_myisam.cc:
Auto merged
sql/handler.cc:
Auto merged
sql/handler.h:
Auto merged
sql/item.cc:
Auto merged
sql/item.h:
Auto merged
sql/item_cmpfunc.cc:
Auto merged
sql/item_cmpfunc.h:
Auto merged
sql/item_create.cc:
Auto merged
sql/item_create.h:
Auto merged
sql/item_subselect.cc:
Auto merged
sql/item_sum.cc:
Auto merged
sql/item_sum.h:
Auto merged
sql/item_timefunc.h:
Auto merged
sql/lock.cc:
Auto merged
sql/log_event.h:
Auto merged
sql/mysqld.cc:
Auto merged
sql/net_serv.cc:
Auto merged
sql/protocol.cc:
Auto merged
sql/protocol.h:
Auto merged
sql/repl_failsafe.cc:
Auto merged
sql/sql_acl.cc:
Auto merged
sql/sql_acl.h:
Auto merged
sql/sql_base.cc:
Auto merged
sql/sql_cache.cc:
Auto merged
sql/sql_class.h:
Auto merged
sql/sql_db.cc:
Auto merged
sql/sql_delete.cc:
Auto merged
sql/sql_derived.cc:
Auto merged
sql/sql_lex.h:
Auto merged
sql/sql_list.h:
Auto merged
sql/sql_load.cc:
Auto merged
sql/sql_rename.cc:
Auto merged
sql/sql_repl.cc:
Auto merged
sql/sql_repl.h:
Auto merged
sql/sql_select.cc:
Auto merged
sql/sql_select.h:
Auto merged
sql/sql_show.cc:
Auto merged
sql/sql_table.cc:
Auto merged
sql/sql_test.cc:
Auto merged
sql/sql_update.cc:
Auto merged
sql-common/client.c:
Auto merged
tests/client_test.c:
Auto merged
Diffstat (limited to 'sql/sql_parse.cc')
-rw-r--r-- | sql/sql_parse.cc | 514 |
1 files changed, 351 insertions, 163 deletions
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 53405eb6fcd..5f52b8d6aac 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -60,16 +60,18 @@ extern "C" int gethostname(char *name, int namelen); #endif +#ifndef NO_EMBEDDED_ACCESS_CHECKS static int check_for_max_user_connections(THD *thd, USER_CONN *uc); +#endif static void decrease_user_connections(USER_CONN *uc); static bool check_db_used(THD *thd,TABLE_LIST *tables); static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables); -static bool single_table_command_access(THD *thd, ulong privilege, - TABLE_LIST *tables, int *res); static void remove_escape(char *name); static void refresh_status(void); -static bool append_file_to_dir(THD *thd, char **filename_ptr, - char *table_name); +static bool append_file_to_dir(THD *thd, const char **filename_ptr, + const char *table_name); +static int check_one_table_access(THD *thd, ulong privilege, + TABLE_LIST *tables, bool no_errors); const char *any_db="*any*"; // Special symbol for check_access @@ -113,6 +115,7 @@ static void unlock_locked_tables(THD *thd) } } + static bool end_active_trans(THD *thd) { int error=0; @@ -128,6 +131,17 @@ static bool end_active_trans(THD *thd) } +#ifdef HAVE_REPLICATION +inline bool all_tables_not_ok(THD *thd, TABLE_LIST *tables) +{ + return (table_rules_on && tables && !tables_ok(thd,tables) && + ((thd->lex->sql_command != SQLCOM_DELETE_MULTI) || + !tables_ok(thd, + (TABLE_LIST *)thd->lex->auxilliary_table_list.first))); +} +#endif + + static HASH hash_user_connections; static int get_or_create_user_conn(THD *thd, const char *user, @@ -218,7 +232,21 @@ int check_user(THD *thd, enum enum_server_command command, #ifdef NO_EMBEDDED_ACCESS_CHECKS thd->master_access= GLOBAL_ACLS; // Full rights - return 0; + /* Change database if necessary: OK or FAIL is sent in mysql_change_db */ + if (db && db[0]) + { + thd->db= 0; + thd->db_length= 0; + if (mysql_change_db(thd, db)) + { + if (thd->user_connect) + decrease_user_connections(thd->user_connect); + DBUG_RETURN(-1); + } + } + else + send_ok(thd); + DBUG_RETURN(0); #else my_bool opt_secure_auth_local; @@ -412,6 +440,8 @@ void init_max_user_conn(void) 1 error */ +#ifndef NO_EMBEDDED_ACCESS_CHECKS + static int check_for_max_user_connections(THD *thd, USER_CONN *uc) { int error=0; @@ -442,7 +472,7 @@ static int check_for_max_user_connections(THD *thd, USER_CONN *uc) (void) pthread_mutex_unlock(&LOCK_user_conn); DBUG_RETURN(error); } - +#endif /* NO_EMBEDDED_ACCESS_CHECKS */ /* Decrease user connection count @@ -531,15 +561,15 @@ bool is_update_query(enum enum_sql_command command) static bool check_mqh(THD *thd, uint check_command) { +#ifdef NO_EMBEDDED_ACCESS_CHECKS + return(0); +#else bool error=0; time_t check_time = thd->start_time ? thd->start_time : time(NULL); USER_CONN *uc=thd->user_connect; DBUG_ENTER("check_mqh"); DBUG_ASSERT(uc != 0); -#ifdef NO_EMBEDDED_ACCESS_CHECKS - DBUG_RETURN(0); -#else /* If more than a hour since last check, reset resource checking */ if (check_time - uc->intime >= 3600) { @@ -986,7 +1016,7 @@ pthread_handler_decl(handle_one_connection,arg) net->compress=1; // Use compression thd->version= refresh_version; - if (sys_init_connect.value && !(thd->master_access & SUPER_ACL)) + if (sys_init_connect.value_length && !(thd->master_access & SUPER_ACL)) { execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect); if (thd->query_error) @@ -1161,9 +1191,7 @@ int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd) if (!(table=open_ltable(thd, table_list, TL_READ_NO_INSERT))) DBUG_RETURN(1); - if (check_access(thd, SELECT_ACL, db, &table_list->grant.privilege,0,0)) - goto err; - if (grant_option && check_grant(thd, SELECT_ACL, table_list, 0, 0)) + if (check_one_table_access(thd, SELECT_ACL, table_list, 0)) goto err; thd->free_list = 0; thd->query_length=(uint) strlen(tbl_name); @@ -1183,9 +1211,18 @@ err: } - /* Execute one command from socket (query or simple command) */ - #ifndef EMBEDDED_LIBRARY + +/* + Read one command from socket and execute it (query or simple command). + This function is called in loop from thread function. + SYNOPSIS + do_command() + RETURN VALUE + 0 success + 1 request of thread shutdown (see dispatch_command() description) +*/ + bool do_command(THD *thd) { char *packet; @@ -1238,10 +1275,34 @@ bool do_command(THD *thd) command_name[command])); } net->read_timeout=old_timeout; // restore it + /* + packet_length contains length of data, as it was stored in packet + header. In case of malformed header, packet_length can be zero. + If packet_length is not zero, my_net_read ensures that this number + of bytes was actually read from network. Additionally my_net_read + sets packet[packet_length]= 0 (thus if packet_length == 0, + command == packet[0] == COM_SLEEP). + In dispatch_command packet[packet_length] points beyond the end of packet. + */ DBUG_RETURN(dispatch_command(command,thd, packet+1, (uint) packet_length)); } #endif /* EMBEDDED_LIBRARY */ +/* + Perform one connection-level (COM_XXXX) command. + SYNOPSIS + dispatch_command() + thd connection handle + command type of command to perform + packet data for the command, packet is always null-terminated + packet_length length of packet + 1 (to show that data is + null-terminated) except for COM_SLEEP, where it + can be zero. + RETURN VALUE + 0 ok + 1 request of thread shutdown, i. e. if command is + COM_QUIT/COM_SHUTDOWN +*/ bool dispatch_command(enum enum_server_command command, THD *thd, char* packet, uint packet_length) @@ -1300,7 +1361,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd, send_error(thd); // dump to NET break; } -#ifndef EMBEDDED_LIBRARY case COM_CHANGE_USER: { thd->change_user(); @@ -1319,13 +1379,14 @@ bool dispatch_command(enum enum_server_command command, THD *thd, uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ? *passwd++ : strlen(passwd); db+= passwd_len + 1; +#ifndef EMBEDDED_LIBRARY /* Small check for incomming packet */ if ((uint) ((uchar*) db - net->read_pos) > packet_length) { send_error(thd, ER_UNKNOWN_COM_ERROR); break; } - +#endif /* Convert database name to utf8 */ db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1, system_charset_info, db, strlen(db), @@ -1350,7 +1411,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, /* Clear variables that are allocated */ thd->user_connect= 0; - int res= check_user(thd, COM_CHANGE_USER, passwd, passwd_len, db, false); + int res= check_user(thd, COM_CHANGE_USER, passwd, passwd_len, db, FALSE); if (res) { @@ -1376,10 +1437,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd, } break; } -#endif /* EMBEDDED_LIBRARY */ case COM_EXECUTE: { - mysql_stmt_execute(thd, packet); + mysql_stmt_execute(thd, packet, packet_length); break; } case COM_LONG_DATA: @@ -1488,9 +1548,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd, my_casedn_str(files_charset_info, table_list.real_name); remove_escape(table_list.real_name); // This can't have wildcards - if (check_access(thd,SELECT_ACL,table_list.db,&thd->col_access,0,0)) + if (check_access(thd,SELECT_ACL,table_list.db,&table_list.grant.privilege, + 0, 0)) break; - table_list.grant.privilege=thd->col_access; if (grant_option && check_grant(thd,SELECT_ACL,&table_list,2,0)) break; mysqld_list_fields(thd,&table_list,fields); @@ -1507,10 +1567,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd, case COM_CREATE_DB: // QQ: To be removed { + char *db=thd->strdup(packet), *alias; + statistic_increment(com_stat[SQLCOM_CREATE_DB],&LOCK_status); - char *db=thd->strdup(packet); // null test to handle EOM - if (!db || !strip_sp(db) || check_db_name(db)) + if (!db || !(alias= thd->strdup(db)) || check_db_name(db)) { net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL"); break; @@ -1518,15 +1579,15 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if (check_access(thd,CREATE_ACL,db,0,1,0)) break; mysql_log.write(thd,command,packet); - mysql_create_db(thd,db,0,0); + mysql_create_db(thd,(lower_case_table_names == 2 ? alias : db),0,0); break; } case COM_DROP_DB: // QQ: To be removed { statistic_increment(com_stat[SQLCOM_DROP_DB],&LOCK_status); - char *db=thd->strdup(packet); + char *db=thd->strdup(packet), *alias; // null test to handle EOM - if (!db || !strip_sp(db) || check_db_name(db)) + if (!db || !(alias= thd->strdup(db)) || check_db_name(db)) { net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL"); break; @@ -1539,7 +1600,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, break; } mysql_log.write(thd,command,db); - mysql_rm_db(thd,db,0,0); + mysql_rm_db(thd,alias,0,0); break; } #ifndef EMBEDDED_LIBRARY @@ -1810,7 +1871,7 @@ mysql_execute_command(THD *thd) Skip if we are in the slave thread, some table rules have been given and the table list says the query should not be replicated */ - if (table_rules_on && tables && !tables_ok(thd,tables)) + if (all_tables_not_ok(thd,tables)) { /* we warn the slave SQL thread */ my_error(ER_SLAVE_IGNORED_TABLE, MYF(0)); @@ -1831,7 +1892,6 @@ mysql_execute_command(THD *thd) } #endif /* !HAVE_REPLICATION */ if (&lex->select_lex != lex->all_selects_list && - lex->sql_command != SQLCOM_CREATE_TABLE && lex->unit.create_total_list(thd, lex, &tables)) DBUG_RETURN(0); @@ -1843,7 +1903,7 @@ mysql_execute_command(THD *thd) !(thd->slave_thread || (thd->master_access & SUPER_ACL)) && (uc_update_queries[lex->sql_command] > 0)) { - send_error(thd, ER_CANT_UPDATE_WITH_READLOCK); + net_printf(thd, ER_OPTION_PREVENTS_STATEMENT, "--read-only"); DBUG_RETURN(-1); } @@ -2038,9 +2098,9 @@ mysql_execute_command(THD *thd) { if (check_global_access(thd, SUPER_ACL)) goto error; - LOCK_ACTIVE_MI; + pthread_mutex_lock(&LOCK_active_mi); res = change_master(thd,active_mi); - UNLOCK_ACTIVE_MI; + pthread_mutex_unlock(&LOCK_active_mi); break; } case SQLCOM_SHOW_SLAVE_STAT: @@ -2048,9 +2108,9 @@ mysql_execute_command(THD *thd) /* Accept one of two privileges */ if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL)) goto error; - LOCK_ACTIVE_MI; + pthread_mutex_lock(&LOCK_active_mi); res = show_master_info(thd,active_mi); - UNLOCK_ACTIVE_MI; + pthread_mutex_unlock(&LOCK_active_mi); break; } case SQLCOM_SHOW_MASTER_STAT: @@ -2102,7 +2162,7 @@ mysql_execute_command(THD *thd) net_printf(thd,ER_WRONG_TABLE_NAME, tables->real_name); break; } - LOCK_ACTIVE_MI; + pthread_mutex_lock(&LOCK_active_mi); /* fetch_master_table will send the error to the client on failure. Give error if the table already exists. @@ -2112,7 +2172,7 @@ mysql_execute_command(THD *thd) { send_ok(thd); } - UNLOCK_ACTIVE_MI; + pthread_mutex_unlock(&LOCK_active_mi); break; } #endif /* HAVE_REPLICATION */ @@ -2121,24 +2181,29 @@ mysql_execute_command(THD *thd) { /* Skip first table, which is the table we are creating */ TABLE_LIST *create_table= tables; + TABLE_LIST *create_table_local= + (TABLE_LIST*)lex->select_lex.table_list.first; + // exclude from global table list tables= tables->next; - lex->select_lex.table_list.first= (byte*) (tables); + // and from local list if it is not the same + if (&lex->select_lex != lex->all_selects_list) + lex->select_lex.table_list.first= (gptr)create_table_local->next; + else + lex->select_lex.table_list.first= (gptr)tables; create_table->next= 0; - if (&lex->select_lex != lex->all_selects_list && - lex->unit.create_total_list(thd, lex, &tables)) - DBUG_RETURN(-1); ulong want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ? CREATE_TMP_ACL : CREATE_ACL); + lex->create_info.alias= create_table->alias; if (check_access(thd, want_priv, create_table->db, &create_table->grant.privilege, 0, 0) || check_merge_table_access(thd, create_table->db, (TABLE_LIST *) lex->create_info.merge_list.first)) - goto error; /* purecov: inspected */ + goto create_eror; /* purecov: inspected */ if (grant_option && want_priv != CREATE_TMP_ACL && check_grant(thd, want_priv, create_table,0,0)) - goto error; + goto create_eror; #ifndef HAVE_READLINK lex->create_info.data_file_name=lex->create_info.index_file_name=0; #else @@ -2149,7 +2214,7 @@ mysql_execute_command(THD *thd) create_table->real_name)) { res=-1; - break; + goto unsent_create_error; } #endif /* @@ -2174,10 +2239,10 @@ mysql_execute_command(THD *thd) create_table->real_name)) { net_printf(thd,ER_UPDATE_TABLE_USED, create_table->real_name); - DBUG_RETURN(-1); + goto create_eror; } if (tables && check_table_access(thd, SELECT_ACL, tables,0)) - goto error; // Error message is given + goto create_eror; // Error message is given select_lex->options|= SELECT_NO_UNLOCK; unit->set_limit(select_lex, select_lex); @@ -2208,15 +2273,40 @@ mysql_execute_command(THD *thd) if (!res) send_ok(thd); } + // put tables back for PS rexecuting + create_table->next= tables; + tables= create_table; + if (&lex->select_lex != lex->all_selects_list) + { + /* + we do not touch local table 'next' field => we need just + put the table in the list + */ + lex->select_lex.table_list.first= (gptr) create_table_local; + } + else + lex->select_lex.table_list.first= (gptr) tables; + break; + +create_eror: + res= 1; //error reported +unsent_create_error: + // put tables back for PS rexecuting + create_table->next= tables; + tables= create_table; + if (&lex->select_lex != lex->all_selects_list) + { + /* + we do not touch local table 'next' field => we need just + put the table in the list + */ + lex->select_lex.table_list.first= (gptr) create_table_local; + } break; } case SQLCOM_CREATE_INDEX: - if (!tables->db) - tables->db=thd->db; - if (check_access(thd,INDEX_ACL,tables->db,&tables->grant.privilege,0,0)) + if (check_one_table_access(thd, INDEX_ACL, tables, 0)) goto error; /* purecov: inspected */ - if (grant_option && check_grant(thd,INDEX_ACL,tables,0,0)) - goto error; thd->slow_command=TRUE; if (end_active_trans(thd)) res= -1; @@ -2227,9 +2317,9 @@ mysql_execute_command(THD *thd) #ifdef HAVE_REPLICATION case SQLCOM_SLAVE_START: { - LOCK_ACTIVE_MI; + pthread_mutex_lock(&LOCK_active_mi); start_slave(thd,active_mi,1 /* net report*/); - UNLOCK_ACTIVE_MI; + pthread_mutex_unlock(&LOCK_active_mi); break; } case SQLCOM_SLAVE_STOP: @@ -2252,9 +2342,9 @@ mysql_execute_command(THD *thd) goto error; } { - LOCK_ACTIVE_MI; + pthread_mutex_lock(&LOCK_active_mi); stop_slave(thd,active_mi,1/* net report*/); - UNLOCK_ACTIVE_MI; + pthread_mutex_unlock(&LOCK_active_mi); break; } #endif /* HAVE_REPLICATION */ @@ -2272,8 +2362,6 @@ mysql_execute_command(THD *thd) res=0; break; } - if (!tables->db) - tables->db=thd->db; if (!select_lex->db) select_lex->db=tables->db; if (check_access(thd,ALTER_ACL,tables->db,&tables->grant.privilege,0,0) || @@ -2282,8 +2370,6 @@ mysql_execute_command(THD *thd) (TABLE_LIST *) lex->create_info.merge_list.first)) goto error; /* purecov: inspected */ - if (!tables->db) - tables->db=thd->db; if (grant_option) { if (check_grant(thd,ALTER_ACL,tables,0,0)) @@ -2295,7 +2381,7 @@ mysql_execute_command(THD *thd) tmp_table.real_name=lex->name; tmp_table.db=select_lex->db; tmp_table.grant.privilege=priv; - if (check_grant(thd,INSERT_ACL | CREATE_ACL,tables,0,0)) + if (check_grant(thd, INSERT_ACL | CREATE_ACL, &tmp_table, 0, 0)) goto error; } } @@ -2336,8 +2422,10 @@ mysql_execute_command(THD *thd) if (grant_option) { TABLE_LIST old_list,new_list; - bzero((char*) &old_list, sizeof(old_list)); - bzero((char*) &new_list, sizeof(new_list)); // Safety + /* + we do not need initialize old_list and new_list because we will + come table[0] and table->next[0] there + */ old_list=table[0]; new_list=table->next[0]; old_list.next=new_list.next=0; @@ -2476,16 +2564,15 @@ mysql_execute_command(THD *thd) break; } case SQLCOM_UPDATE: - if (check_db_used(thd,tables)) - goto error; - - if (single_table_command_access(thd, UPDATE_ACL, tables, &res)) - goto error; if (select_lex->item_list.elements != lex->value_list.elements) { send_error(thd,ER_WRONG_VALUE_COUNT); goto error; } + if (check_db_used(thd,tables)) + goto error; + if (check_one_table_access(thd, UPDATE_ACL, tables, 0)) + goto error; res= mysql_update(thd,tables, select_lex->item_list, lex->value_list, @@ -2498,36 +2585,48 @@ mysql_execute_command(THD *thd) res= -1; break; case SQLCOM_UPDATE_MULTI: - if (check_access(thd,UPDATE_ACL,tables->db,&tables->grant.privilege,0,0)) - goto error; - if (grant_option && check_grant(thd,UPDATE_ACL,tables,0,0)) - goto error; + { + const char *msg= 0; + TABLE_LIST *table; + if (select_lex->item_list.elements != lex->value_list.elements) { send_error(thd,ER_WRONG_VALUE_COUNT); goto error; } + /* + Ensure that we have UPDATE or SELECT privilege for each table + The exact privilege is checked in mysql_multi_update() + */ + for (table= tables ; table ; table= table->next) { - const char *msg= 0; - if (select_lex->order_list.elements) - msg= "ORDER BY"; - else if (select_lex->select_limit && select_lex->select_limit != - HA_POS_ERROR) - msg= "LIMIT"; - if (msg) - { - net_printf(thd, ER_WRONG_USAGE, "UPDATE", msg); - res= 1; - break; - } - res= mysql_multi_update(thd,tables, - &select_lex->item_list, - &lex->value_list, - select_lex->where, - select_lex->options, - lex->duplicates, unit, select_lex); + TABLE_LIST *save= table->next; + table->next= 0; + if (check_one_table_access(thd, UPDATE_ACL, table, 1) && + check_one_table_access(thd, SELECT_ACL, table, 0)) + goto error; + table->next= save; + } + + if (select_lex->order_list.elements) + msg= "ORDER BY"; + else if (select_lex->select_limit && select_lex->select_limit != + HA_POS_ERROR) + msg= "LIMIT"; + if (msg) + { + net_printf(thd, ER_WRONG_USAGE, "UPDATE", msg); + res= 1; + break; } + res= mysql_multi_update(thd,tables, + &select_lex->item_list, + &lex->value_list, + select_lex->where, + select_lex->options, + lex->duplicates, unit, select_lex); break; + } case SQLCOM_REPLACE: case SQLCOM_INSERT: { @@ -2535,7 +2634,7 @@ mysql_execute_command(THD *thd) ulong privilege= (lex->duplicates == DUP_REPLACE ? INSERT_ACL | DELETE_ACL : INSERT_ACL | update); - if (single_table_command_access(thd, privilege, tables, &res)) + if (check_one_table_access(thd, privilege, tables, 0)) goto error; if (select_lex->item_list.elements != lex->value_list.elements) { @@ -2559,15 +2658,7 @@ mysql_execute_command(THD *thd) { ulong privilege= (lex->duplicates == DUP_REPLACE ? INSERT_ACL | DELETE_ACL : INSERT_ACL); - TABLE_LIST *save_next=tables->next; - tables->next=0; - if (check_access(thd, privilege, - tables->db,&tables->grant.privilege,0,0) || - (grant_option && check_grant(thd, privilege, tables,0,0))) - goto error; - - tables->next=save_next; - if ((res=check_table_access(thd, SELECT_ACL, save_next,0))) + if (check_one_table_access(thd, privilege, tables, 0)) goto error; } @@ -2605,9 +2696,7 @@ mysql_execute_command(THD *thd) break; } case SQLCOM_TRUNCATE: - if (check_access(thd,DELETE_ACL,tables->db,&tables->grant.privilege,0,0)) - goto error; /* purecov: inspected */ - if (grant_option && check_grant(thd,DELETE_ACL,tables,0,0)) + if (check_one_table_access(thd, DELETE_ACL, tables, 0)) goto error; /* Don't allow this within a transaction because we want to use @@ -2622,7 +2711,7 @@ mysql_execute_command(THD *thd) break; case SQLCOM_DELETE: { - if (single_table_command_access(thd, DELETE_ACL, tables, &res)) + if (check_one_table_access(thd, DELETE_ACL, tables, 0)) goto error; // Set privilege for the WHERE clause tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege); @@ -2657,7 +2746,7 @@ mysql_execute_command(THD *thd) TABLE_LIST *walk; for (walk= (TABLE_LIST*) tables; walk; walk= walk->next) { - if (!strcmp(auxi->real_name, walk->alias) && + if (!my_strcasecmp(table_alias_charset, auxi->alias, walk->alias) && !strcmp(walk->db, auxi->db)) break; } @@ -2747,8 +2836,8 @@ mysql_execute_command(THD *thd) DROP / * 40005 TEMPORARY * / TABLE that come from parts of binlogs (likely if we use RESET SLAVE or CHANGE MASTER TO), while the temporary table has already been dropped. - To not generate such irrelevant "table does not exist errors", we - silently add IF EXISTS if TEMPORARY was used. + To not generate such irrelevant "table does not exist errors", + we silently add IF EXISTS if TEMPORARY was used. */ if (thd->slave_thread) lex->drop_if_exists= 1; @@ -2757,12 +2846,8 @@ mysql_execute_command(THD *thd) } break; case SQLCOM_DROP_INDEX: - if (!tables->db) - tables->db=thd->db; - if (check_access(thd,INDEX_ACL,tables->db,&tables->grant.privilege,0,0)) + if (check_one_table_access(thd, INDEX_ACL, tables, 0)) goto error; /* purecov: inspected */ - if (grant_option && check_grant(thd,INDEX_ACL,tables,0,0)) - goto error; if (end_active_trans(thd)) res= -1; else @@ -2871,16 +2956,11 @@ mysql_execute_command(THD *thd) #else { char *db=tables->db; - if (!*db) - { - send_error(thd,ER_NO_DB_ERROR); /* purecov: inspected */ - goto error; /* purecov: inspected */ - } remove_escape(db); // Fix escaped '_' remove_escape(tables->real_name); - if (check_access(thd,SELECT_ACL | EXTRA_ACL,db,&thd->col_access,0,0)) + if (check_access(thd,SELECT_ACL | EXTRA_ACL,db, + &tables->grant.privilege, 0, 0)) goto error; /* purecov: inspected */ - tables->grant.privilege=thd->col_access; if (grant_option && check_grant(thd,SELECT_ACL,tables,2,0)) goto error; res= mysqld_show_fields(thd,tables, @@ -2896,18 +2976,11 @@ mysql_execute_command(THD *thd) #else { char *db=tables->db; - if (!db) - { - send_error(thd,ER_NO_DB_ERROR); /* purecov: inspected */ - goto error; /* purecov: inspected */ - } remove_escape(db); // Fix escaped '_' remove_escape(tables->real_name); - if (!tables->db) - tables->db=thd->db; - if (check_access(thd,SELECT_ACL,db,&thd->col_access,0,0)) - goto error; /* purecov: inspected */ - tables->grant.privilege=thd->col_access; + if (check_access(thd,SELECT_ACL | EXTRA_ACL,db, + &tables->grant.privilege, 0, 0)) + goto error; /* purecov: inspected */ if (grant_option && check_grant(thd,SELECT_ACL,tables,2,0)) goto error; res= mysqld_show_keys(thd,tables); @@ -2936,9 +3009,7 @@ mysql_execute_command(THD *thd) send_error(thd,ER_NOT_ALLOWED_COMMAND); goto error; } - if (check_access(thd,privilege,tables->db,&tables->grant.privilege,0, - 0) || - grant_option && check_grant(thd,privilege,tables,0,0)) + if (check_one_table_access(thd, privilege, tables, 0)) goto error; } res=mysql_load(thd, lex->exchange, tables, lex->field_list, @@ -2975,8 +3046,12 @@ mysql_execute_command(THD *thd) goto error; thd->in_lock_tables=1; thd->options|= OPTION_TABLE_LOCK; - if (!(res=open_and_lock_tables(thd,tables))) + if (!(res= open_and_lock_tables(thd, tables))) { +#ifdef HAVE_QUERY_CACHE + if (thd->variables.query_cache_wlock_invalidate) + query_cache.invalidate_locked_for_write(tables); +#endif /*HAVE_QUERY_CACHE*/ thd->locked_tables=thd->lock; thd->lock=0; send_ok(thd); @@ -2987,7 +3062,8 @@ mysql_execute_command(THD *thd) break; case SQLCOM_CREATE_DB: { - if (!strip_sp(lex->name) || check_db_name(lex->name)) + char *alias; + if (!(alias=thd->strdup(lex->name)) || check_db_name(lex->name)) { net_printf(thd,ER_WRONG_DB_NAME, lex->name); break; @@ -3010,12 +3086,14 @@ mysql_execute_command(THD *thd) #endif if (check_access(thd,CREATE_ACL,lex->name,0,1,0)) break; - res=mysql_create_db(thd,lex->name,&lex->create_info,0); + res= mysql_create_db(thd,(lower_case_table_names == 2 ? alias : lex->name), + &lex->create_info, 0); break; } case SQLCOM_DROP_DB: { - if (!strip_sp(lex->name) || check_db_name(lex->name)) + char *alias; + if (!(alias=thd->strdup(lex->name)) || check_db_name(lex->name)) { net_printf(thd, ER_WRONG_DB_NAME, lex->name); break; @@ -3043,7 +3121,7 @@ mysql_execute_command(THD *thd) send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION); goto error; } - res=mysql_rm_db(thd,lex->name,lex->drop_if_exists,0); + res=mysql_rm_db(thd,alias,lex->drop_if_exists,0); break; } case SQLCOM_ALTER_DB: @@ -3053,6 +3131,22 @@ mysql_execute_command(THD *thd) net_printf(thd, ER_WRONG_DB_NAME, lex->name); 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 && + (!db_ok(lex->name, replicate_do_db, replicate_ignore_db) || + !db_ok_with_wild_table(lex->name))) + { + my_error(ER_SLAVE_IGNORED_TABLE, MYF(0)); + break; + } +#endif if (check_access(thd,ALTER_ACL,lex->name,0,1,0)) break; if (thd->locked_tables || thd->active_transaction()) @@ -3070,7 +3164,7 @@ mysql_execute_command(THD *thd) net_printf(thd,ER_WRONG_DB_NAME, lex->name); break; } - if (check_access(thd,DROP_ACL,lex->name,0,1,0)) + if (check_access(thd,SELECT_ACL,lex->name,0,1,0)) break; if (thd->locked_tables || thd->active_transaction()) { @@ -3650,19 +3744,19 @@ error: tables belong to subselects. SYNOPSIS - single_table_command_access() - thd - Thread handler - privilege - asked privelage - tables - table list of command - res - pointer on result code variable + check_one_table_access() + thd Thread handler + privilege requested privelage + tables table list of command + no_errors Don't send error to client RETURN 0 - OK - 1 - access denied + 1 - access denied, error is sent to client */ -static bool single_table_command_access(THD *thd, ulong privilege, - TABLE_LIST *tables, int *res) +static int check_one_table_access(THD *thd, ulong privilege, + TABLE_LIST *tables, bool no_errors) { if (check_access(thd, privilege, tables->db, &tables->grant.privilege,0,0)) @@ -3672,13 +3766,16 @@ static bool single_table_command_access(THD *thd, ulong privilege, TABLE_LIST *subselects_tables= tables->next; tables->next= 0; if (grant_option && check_grant(thd, privilege, tables, 0, 0)) + { + tables->next= subselects_tables; return 1; + } // check rights on tables of subselect (if exists) if (subselects_tables) { tables->next= subselects_tables; - if ((*res= check_table_access(thd, SELECT_ACL, subselects_tables,0))) + if ((check_table_access(thd, SELECT_ACL, subselects_tables,0))) return 1; } return 0; @@ -3711,7 +3808,10 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, DBUG_ENTER("check_access"); DBUG_PRINT("enter",("want_access: %lu master_access: %lu", want_access, thd->master_access)); - ulong db_access,dummy; +#ifndef NO_EMBEDDED_ACCESS_CHECKS + ulong db_access; +#endif + ulong dummy; if (save_priv) *save_priv=0; else @@ -3903,6 +4003,10 @@ static bool check_db_used(THD *thd,TABLE_LIST *tables) #define used_stack(A,B) (long) (B - A) #endif +#ifndef DBUG_OFF +long max_stack_used; +#endif + #ifndef EMBEDDED_LIBRARY bool check_stack_overrun(THD *thd,char *buf __attribute__((unused))) { @@ -3915,6 +4019,9 @@ bool check_stack_overrun(THD *thd,char *buf __attribute__((unused))) thd->fatal_error(); return 1; } +#ifndef DBUG_OFF + max_stack_used= max(max_stack_used, stack_used); +#endif return 0; } #endif /* EMBEDDED_LIBRARY */ @@ -4008,7 +4115,9 @@ mysql_init_select(LEX *lex) { SELECT_LEX *select_lex= lex->current_select; select_lex->init_select(); - select_lex->select_limit= lex->thd->variables.select_limit; + select_lex->select_limit= (&lex->select_lex == select_lex) ? + lex->thd->variables.select_limit : /* Primry UNION */ + HA_POS_ERROR; /* subquery */ if (select_lex == &lex->select_lex) { lex->exchange= 0; @@ -4060,7 +4169,9 @@ mysql_new_select(LEX *lex, bool move_down) fake->select_number= INT_MAX; fake->make_empty_select(); fake->linkage= GLOBAL_OPTIONS_TYPE; - fake->select_limit= lex->thd->variables.select_limit; + fake->select_limit= (&lex->unit == unit) ? + lex->thd->variables.select_limit : /* Primry UNION */ + HA_POS_ERROR; /* subquery */ } } @@ -4114,8 +4225,11 @@ void mysql_init_multi_delete(LEX *lex) } -void -mysql_parse(THD *thd, char *inBuf, uint length) +/* + When you modify mysql_parse(), you may need to mofify + mysql_test_parse_for_slave() in this same file. +*/ +void mysql_parse(THD *thd, char *inBuf, uint length) { DBUG_ENTER("mysql_parse"); @@ -4174,6 +4288,33 @@ mysql_parse(THD *thd, char *inBuf, uint length) } +#ifdef HAVE_REPLICATION +/* + Usable by the replication SQL thread only: just parse a query to know if it + can be ignored because of replicate-*-table rules. + + RETURN VALUES + 0 cannot be ignored + 1 can be ignored +*/ + +bool mysql_test_parse_for_slave(THD *thd, char *inBuf, uint length) +{ + LEX *lex; + bool error= 0; + + mysql_init_query(thd); + lex= lex_start(thd, (uchar*) inBuf, length); + if (!yyparse((void*) thd) && ! thd->is_fatal_error && + all_tables_not_ok(thd,(TABLE_LIST*) lex->select_lex.table_list.first)) + error= 1; /* Ignore question */ + free_items(thd->free_list); /* Free strings used by items */ + lex_end(lex); + + return error; +} +#endif + /***************************************************************************** ** Store field definition for create ** Return 0 if ok @@ -4182,7 +4323,8 @@ mysql_parse(THD *thd, char *inBuf, uint length) bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, char *length, char *decimals, uint type_modifier, - Item *default_value, LEX_STRING *comment, + Item *default_value, Item *on_update_value, + LEX_STRING *comment, char *change, TYPELIB *interval, CHARSET_INFO *cs, uint uint_geom_type) { @@ -4214,7 +4356,16 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, if (default_value) { - if (type == FIELD_TYPE_TIMESTAMP) + /* + Default value should be literal => basic constants => + no need fix_fields() + + We allow only one function as part of default value - + NOW() as default for TIMESTAMP type. + */ + if (default_value->type() == Item::FUNC_ITEM && + !(((Item_func*)default_value)->functype() == Item_func::NOW_FUNC && + type == FIELD_TYPE_TIMESTAMP)) { net_printf(thd, ER_INVALID_DEFAULT, field_name); DBUG_RETURN(1); @@ -4235,6 +4386,13 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, DBUG_RETURN(1); } } + + if (on_update_value && type != FIELD_TYPE_TIMESTAMP) + { + net_printf(thd, ER_INVALID_ON_UPDATE, field_name); + DBUG_RETURN(1); + } + if (!(new_field=new create_field())) DBUG_RETURN(1); new_field->field=0; @@ -4398,6 +4556,34 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, new_field->length= min(new_field->length,14); /* purecov: inspected */ } new_field->flags|= ZEROFILL_FLAG | UNSIGNED_FLAG | NOT_NULL_FLAG; + if (default_value) + { + /* Grammar allows only NOW() value for ON UPDATE clause */ + if (default_value->type() == Item::FUNC_ITEM && + ((Item_func*)default_value)->functype() == Item_func::NOW_FUNC) + { + new_field->unireg_check= (on_update_value?Field::TIMESTAMP_DNUN_FIELD: + Field::TIMESTAMP_DN_FIELD); + /* + We don't need default value any longer moreover it is dangerous. + Everything handled by unireg_check further. + */ + new_field->def= 0; + } + else + new_field->unireg_check= (on_update_value?Field::TIMESTAMP_UN_FIELD: + Field::NONE); + } + else + { + /* + We are setting TIMESTAMP_OLD_FIELD here only temporary, we will + replace this value by TIMESTAMP_DNUN_FIELD or NONE later when + information about all TIMESTAMP fields in table will be availiable. + */ + new_field->unireg_check= on_update_value?Field::TIMESTAMP_UN_FIELD: + Field::TIMESTAMP_OLD_FIELD; + } break; case FIELD_TYPE_DATE: // Old date type if (protocol_version != PROTOCOL_VERSION-1) @@ -4567,11 +4753,10 @@ bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc) ORDER *order; Item **item_ptr; DBUG_ENTER("add_to_list"); - if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)+sizeof(Item*)))) + if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)))) DBUG_RETURN(1); - item_ptr = (Item**) (order+1); - *item_ptr=item; - order->item= item_ptr; + order->item_ptr= item; + order->item= &order->item_ptr; order->asc = asc; order->free_me=0; order->used=0; @@ -4661,6 +4846,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX); ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES); ptr->derived= table->sel; + ptr->cacheable_table= 1; if (use_index_arg) ptr->use_index=(List<String> *) thd->memdup((gptr) use_index_arg, sizeof(*use_index_arg)); @@ -4675,7 +4861,8 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, tables ; tables=tables->next) { - if (!strcmp(alias_str,tables->alias) && !strcmp(ptr->db, tables->db)) + if (!my_strcasecmp(table_alias_charset, alias_str, tables->alias) && + !strcmp(ptr->db, tables->db)) { net_printf(thd,ER_NONUNIQ_TABLE,alias_str); /* purecov: tested */ DBUG_RETURN(0); /* purecov: tested */ @@ -4815,9 +5002,9 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, if (purge_time >= 0) mysql_bin_log.purge_logs_before_date(purge_time); } - LOCK_ACTIVE_MI; + pthread_mutex_lock(&LOCK_active_mi); rotate_relay_log(active_mi); - UNLOCK_ACTIVE_MI; + pthread_mutex_unlock(&LOCK_active_mi); #endif if (ha_flush_logs()) result=1; @@ -4878,10 +5065,10 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, if (options & REFRESH_SLAVE) { tmp_write_to_binlog= 0; - LOCK_ACTIVE_MI; + pthread_mutex_lock(&LOCK_active_mi); if (reset_slave(thd, active_mi)) result=1; - UNLOCK_ACTIVE_MI; + pthread_mutex_unlock(&LOCK_active_mi); } #endif if (options & REFRESH_USER_RESOURCES) @@ -4964,7 +5151,8 @@ static void refresh_status(void) /* If pointer is not a null pointer, append filename to it */ -static bool append_file_to_dir(THD *thd, char **filename_ptr, char *table_name) +static bool append_file_to_dir(THD *thd, const char **filename_ptr, + const char *table_name) { char buff[FN_REFLEN],*ptr, *end; if (!*filename_ptr) |