summaryrefslogtreecommitdiff
path: root/sql/sql_parse.cc
diff options
context:
space:
mode:
authorunknown <pem@mysql.com>2004-05-07 18:52:06 +0200
committerunknown <pem@mysql.com>2004-05-07 18:52:06 +0200
commite9c1e75b48e5d2c0047a3e88b35667a33d6395e4 (patch)
tree2f7b236a8721d14f1b398964b898d922fd133131 /sql/sql_parse.cc
parentf3d691a970627f34ed825a9cf7b84520dcdd43b3 (diff)
parente3211fbd6a59c3dc6a97066c97ab86bfc67d382f (diff)
downloadmariadb-git-e9c1e75b48e5d2c0047a3e88b35667a33d6395e4.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 configure.in: Auto merged include/my_global.h: Auto merged include/mysql_com.h: Auto merged libmysql/libmysql.c: Auto merged libmysqld/Makefile.am: Auto merged myisam/myisamchk.c: Auto merged myisam/myisamdef.h: Auto merged mysql-test/install_test_db.sh: Auto merged mysql-test/r/func_time.result: Auto merged mysql-test/r/mysqldump.result: Auto merged mysql-test/r/show_check.result: Auto merged mysql-test/r/subselect.result: Auto merged mysql-test/r/union.result: Auto merged mysql-test/t/func_time.test: Auto merged mysql-test/t/subselect.test: Auto merged scripts/make_binary_distribution.sh: Auto merged scripts/mysql_install_db.sh: Auto merged sql/ha_berkeley.cc: Auto merged mysql-test/t/rpl_error_ignored_table.test: Auto merged sql/ha_berkeley.h: Auto merged sql/ha_innodb.cc: 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_subselect.cc: Auto merged sql/item_sum.cc: Auto merged sql/item_sum.h: Auto merged sql/lex.h: Auto merged sql/log.cc: Auto merged sql/mysql_priv.h: Auto merged sql/mysqld.cc: Auto merged sql/protocol.cc: Auto merged sql/records.cc: Auto merged sql/set_var.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.cc: Auto merged sql/sql_class.h: Auto merged sql/sql_db.cc: Auto merged sql/sql_delete.cc: Auto merged sql/sql_insert.cc: Auto merged sql/sql_lex.cc: Auto merged sql/sql_load.cc: Auto merged sql/sql_prepare.cc: Auto merged sql/sql_select.h: Auto merged sql/sql_show.cc: Auto merged sql/sql_string.cc: Auto merged sql/sql_test.cc: Auto merged sql/sql_update.cc: Auto merged sql/sql_yacc.yy: Auto merged sql/table.h: Auto merged tests/client_test.c: Auto merged
Diffstat (limited to 'sql/sql_parse.cc')
-rw-r--r--sql/sql_parse.cc658
1 files changed, 450 insertions, 208 deletions
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 4ea1fcf3301..057ea6e8bd5 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -65,13 +65,10 @@ 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 void remove_escape(char *name);
static void refresh_status(void);
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
@@ -1109,6 +1106,12 @@ extern "C" pthread_handler_decl(handle_bootstrap,arg)
while (fgets(buff, thd->net.max_packet, file))
{
uint length=(uint) strlen(buff);
+ if (buff[length-1]!='\n' && !feof(file))
+ {
+ send_error(thd,ER_NET_PACKET_TOO_LARGE, NullS);
+ thd->is_fatal_error= 1;
+ break;
+ }
while (length && (my_isspace(thd->charset(), buff[length-1]) ||
buff[length-1] == ';'))
length--;
@@ -1191,7 +1194,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_one_table_access(thd, SELECT_ACL, table_list, 0))
+ if (check_one_table_access(thd, SELECT_ACL, table_list))
goto err;
thd->free_list = 0;
thd->query_length=(uint) strlen(tbl_name);
@@ -1439,6 +1442,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
case COM_EXECUTE:
{
+ thd->free_list= NULL;
mysql_stmt_execute(thd, packet, packet_length);
break;
}
@@ -1551,7 +1555,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if (check_access(thd,SELECT_ACL,table_list.db,&table_list.grant.privilege,
0, 0))
break;
- if (grant_option && check_grant(thd,SELECT_ACL,&table_list,2,0))
+ if (grant_option &&
+ check_grant(thd, SELECT_ACL, &table_list, 2, UINT_MAX, 0))
break;
mysqld_list_fields(thd,&table_list,fields);
free_items(thd->free_list);
@@ -1894,7 +1899,7 @@ mysql_execute_command(THD *thd)
if (&lex->select_lex != lex->all_selects_list &&
lex->unit.create_total_list(thd, lex, &tables))
DBUG_RETURN(0);
-
+
/*
When option readonly is set deny operations which change tables.
Except for the replication thread and the 'super' users.
@@ -1911,6 +1916,13 @@ mysql_execute_command(THD *thd)
switch (lex->sql_command) {
case SQLCOM_SELECT:
{
+ /* assign global limit variable if limit is not given */
+ {
+ SELECT_LEX *param= lex->unit.global_parameters;
+ if (!param->explicit_limit)
+ param->select_limit= thd->variables.select_limit;
+ }
+
select_result *result=lex->result;
if (tables)
{
@@ -2150,11 +2162,7 @@ mysql_execute_command(THD *thd)
if (grant_option)
{
/* Check that the first table has CREATE privilege */
- TABLE_LIST *tmp_table_list=tables->next;
- tables->next=0;
- bool error=check_grant(thd,CREATE_ACL,tables,0,0);
- tables->next=tmp_table_list;
- if (error)
+ if (check_grant(thd, CREATE_ACL, tables, 0, 1, 0))
goto error;
}
if (strlen(tables->real_name) > NAME_LEN)
@@ -2180,30 +2188,13 @@ mysql_execute_command(THD *thd)
case SQLCOM_CREATE_TABLE:
{
/* 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;
- // 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;
-
- 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 create_eror; /* purecov: inspected */
- if (grant_option && want_priv != CREATE_TMP_ACL &&
- check_grant(thd, want_priv, create_table,0,0))
- goto create_eror;
+ TABLE_LIST *create_table, *create_table_local;
+ tables= lex->unlink_first_table(tables, &create_table,
+ &create_table_local);
+
+ if ((res= create_table_precheck(thd, tables, create_table)))
+ goto unsent_create_error;
+
#ifndef HAVE_READLINK
lex->create_info.data_file_name=lex->create_info.index_file_name=0;
#else
@@ -2239,10 +2230,10 @@ mysql_execute_command(THD *thd)
create_table->real_name))
{
net_printf(thd,ER_UPDATE_TABLE_USED, create_table->real_name);
- goto create_eror;
+ goto create_error;
}
if (tables && check_table_access(thd, SELECT_ACL, tables,0))
- goto create_eror; // Error message is given
+ goto create_error; // Error message is given
select_lex->options|= SELECT_NO_UNLOCK;
unit->set_limit(select_lex, select_lex);
@@ -2256,6 +2247,9 @@ mysql_execute_command(THD *thd)
lex->key_list,
select_lex->item_list,lex->duplicates)))
res=handle_select(thd, lex, result);
+ //reset for PS
+ lex->create_list.empty();
+ lex->key_list.empty();
}
}
else // regular create
@@ -2273,39 +2267,22 @@ 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;
+ tables= lex->link_first_table_back(tables, create_table,
+ create_table_local);
break;
-create_eror:
+create_error:
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;
- }
+ tables= lex->link_first_table_back(tables, create_table,
+ create_table_local);
break;
}
case SQLCOM_CREATE_INDEX:
- if (check_one_table_access(thd, INDEX_ACL, tables, 0))
+ if (check_one_table_access(thd, INDEX_ACL, tables))
goto error; /* purecov: inspected */
thd->slow_command=TRUE;
if (end_active_trans(thd))
@@ -2372,7 +2349,7 @@ unsent_create_error:
goto error; /* purecov: inspected */
if (grant_option)
{
- if (check_grant(thd,ALTER_ACL,tables,0,0))
+ if (check_grant(thd, ALTER_ACL, tables, 0, UINT_MAX, 0))
goto error;
if (lex->name && !test_all_bits(priv,INSERT_ACL | CREATE_ACL))
{ // Rename of table
@@ -2381,7 +2358,8 @@ unsent_create_error:
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, &tmp_table, 0, 0))
+ if (check_grant(thd, INSERT_ACL | CREATE_ACL, &tmp_table, 0,
+ UINT_MAX, 0))
goto error;
}
}
@@ -2399,6 +2377,7 @@ unsent_create_error:
lex->key_list, lex->drop_list, lex->alter_list,
select_lex->order_list.elements,
(ORDER *) select_lex->order_list.first,
+ lex->alter_flags,
lex->duplicates,
lex->alter_keys_onoff,
lex->tablespace_op,
@@ -2429,10 +2408,11 @@ unsent_create_error:
old_list=table[0];
new_list=table->next[0];
old_list.next=new_list.next=0;
- if (check_grant(thd,ALTER_ACL,&old_list,0,0) ||
+ if (check_grant(thd, ALTER_ACL, &old_list, 0, UINT_MAX, 0) ||
(!test_all_bits(table->next->grant.privilege,
INSERT_ACL | CREATE_ACL) &&
- check_grant(thd,INSERT_ACL | CREATE_ACL, &new_list,0,0)))
+ check_grant(thd, INSERT_ACL | CREATE_ACL, &new_list, 0,
+ UINT_MAX, 0)))
goto error;
}
}
@@ -2547,7 +2527,7 @@ unsent_create_error:
res= mysql_alter_table(thd, NullS, NullS, &create_info,
tables, lex->create_list,
lex->key_list, lex->drop_list, lex->alter_list,
- 0, (ORDER *) 0,
+ 0, (ORDER *) 0, 0,
DUP_ERROR);
}
else
@@ -2564,15 +2544,8 @@ unsent_create_error:
break;
}
case SQLCOM_UPDATE:
- 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;
+ if (update_precheck(thd, tables))
+ break;
res= mysql_update(thd,tables,
select_lex->item_list,
lex->value_list,
@@ -2586,39 +2559,8 @@ unsent_create_error:
break;
case SQLCOM_UPDATE_MULTI:
{
- 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)
- {
- 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;
+ if ((res= multi_update_precheck(thd, tables)))
break;
- }
res= mysql_multi_update(thd,tables,
&select_lex->item_list,
&lex->value_list,
@@ -2630,17 +2572,9 @@ unsent_create_error:
case SQLCOM_REPLACE:
case SQLCOM_INSERT:
{
- my_bool update=(lex->value_list.elements ? UPDATE_ACL : 0);
- ulong privilege= (lex->duplicates == DUP_REPLACE ?
- INSERT_ACL | DELETE_ACL : INSERT_ACL | update);
-
- if (check_one_table_access(thd, privilege, tables, 0))
- goto error;
- if (select_lex->item_list.elements != lex->value_list.elements)
- {
- send_error(thd,ER_WRONG_VALUE_COUNT);
- goto error;
- }
+ my_bool update= (lex->value_list.elements ? UPDATE_ACL : 0);
+ if ((res= insert_precheck(thd, tables, update)))
+ break;
res = mysql_insert(thd,tables,lex->field_list,lex->many_values,
select_lex->item_list, lex->value_list,
(update ? DUP_UPDATE : lex->duplicates));
@@ -2651,16 +2585,9 @@ unsent_create_error:
case SQLCOM_REPLACE_SELECT:
case SQLCOM_INSERT_SELECT:
{
- /*
- Check that we have modify privileges for the first table and
- select privileges for the rest
- */
- {
- ulong privilege= (lex->duplicates == DUP_REPLACE ?
- INSERT_ACL | DELETE_ACL : INSERT_ACL);
- if (check_one_table_access(thd, privilege, tables, 0))
- goto error;
- }
+ TABLE_LIST *first_local_table= (TABLE_LIST *) select_lex->table_list.first;
+ if ((res= insert_select_precheck(thd, tables)))
+ break;
/* Fix lock for first table */
if (tables->lock_type == TL_WRITE_DELAYED)
@@ -2678,16 +2605,18 @@ unsent_create_error:
select_lex->options |= OPTION_BUFFER_RESULT;
}
- /* Skip first table, which is the table we are inserting in */
- lex->select_lex.table_list.first=
- (byte*) (((TABLE_LIST *) lex->select_lex.table_list.first)->next);
- lex->select_lex.resolve_mode= SELECT_LEX::NOMATTER_MODE;
if (!(res=open_and_lock_tables(thd, tables)))
{
if ((result=new select_insert(tables->table,&lex->field_list,
lex->duplicates)))
+ /* Skip first table, which is the table we are inserting in */
+ lex->select_lex.table_list.first= (byte*) first_local_table->next;
+ lex->select_lex.resolve_mode= SELECT_LEX::NOMATTER_MODE;
res=handle_select(thd,lex,result);
+ /* revert changes for SP */
+ lex->select_lex.table_list.first= (byte*) first_local_table;
+ lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE;
if (thd->net.report_error)
res= -1;
}
@@ -2696,7 +2625,7 @@ unsent_create_error:
break;
}
case SQLCOM_TRUNCATE:
- if (check_one_table_access(thd, DELETE_ACL, tables, 0))
+ if (check_one_table_access(thd, DELETE_ACL, tables))
goto error;
/*
Don't allow this within a transaction because we want to use
@@ -2711,10 +2640,8 @@ unsent_create_error:
break;
case SQLCOM_DELETE:
{
- 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);
+ if ((res= delete_precheck(thd, tables)))
+ break;
res = mysql_delete(thd,tables, select_lex->where,
&select_lex->order_list,
select_lex->select_limit, select_lex->options);
@@ -2724,58 +2651,33 @@ unsent_create_error:
}
case SQLCOM_DELETE_MULTI:
{
- TABLE_LIST *aux_tables= (TABLE_LIST *)thd->lex->auxilliary_table_list.first;
- TABLE_LIST *auxi;
- uint table_count=0;
+ TABLE_LIST *aux_tables=
+ (TABLE_LIST *)thd->lex->auxilliary_table_list.first;
+ TABLE_LIST *target_tbl;
+ uint table_count;
multi_delete *result;
- /* sql_yacc guarantees that tables and aux_tables are not zero */
- if (check_db_used(thd, tables) || check_db_used(thd,aux_tables) ||
- check_table_access(thd,SELECT_ACL, tables,0) ||
- check_table_access(thd,DELETE_ACL, aux_tables,0))
- goto error;
- if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where)
- {
- send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
- goto error;
- }
- for (auxi=(TABLE_LIST*) aux_tables ; auxi ; auxi=auxi->next)
- {
- table_count++;
- /* All tables in aux_tables must be found in FROM PART */
- TABLE_LIST *walk;
- for (walk= (TABLE_LIST*) tables; walk; walk= walk->next)
- {
- if (!my_strcasecmp(table_alias_charset, auxi->alias, walk->alias) &&
- !strcmp(walk->db, auxi->db))
- break;
- }
- if (!walk)
- {
- net_printf(thd, ER_NONUNIQ_TABLE, auxi->real_name);
- goto error;
- }
- if (walk->derived)
- {
- net_printf(thd, ER_NON_UPDATABLE_TABLE,
- auxi->real_name, "DELETE");
- goto error;
- }
- walk->lock_type= auxi->lock_type;
- auxi->table_list= walk; // Remember corresponding table
- }
+ if ((res= multi_delete_precheck(thd, tables, &table_count)))
+ break;
+
+ /* condition will be TRUE on SP re-excuting */
+ if (select_lex->item_list.elements != 0)
+ select_lex->item_list.empty();
if (add_item_to_list(thd, new Item_null()))
{
res= -1;
break;
}
+
thd->proc_info="init";
if ((res=open_and_lock_tables(thd,tables)))
break;
/* Fix tables-to-be-deleted-from list to point at opened tables */
- for (auxi=(TABLE_LIST*) aux_tables ; auxi ; auxi=auxi->next)
+ for (target_tbl= (TABLE_LIST*) aux_tables;
+ target_tbl;
+ target_tbl= target_tbl->next)
{
- auxi->table= auxi->table_list->table;
+ target_tbl->table= target_tbl->table_list->table;
/*
Multi-delete can't be constructed over-union => we always have
single SELECT on top and have to check underlaying SELECTs of it
@@ -2785,10 +2687,11 @@ unsent_create_error:
un= un->next_unit())
{
if (un->first_select()->linkage != DERIVED_TABLE_TYPE &&
- un->check_updateable(auxi->table_list->db,
- auxi->table_list->real_name))
+ un->check_updateable(target_tbl->table_list->db,
+ target_tbl->table_list->real_name))
{
- my_error(ER_UPDATE_TABLE_USED, MYF(0), auxi->table_list->real_name);
+ my_error(ER_UPDATE_TABLE_USED, MYF(0),
+ target_tbl->table_list->real_name);
res= -1;
break;
}
@@ -2846,7 +2749,7 @@ unsent_create_error:
}
break;
case SQLCOM_DROP_INDEX:
- if (check_one_table_access(thd, INDEX_ACL, tables, 0))
+ if (check_one_table_access(thd, INDEX_ACL, tables))
goto error; /* purecov: inspected */
if (end_active_trans(thd))
res= -1;
@@ -2961,7 +2864,7 @@ unsent_create_error:
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))
+ if (grant_option && check_grant(thd, SELECT_ACL, tables, 2, UINT_MAX, 0))
goto error;
res= mysqld_show_fields(thd,tables,
(lex->wild ? lex->wild->ptr() : NullS),
@@ -2981,7 +2884,7 @@ unsent_create_error:
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))
+ if (grant_option && check_grant(thd, SELECT_ACL, tables, 2, UINT_MAX, 0))
goto error;
res= mysqld_show_keys(thd,tables);
break;
@@ -3009,7 +2912,7 @@ unsent_create_error:
send_error(thd,ER_NOT_ALLOWED_COMMAND);
goto error;
}
- if (check_one_table_access(thd, privilege, tables, 0))
+ if (check_one_table_access(thd, privilege, tables))
goto error;
}
res=mysql_load(thd, lex->exchange, tables, lex->field_list,
@@ -3273,7 +3176,7 @@ unsent_create_error:
if (grant_option && check_grant(thd,
(lex->grant | lex->grant_tot_col |
GRANT_ACL),
- tables,0,0))
+ tables, 0, UINT_MAX, 0))
goto error;
if (!(res = mysql_table_grant(thd,tables,lex->users_list, lex->columns,
lex->grant,
@@ -3768,33 +3671,26 @@ error:
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, error is sent to client
*/
-static int check_one_table_access(THD *thd, ulong privilege,
- TABLE_LIST *tables, bool no_errors)
+int check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *tables)
{
if (check_access(thd, privilege, tables->db, &tables->grant.privilege,0,0))
return 1;
- // Show only 1 table for check_grant
- TABLE_LIST *subselects_tables= tables->next;
- tables->next= 0;
- if (grant_option && check_grant(thd, privilege, tables, 0, 0))
- {
- tables->next= subselects_tables;
+ /* Show only 1 table for check_grant */
+ if (grant_option && check_grant(thd, privilege, tables, 0, 1, 0))
return 1;
- }
- // check rights on tables of subselect (if exists)
- if (subselects_tables)
+ /* Check rights on tables of subselect (if exists) */
+ TABLE_LIST *subselects_tables;
+ if ((subselects_tables= tables->next))
{
- tables->next= subselects_tables;
if ((check_table_access(thd, SELECT_ACL, subselects_tables,0)))
return 1;
}
@@ -3973,12 +3869,12 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
}
if (grant_option)
return check_grant(thd,want_access & ~EXTRA_ACL,org_tables,
- test(want_access & EXTRA_ACL), no_errors);
+ test(want_access & EXTRA_ACL), UINT_MAX, no_errors);
return FALSE;
}
-static bool check_merge_table_access(THD *thd, char *db,
- TABLE_LIST *table_list)
+bool check_merge_table_access(THD *thd, char *db,
+ TABLE_LIST *table_list)
{
int error=0;
if (table_list)
@@ -4135,9 +4031,7 @@ mysql_init_select(LEX *lex)
{
SELECT_LEX *select_lex= lex->current_select;
select_lex->init_select();
- select_lex->select_limit= (&lex->select_lex == select_lex) ?
- lex->thd->variables.select_limit : /* Primry UNION */
- HA_POS_ERROR; /* subquery */
+ select_lex->select_limit= HA_POS_ERROR;
if (select_lex == &lex->select_lex)
{
lex->exchange= 0;
@@ -4189,9 +4083,7 @@ 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->unit == unit) ?
- lex->thd->variables.select_limit : /* Primry UNION */
- HA_POS_ERROR; /* subquery */
+ fake->select_limit= HA_POS_ERROR;
}
}
@@ -4249,6 +4141,7 @@ void mysql_init_multi_delete(LEX *lex)
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");
@@ -4771,7 +4664,6 @@ static void remove_escape(char *name)
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))))
DBUG_RETURN(1);
@@ -5289,3 +5181,353 @@ Item * all_any_subquery_creator(Item *left_expr,
return it; /* ANY/SOME */
}
+
+
+/*
+ CREATE INDEX and DROP INDEX are implemented by calling ALTER TABLE with
+ the proper arguments. This isn't very fast but it should work for most
+ cases.
+
+ In the future ALTER TABLE will notice that only added indexes
+ and create these one by one for the existing table without having to do
+ a full rebuild.
+
+ One should normally create all indexes with CREATE TABLE or ALTER TABLE.
+*/
+
+int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys)
+{
+ List<create_field> fields;
+ List<Alter_drop> drop;
+ List<Alter_column> alter;
+ HA_CREATE_INFO create_info;
+ DBUG_ENTER("mysql_create_index");
+ bzero((char*) &create_info,sizeof(create_info));
+ create_info.db_type=DB_TYPE_DEFAULT;
+ create_info.default_table_charset= thd->variables.collation_database;
+ DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->real_name,
+ &create_info, table_list,
+ fields, keys, drop, alter, 0, (ORDER*)0,
+ ALTER_ADD_INDEX, DUP_ERROR));
+}
+
+
+int mysql_drop_index(THD *thd, TABLE_LIST *table_list, List<Alter_drop> &drop)
+{
+ List<create_field> fields;
+ List<Key> keys;
+ List<Alter_column> alter;
+ HA_CREATE_INFO create_info;
+ DBUG_ENTER("mysql_drop_index");
+ bzero((char*) &create_info,sizeof(create_info));
+ create_info.db_type=DB_TYPE_DEFAULT;
+ create_info.default_table_charset= thd->variables.collation_database;
+ DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->real_name,
+ &create_info, table_list,
+ fields, keys, drop, alter, 0, (ORDER*)0,
+ ALTER_DROP_INDEX, DUP_ERROR));
+}
+
+
+/*
+ Multi update query pre-check
+
+ SYNOPSIS
+ multi_update_precheck()
+ thd Thread handler
+ tables Global table list
+
+ RETURN VALUE
+ 0 OK
+ 1 Error (message is sent to user)
+ -1 Error (message is not sent to user)
+*/
+
+int multi_update_precheck(THD *thd, TABLE_LIST *tables)
+{
+ DBUG_ENTER("multi_update_precheck");
+ const char *msg= 0;
+ TABLE_LIST *table;
+ LEX *lex= thd->lex;
+ SELECT_LEX *select_lex= &lex->select_lex;
+ TABLE_LIST *update_list= (TABLE_LIST*)select_lex->table_list.first;
+
+ if (select_lex->item_list.elements != lex->value_list.elements)
+ {
+ my_error(ER_WRONG_VALUE_COUNT, MYF(0));
+ DBUG_RETURN(-1);
+ }
+ /*
+ Ensure that we have UPDATE or SELECT privilege for each table
+ The exact privilege is checked in mysql_multi_update()
+ */
+ for (table= update_list; table; table= table->next)
+ {
+ if ((check_access(thd, UPDATE_ACL, table->db,
+ &table->grant.privilege, 0, 1) ||
+ grant_option && check_grant(thd, UPDATE_ACL, table, 0, 1, 1)) &&
+ (check_access(thd, SELECT_ACL, table->db,
+ &table->grant.privilege, 0, 0) ||
+ grant_option && check_grant(thd, SELECT_ACL, table, 0, 1, 0)))
+ DBUG_RETURN(1);
+
+ /*
+ We assign following flag only to copy of table, because it will
+ be checked only if query contains subqueries i.e. only if copy exists
+ */
+ if (table->table_list)
+ table->table_list->table_in_update_from_clause= 1;
+ }
+ /*
+ Is there tables of subqueries?
+ */
+ if (&lex->select_lex != lex->all_selects_list)
+ {
+ for (table= tables; table; table= table->next)
+ {
+ if (table->table_in_update_from_clause)
+ {
+ /*
+ If we check table by local TABLE_LIST copy then we should copy
+ grants to global table list, because it will be used for table
+ opening.
+ */
+ if (table->table_list)
+ table->grant= table->table_list->grant;
+ }
+ else
+ {
+ if (check_access(thd, SELECT_ACL, table->db,
+ &table->grant.privilege, 0, 0) ||
+ grant_option && check_grant(thd, SELECT_ACL, table, 0, 1, 0))
+ DBUG_RETURN(1);
+ }
+ }
+ }
+
+ 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)
+ {
+ my_error(ER_WRONG_USAGE, MYF(0), "UPDATE", msg);
+ DBUG_RETURN(-1);
+ }
+ DBUG_RETURN(0);
+}
+
+/*
+ Multi delete query pre-check
+
+ SYNOPSIS
+ multi_delete_precheck()
+ thd Thread handler
+ tables Global table list
+ table_count Pointer to table counter
+
+ RETURN VALUE
+ 0 OK
+ 1 error (message is sent to user)
+ -1 error (message is not sent to user)
+*/
+int multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count)
+{
+ DBUG_ENTER("multi_delete_precheck");
+ SELECT_LEX *select_lex= &thd->lex->select_lex;
+ TABLE_LIST *aux_tables=
+ (TABLE_LIST *)thd->lex->auxilliary_table_list.first;
+ TABLE_LIST *delete_tables= (TABLE_LIST *)select_lex->table_list.first;
+ TABLE_LIST *target_tbl;
+
+ *table_count= 0;
+
+ /* sql_yacc guarantees that tables and aux_tables are not zero */
+ DBUG_ASSERT(aux_tables != 0);
+ if (check_db_used(thd, tables) || check_db_used(thd,aux_tables) ||
+ check_table_access(thd,SELECT_ACL, tables,0) ||
+ check_table_access(thd,DELETE_ACL, aux_tables,0))
+ DBUG_RETURN(1);
+ if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where)
+ {
+ my_error(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE, MYF(0));
+ DBUG_RETURN(-1);
+ }
+ for (target_tbl= aux_tables; target_tbl; target_tbl= target_tbl->next)
+ {
+ (*table_count)++;
+ /* All tables in aux_tables must be found in FROM PART */
+ TABLE_LIST *walk;
+ for (walk= delete_tables; walk; walk= walk->next)
+ {
+ if (!my_strcasecmp(table_alias_charset,
+ target_tbl->alias, walk->alias) &&
+ !strcmp(walk->db, target_tbl->db))
+ break;
+ }
+ if (!walk)
+ {
+ my_error(ER_UNKNOWN_TABLE, MYF(0), target_tbl->real_name,
+ "MULTI DELETE");
+ DBUG_RETURN(-1);
+ }
+ if (walk->derived)
+ {
+ my_error(ER_NON_UPDATABLE_TABLE, MYF(0), target_tbl->real_name,
+ "DELETE");
+ DBUG_RETURN(-1);
+ }
+ walk->lock_type= target_tbl->lock_type;
+ target_tbl->table_list= walk; // Remember corresponding table
+ }
+ DBUG_RETURN(0);
+}
+
+
+/*
+ INSERT ... SELECT query pre-check
+
+ SYNOPSIS
+ multi_delete_precheck()
+ thd Thread handler
+ tables Global table list
+
+ RETURN VALUE
+ 0 OK
+ 1 Error (message is sent to user)
+ -1 Error (message is not sent to user)
+*/
+
+int insert_select_precheck(THD *thd, TABLE_LIST *tables)
+{
+ DBUG_ENTER("insert_select_precheck");
+ /*
+ Check that we have modify privileges for the first table and
+ select privileges for the rest
+ */
+ ulong privilege= (thd->lex->duplicates == DUP_REPLACE ?
+ INSERT_ACL | DELETE_ACL : INSERT_ACL);
+ DBUG_RETURN(check_one_table_access(thd, privilege, tables) ? 1 : 0);
+}
+
+
+/*
+ simple UPDATE query pre-check
+
+ SYNOPSIS
+ update_precheck()
+ thd Thread handler
+ tables Global table list
+
+ RETURN VALUE
+ 0 OK
+ 1 Error (message is sent to user)
+ -1 Error (message is not sent to user)
+*/
+
+int update_precheck(THD *thd, TABLE_LIST *tables)
+{
+ DBUG_ENTER("update_precheck");
+ if (thd->lex->select_lex.item_list.elements != thd->lex->value_list.elements)
+ {
+ my_error(ER_WRONG_VALUE_COUNT, MYF(0));
+ DBUG_RETURN(-1);
+ }
+ DBUG_RETURN((check_db_used(thd, tables) ||
+ check_one_table_access(thd, UPDATE_ACL, tables)) ? 1 : 0);
+}
+
+
+/*
+ simple DELETE query pre-check
+
+ SYNOPSIS
+ delete_precheck()
+ thd Thread handler
+ tables Global table list
+
+ RETURN VALUE
+ 0 OK
+ 1 error (message is sent to user)
+ -1 error (message is not sent to user)
+*/
+
+int delete_precheck(THD *thd, TABLE_LIST *tables)
+{
+ DBUG_ENTER("delete_precheck");
+ if (check_one_table_access(thd, DELETE_ACL, tables))
+ DBUG_RETURN(1);
+ /* Set privilege for the WHERE clause */
+ tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
+ DBUG_RETURN(0);
+}
+
+
+/*
+ simple INSERT query pre-check
+
+ SYNOPSIS
+ insert_precheck()
+ thd Thread handler
+ tables Global table list
+
+ RETURN VALUE
+ 0 OK
+ 1 error (message is sent to user)
+ -1 error (message is not sent to user)
+*/
+
+int insert_precheck(THD *thd, TABLE_LIST *tables, bool update)
+{
+ LEX *lex= thd->lex;
+ DBUG_ENTER("insert_precheck");
+
+ ulong privilege= (lex->duplicates == DUP_REPLACE ?
+ INSERT_ACL | DELETE_ACL : INSERT_ACL | update);
+
+ if (check_one_table_access(thd, privilege, tables))
+ DBUG_RETURN(1);
+
+ if (lex->select_lex.item_list.elements != lex->value_list.elements)
+ {
+ my_error(ER_WRONG_VALUE_COUNT, MYF(0));
+ DBUG_RETURN(-1);
+ }
+ DBUG_RETURN(0);
+}
+
+
+/*
+ CREATE TABLE query pre-check
+
+ SYNOPSIS
+ create_table_precheck()
+ thd Thread handler
+ tables Global table list
+ create_table Table which will be created
+
+ RETURN VALUE
+ 0 OK
+ 1 Error (message is sent to user)
+ -1 Error (message is not sent to user)
+*/
+
+int create_table_precheck(THD *thd, TABLE_LIST *tables,
+ TABLE_LIST *create_table)
+{
+ LEX *lex= thd->lex;
+ DBUG_ENTER("create_table_precheck");
+ 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))
+ DBUG_RETURN(1);
+ DBUG_RETURN((grant_option && want_priv != CREATE_TMP_ACL &&
+ check_grant(thd, want_priv, create_table, 0, UINT_MAX, 0)) ?
+ 1 : 0);
+}