2003-06-23 19:03:59 +02:00
|
|
|
/* Copyright (C) 2000-2003 MySQL AB
|
2001-12-06 13:10:51 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
2006-12-23 20:17:15 +01:00
|
|
|
the Free Software Foundation; version 2 of the License.
|
2001-12-06 13:10:51 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
2001-12-06 13:10:51 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
The privileges are saved in the following tables:
|
2004-10-07 00:45:06 +02:00
|
|
|
mysql/user ; super user who are allowed to do almost anything
|
|
|
|
mysql/host ; host privileges. This is used if host is empty in mysql/db.
|
2000-07-31 21:29:14 +02:00
|
|
|
mysql/db ; database privileges / user
|
|
|
|
|
|
|
|
data in tables is sorted according to how many not-wild-cards there is
|
|
|
|
in the relevant fields. Empty strings comes last.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "mysql_priv.h"
|
|
|
|
#include "hash_filo.h"
|
|
|
|
#include <m_ctype.h>
|
|
|
|
#include <stdarg.h>
|
2004-12-23 11:46:24 +01:00
|
|
|
#include "sp_head.h"
|
|
|
|
#include "sp.h"
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2009-11-21 12:18:21 +01:00
|
|
|
static const
|
|
|
|
TABLE_FIELD_TYPE mysql_db_table_fields[MYSQL_DB_FIELD_COUNT] = {
|
2006-02-14 16:20:48 +01:00
|
|
|
{
|
2006-08-17 18:13:45 +02:00
|
|
|
{ C_STRING_WITH_LEN("Host") },
|
|
|
|
{ C_STRING_WITH_LEN("char(60)") },
|
2006-02-14 16:20:48 +01:00
|
|
|
{NULL, 0}
|
|
|
|
},
|
|
|
|
{
|
2006-08-17 18:13:45 +02:00
|
|
|
{ C_STRING_WITH_LEN("Db") },
|
|
|
|
{ C_STRING_WITH_LEN("char(64)") },
|
2006-02-14 16:20:48 +01:00
|
|
|
{NULL, 0}
|
|
|
|
},
|
|
|
|
{
|
2006-08-17 18:13:45 +02:00
|
|
|
{ C_STRING_WITH_LEN("User") },
|
|
|
|
{ C_STRING_WITH_LEN("char(16)") },
|
2006-02-14 16:20:48 +01:00
|
|
|
{NULL, 0}
|
|
|
|
},
|
|
|
|
{
|
2006-08-17 18:13:45 +02:00
|
|
|
{ C_STRING_WITH_LEN("Select_priv") },
|
|
|
|
{ C_STRING_WITH_LEN("enum('N','Y')") },
|
|
|
|
{ C_STRING_WITH_LEN("utf8") }
|
2006-02-14 16:20:48 +01:00
|
|
|
},
|
|
|
|
{
|
2006-08-17 18:13:45 +02:00
|
|
|
{ C_STRING_WITH_LEN("Insert_priv") },
|
|
|
|
{ C_STRING_WITH_LEN("enum('N','Y')") },
|
|
|
|
{ C_STRING_WITH_LEN("utf8") }
|
2006-02-14 16:20:48 +01:00
|
|
|
},
|
|
|
|
{
|
2006-08-17 18:13:45 +02:00
|
|
|
{ C_STRING_WITH_LEN("Update_priv") },
|
|
|
|
{ C_STRING_WITH_LEN("enum('N','Y')") },
|
|
|
|
{ C_STRING_WITH_LEN("utf8") }
|
2006-02-14 16:20:48 +01:00
|
|
|
},
|
|
|
|
{
|
2006-08-17 18:13:45 +02:00
|
|
|
{ C_STRING_WITH_LEN("Delete_priv") },
|
|
|
|
{ C_STRING_WITH_LEN("enum('N','Y')") },
|
|
|
|
{ C_STRING_WITH_LEN("utf8") }
|
2006-02-14 16:20:48 +01:00
|
|
|
},
|
|
|
|
{
|
2006-08-17 18:13:45 +02:00
|
|
|
{ C_STRING_WITH_LEN("Create_priv") },
|
|
|
|
{ C_STRING_WITH_LEN("enum('N','Y')") },
|
|
|
|
{ C_STRING_WITH_LEN("utf8") }
|
2006-02-14 16:20:48 +01:00
|
|
|
},
|
|
|
|
{
|
2006-08-17 18:13:45 +02:00
|
|
|
{ C_STRING_WITH_LEN("Drop_priv") },
|
|
|
|
{ C_STRING_WITH_LEN("enum('N','Y')") },
|
|
|
|
{ C_STRING_WITH_LEN("utf8") }
|
2006-02-14 16:20:48 +01:00
|
|
|
},
|
|
|
|
{
|
2006-08-17 18:13:45 +02:00
|
|
|
{ C_STRING_WITH_LEN("Grant_priv") },
|
|
|
|
{ C_STRING_WITH_LEN("enum('N','Y')") },
|
|
|
|
{ C_STRING_WITH_LEN("utf8") }
|
2006-02-14 16:20:48 +01:00
|
|
|
},
|
|
|
|
{
|
2006-08-17 18:13:45 +02:00
|
|
|
{ C_STRING_WITH_LEN("References_priv") },
|
|
|
|
{ C_STRING_WITH_LEN("enum('N','Y')") },
|
|
|
|
{ C_STRING_WITH_LEN("utf8") }
|
2006-02-14 16:20:48 +01:00
|
|
|
},
|
|
|
|
{
|
2006-08-17 18:13:45 +02:00
|
|
|
{ C_STRING_WITH_LEN("Index_priv") },
|
|
|
|
{ C_STRING_WITH_LEN("enum('N','Y')") },
|
|
|
|
{ C_STRING_WITH_LEN("utf8") }
|
2006-02-14 16:20:48 +01:00
|
|
|
},
|
|
|
|
{
|
2006-08-17 18:13:45 +02:00
|
|
|
{ C_STRING_WITH_LEN("Alter_priv") },
|
|
|
|
{ C_STRING_WITH_LEN("enum('N','Y')") },
|
|
|
|
{ C_STRING_WITH_LEN("utf8") }
|
2006-02-14 16:20:48 +01:00
|
|
|
},
|
|
|
|
{
|
2006-08-17 18:13:45 +02:00
|
|
|
{ C_STRING_WITH_LEN("Create_tmp_table_priv") },
|
|
|
|
{ C_STRING_WITH_LEN("enum('N','Y')") },
|
|
|
|
{ C_STRING_WITH_LEN("utf8") }
|
2006-02-14 16:20:48 +01:00
|
|
|
},
|
|
|
|
{
|
2006-08-17 18:13:45 +02:00
|
|
|
{ C_STRING_WITH_LEN("Lock_tables_priv") },
|
|
|
|
{ C_STRING_WITH_LEN("enum('N','Y')") },
|
|
|
|
{ C_STRING_WITH_LEN("utf8") }
|
2006-02-14 16:20:48 +01:00
|
|
|
},
|
|
|
|
{
|
2006-08-17 18:13:45 +02:00
|
|
|
{ C_STRING_WITH_LEN("Create_view_priv") },
|
|
|
|
{ C_STRING_WITH_LEN("enum('N','Y')") },
|
|
|
|
{ C_STRING_WITH_LEN("utf8") }
|
2006-02-14 16:20:48 +01:00
|
|
|
},
|
|
|
|
{
|
2006-08-17 18:13:45 +02:00
|
|
|
{ C_STRING_WITH_LEN("Show_view_priv") },
|
|
|
|
{ C_STRING_WITH_LEN("enum('N','Y')") },
|
|
|
|
{ C_STRING_WITH_LEN("utf8") }
|
2006-02-14 16:20:48 +01:00
|
|
|
},
|
|
|
|
{
|
2006-08-17 18:13:45 +02:00
|
|
|
{ C_STRING_WITH_LEN("Create_routine_priv") },
|
|
|
|
{ C_STRING_WITH_LEN("enum('N','Y')") },
|
|
|
|
{ C_STRING_WITH_LEN("utf8") }
|
2006-02-14 16:20:48 +01:00
|
|
|
},
|
|
|
|
{
|
2006-08-17 18:13:45 +02:00
|
|
|
{ C_STRING_WITH_LEN("Alter_routine_priv") },
|
|
|
|
{ C_STRING_WITH_LEN("enum('N','Y')") },
|
|
|
|
{ C_STRING_WITH_LEN("utf8") }
|
2006-02-14 16:20:48 +01:00
|
|
|
},
|
|
|
|
{
|
2006-08-17 18:13:45 +02:00
|
|
|
{ C_STRING_WITH_LEN("Execute_priv") },
|
|
|
|
{ C_STRING_WITH_LEN("enum('N','Y')") },
|
|
|
|
{ C_STRING_WITH_LEN("utf8") }
|
2006-02-14 16:20:48 +01:00
|
|
|
},
|
|
|
|
{
|
2006-08-17 18:13:45 +02:00
|
|
|
{ C_STRING_WITH_LEN("Event_priv") },
|
|
|
|
{ C_STRING_WITH_LEN("enum('N','Y')") },
|
|
|
|
{ C_STRING_WITH_LEN("utf8") }
|
2006-02-14 16:20:48 +01:00
|
|
|
},
|
|
|
|
{
|
2006-08-17 18:13:45 +02:00
|
|
|
{ C_STRING_WITH_LEN("Trigger_priv") },
|
|
|
|
{ C_STRING_WITH_LEN("enum('N','Y')") },
|
|
|
|
{ C_STRING_WITH_LEN("utf8") }
|
2006-02-14 16:20:48 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2009-11-21 12:18:21 +01:00
|
|
|
const TABLE_FIELD_DEF
|
|
|
|
mysql_db_table_def= {MYSQL_DB_FIELD_COUNT, mysql_db_table_fields};
|
2006-02-14 16:20:48 +01:00
|
|
|
|
2006-02-14 22:21:23 +01:00
|
|
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
|
|
|
|
|
|
|
#define FIRST_NON_YN_FIELD 26
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
class acl_entry :public hash_filo_element
|
|
|
|
{
|
|
|
|
public:
|
2002-06-12 14:04:18 +02:00
|
|
|
ulong access;
|
2000-07-31 21:29:14 +02:00
|
|
|
uint16 length;
|
|
|
|
char key[1]; // Key will be stored here
|
|
|
|
};
|
|
|
|
|
2002-06-12 14:04:18 +02:00
|
|
|
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
static uchar* acl_entry_get_key(acl_entry *entry, size_t *length,
|
|
|
|
my_bool not_used __attribute__((unused)))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
*length=(uint) entry->length;
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
return (uchar*) entry->key;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2003-12-21 21:18:59 +01:00
|
|
|
#define IP_ADDR_STRLEN (3+1+3+1+3+1+3)
|
2006-09-27 16:21:29 +02:00
|
|
|
#define ACL_KEY_LENGTH (IP_ADDR_STRLEN+1+NAME_LEN+1+USERNAME_LENGTH+1)
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
static DYNAMIC_ARRAY acl_hosts,acl_users,acl_dbs;
|
|
|
|
static MEM_ROOT mem, memex;
|
|
|
|
static bool initialized=0;
|
|
|
|
static bool allow_all_hosts=1;
|
2005-05-17 20:54:20 +02:00
|
|
|
static HASH acl_check_hosts, column_priv_hash, proc_priv_hash, func_priv_hash;
|
2000-07-31 21:29:14 +02:00
|
|
|
static DYNAMIC_ARRAY acl_wild_hosts;
|
|
|
|
static hash_filo *acl_cache;
|
2005-09-01 21:25:29 +02:00
|
|
|
static uint grant_version=0; /* Version of priv tables. incremented by acl_load */
|
2004-07-19 16:01:53 +02:00
|
|
|
static ulong get_access(TABLE *form,uint fieldnr, uint *next_field=0);
|
2000-07-31 21:29:14 +02:00
|
|
|
static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b);
|
|
|
|
static ulong get_sort(uint count,...);
|
|
|
|
static void init_check_host(void);
|
2005-12-28 14:43:50 +01:00
|
|
|
static void rebuild_check_host(void);
|
2005-08-23 00:48:50 +02:00
|
|
|
static ACL_USER *find_acl_user(const char *host, const char *user,
|
|
|
|
my_bool exact);
|
2005-09-01 14:52:59 +02:00
|
|
|
static bool update_user_table(THD *thd, TABLE *table,
|
|
|
|
const char *host, const char *user,
|
2003-07-01 21:40:59 +02:00
|
|
|
const char *new_password, uint new_password_len);
|
2000-07-31 21:29:14 +02:00
|
|
|
static void update_hostname(acl_host_and_ip *host, const char *hostname);
|
2003-04-29 00:15:18 +02:00
|
|
|
static bool compare_hostname(const acl_host_and_ip *host,const char *hostname,
|
2000-07-31 21:29:14 +02:00
|
|
|
const char *ip);
|
2005-09-01 14:52:59 +02:00
|
|
|
static my_bool acl_load(THD *thd, TABLE_LIST *tables);
|
2008-02-24 13:58:07 +01:00
|
|
|
static my_bool grant_load(THD *thd, TABLE_LIST *tables);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2003-07-01 21:40:59 +02:00
|
|
|
/*
|
|
|
|
Convert scrambled password to binary form, according to scramble type,
|
|
|
|
Binary form is stored in user.salt.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static
|
|
|
|
void
|
|
|
|
set_user_salt(ACL_USER *acl_user, const char *password, uint password_len)
|
|
|
|
{
|
|
|
|
if (password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH)
|
|
|
|
{
|
|
|
|
get_salt_from_password(acl_user->salt, password);
|
|
|
|
acl_user->salt_len= SCRAMBLE_LENGTH;
|
|
|
|
}
|
2003-07-08 00:36:14 +02:00
|
|
|
else if (password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
|
2003-07-01 21:40:59 +02:00
|
|
|
{
|
|
|
|
get_salt_from_password_323((ulong *) acl_user->salt, password);
|
2003-07-08 00:36:14 +02:00
|
|
|
acl_user->salt_len= SCRAMBLE_LENGTH_323;
|
2003-07-01 21:40:59 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
acl_user->salt_len= 0;
|
|
|
|
}
|
|
|
|
|
2003-07-08 00:36:14 +02:00
|
|
|
/*
|
|
|
|
This after_update function is used when user.password is less than
|
|
|
|
SCRAMBLE_LENGTH bytes.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void restrict_update_of_old_passwords_var(THD *thd,
|
|
|
|
enum_var_type var_type)
|
|
|
|
{
|
|
|
|
if (var_type == OPT_GLOBAL)
|
|
|
|
{
|
|
|
|
pthread_mutex_lock(&LOCK_global_system_variables);
|
|
|
|
global_system_variables.old_passwords= 1;
|
|
|
|
pthread_mutex_unlock(&LOCK_global_system_variables);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
thd->variables.old_passwords= 1;
|
|
|
|
}
|
|
|
|
|
2003-07-01 21:40:59 +02:00
|
|
|
|
2002-09-05 15:17:08 +02:00
|
|
|
/*
|
2005-09-01 14:52:59 +02:00
|
|
|
Initialize structures responsible for user/db-level privilege checking and
|
|
|
|
load privilege information for them from tables in the 'mysql' database.
|
2002-09-05 15:17:08 +02:00
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
acl_init()
|
2005-09-01 14:52:59 +02:00
|
|
|
dont_read_acl_tables TRUE if we want to skip loading data from
|
|
|
|
privilege tables and disable privilege checking.
|
|
|
|
|
|
|
|
NOTES
|
|
|
|
This function is mostly responsible for preparatory steps, main work
|
|
|
|
on initialization and grants loading is done in acl_reload().
|
2002-09-05 15:17:08 +02:00
|
|
|
|
|
|
|
RETURN VALUES
|
|
|
|
0 ok
|
|
|
|
1 Could not initialize grant's
|
|
|
|
*/
|
|
|
|
|
2005-09-01 14:52:59 +02:00
|
|
|
my_bool acl_init(bool dont_read_acl_tables)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2002-10-29 20:59:03 +01:00
|
|
|
THD *thd;
|
2005-09-01 14:52:59 +02:00
|
|
|
my_bool return_val;
|
2000-07-31 21:29:14 +02:00
|
|
|
DBUG_ENTER("acl_init");
|
|
|
|
|
2005-09-01 14:52:59 +02:00
|
|
|
acl_cache= new hash_filo(ACL_CACHE_SIZE, 0, 0,
|
2009-10-14 18:37:38 +02:00
|
|
|
(my_hash_get_key) acl_entry_get_key,
|
|
|
|
(my_hash_free_key) free,
|
2009-10-27 09:09:19 +01:00
|
|
|
&my_charset_utf8_bin);
|
2000-07-31 21:29:14 +02:00
|
|
|
if (dont_read_acl_tables)
|
2002-10-19 21:18:31 +02:00
|
|
|
{
|
2000-07-31 21:29:14 +02:00
|
|
|
DBUG_RETURN(0); /* purecov: tested */
|
2002-11-30 18:58:53 +01:00
|
|
|
}
|
|
|
|
|
2002-09-05 15:17:08 +02:00
|
|
|
/*
|
|
|
|
To be able to run this from boot, we allocate a temporary THD
|
|
|
|
*/
|
2000-07-31 21:29:14 +02:00
|
|
|
if (!(thd=new THD))
|
|
|
|
DBUG_RETURN(1); /* purecov: inspected */
|
2005-11-23 19:18:10 +01:00
|
|
|
thd->thread_stack= (char*) &thd;
|
2002-09-05 15:17:08 +02:00
|
|
|
thd->store_globals();
|
2005-09-01 14:52:59 +02:00
|
|
|
/*
|
|
|
|
It is safe to call acl_reload() since acl_* arrays and hashes which
|
|
|
|
will be freed there are global static objects and thus are initialized
|
|
|
|
by zeros at startup.
|
|
|
|
*/
|
|
|
|
return_val= acl_reload(thd);
|
|
|
|
delete thd;
|
|
|
|
/* Remember that we don't have a THD */
|
|
|
|
my_pthread_setspecific_ptr(THR_THD, 0);
|
|
|
|
DBUG_RETURN(return_val);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Initialize structures responsible for user/db-level privilege checking
|
|
|
|
and load information about grants from open privilege tables.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
acl_load()
|
|
|
|
thd Current thread
|
|
|
|
tables List containing open "mysql.host", "mysql.user" and
|
|
|
|
"mysql.db" tables.
|
|
|
|
|
|
|
|
RETURN VALUES
|
|
|
|
FALSE Success
|
|
|
|
TRUE Error
|
|
|
|
*/
|
|
|
|
|
|
|
|
static my_bool acl_load(THD *thd, TABLE_LIST *tables)
|
|
|
|
{
|
|
|
|
TABLE *table;
|
|
|
|
READ_RECORD read_record_info;
|
|
|
|
my_bool return_val= 1;
|
|
|
|
bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE;
|
2006-09-27 16:21:29 +02:00
|
|
|
char tmp_name[NAME_LEN+1];
|
2005-09-21 01:57:58 +02:00
|
|
|
int password_length;
|
2008-02-24 13:58:07 +01:00
|
|
|
ulong old_sql_mode= thd->variables.sql_mode;
|
2005-09-01 14:52:59 +02:00
|
|
|
DBUG_ENTER("acl_load");
|
|
|
|
|
2008-02-24 13:58:07 +01:00
|
|
|
thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH;
|
|
|
|
|
2005-09-01 21:25:29 +02:00
|
|
|
grant_version++; /* Privileges updated */
|
2002-09-05 15:17:08 +02:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
acl_cache->clear(1); // Clear locked hostname cache
|
|
|
|
|
2003-10-11 21:00:24 +02:00
|
|
|
init_sql_alloc(&mem, ACL_ALLOC_BLOCK_SIZE, 0);
|
2008-07-15 16:13:21 +02:00
|
|
|
init_read_record(&read_record_info,thd,table= tables[0].table,NULL,1,0,
|
|
|
|
FALSE);
|
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes
Changes that requires code changes in other code of other storage engines.
(Note that all changes are very straightforward and one should find all issues
by compiling a --debug build and fixing all compiler errors and all
asserts in field.cc while running the test suite),
- New optional handler function introduced: reset()
This is called after every DML statement to make it easy for a handler to
statement specific cleanups.
(The only case it's not called is if force the file to be closed)
- handler::extra(HA_EXTRA_RESET) is removed. Code that was there before
should be moved to handler::reset()
- table->read_set contains a bitmap over all columns that are needed
in the query. read_row() and similar functions only needs to read these
columns
- table->write_set contains a bitmap over all columns that will be updated
in the query. write_row() and update_row() only needs to update these
columns.
The above bitmaps should now be up to date in all context
(including ALTER TABLE, filesort()).
The handler is informed of any changes to the bitmap after
fix_fields() by calling the virtual function
handler::column_bitmaps_signal(). If the handler does caching of
these bitmaps (instead of using table->read_set, table->write_set),
it should redo the caching in this code. as the signal() may be sent
several times, it's probably best to set a variable in the signal
and redo the caching on read_row() / write_row() if the variable was
set.
- Removed the read_set and write_set bitmap objects from the handler class
- Removed all column bit handling functions from the handler class.
(Now one instead uses the normal bitmap functions in my_bitmap.c instead
of handler dedicated bitmap functions)
- field->query_id is removed. One should instead instead check
table->read_set and table->write_set if a field is used in the query.
- handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and
handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now
instead use table->read_set to check for which columns to retrieve.
- If a handler needs to call Field->val() or Field->store() on columns
that are not used in the query, one should install a temporary
all-columns-used map while doing so. For this, we provide the following
functions:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
field->val();
dbug_tmp_restore_column_map(table->read_set, old_map);
and similar for the write map:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
field->val();
dbug_tmp_restore_column_map(table->write_set, old_map);
If this is not done, you will sooner or later hit a DBUG_ASSERT
in the field store() / val() functions.
(For not DBUG binaries, the dbug_tmp_restore_column_map() and
dbug_tmp_restore_column_map() are inline dummy functions and should
be optimized away be the compiler).
- If one needs to temporary set the column map for all binaries (and not
just to avoid the DBUG_ASSERT() in the Field::store() / Field::val()
methods) one should use the functions tmp_use_all_columns() and
tmp_restore_column_map() instead of the above dbug_ variants.
- All 'status' fields in the handler base class (like records,
data_file_length etc) are now stored in a 'stats' struct. This makes
it easier to know what status variables are provided by the base
handler. This requires some trivial variable names in the extra()
function.
- New virtual function handler::records(). This is called to optimize
COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true.
(stats.records is not supposed to be an exact value. It's only has to
be 'reasonable enough' for the optimizer to be able to choose a good
optimization path).
- Non virtual handler::init() function added for caching of virtual
constants from engine.
- Removed has_transactions() virtual method. Now one should instead return
HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support
transactions.
- The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument
that is to be used with 'new handler_name()' to allocate the handler
in the right area. The xxxx_create_handler() function is also
responsible for any initialization of the object before returning.
For example, one should change:
static handler *myisam_create_handler(TABLE_SHARE *table)
{
return new ha_myisam(table);
}
->
static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisam(table);
}
- New optional virtual function: use_hidden_primary_key().
This is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key. This allows the handler to take precisions
in remembering any hidden primary key to able to update/delete any
found row. The default handler marks all columns to be read.
- handler::table_flags() now returns a ulonglong (to allow for more flags).
- New/changed table_flags()
- HA_HAS_RECORDS Set if ::records() is supported
- HA_NO_TRANSACTIONS Set if engine doesn't support transactions
- HA_PRIMARY_KEY_REQUIRED_FOR_DELETE
Set if we should mark all primary key columns for
read when reading rows as part of a DELETE
statement. If there is no primary key,
all columns are marked for read.
- HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some
cases (based on table->read_set)
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
- HA_DUPP_POS Renamed to HA_DUPLICATE_POS
- HA_REQUIRES_KEY_COLUMNS_FOR_DELETE
Set this if we should mark ALL key columns for
read when when reading rows as part of a DELETE
statement. In case of an update we will mark
all keys for read for which key part changed
value.
- HA_STATS_RECORDS_IS_EXACT
Set this if stats.records is exact.
(This saves us some extra records() calls
when optimizing COUNT(*))
- Removed table_flags()
- HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if
handler::records() gives an exact count() and
HA_STATS_RECORDS_IS_EXACT if stats.records is exact.
- HA_READ_RND_SAME Removed (no one supported this one)
- Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk()
- Renamed handler::dupp_pos to handler::dup_pos
- Removed not used variable handler::sortkey
Upper level handler changes:
- ha_reset() now does some overall checks and calls ::reset()
- ha_table_flags() added. This is a cached version of table_flags(). The
cache is updated on engine creation time and updated on open.
MySQL level changes (not obvious from the above):
- DBUG_ASSERT() added to check that column usage matches what is set
in the column usage bit maps. (This found a LOT of bugs in current
column marking code).
- In 5.1 before, all used columns was marked in read_set and only updated
columns was marked in write_set. Now we only mark columns for which we
need a value in read_set.
- Column bitmaps are created in open_binary_frm() and open_table_from_share().
(Before this was in table.cc)
- handler::table_flags() calls are replaced with handler::ha_table_flags()
- For calling field->val() you must have the corresponding bit set in
table->read_set. For calling field->store() you must have the
corresponding bit set in table->write_set. (There are asserts in
all store()/val() functions to catch wrong usage)
- thd->set_query_id is renamed to thd->mark_used_columns and instead
of setting this to an integer value, this has now the values:
MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE
Changed also all variables named 'set_query_id' to mark_used_columns.
- In filesort() we now inform the handler of exactly which columns are needed
doing the sort and choosing the rows.
- The TABLE_SHARE object has a 'all_set' column bitmap one can use
when one needs a column bitmap with all columns set.
(This is used for table->use_all_columns() and other places)
- The TABLE object has 3 column bitmaps:
- def_read_set Default bitmap for columns to be read
- def_write_set Default bitmap for columns to be written
- tmp_set Can be used as a temporary bitmap when needed.
The table object has also two pointer to bitmaps read_set and write_set
that the handler should use to find out which columns are used in which way.
- count() optimization now calls handler::records() instead of using
handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true).
- Added extra argument to Item::walk() to indicate if we should also
traverse sub queries.
- Added TABLE parameter to cp_buffer_from_ref()
- Don't close tables created with CREATE ... SELECT but keep them in
the table cache. (Faster usage of newly created tables).
New interfaces:
- table->clear_column_bitmaps() to initialize the bitmaps for tables
at start of new statements.
- table->column_bitmaps_set() to set up new column bitmaps and signal
the handler about this.
- table->column_bitmaps_set_no_signal() for some few cases where we need
to setup new column bitmaps but don't signal the handler (as the handler
has already been signaled about these before). Used for the momement
only in opt_range.cc when doing ROR scans.
- table->use_all_columns() to install a bitmap where all columns are marked
as use in the read and the write set.
- table->default_column_bitmaps() to install the normal read and write
column bitmaps, but not signaling the handler about this.
This is mainly used when creating TABLE instances.
- table->mark_columns_needed_for_delete(),
table->mark_columns_needed_for_delete() and
table->mark_columns_needed_for_insert() to allow us to put additional
columns in column usage maps if handler so requires.
(The handler indicates what it neads in handler->table_flags())
- table->prepare_for_position() to allow us to tell handler that it
needs to read primary key parts to be able to store them in
future table->position() calls.
(This replaces the table->file->ha_retrieve_all_pk function)
- table->mark_auto_increment_column() to tell handler are going to update
columns part of any auto_increment key.
- table->mark_columns_used_by_index() to mark all columns that is part of
an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow
it to quickly know that it only needs to read colums that are part
of the key. (The handler can also use the column map for detecting this,
but simpler/faster handler can just monitor the extra() call).
- table->mark_columns_used_by_index_no_reset() to in addition to other columns,
also mark all columns that is used by the given key.
- table->restore_column_maps_after_mark_index() to restore to default
column maps after a call to table->mark_columns_used_by_index().
- New item function register_field_in_read_map(), for marking used columns
in table->read_map. Used by filesort() to mark all used columns
- Maintain in TABLE->merge_keys set of all keys that are used in query.
(Simplices some optimization loops)
- Maintain Field->part_of_key_not_clustered which is like Field->part_of_key
but the field in the clustered key is not assumed to be part of all index.
(used in opt_range.cc for faster loops)
- dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map()
tmp_use_all_columns() and tmp_restore_column_map() functions to temporally
mark all columns as usable. The 'dbug_' version is primarily intended
inside a handler when it wants to just call Field:store() & Field::val()
functions, but don't need the column maps set for any other usage.
(ie:: bitmap_is_set() is never called)
- We can't use compare_records() to skip updates for handlers that returns
a partial column set and the read_set doesn't cover all columns in the
write set. The reason for this is that if we have a column marked only for
write we can't in the MySQL level know if the value changed or not.
The reason this worked before was that MySQL marked all to be written
columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden
bug'.
- open_table_from_share() does not anymore setup temporary MEM_ROOT
object as a thread specific variable for the handler. Instead we
send the to-be-used MEMROOT to get_new_handler().
(Simpler, faster code)
Bugs fixed:
- Column marking was not done correctly in a lot of cases.
(ALTER TABLE, when using triggers, auto_increment fields etc)
(Could potentially result in wrong values inserted in table handlers
relying on that the old column maps or field->set_query_id was correct)
Especially when it comes to triggers, there may be cases where the
old code would cause lost/wrong values for NDB and/or InnoDB tables.
- Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags:
OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG.
This allowed me to remove some wrong warnings about:
"Some non-transactional changed tables couldn't be rolled back"
- Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset
(thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose
some warnings about
"Some non-transactional changed tables couldn't be rolled back")
- Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table()
which could cause delete_table to report random failures.
- Fixed core dumps for some tests when running with --debug
- Added missing FN_LIBCHAR in mysql_rm_tmp_tables()
(This has probably caused us to not properly remove temporary files after
crash)
- slow_logs was not properly initialized, which could maybe cause
extra/lost entries in slow log.
- If we get an duplicate row on insert, change column map to read and
write all columns while retrying the operation. This is required by
the definition of REPLACE and also ensures that fields that are only
part of UPDATE are properly handled. This fixed a bug in NDB and
REPLACE where REPLACE wrongly copied some column values from the replaced
row.
- For table handler that doesn't support NULL in keys, we would give an error
when creating a primary key with NULL fields, even after the fields has been
automaticly converted to NOT NULL.
- Creating a primary key on a SPATIAL key, would fail if field was not
declared as NOT NULL.
Cleanups:
- Removed not used condition argument to setup_tables
- Removed not needed item function reset_query_id_processor().
- Field->add_index is removed. Now this is instead maintained in
(field->flags & FIELD_IN_ADD_INDEX)
- Field->fieldnr is removed (use field->field_index instead)
- New argument to filesort() to indicate that it should return a set of
row pointers (not used columns). This allowed me to remove some references
to sql_command in filesort and should also enable us to return column
results in some cases where we couldn't before.
- Changed column bitmap handling in opt_range.cc to be aligned with TABLE
bitmap, which allowed me to use bitmap functions instead of looping over
all fields to create some needed bitmaps. (Faster and smaller code)
- Broke up found too long lines
- Moved some variable declaration at start of function for better code
readability.
- Removed some not used arguments from functions.
(setup_fields(), mysql_prepare_insert_check_table())
- setup_fields() now takes an enum instead of an int for marking columns
usage.
- For internal temporary tables, use handler::write_row(),
handler::delete_row() and handler::update_row() instead of
handler::ha_xxxx() for faster execution.
- Changed some constants to enum's and define's.
- Using separate column read and write sets allows for easier checking
of timestamp field was set by statement.
- Remove calls to free_io_cache() as this is now done automaticly in ha_reset()
- Don't build table->normalized_path as this is now identical to table->path
(after bar's fixes to convert filenames)
- Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to
do comparision with the 'convert-dbug-for-diff' tool.
Things left to do in 5.1:
- We wrongly log failed CREATE TABLE ... SELECT in some cases when using
row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result)
Mats has promised to look into this.
- Test that my fix for CREATE TABLE ... SELECT is indeed correct.
(I added several test cases for this, but in this case it's better that
someone else also tests this throughly).
Lars has promosed to do this.
2006-06-04 17:52:22 +02:00
|
|
|
table->use_all_columns();
|
2009-11-24 14:54:59 +01:00
|
|
|
(void) my_init_dynamic_array(&acl_hosts,sizeof(ACL_HOST),20,50);
|
2000-07-31 21:29:14 +02:00
|
|
|
while (!(read_record_info.read_record(&read_record_info)))
|
|
|
|
{
|
|
|
|
ACL_HOST host;
|
2003-02-12 20:55:37 +01:00
|
|
|
update_hostname(&host.host,get_field(&mem, table->field[0]));
|
|
|
|
host.db= get_field(&mem, table->field[1]);
|
2005-05-26 21:02:18 +02:00
|
|
|
if (lower_case_table_names && host.db)
|
2005-02-15 22:36:46 +01:00
|
|
|
{
|
|
|
|
/*
|
2005-02-21 13:47:57 +01:00
|
|
|
convert db to lower case and give a warning if the db wasn't
|
|
|
|
already in lower case
|
2005-02-15 22:36:46 +01:00
|
|
|
*/
|
2005-02-21 13:47:57 +01:00
|
|
|
(void) strmov(tmp_name, host.db);
|
|
|
|
my_casedn_str(files_charset_info, host.db);
|
2005-02-15 22:36:46 +01:00
|
|
|
if (strcmp(host.db, tmp_name) != 0)
|
|
|
|
sql_print_warning("'host' entry '%s|%s' had database in mixed "
|
|
|
|
"case that has been forced to lowercase because "
|
2005-02-18 21:47:33 +01:00
|
|
|
"lower_case_table_names is set. It will not be "
|
|
|
|
"possible to remove this privilege using REVOKE.",
|
2006-06-06 13:21:07 +02:00
|
|
|
host.host.hostname ? host.host.hostname : "",
|
|
|
|
host.db ? host.db : "");
|
2005-02-15 22:36:46 +01:00
|
|
|
}
|
2002-06-12 14:04:18 +02:00
|
|
|
host.access= get_access(table,2);
|
|
|
|
host.access= fix_rights_for_db(host.access);
|
2003-06-23 19:03:59 +02:00
|
|
|
host.sort= get_sort(2,host.host.hostname,host.db);
|
2003-11-20 09:55:48 +01:00
|
|
|
if (check_no_resolve && hostname_requires_resolving(host.host.hostname))
|
|
|
|
{
|
2004-09-04 20:17:09 +02:00
|
|
|
sql_print_warning("'host' entry '%s|%s' "
|
2003-11-26 10:38:32 +01:00
|
|
|
"ignored in --skip-name-resolve mode.",
|
2006-06-06 13:21:07 +02:00
|
|
|
host.host.hostname ? host.host.hostname : "",
|
|
|
|
host.db ? host.db : "");
|
2003-11-20 09:55:48 +01:00
|
|
|
continue;
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
#ifndef TO_BE_REMOVED
|
2005-01-06 12:00:13 +01:00
|
|
|
if (table->s->fields == 8)
|
2000-07-31 21:29:14 +02:00
|
|
|
{ // Without grant
|
|
|
|
if (host.access & CREATE_ACL)
|
2002-09-16 14:55:19 +02:00
|
|
|
host.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL | CREATE_TMP_ACL;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
#endif
|
2009-11-24 14:54:59 +01:00
|
|
|
(void) push_dynamic(&acl_hosts,(uchar*) &host);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2007-10-18 12:32:43 +02:00
|
|
|
my_qsort((uchar*) dynamic_element(&acl_hosts,0,ACL_HOST*),acl_hosts.elements,
|
|
|
|
sizeof(ACL_HOST),(qsort_cmp) acl_compare);
|
2000-07-31 21:29:14 +02:00
|
|
|
end_read_record(&read_record_info);
|
|
|
|
freeze_size(&acl_hosts);
|
|
|
|
|
2008-07-15 16:13:21 +02:00
|
|
|
init_read_record(&read_record_info,thd,table=tables[1].table,NULL,1,0,FALSE);
|
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes
Changes that requires code changes in other code of other storage engines.
(Note that all changes are very straightforward and one should find all issues
by compiling a --debug build and fixing all compiler errors and all
asserts in field.cc while running the test suite),
- New optional handler function introduced: reset()
This is called after every DML statement to make it easy for a handler to
statement specific cleanups.
(The only case it's not called is if force the file to be closed)
- handler::extra(HA_EXTRA_RESET) is removed. Code that was there before
should be moved to handler::reset()
- table->read_set contains a bitmap over all columns that are needed
in the query. read_row() and similar functions only needs to read these
columns
- table->write_set contains a bitmap over all columns that will be updated
in the query. write_row() and update_row() only needs to update these
columns.
The above bitmaps should now be up to date in all context
(including ALTER TABLE, filesort()).
The handler is informed of any changes to the bitmap after
fix_fields() by calling the virtual function
handler::column_bitmaps_signal(). If the handler does caching of
these bitmaps (instead of using table->read_set, table->write_set),
it should redo the caching in this code. as the signal() may be sent
several times, it's probably best to set a variable in the signal
and redo the caching on read_row() / write_row() if the variable was
set.
- Removed the read_set and write_set bitmap objects from the handler class
- Removed all column bit handling functions from the handler class.
(Now one instead uses the normal bitmap functions in my_bitmap.c instead
of handler dedicated bitmap functions)
- field->query_id is removed. One should instead instead check
table->read_set and table->write_set if a field is used in the query.
- handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and
handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now
instead use table->read_set to check for which columns to retrieve.
- If a handler needs to call Field->val() or Field->store() on columns
that are not used in the query, one should install a temporary
all-columns-used map while doing so. For this, we provide the following
functions:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
field->val();
dbug_tmp_restore_column_map(table->read_set, old_map);
and similar for the write map:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
field->val();
dbug_tmp_restore_column_map(table->write_set, old_map);
If this is not done, you will sooner or later hit a DBUG_ASSERT
in the field store() / val() functions.
(For not DBUG binaries, the dbug_tmp_restore_column_map() and
dbug_tmp_restore_column_map() are inline dummy functions and should
be optimized away be the compiler).
- If one needs to temporary set the column map for all binaries (and not
just to avoid the DBUG_ASSERT() in the Field::store() / Field::val()
methods) one should use the functions tmp_use_all_columns() and
tmp_restore_column_map() instead of the above dbug_ variants.
- All 'status' fields in the handler base class (like records,
data_file_length etc) are now stored in a 'stats' struct. This makes
it easier to know what status variables are provided by the base
handler. This requires some trivial variable names in the extra()
function.
- New virtual function handler::records(). This is called to optimize
COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true.
(stats.records is not supposed to be an exact value. It's only has to
be 'reasonable enough' for the optimizer to be able to choose a good
optimization path).
- Non virtual handler::init() function added for caching of virtual
constants from engine.
- Removed has_transactions() virtual method. Now one should instead return
HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support
transactions.
- The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument
that is to be used with 'new handler_name()' to allocate the handler
in the right area. The xxxx_create_handler() function is also
responsible for any initialization of the object before returning.
For example, one should change:
static handler *myisam_create_handler(TABLE_SHARE *table)
{
return new ha_myisam(table);
}
->
static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisam(table);
}
- New optional virtual function: use_hidden_primary_key().
This is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key. This allows the handler to take precisions
in remembering any hidden primary key to able to update/delete any
found row. The default handler marks all columns to be read.
- handler::table_flags() now returns a ulonglong (to allow for more flags).
- New/changed table_flags()
- HA_HAS_RECORDS Set if ::records() is supported
- HA_NO_TRANSACTIONS Set if engine doesn't support transactions
- HA_PRIMARY_KEY_REQUIRED_FOR_DELETE
Set if we should mark all primary key columns for
read when reading rows as part of a DELETE
statement. If there is no primary key,
all columns are marked for read.
- HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some
cases (based on table->read_set)
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
- HA_DUPP_POS Renamed to HA_DUPLICATE_POS
- HA_REQUIRES_KEY_COLUMNS_FOR_DELETE
Set this if we should mark ALL key columns for
read when when reading rows as part of a DELETE
statement. In case of an update we will mark
all keys for read for which key part changed
value.
- HA_STATS_RECORDS_IS_EXACT
Set this if stats.records is exact.
(This saves us some extra records() calls
when optimizing COUNT(*))
- Removed table_flags()
- HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if
handler::records() gives an exact count() and
HA_STATS_RECORDS_IS_EXACT if stats.records is exact.
- HA_READ_RND_SAME Removed (no one supported this one)
- Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk()
- Renamed handler::dupp_pos to handler::dup_pos
- Removed not used variable handler::sortkey
Upper level handler changes:
- ha_reset() now does some overall checks and calls ::reset()
- ha_table_flags() added. This is a cached version of table_flags(). The
cache is updated on engine creation time and updated on open.
MySQL level changes (not obvious from the above):
- DBUG_ASSERT() added to check that column usage matches what is set
in the column usage bit maps. (This found a LOT of bugs in current
column marking code).
- In 5.1 before, all used columns was marked in read_set and only updated
columns was marked in write_set. Now we only mark columns for which we
need a value in read_set.
- Column bitmaps are created in open_binary_frm() and open_table_from_share().
(Before this was in table.cc)
- handler::table_flags() calls are replaced with handler::ha_table_flags()
- For calling field->val() you must have the corresponding bit set in
table->read_set. For calling field->store() you must have the
corresponding bit set in table->write_set. (There are asserts in
all store()/val() functions to catch wrong usage)
- thd->set_query_id is renamed to thd->mark_used_columns and instead
of setting this to an integer value, this has now the values:
MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE
Changed also all variables named 'set_query_id' to mark_used_columns.
- In filesort() we now inform the handler of exactly which columns are needed
doing the sort and choosing the rows.
- The TABLE_SHARE object has a 'all_set' column bitmap one can use
when one needs a column bitmap with all columns set.
(This is used for table->use_all_columns() and other places)
- The TABLE object has 3 column bitmaps:
- def_read_set Default bitmap for columns to be read
- def_write_set Default bitmap for columns to be written
- tmp_set Can be used as a temporary bitmap when needed.
The table object has also two pointer to bitmaps read_set and write_set
that the handler should use to find out which columns are used in which way.
- count() optimization now calls handler::records() instead of using
handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true).
- Added extra argument to Item::walk() to indicate if we should also
traverse sub queries.
- Added TABLE parameter to cp_buffer_from_ref()
- Don't close tables created with CREATE ... SELECT but keep them in
the table cache. (Faster usage of newly created tables).
New interfaces:
- table->clear_column_bitmaps() to initialize the bitmaps for tables
at start of new statements.
- table->column_bitmaps_set() to set up new column bitmaps and signal
the handler about this.
- table->column_bitmaps_set_no_signal() for some few cases where we need
to setup new column bitmaps but don't signal the handler (as the handler
has already been signaled about these before). Used for the momement
only in opt_range.cc when doing ROR scans.
- table->use_all_columns() to install a bitmap where all columns are marked
as use in the read and the write set.
- table->default_column_bitmaps() to install the normal read and write
column bitmaps, but not signaling the handler about this.
This is mainly used when creating TABLE instances.
- table->mark_columns_needed_for_delete(),
table->mark_columns_needed_for_delete() and
table->mark_columns_needed_for_insert() to allow us to put additional
columns in column usage maps if handler so requires.
(The handler indicates what it neads in handler->table_flags())
- table->prepare_for_position() to allow us to tell handler that it
needs to read primary key parts to be able to store them in
future table->position() calls.
(This replaces the table->file->ha_retrieve_all_pk function)
- table->mark_auto_increment_column() to tell handler are going to update
columns part of any auto_increment key.
- table->mark_columns_used_by_index() to mark all columns that is part of
an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow
it to quickly know that it only needs to read colums that are part
of the key. (The handler can also use the column map for detecting this,
but simpler/faster handler can just monitor the extra() call).
- table->mark_columns_used_by_index_no_reset() to in addition to other columns,
also mark all columns that is used by the given key.
- table->restore_column_maps_after_mark_index() to restore to default
column maps after a call to table->mark_columns_used_by_index().
- New item function register_field_in_read_map(), for marking used columns
in table->read_map. Used by filesort() to mark all used columns
- Maintain in TABLE->merge_keys set of all keys that are used in query.
(Simplices some optimization loops)
- Maintain Field->part_of_key_not_clustered which is like Field->part_of_key
but the field in the clustered key is not assumed to be part of all index.
(used in opt_range.cc for faster loops)
- dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map()
tmp_use_all_columns() and tmp_restore_column_map() functions to temporally
mark all columns as usable. The 'dbug_' version is primarily intended
inside a handler when it wants to just call Field:store() & Field::val()
functions, but don't need the column maps set for any other usage.
(ie:: bitmap_is_set() is never called)
- We can't use compare_records() to skip updates for handlers that returns
a partial column set and the read_set doesn't cover all columns in the
write set. The reason for this is that if we have a column marked only for
write we can't in the MySQL level know if the value changed or not.
The reason this worked before was that MySQL marked all to be written
columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden
bug'.
- open_table_from_share() does not anymore setup temporary MEM_ROOT
object as a thread specific variable for the handler. Instead we
send the to-be-used MEMROOT to get_new_handler().
(Simpler, faster code)
Bugs fixed:
- Column marking was not done correctly in a lot of cases.
(ALTER TABLE, when using triggers, auto_increment fields etc)
(Could potentially result in wrong values inserted in table handlers
relying on that the old column maps or field->set_query_id was correct)
Especially when it comes to triggers, there may be cases where the
old code would cause lost/wrong values for NDB and/or InnoDB tables.
- Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags:
OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG.
This allowed me to remove some wrong warnings about:
"Some non-transactional changed tables couldn't be rolled back"
- Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset
(thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose
some warnings about
"Some non-transactional changed tables couldn't be rolled back")
- Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table()
which could cause delete_table to report random failures.
- Fixed core dumps for some tests when running with --debug
- Added missing FN_LIBCHAR in mysql_rm_tmp_tables()
(This has probably caused us to not properly remove temporary files after
crash)
- slow_logs was not properly initialized, which could maybe cause
extra/lost entries in slow log.
- If we get an duplicate row on insert, change column map to read and
write all columns while retrying the operation. This is required by
the definition of REPLACE and also ensures that fields that are only
part of UPDATE are properly handled. This fixed a bug in NDB and
REPLACE where REPLACE wrongly copied some column values from the replaced
row.
- For table handler that doesn't support NULL in keys, we would give an error
when creating a primary key with NULL fields, even after the fields has been
automaticly converted to NOT NULL.
- Creating a primary key on a SPATIAL key, would fail if field was not
declared as NOT NULL.
Cleanups:
- Removed not used condition argument to setup_tables
- Removed not needed item function reset_query_id_processor().
- Field->add_index is removed. Now this is instead maintained in
(field->flags & FIELD_IN_ADD_INDEX)
- Field->fieldnr is removed (use field->field_index instead)
- New argument to filesort() to indicate that it should return a set of
row pointers (not used columns). This allowed me to remove some references
to sql_command in filesort and should also enable us to return column
results in some cases where we couldn't before.
- Changed column bitmap handling in opt_range.cc to be aligned with TABLE
bitmap, which allowed me to use bitmap functions instead of looping over
all fields to create some needed bitmaps. (Faster and smaller code)
- Broke up found too long lines
- Moved some variable declaration at start of function for better code
readability.
- Removed some not used arguments from functions.
(setup_fields(), mysql_prepare_insert_check_table())
- setup_fields() now takes an enum instead of an int for marking columns
usage.
- For internal temporary tables, use handler::write_row(),
handler::delete_row() and handler::update_row() instead of
handler::ha_xxxx() for faster execution.
- Changed some constants to enum's and define's.
- Using separate column read and write sets allows for easier checking
of timestamp field was set by statement.
- Remove calls to free_io_cache() as this is now done automaticly in ha_reset()
- Don't build table->normalized_path as this is now identical to table->path
(after bar's fixes to convert filenames)
- Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to
do comparision with the 'convert-dbug-for-diff' tool.
Things left to do in 5.1:
- We wrongly log failed CREATE TABLE ... SELECT in some cases when using
row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result)
Mats has promised to look into this.
- Test that my fix for CREATE TABLE ... SELECT is indeed correct.
(I added several test cases for this, but in this case it's better that
someone else also tests this throughly).
Lars has promosed to do this.
2006-06-04 17:52:22 +02:00
|
|
|
table->use_all_columns();
|
2009-11-24 14:54:59 +01:00
|
|
|
(void) my_init_dynamic_array(&acl_users,sizeof(ACL_USER),50,100);
|
2005-09-21 01:57:58 +02:00
|
|
|
password_length= table->field[2]->field_length /
|
|
|
|
table->field[2]->charset()->mbmaxlen;
|
|
|
|
if (password_length < SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2003-07-08 00:36:14 +02:00
|
|
|
sql_print_error("Fatal error: mysql.user table is damaged or in "
|
|
|
|
"unsupported 3.20 format.");
|
|
|
|
goto end;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2003-01-18 15:39:21 +01:00
|
|
|
DBUG_PRINT("info",("user table fields: %d, password length: %d",
|
2005-10-19 22:47:05 +02:00
|
|
|
table->s->fields, password_length));
|
2005-03-22 15:54:18 +01:00
|
|
|
|
2003-07-08 00:36:14 +02:00
|
|
|
pthread_mutex_lock(&LOCK_global_system_variables);
|
2005-09-21 01:57:58 +02:00
|
|
|
if (password_length < SCRAMBLED_PASSWORD_CHAR_LENGTH)
|
2003-01-18 15:39:21 +01:00
|
|
|
{
|
2003-07-08 00:36:14 +02:00
|
|
|
if (opt_secure_auth)
|
|
|
|
{
|
|
|
|
pthread_mutex_unlock(&LOCK_global_system_variables);
|
|
|
|
sql_print_error("Fatal error: mysql.user table is in old format, "
|
|
|
|
"but server started with --secure-auth option.");
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
sys_old_passwords.after_update= restrict_update_of_old_passwords_var;
|
|
|
|
if (global_system_variables.old_passwords)
|
|
|
|
pthread_mutex_unlock(&LOCK_global_system_variables);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
global_system_variables.old_passwords= 1;
|
|
|
|
pthread_mutex_unlock(&LOCK_global_system_variables);
|
2004-08-30 08:37:36 +02:00
|
|
|
sql_print_warning("mysql.user table is not updated to new password format; "
|
|
|
|
"Disabling new password usage until "
|
|
|
|
"mysql_fix_privilege_tables is run");
|
2003-07-08 00:36:14 +02:00
|
|
|
}
|
|
|
|
thd->variables.old_passwords= 1;
|
|
|
|
}
|
|
|
|
else
|
2003-01-18 15:39:21 +01:00
|
|
|
{
|
2003-07-08 00:36:14 +02:00
|
|
|
sys_old_passwords.after_update= 0;
|
|
|
|
pthread_mutex_unlock(&LOCK_global_system_variables);
|
2003-01-18 15:39:21 +01:00
|
|
|
}
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
allow_all_hosts=0;
|
|
|
|
while (!(read_record_info.read_record(&read_record_info)))
|
|
|
|
{
|
|
|
|
ACL_USER user;
|
2003-07-01 21:40:59 +02:00
|
|
|
update_hostname(&user.host, get_field(&mem, table->field[0]));
|
|
|
|
user.user= get_field(&mem, table->field[1]);
|
2003-11-20 09:55:48 +01:00
|
|
|
if (check_no_resolve && hostname_requires_resolving(user.host.hostname))
|
|
|
|
{
|
2004-09-04 20:17:09 +02:00
|
|
|
sql_print_warning("'user' entry '%s@%s' "
|
|
|
|
"ignored in --skip-name-resolve mode.",
|
2006-06-06 13:21:07 +02:00
|
|
|
user.user ? user.user : "",
|
|
|
|
user.host.hostname ? user.host.hostname : "");
|
2003-11-20 09:55:48 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2007-10-31 12:25:18 +01:00
|
|
|
const char *password= get_field(thd->mem_root, table->field[2]);
|
2003-07-01 21:40:59 +02:00
|
|
|
uint password_len= password ? strlen(password) : 0;
|
|
|
|
set_user_salt(&user, password, password_len);
|
|
|
|
if (user.salt_len == 0 && password_len != 0)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2003-07-01 21:40:59 +02:00
|
|
|
switch (password_len) {
|
|
|
|
case 45: /* 4.1: to be removed */
|
2004-09-04 20:17:09 +02:00
|
|
|
sql_print_warning("Found 4.1 style password for user '%s@%s'. "
|
|
|
|
"Ignoring user. "
|
|
|
|
"You should change password for this user.",
|
|
|
|
user.user ? user.user : "",
|
|
|
|
user.host.hostname ? user.host.hostname : "");
|
2003-07-01 21:40:59 +02:00
|
|
|
break;
|
|
|
|
default:
|
2004-09-04 20:17:09 +02:00
|
|
|
sql_print_warning("Found invalid password for user: '%s@%s'; "
|
|
|
|
"Ignoring user", user.user ? user.user : "",
|
|
|
|
user.host.hostname ? user.host.hostname : "");
|
2003-07-01 21:40:59 +02:00
|
|
|
break;
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2003-07-01 21:40:59 +02:00
|
|
|
else // password is correct
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-07-19 16:01:53 +02:00
|
|
|
uint next_field;
|
|
|
|
user.access= get_access(table,3,&next_field) & GLOBAL_ACLS;
|
2004-10-10 17:51:02 +02:00
|
|
|
/*
|
|
|
|
if it is pre 5.0.1 privilege table then map CREATE privilege on
|
|
|
|
CREATE VIEW & SHOW VIEW privileges
|
|
|
|
*/
|
2005-01-06 12:00:13 +01:00
|
|
|
if (table->s->fields <= 31 && (user.access & CREATE_ACL))
|
2004-10-10 17:51:02 +02:00
|
|
|
user.access|= (CREATE_VIEW_ACL | SHOW_VIEW_ACL);
|
2004-12-23 11:46:24 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
if it is pre 5.0.2 privilege table then map CREATE/ALTER privilege on
|
|
|
|
CREATE PROCEDURE & ALTER PROCEDURE privileges
|
|
|
|
*/
|
2005-01-06 12:00:13 +01:00
|
|
|
if (table->s->fields <= 33 && (user.access & CREATE_ACL))
|
2004-12-23 11:46:24 +01:00
|
|
|
user.access|= CREATE_PROC_ACL;
|
2005-01-06 12:00:13 +01:00
|
|
|
if (table->s->fields <= 33 && (user.access & ALTER_ACL))
|
2004-12-23 11:46:24 +01:00
|
|
|
user.access|= ALTER_PROC_ACL;
|
|
|
|
|
2005-03-22 15:54:18 +01:00
|
|
|
/*
|
|
|
|
pre 5.0.3 did not have CREATE_USER_ACL
|
|
|
|
*/
|
|
|
|
if (table->s->fields <= 36 && (user.access & GRANT_ACL))
|
|
|
|
user.access|= CREATE_USER_ACL;
|
|
|
|
|
2005-12-05 11:45:04 +01:00
|
|
|
|
|
|
|
/*
|
2006-02-24 00:29:50 +01:00
|
|
|
if it is pre 5.1.6 privilege table then map CREATE privilege on
|
2005-12-05 11:45:04 +01:00
|
|
|
CREATE|ALTER|DROP|EXECUTE EVENT
|
|
|
|
*/
|
2006-02-24 00:29:50 +01:00
|
|
|
if (table->s->fields <= 37 && (user.access & SUPER_ACL))
|
2005-12-05 11:45:04 +01:00
|
|
|
user.access|= EVENT_ACL;
|
|
|
|
|
2006-02-01 11:28:45 +01:00
|
|
|
/*
|
|
|
|
if it is pre 5.1.6 privilege then map TRIGGER privilege on CREATE.
|
|
|
|
*/
|
|
|
|
if (table->s->fields <= 38 && (user.access & SUPER_ACL))
|
|
|
|
user.access|= TRIGGER_ACL;
|
|
|
|
|
2003-07-01 21:40:59 +02:00
|
|
|
user.sort= get_sort(2,user.host.hostname,user.user);
|
|
|
|
user.hostname_length= (user.host.hostname ?
|
|
|
|
(uint) strlen(user.host.hostname) : 0);
|
2004-07-16 00:15:55 +02:00
|
|
|
|
2005-01-06 12:00:13 +01:00
|
|
|
/* Starting from 4.0.2 we have more fields */
|
|
|
|
if (table->s->fields >= 31)
|
2002-11-24 15:07:53 +01:00
|
|
|
{
|
2007-10-31 12:25:18 +01:00
|
|
|
char *ssl_type=get_field(thd->mem_root, table->field[next_field++]);
|
2003-07-01 21:40:59 +02:00
|
|
|
if (!ssl_type)
|
|
|
|
user.ssl_type=SSL_TYPE_NONE;
|
|
|
|
else if (!strcmp(ssl_type, "ANY"))
|
|
|
|
user.ssl_type=SSL_TYPE_ANY;
|
|
|
|
else if (!strcmp(ssl_type, "X509"))
|
|
|
|
user.ssl_type=SSL_TYPE_X509;
|
|
|
|
else /* !strcmp(ssl_type, "SPECIFIED") */
|
|
|
|
user.ssl_type=SSL_TYPE_SPECIFIED;
|
|
|
|
|
2004-07-19 16:01:53 +02:00
|
|
|
user.ssl_cipher= get_field(&mem, table->field[next_field++]);
|
|
|
|
user.x509_issuer= get_field(&mem, table->field[next_field++]);
|
|
|
|
user.x509_subject= get_field(&mem, table->field[next_field++]);
|
2003-07-01 21:40:59 +02:00
|
|
|
|
2007-10-31 12:25:18 +01:00
|
|
|
char *ptr = get_field(thd->mem_root, table->field[next_field++]);
|
2004-07-19 16:01:53 +02:00
|
|
|
user.user_resource.questions=ptr ? atoi(ptr) : 0;
|
2007-10-31 12:25:18 +01:00
|
|
|
ptr = get_field(thd->mem_root, table->field[next_field++]);
|
2004-07-19 16:01:53 +02:00
|
|
|
user.user_resource.updates=ptr ? atoi(ptr) : 0;
|
2007-10-31 12:25:18 +01:00
|
|
|
ptr = get_field(thd->mem_root, table->field[next_field++]);
|
2004-12-29 18:30:37 +01:00
|
|
|
user.user_resource.conn_per_hour= ptr ? atoi(ptr) : 0;
|
2003-07-01 21:40:59 +02:00
|
|
|
if (user.user_resource.questions || user.user_resource.updates ||
|
2004-12-29 18:30:37 +01:00
|
|
|
user.user_resource.conn_per_hour)
|
2003-07-01 21:40:59 +02:00
|
|
|
mqh_used=1;
|
2004-12-29 18:30:37 +01:00
|
|
|
|
2005-01-06 12:00:13 +01:00
|
|
|
if (table->s->fields >= 36)
|
2004-12-29 18:30:37 +01:00
|
|
|
{
|
|
|
|
/* Starting from 5.0.3 we have max_user_connections field */
|
2007-10-31 12:25:18 +01:00
|
|
|
ptr= get_field(thd->mem_root, table->field[next_field++]);
|
2004-12-29 18:30:37 +01:00
|
|
|
user.user_resource.user_conn= ptr ? atoi(ptr) : 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
user.user_resource.user_conn= 0;
|
2002-11-24 15:07:53 +01:00
|
|
|
}
|
2003-07-01 21:40:59 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
user.ssl_type=SSL_TYPE_NONE;
|
2003-09-03 12:12:10 +02:00
|
|
|
bzero((char *)&(user.user_resource),sizeof(user.user_resource));
|
2000-07-31 21:29:14 +02:00
|
|
|
#ifndef TO_BE_REMOVED
|
2005-01-06 12:00:13 +01:00
|
|
|
if (table->s->fields <= 13)
|
2003-07-01 21:40:59 +02:00
|
|
|
{ // Without grant
|
|
|
|
if (user.access & CREATE_ACL)
|
|
|
|
user.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL;
|
|
|
|
}
|
|
|
|
/* Convert old privileges */
|
|
|
|
user.access|= LOCK_TABLES_ACL | CREATE_TMP_ACL | SHOW_DB_ACL;
|
|
|
|
if (user.access & FILE_ACL)
|
|
|
|
user.access|= REPL_CLIENT_ACL | REPL_SLAVE_ACL;
|
|
|
|
if (user.access & PROCESS_ACL)
|
|
|
|
user.access|= SUPER_ACL | EXECUTE_ACL;
|
2000-07-31 21:29:14 +02:00
|
|
|
#endif
|
2003-07-01 21:40:59 +02:00
|
|
|
}
|
2009-11-24 14:54:59 +01:00
|
|
|
(void) push_dynamic(&acl_users,(uchar*) &user);
|
2006-06-06 13:21:07 +02:00
|
|
|
if (!user.host.hostname ||
|
|
|
|
(user.host.hostname[0] == wild_many && !user.host.hostname[1]))
|
2003-07-01 21:40:59 +02:00
|
|
|
allow_all_hosts=1; // Anyone can connect
|
2002-06-12 14:04:18 +02:00
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2007-10-18 12:32:43 +02:00
|
|
|
my_qsort((uchar*) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements,
|
|
|
|
sizeof(ACL_USER),(qsort_cmp) acl_compare);
|
2000-07-31 21:29:14 +02:00
|
|
|
end_read_record(&read_record_info);
|
|
|
|
freeze_size(&acl_users);
|
2002-11-30 18:58:53 +01:00
|
|
|
|
2008-07-15 16:13:21 +02:00
|
|
|
init_read_record(&read_record_info,thd,table=tables[2].table,NULL,1,0,FALSE);
|
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes
Changes that requires code changes in other code of other storage engines.
(Note that all changes are very straightforward and one should find all issues
by compiling a --debug build and fixing all compiler errors and all
asserts in field.cc while running the test suite),
- New optional handler function introduced: reset()
This is called after every DML statement to make it easy for a handler to
statement specific cleanups.
(The only case it's not called is if force the file to be closed)
- handler::extra(HA_EXTRA_RESET) is removed. Code that was there before
should be moved to handler::reset()
- table->read_set contains a bitmap over all columns that are needed
in the query. read_row() and similar functions only needs to read these
columns
- table->write_set contains a bitmap over all columns that will be updated
in the query. write_row() and update_row() only needs to update these
columns.
The above bitmaps should now be up to date in all context
(including ALTER TABLE, filesort()).
The handler is informed of any changes to the bitmap after
fix_fields() by calling the virtual function
handler::column_bitmaps_signal(). If the handler does caching of
these bitmaps (instead of using table->read_set, table->write_set),
it should redo the caching in this code. as the signal() may be sent
several times, it's probably best to set a variable in the signal
and redo the caching on read_row() / write_row() if the variable was
set.
- Removed the read_set and write_set bitmap objects from the handler class
- Removed all column bit handling functions from the handler class.
(Now one instead uses the normal bitmap functions in my_bitmap.c instead
of handler dedicated bitmap functions)
- field->query_id is removed. One should instead instead check
table->read_set and table->write_set if a field is used in the query.
- handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and
handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now
instead use table->read_set to check for which columns to retrieve.
- If a handler needs to call Field->val() or Field->store() on columns
that are not used in the query, one should install a temporary
all-columns-used map while doing so. For this, we provide the following
functions:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
field->val();
dbug_tmp_restore_column_map(table->read_set, old_map);
and similar for the write map:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
field->val();
dbug_tmp_restore_column_map(table->write_set, old_map);
If this is not done, you will sooner or later hit a DBUG_ASSERT
in the field store() / val() functions.
(For not DBUG binaries, the dbug_tmp_restore_column_map() and
dbug_tmp_restore_column_map() are inline dummy functions and should
be optimized away be the compiler).
- If one needs to temporary set the column map for all binaries (and not
just to avoid the DBUG_ASSERT() in the Field::store() / Field::val()
methods) one should use the functions tmp_use_all_columns() and
tmp_restore_column_map() instead of the above dbug_ variants.
- All 'status' fields in the handler base class (like records,
data_file_length etc) are now stored in a 'stats' struct. This makes
it easier to know what status variables are provided by the base
handler. This requires some trivial variable names in the extra()
function.
- New virtual function handler::records(). This is called to optimize
COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true.
(stats.records is not supposed to be an exact value. It's only has to
be 'reasonable enough' for the optimizer to be able to choose a good
optimization path).
- Non virtual handler::init() function added for caching of virtual
constants from engine.
- Removed has_transactions() virtual method. Now one should instead return
HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support
transactions.
- The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument
that is to be used with 'new handler_name()' to allocate the handler
in the right area. The xxxx_create_handler() function is also
responsible for any initialization of the object before returning.
For example, one should change:
static handler *myisam_create_handler(TABLE_SHARE *table)
{
return new ha_myisam(table);
}
->
static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisam(table);
}
- New optional virtual function: use_hidden_primary_key().
This is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key. This allows the handler to take precisions
in remembering any hidden primary key to able to update/delete any
found row. The default handler marks all columns to be read.
- handler::table_flags() now returns a ulonglong (to allow for more flags).
- New/changed table_flags()
- HA_HAS_RECORDS Set if ::records() is supported
- HA_NO_TRANSACTIONS Set if engine doesn't support transactions
- HA_PRIMARY_KEY_REQUIRED_FOR_DELETE
Set if we should mark all primary key columns for
read when reading rows as part of a DELETE
statement. If there is no primary key,
all columns are marked for read.
- HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some
cases (based on table->read_set)
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
- HA_DUPP_POS Renamed to HA_DUPLICATE_POS
- HA_REQUIRES_KEY_COLUMNS_FOR_DELETE
Set this if we should mark ALL key columns for
read when when reading rows as part of a DELETE
statement. In case of an update we will mark
all keys for read for which key part changed
value.
- HA_STATS_RECORDS_IS_EXACT
Set this if stats.records is exact.
(This saves us some extra records() calls
when optimizing COUNT(*))
- Removed table_flags()
- HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if
handler::records() gives an exact count() and
HA_STATS_RECORDS_IS_EXACT if stats.records is exact.
- HA_READ_RND_SAME Removed (no one supported this one)
- Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk()
- Renamed handler::dupp_pos to handler::dup_pos
- Removed not used variable handler::sortkey
Upper level handler changes:
- ha_reset() now does some overall checks and calls ::reset()
- ha_table_flags() added. This is a cached version of table_flags(). The
cache is updated on engine creation time and updated on open.
MySQL level changes (not obvious from the above):
- DBUG_ASSERT() added to check that column usage matches what is set
in the column usage bit maps. (This found a LOT of bugs in current
column marking code).
- In 5.1 before, all used columns was marked in read_set and only updated
columns was marked in write_set. Now we only mark columns for which we
need a value in read_set.
- Column bitmaps are created in open_binary_frm() and open_table_from_share().
(Before this was in table.cc)
- handler::table_flags() calls are replaced with handler::ha_table_flags()
- For calling field->val() you must have the corresponding bit set in
table->read_set. For calling field->store() you must have the
corresponding bit set in table->write_set. (There are asserts in
all store()/val() functions to catch wrong usage)
- thd->set_query_id is renamed to thd->mark_used_columns and instead
of setting this to an integer value, this has now the values:
MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE
Changed also all variables named 'set_query_id' to mark_used_columns.
- In filesort() we now inform the handler of exactly which columns are needed
doing the sort and choosing the rows.
- The TABLE_SHARE object has a 'all_set' column bitmap one can use
when one needs a column bitmap with all columns set.
(This is used for table->use_all_columns() and other places)
- The TABLE object has 3 column bitmaps:
- def_read_set Default bitmap for columns to be read
- def_write_set Default bitmap for columns to be written
- tmp_set Can be used as a temporary bitmap when needed.
The table object has also two pointer to bitmaps read_set and write_set
that the handler should use to find out which columns are used in which way.
- count() optimization now calls handler::records() instead of using
handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true).
- Added extra argument to Item::walk() to indicate if we should also
traverse sub queries.
- Added TABLE parameter to cp_buffer_from_ref()
- Don't close tables created with CREATE ... SELECT but keep them in
the table cache. (Faster usage of newly created tables).
New interfaces:
- table->clear_column_bitmaps() to initialize the bitmaps for tables
at start of new statements.
- table->column_bitmaps_set() to set up new column bitmaps and signal
the handler about this.
- table->column_bitmaps_set_no_signal() for some few cases where we need
to setup new column bitmaps but don't signal the handler (as the handler
has already been signaled about these before). Used for the momement
only in opt_range.cc when doing ROR scans.
- table->use_all_columns() to install a bitmap where all columns are marked
as use in the read and the write set.
- table->default_column_bitmaps() to install the normal read and write
column bitmaps, but not signaling the handler about this.
This is mainly used when creating TABLE instances.
- table->mark_columns_needed_for_delete(),
table->mark_columns_needed_for_delete() and
table->mark_columns_needed_for_insert() to allow us to put additional
columns in column usage maps if handler so requires.
(The handler indicates what it neads in handler->table_flags())
- table->prepare_for_position() to allow us to tell handler that it
needs to read primary key parts to be able to store them in
future table->position() calls.
(This replaces the table->file->ha_retrieve_all_pk function)
- table->mark_auto_increment_column() to tell handler are going to update
columns part of any auto_increment key.
- table->mark_columns_used_by_index() to mark all columns that is part of
an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow
it to quickly know that it only needs to read colums that are part
of the key. (The handler can also use the column map for detecting this,
but simpler/faster handler can just monitor the extra() call).
- table->mark_columns_used_by_index_no_reset() to in addition to other columns,
also mark all columns that is used by the given key.
- table->restore_column_maps_after_mark_index() to restore to default
column maps after a call to table->mark_columns_used_by_index().
- New item function register_field_in_read_map(), for marking used columns
in table->read_map. Used by filesort() to mark all used columns
- Maintain in TABLE->merge_keys set of all keys that are used in query.
(Simplices some optimization loops)
- Maintain Field->part_of_key_not_clustered which is like Field->part_of_key
but the field in the clustered key is not assumed to be part of all index.
(used in opt_range.cc for faster loops)
- dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map()
tmp_use_all_columns() and tmp_restore_column_map() functions to temporally
mark all columns as usable. The 'dbug_' version is primarily intended
inside a handler when it wants to just call Field:store() & Field::val()
functions, but don't need the column maps set for any other usage.
(ie:: bitmap_is_set() is never called)
- We can't use compare_records() to skip updates for handlers that returns
a partial column set and the read_set doesn't cover all columns in the
write set. The reason for this is that if we have a column marked only for
write we can't in the MySQL level know if the value changed or not.
The reason this worked before was that MySQL marked all to be written
columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden
bug'.
- open_table_from_share() does not anymore setup temporary MEM_ROOT
object as a thread specific variable for the handler. Instead we
send the to-be-used MEMROOT to get_new_handler().
(Simpler, faster code)
Bugs fixed:
- Column marking was not done correctly in a lot of cases.
(ALTER TABLE, when using triggers, auto_increment fields etc)
(Could potentially result in wrong values inserted in table handlers
relying on that the old column maps or field->set_query_id was correct)
Especially when it comes to triggers, there may be cases where the
old code would cause lost/wrong values for NDB and/or InnoDB tables.
- Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags:
OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG.
This allowed me to remove some wrong warnings about:
"Some non-transactional changed tables couldn't be rolled back"
- Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset
(thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose
some warnings about
"Some non-transactional changed tables couldn't be rolled back")
- Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table()
which could cause delete_table to report random failures.
- Fixed core dumps for some tests when running with --debug
- Added missing FN_LIBCHAR in mysql_rm_tmp_tables()
(This has probably caused us to not properly remove temporary files after
crash)
- slow_logs was not properly initialized, which could maybe cause
extra/lost entries in slow log.
- If we get an duplicate row on insert, change column map to read and
write all columns while retrying the operation. This is required by
the definition of REPLACE and also ensures that fields that are only
part of UPDATE are properly handled. This fixed a bug in NDB and
REPLACE where REPLACE wrongly copied some column values from the replaced
row.
- For table handler that doesn't support NULL in keys, we would give an error
when creating a primary key with NULL fields, even after the fields has been
automaticly converted to NOT NULL.
- Creating a primary key on a SPATIAL key, would fail if field was not
declared as NOT NULL.
Cleanups:
- Removed not used condition argument to setup_tables
- Removed not needed item function reset_query_id_processor().
- Field->add_index is removed. Now this is instead maintained in
(field->flags & FIELD_IN_ADD_INDEX)
- Field->fieldnr is removed (use field->field_index instead)
- New argument to filesort() to indicate that it should return a set of
row pointers (not used columns). This allowed me to remove some references
to sql_command in filesort and should also enable us to return column
results in some cases where we couldn't before.
- Changed column bitmap handling in opt_range.cc to be aligned with TABLE
bitmap, which allowed me to use bitmap functions instead of looping over
all fields to create some needed bitmaps. (Faster and smaller code)
- Broke up found too long lines
- Moved some variable declaration at start of function for better code
readability.
- Removed some not used arguments from functions.
(setup_fields(), mysql_prepare_insert_check_table())
- setup_fields() now takes an enum instead of an int for marking columns
usage.
- For internal temporary tables, use handler::write_row(),
handler::delete_row() and handler::update_row() instead of
handler::ha_xxxx() for faster execution.
- Changed some constants to enum's and define's.
- Using separate column read and write sets allows for easier checking
of timestamp field was set by statement.
- Remove calls to free_io_cache() as this is now done automaticly in ha_reset()
- Don't build table->normalized_path as this is now identical to table->path
(after bar's fixes to convert filenames)
- Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to
do comparision with the 'convert-dbug-for-diff' tool.
Things left to do in 5.1:
- We wrongly log failed CREATE TABLE ... SELECT in some cases when using
row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result)
Mats has promised to look into this.
- Test that my fix for CREATE TABLE ... SELECT is indeed correct.
(I added several test cases for this, but in this case it's better that
someone else also tests this throughly).
Lars has promosed to do this.
2006-06-04 17:52:22 +02:00
|
|
|
table->use_all_columns();
|
2009-11-24 14:54:59 +01:00
|
|
|
(void) my_init_dynamic_array(&acl_dbs,sizeof(ACL_DB),50,100);
|
2000-07-31 21:29:14 +02:00
|
|
|
while (!(read_record_info.read_record(&read_record_info)))
|
|
|
|
{
|
|
|
|
ACL_DB db;
|
2006-02-14 16:20:48 +01:00
|
|
|
update_hostname(&db.host,get_field(&mem, table->field[MYSQL_DB_FIELD_HOST]));
|
|
|
|
db.db=get_field(&mem, table->field[MYSQL_DB_FIELD_DB]);
|
2002-08-07 23:53:00 +02:00
|
|
|
if (!db.db)
|
|
|
|
{
|
2004-09-04 20:17:09 +02:00
|
|
|
sql_print_warning("Found an entry in the 'db' table with empty database name; Skipped");
|
2002-08-07 20:57:32 +02:00
|
|
|
continue;
|
2002-08-07 23:53:00 +02:00
|
|
|
}
|
2006-02-14 16:20:48 +01:00
|
|
|
db.user=get_field(&mem, table->field[MYSQL_DB_FIELD_USER]);
|
2003-11-20 09:55:48 +01:00
|
|
|
if (check_no_resolve && hostname_requires_resolving(db.host.hostname))
|
|
|
|
{
|
2004-09-04 20:17:09 +02:00
|
|
|
sql_print_warning("'db' entry '%s %s@%s' "
|
|
|
|
"ignored in --skip-name-resolve mode.",
|
2006-06-06 13:21:07 +02:00
|
|
|
db.db,
|
|
|
|
db.user ? db.user : "",
|
|
|
|
db.host.hostname ? db.host.hostname : "");
|
2003-11-20 09:55:48 +01:00
|
|
|
continue;
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
db.access=get_access(table,3);
|
|
|
|
db.access=fix_rights_for_db(db.access);
|
2005-02-15 22:36:46 +01:00
|
|
|
if (lower_case_table_names)
|
|
|
|
{
|
|
|
|
/*
|
2005-02-21 13:47:57 +01:00
|
|
|
convert db to lower case and give a warning if the db wasn't
|
|
|
|
already in lower case
|
2005-02-15 22:36:46 +01:00
|
|
|
*/
|
|
|
|
(void)strmov(tmp_name, db.db);
|
2005-02-21 13:47:57 +01:00
|
|
|
my_casedn_str(files_charset_info, db.db);
|
2005-02-15 22:36:46 +01:00
|
|
|
if (strcmp(db.db, tmp_name) != 0)
|
|
|
|
{
|
|
|
|
sql_print_warning("'db' entry '%s %s@%s' had database in mixed "
|
|
|
|
"case that has been forced to lowercase because "
|
2005-02-18 21:47:33 +01:00
|
|
|
"lower_case_table_names is set. It will not be "
|
|
|
|
"possible to remove this privilege using REVOKE.",
|
2006-06-06 13:21:07 +02:00
|
|
|
db.db,
|
|
|
|
db.user ? db.user : "",
|
|
|
|
db.host.hostname ? db.host.hostname : "");
|
2005-02-15 22:36:46 +01:00
|
|
|
}
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
db.sort=get_sort(3,db.host.hostname,db.db,db.user);
|
|
|
|
#ifndef TO_BE_REMOVED
|
2005-01-06 12:00:13 +01:00
|
|
|
if (table->s->fields <= 9)
|
2000-07-31 21:29:14 +02:00
|
|
|
{ // Without grant
|
|
|
|
if (db.access & CREATE_ACL)
|
|
|
|
db.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL;
|
|
|
|
}
|
|
|
|
#endif
|
2009-11-24 14:54:59 +01:00
|
|
|
(void) push_dynamic(&acl_dbs,(uchar*) &db);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2007-10-18 12:32:43 +02:00
|
|
|
my_qsort((uchar*) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements,
|
|
|
|
sizeof(ACL_DB),(qsort_cmp) acl_compare);
|
2000-07-31 21:29:14 +02:00
|
|
|
end_read_record(&read_record_info);
|
|
|
|
freeze_size(&acl_dbs);
|
|
|
|
init_check_host();
|
|
|
|
|
2002-09-05 15:17:08 +02:00
|
|
|
initialized=1;
|
|
|
|
return_val=0;
|
|
|
|
|
|
|
|
end:
|
2008-02-24 13:58:07 +01:00
|
|
|
thd->variables.sql_mode= old_sql_mode;
|
2002-09-05 15:17:08 +02:00
|
|
|
DBUG_RETURN(return_val);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void acl_free(bool end)
|
|
|
|
{
|
2000-09-12 02:02:33 +02:00
|
|
|
free_root(&mem,MYF(0));
|
2000-07-31 21:29:14 +02:00
|
|
|
delete_dynamic(&acl_hosts);
|
|
|
|
delete_dynamic(&acl_users);
|
|
|
|
delete_dynamic(&acl_dbs);
|
|
|
|
delete_dynamic(&acl_wild_hosts);
|
2009-10-14 18:37:38 +02:00
|
|
|
my_hash_free(&acl_check_hosts);
|
2000-07-31 21:29:14 +02:00
|
|
|
if (!end)
|
|
|
|
acl_cache->clear(1); /* purecov: inspected */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
delete acl_cache;
|
|
|
|
acl_cache=0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-06-23 19:03:59 +02:00
|
|
|
|
|
|
|
/*
|
2005-09-01 14:52:59 +02:00
|
|
|
Forget current user/db-level privileges and read new privileges
|
|
|
|
from the privilege tables.
|
2003-06-23 19:03:59 +02:00
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
acl_reload()
|
2005-09-01 14:52:59 +02:00
|
|
|
thd Current thread
|
|
|
|
|
|
|
|
NOTE
|
|
|
|
All tables of calling thread which were open and locked by LOCK TABLES
|
|
|
|
statement will be unlocked and closed.
|
|
|
|
This function is also used for initialization of structures responsible
|
|
|
|
for user/db-level privilege checking.
|
|
|
|
|
|
|
|
RETURN VALUE
|
|
|
|
FALSE Success
|
|
|
|
TRUE Failure
|
2003-06-23 19:03:59 +02:00
|
|
|
*/
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2005-09-01 14:52:59 +02:00
|
|
|
my_bool acl_reload(THD *thd)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2005-09-01 14:52:59 +02:00
|
|
|
TABLE_LIST tables[3];
|
2000-07-31 21:29:14 +02:00
|
|
|
DYNAMIC_ARRAY old_acl_hosts,old_acl_users,old_acl_dbs;
|
|
|
|
MEM_ROOT old_mem;
|
|
|
|
bool old_initialized;
|
2005-09-01 14:52:59 +02:00
|
|
|
my_bool return_val= 1;
|
2000-07-31 21:29:14 +02:00
|
|
|
DBUG_ENTER("acl_reload");
|
|
|
|
|
2005-09-01 14:52:59 +02:00
|
|
|
if (thd->locked_tables)
|
2000-07-31 21:29:14 +02:00
|
|
|
{ // Can't have locked tables here
|
2002-09-05 15:17:08 +02:00
|
|
|
thd->lock=thd->locked_tables;
|
|
|
|
thd->locked_tables=0;
|
|
|
|
close_thread_tables(thd);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2005-09-01 14:52:59 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
To avoid deadlocks we should obtain table locks before
|
|
|
|
obtaining acl_cache->lock mutex.
|
|
|
|
*/
|
|
|
|
bzero((char*) tables, sizeof(tables));
|
2005-09-01 23:01:33 +02:00
|
|
|
tables[0].alias= tables[0].table_name= (char*) "host";
|
|
|
|
tables[1].alias= tables[1].table_name= (char*) "user";
|
|
|
|
tables[2].alias= tables[2].table_name= (char*) "db";
|
|
|
|
tables[0].db=tables[1].db=tables[2].db=(char*) "mysql";
|
|
|
|
tables[0].next_local= tables[0].next_global= tables+1;
|
|
|
|
tables[1].next_local= tables[1].next_global= tables+2;
|
2005-09-01 14:52:59 +02:00
|
|
|
tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_READ;
|
2008-03-25 12:52:55 +01:00
|
|
|
tables[0].skip_temporary= tables[1].skip_temporary=
|
|
|
|
tables[2].skip_temporary= TRUE;
|
2005-09-01 14:52:59 +02:00
|
|
|
|
|
|
|
if (simple_open_n_lock_tables(thd, tables))
|
|
|
|
{
|
|
|
|
sql_print_error("Fatal error: Can't open and lock privilege tables: %s",
|
2009-09-10 11:18:29 +02:00
|
|
|
thd->stmt_da->message());
|
2005-09-01 14:52:59 +02:00
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
if ((old_initialized=initialized))
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_lock(&acl_cache->lock);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
old_acl_hosts=acl_hosts;
|
|
|
|
old_acl_users=acl_users;
|
|
|
|
old_acl_dbs=acl_dbs;
|
|
|
|
old_mem=mem;
|
|
|
|
delete_dynamic(&acl_wild_hosts);
|
2009-10-14 18:37:38 +02:00
|
|
|
my_hash_free(&acl_check_hosts);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2005-09-01 14:52:59 +02:00
|
|
|
if ((return_val= acl_load(thd, tables)))
|
2000-07-31 21:29:14 +02:00
|
|
|
{ // Error. Revert to old list
|
2003-01-18 15:39:21 +01:00
|
|
|
DBUG_PRINT("error",("Reverting to old privileges"));
|
2002-09-05 15:17:08 +02:00
|
|
|
acl_free(); /* purecov: inspected */
|
2000-07-31 21:29:14 +02:00
|
|
|
acl_hosts=old_acl_hosts;
|
|
|
|
acl_users=old_acl_users;
|
|
|
|
acl_dbs=old_acl_dbs;
|
|
|
|
mem=old_mem;
|
|
|
|
init_check_host();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2000-09-12 02:02:33 +02:00
|
|
|
free_root(&old_mem,MYF(0));
|
2000-07-31 21:29:14 +02:00
|
|
|
delete_dynamic(&old_acl_hosts);
|
|
|
|
delete_dynamic(&old_acl_users);
|
|
|
|
delete_dynamic(&old_acl_dbs);
|
|
|
|
}
|
|
|
|
if (old_initialized)
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_unlock(&acl_cache->lock);
|
2005-09-01 14:52:59 +02:00
|
|
|
end:
|
|
|
|
close_thread_tables(thd);
|
|
|
|
DBUG_RETURN(return_val);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-06-12 14:04:18 +02:00
|
|
|
/*
|
|
|
|
Get all access bits from table after fieldnr
|
2004-07-19 16:01:53 +02:00
|
|
|
|
|
|
|
IMPLEMENTATION
|
2002-06-12 14:04:18 +02:00
|
|
|
We know that the access privileges ends when there is no more fields
|
|
|
|
or the field is not an enum with two elements.
|
2004-07-19 16:01:53 +02:00
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
get_access()
|
|
|
|
form an open table to read privileges from.
|
|
|
|
The record should be already read in table->record[0]
|
|
|
|
fieldnr number of the first privilege (that is ENUM('N','Y') field
|
|
|
|
next_field on return - number of the field next to the last ENUM
|
|
|
|
(unless next_field == 0)
|
|
|
|
|
|
|
|
RETURN VALUE
|
|
|
|
privilege mask
|
2002-06-12 14:04:18 +02:00
|
|
|
*/
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2004-07-19 16:01:53 +02:00
|
|
|
static ulong get_access(TABLE *form, uint fieldnr, uint *next_field)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2002-06-12 14:04:18 +02:00
|
|
|
ulong access_bits=0,bit;
|
2000-07-31 21:29:14 +02:00
|
|
|
char buff[2];
|
2003-01-29 14:31:20 +01:00
|
|
|
String res(buff,sizeof(buff),&my_charset_latin1);
|
2000-07-31 21:29:14 +02:00
|
|
|
Field **pos;
|
|
|
|
|
2002-06-12 14:04:18 +02:00
|
|
|
for (pos=form->field+fieldnr, bit=1;
|
2006-12-02 02:26:52 +01:00
|
|
|
*pos && (*pos)->real_type() == MYSQL_TYPE_ENUM &&
|
2002-06-12 14:04:18 +02:00
|
|
|
((Field_enum*) (*pos))->typelib->count == 2 ;
|
2004-07-19 16:01:53 +02:00
|
|
|
pos++, fieldnr++, bit<<=1)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-04-06 21:35:26 +02:00
|
|
|
(*pos)->val_str(&res);
|
2003-01-29 14:31:20 +01:00
|
|
|
if (my_toupper(&my_charset_latin1, res[0]) == 'Y')
|
2002-06-12 14:04:18 +02:00
|
|
|
access_bits|= bit;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2004-07-19 16:01:53 +02:00
|
|
|
if (next_field)
|
|
|
|
*next_field=fieldnr;
|
2000-07-31 21:29:14 +02:00
|
|
|
return access_bits;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2002-06-12 14:04:18 +02:00
|
|
|
Return a number which, if sorted 'desc', puts strings in this order:
|
|
|
|
no wildcards
|
|
|
|
wildcards
|
|
|
|
empty string
|
|
|
|
*/
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
static ulong get_sort(uint count,...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
va_start(args,count);
|
|
|
|
ulong sort=0;
|
|
|
|
|
2004-08-12 06:41:35 +02:00
|
|
|
/* Should not use this function with more than 4 arguments for compare. */
|
|
|
|
DBUG_ASSERT(count <= 4);
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
while (count--)
|
|
|
|
{
|
2004-08-12 06:41:35 +02:00
|
|
|
char *start, *str= va_arg(args,char*);
|
|
|
|
uint chars= 0;
|
|
|
|
uint wild_pos= 0; /* first wildcard position */
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2004-08-26 17:26:38 +02:00
|
|
|
if ((start= str))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
for (; *str ; str++)
|
|
|
|
{
|
2008-02-13 16:34:12 +01:00
|
|
|
if (*str == wild_prefix && str[1])
|
|
|
|
str++;
|
|
|
|
else if (*str == wild_many || *str == wild_one)
|
2004-08-12 06:41:35 +02:00
|
|
|
{
|
2004-08-26 17:26:38 +02:00
|
|
|
wild_pos= (uint) (str - start) + 1;
|
2004-08-12 06:41:35 +02:00
|
|
|
break;
|
|
|
|
}
|
2004-08-26 17:26:38 +02:00
|
|
|
chars= 128; // Marker that chars existed
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
}
|
2004-08-26 17:26:38 +02:00
|
|
|
sort= (sort << 8) + (wild_pos ? min(wild_pos, 127) : chars);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
va_end(args);
|
|
|
|
return sort;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b)
|
|
|
|
{
|
|
|
|
if (a->sort > b->sort)
|
|
|
|
return -1;
|
|
|
|
if (a->sort < b->sort)
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-02-12 20:55:37 +01:00
|
|
|
|
2002-11-24 15:07:53 +01:00
|
|
|
/*
|
2003-09-11 18:06:23 +02:00
|
|
|
Seek ACL entry for a user, check password, SSL cypher, and if
|
|
|
|
everything is OK, update THD user data and USER_RESOURCES struct.
|
2002-11-24 15:07:53 +01:00
|
|
|
|
2003-09-11 18:06:23 +02:00
|
|
|
IMPLEMENTATION
|
|
|
|
This function does not check if the user has any sensible privileges:
|
|
|
|
only user's existence and validity is checked.
|
|
|
|
Note, that entire operation is protected by acl_cache_lock.
|
2002-11-30 18:58:53 +01:00
|
|
|
|
2003-07-01 21:40:59 +02:00
|
|
|
SYNOPSIS
|
2003-07-18 16:25:54 +02:00
|
|
|
acl_getroot()
|
|
|
|
thd thread handle. If all checks are OK,
|
2005-09-28 16:43:46 +02:00
|
|
|
thd->security_ctx->priv_user/master_access are updated.
|
|
|
|
thd->security_ctx->host/ip/user are used for checks.
|
2003-07-18 16:25:54 +02:00
|
|
|
mqh user resources; on success mqh is reset, else
|
|
|
|
unchanged
|
2004-10-07 00:45:06 +02:00
|
|
|
passwd scrambled & crypted password, received from client
|
2003-07-18 16:25:54 +02:00
|
|
|
(to check): thd->scramble or thd->scramble_323 is
|
|
|
|
used to decrypt passwd, so they must contain
|
|
|
|
original random string,
|
|
|
|
passwd_len length of passwd, must be one of 0, 8,
|
|
|
|
SCRAMBLE_LENGTH_323, SCRAMBLE_LENGTH
|
|
|
|
'thd' and 'mqh' are updated on success; other params are IN.
|
|
|
|
|
2003-09-11 18:06:23 +02:00
|
|
|
RETURN VALUE
|
2003-07-18 16:25:54 +02:00
|
|
|
0 success: thd->priv_user, thd->priv_host, thd->master_access, mqh are
|
|
|
|
updated
|
2004-10-07 00:45:06 +02:00
|
|
|
1 user not found or authentication failure
|
2003-07-04 18:52:04 +02:00
|
|
|
2 user found, has long (4.1.1) salt, but passwd is in old (3.23) format.
|
2003-07-01 21:40:59 +02:00
|
|
|
-1 user found, has short (3.23) salt, but passwd is in new (4.1.1) format.
|
2002-01-29 17:32:16 +01:00
|
|
|
*/
|
|
|
|
|
2003-07-08 00:36:14 +02:00
|
|
|
int acl_getroot(THD *thd, USER_RESOURCES *mqh,
|
|
|
|
const char *passwd, uint passwd_len)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2003-09-03 18:53:08 +02:00
|
|
|
ulong user_access= NO_ACCESS;
|
|
|
|
int res= 1;
|
|
|
|
ACL_USER *acl_user= 0;
|
2005-09-20 20:20:38 +02:00
|
|
|
Security_context *sctx= thd->security_ctx;
|
2002-08-08 02:12:02 +02:00
|
|
|
DBUG_ENTER("acl_getroot");
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
if (!initialized)
|
2002-08-08 02:12:02 +02:00
|
|
|
{
|
2003-07-18 16:25:54 +02:00
|
|
|
/*
|
|
|
|
here if mysqld's been started with --skip-grant-tables option.
|
|
|
|
*/
|
2005-09-15 21:29:07 +02:00
|
|
|
sctx->skip_grants();
|
2003-09-03 18:53:08 +02:00
|
|
|
bzero((char*) mqh, sizeof(*mqh));
|
2003-07-18 16:25:54 +02:00
|
|
|
DBUG_RETURN(0);
|
2002-08-08 02:12:02 +02:00
|
|
|
}
|
2003-07-01 21:40:59 +02:00
|
|
|
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_lock(&acl_cache->lock);
|
2002-11-30 18:58:53 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
/*
|
2003-07-01 21:40:59 +02:00
|
|
|
Find acl entry in user database. Note, that find_acl_user is not the same,
|
|
|
|
because it doesn't take into account the case when user is not empty,
|
|
|
|
but acl_user->user is empty
|
2000-07-31 21:29:14 +02:00
|
|
|
*/
|
2002-11-30 18:58:53 +01:00
|
|
|
|
2003-07-01 21:40:59 +02:00
|
|
|
for (uint i=0 ; i < acl_users.elements ; i++)
|
2003-02-14 10:47:41 +01:00
|
|
|
{
|
2003-09-11 18:06:23 +02:00
|
|
|
ACL_USER *acl_user_tmp= dynamic_element(&acl_users,i,ACL_USER*);
|
2005-09-15 21:29:07 +02:00
|
|
|
if (!acl_user_tmp->user || !strcmp(sctx->user, acl_user_tmp->user))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2005-09-15 21:29:07 +02:00
|
|
|
if (compare_hostname(&acl_user_tmp->host, sctx->host, sctx->ip))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2003-07-01 21:40:59 +02:00
|
|
|
/* check password: it should be empty or valid */
|
2003-09-11 18:06:23 +02:00
|
|
|
if (passwd_len == acl_user_tmp->salt_len)
|
2002-11-30 14:31:58 +01:00
|
|
|
{
|
2003-09-11 18:06:23 +02:00
|
|
|
if (acl_user_tmp->salt_len == 0 ||
|
2004-06-02 00:27:59 +02:00
|
|
|
(acl_user_tmp->salt_len == SCRAMBLE_LENGTH ?
|
|
|
|
check_scramble(passwd, thd->scramble, acl_user_tmp->salt) :
|
2003-07-18 16:25:54 +02:00
|
|
|
check_scramble_323(passwd, thd->scramble,
|
2004-06-02 00:27:59 +02:00
|
|
|
(ulong *) acl_user_tmp->salt)) == 0)
|
2003-07-01 21:40:59 +02:00
|
|
|
{
|
2003-09-11 18:06:23 +02:00
|
|
|
acl_user= acl_user_tmp;
|
2003-07-01 21:40:59 +02:00
|
|
|
res= 0;
|
|
|
|
}
|
2002-11-30 18:58:53 +01:00
|
|
|
}
|
2003-07-01 21:40:59 +02:00
|
|
|
else if (passwd_len == SCRAMBLE_LENGTH &&
|
2003-09-11 18:06:23 +02:00
|
|
|
acl_user_tmp->salt_len == SCRAMBLE_LENGTH_323)
|
2003-07-01 21:40:59 +02:00
|
|
|
res= -1;
|
2003-07-04 18:52:04 +02:00
|
|
|
else if (passwd_len == SCRAMBLE_LENGTH_323 &&
|
2003-09-11 18:06:23 +02:00
|
|
|
acl_user_tmp->salt_len == SCRAMBLE_LENGTH)
|
2003-07-04 18:52:04 +02:00
|
|
|
res= 2;
|
2003-07-01 21:40:59 +02:00
|
|
|
/* linear search complete: */
|
|
|
|
break;
|
2002-11-30 14:31:58 +01:00
|
|
|
}
|
2002-11-30 18:58:53 +01:00
|
|
|
}
|
2003-02-14 10:47:41 +01:00
|
|
|
}
|
2003-07-01 21:40:59 +02:00
|
|
|
/*
|
|
|
|
This was moved to separate tree because of heavy HAVE_OPENSSL case.
|
|
|
|
If acl_user is not null, res is 0.
|
|
|
|
*/
|
2002-11-30 18:58:53 +01:00
|
|
|
|
|
|
|
if (acl_user)
|
|
|
|
{
|
2003-07-01 21:40:59 +02:00
|
|
|
/* OK. User found and password checked continue validation */
|
2003-08-27 01:51:39 +02:00
|
|
|
#ifdef HAVE_OPENSSL
|
2003-11-20 21:06:25 +01:00
|
|
|
Vio *vio=thd->net.vio;
|
2003-08-29 12:44:35 +02:00
|
|
|
SSL *ssl= (SSL*) vio->ssl_arg;
|
2009-05-25 15:00:18 +02:00
|
|
|
X509 *cert;
|
2003-08-27 01:51:39 +02:00
|
|
|
#endif
|
2003-09-03 18:53:08 +02:00
|
|
|
|
2002-12-06 21:01:12 +01:00
|
|
|
/*
|
2003-05-19 15:35:49 +02:00
|
|
|
At this point we know that user is allowed to connect
|
2002-12-06 21:01:12 +01:00
|
|
|
from given host by given username/password pair. Now
|
|
|
|
we check if SSL is required, if user is using SSL and
|
|
|
|
if X509 certificate attributes are OK
|
|
|
|
*/
|
|
|
|
switch (acl_user->ssl_type) {
|
|
|
|
case SSL_TYPE_NOT_SPECIFIED: // Impossible
|
2003-09-03 18:53:08 +02:00
|
|
|
case SSL_TYPE_NONE: // SSL is not required
|
|
|
|
user_access= acl_user->access;
|
2002-12-06 21:01:12 +01:00
|
|
|
break;
|
2003-07-23 16:50:18 +02:00
|
|
|
#ifdef HAVE_OPENSSL
|
2003-09-03 18:53:08 +02:00
|
|
|
case SSL_TYPE_ANY: // Any kind of SSL is ok
|
2002-12-06 21:01:12 +01:00
|
|
|
if (vio_type(vio) == VIO_TYPE_SSL)
|
2003-09-03 18:53:08 +02:00
|
|
|
user_access= acl_user->access;
|
2002-12-06 21:01:12 +01:00
|
|
|
break;
|
|
|
|
case SSL_TYPE_X509: /* Client should have any valid certificate. */
|
|
|
|
/*
|
|
|
|
Connections with non-valid certificates are dropped already
|
|
|
|
in sslaccept() anyway, so we do not check validity here.
|
2003-09-03 18:53:08 +02:00
|
|
|
|
2003-05-19 15:35:49 +02:00
|
|
|
We need to check for absence of SSL because without SSL
|
|
|
|
we should reject connection.
|
2002-12-06 21:01:12 +01:00
|
|
|
*/
|
2003-08-11 21:44:43 +02:00
|
|
|
if (vio_type(vio) == VIO_TYPE_SSL &&
|
2003-08-29 12:44:35 +02:00
|
|
|
SSL_get_verify_result(ssl) == X509_V_OK &&
|
2009-05-25 15:00:18 +02:00
|
|
|
(cert= SSL_get_peer_certificate(ssl)))
|
|
|
|
{
|
2003-09-03 18:53:08 +02:00
|
|
|
user_access= acl_user->access;
|
2009-05-25 15:00:18 +02:00
|
|
|
X509_free(cert);
|
|
|
|
}
|
2002-12-06 21:01:12 +01:00
|
|
|
break;
|
|
|
|
case SSL_TYPE_SPECIFIED: /* Client should have specified attrib */
|
|
|
|
/*
|
|
|
|
We do not check for absence of SSL because without SSL it does
|
|
|
|
not pass all checks here anyway.
|
|
|
|
If cipher name is specified, we compare it to actual cipher in
|
|
|
|
use.
|
|
|
|
*/
|
2003-08-11 21:44:43 +02:00
|
|
|
if (vio_type(vio) != VIO_TYPE_SSL ||
|
2003-08-29 12:44:35 +02:00
|
|
|
SSL_get_verify_result(ssl) != X509_V_OK)
|
2003-05-19 15:35:49 +02:00
|
|
|
break;
|
2002-12-06 21:01:12 +01:00
|
|
|
if (acl_user->ssl_cipher)
|
2002-11-30 14:31:58 +01:00
|
|
|
{
|
2002-12-06 21:01:12 +01:00
|
|
|
DBUG_PRINT("info",("comparing ciphers: '%s' and '%s'",
|
2003-08-29 12:44:35 +02:00
|
|
|
acl_user->ssl_cipher,SSL_get_cipher(ssl)));
|
|
|
|
if (!strcmp(acl_user->ssl_cipher,SSL_get_cipher(ssl)))
|
2003-09-03 18:53:08 +02:00
|
|
|
user_access= acl_user->access;
|
2002-12-06 21:01:12 +01:00
|
|
|
else
|
|
|
|
{
|
2003-05-19 15:35:49 +02:00
|
|
|
if (global_system_variables.log_warnings)
|
2004-09-04 20:17:09 +02:00
|
|
|
sql_print_information("X509 ciphers mismatch: should be '%s' but is '%s'",
|
|
|
|
acl_user->ssl_cipher,
|
|
|
|
SSL_get_cipher(ssl));
|
2002-12-06 21:01:12 +01:00
|
|
|
break;
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2002-12-06 21:01:12 +01:00
|
|
|
/* Prepare certificate (if exists) */
|
|
|
|
DBUG_PRINT("info",("checkpoint 1"));
|
2003-12-17 16:35:34 +01:00
|
|
|
if (!(cert= SSL_get_peer_certificate(ssl)))
|
|
|
|
{
|
|
|
|
user_access=NO_ACCESS;
|
|
|
|
break;
|
|
|
|
}
|
2002-12-06 21:01:12 +01:00
|
|
|
DBUG_PRINT("info",("checkpoint 2"));
|
2004-10-07 00:45:06 +02:00
|
|
|
/* If X509 issuer is specified, we check it... */
|
2002-12-06 21:01:12 +01:00
|
|
|
if (acl_user->x509_issuer)
|
2002-11-30 14:31:58 +01:00
|
|
|
{
|
2003-07-31 15:11:52 +02:00
|
|
|
DBUG_PRINT("info",("checkpoint 3"));
|
2006-03-10 16:41:14 +01:00
|
|
|
char *ptr = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
|
|
|
|
DBUG_PRINT("info",("comparing issuers: '%s' and '%s'",
|
2002-12-06 21:01:12 +01:00
|
|
|
acl_user->x509_issuer, ptr));
|
2003-07-31 15:11:52 +02:00
|
|
|
if (strcmp(acl_user->x509_issuer, ptr))
|
2003-07-01 21:40:59 +02:00
|
|
|
{
|
2003-07-31 15:11:52 +02:00
|
|
|
if (global_system_variables.log_warnings)
|
2004-09-04 20:17:09 +02:00
|
|
|
sql_print_information("X509 issuer mismatch: should be '%s' "
|
|
|
|
"but is '%s'", acl_user->x509_issuer, ptr);
|
2003-07-01 21:40:59 +02:00
|
|
|
free(ptr);
|
2009-05-25 15:00:18 +02:00
|
|
|
X509_free(cert);
|
2006-08-22 14:29:48 +02:00
|
|
|
user_access=NO_ACCESS;
|
2003-07-31 15:11:52 +02:00
|
|
|
break;
|
2003-07-01 21:40:59 +02:00
|
|
|
}
|
2003-09-03 18:53:08 +02:00
|
|
|
user_access= acl_user->access;
|
2003-07-31 15:11:52 +02:00
|
|
|
free(ptr);
|
2002-11-30 14:31:58 +01:00
|
|
|
}
|
2002-12-06 21:01:12 +01:00
|
|
|
DBUG_PRINT("info",("checkpoint 4"));
|
|
|
|
/* X509 subject is specified, we check it .. */
|
|
|
|
if (acl_user->x509_subject)
|
|
|
|
{
|
2003-07-31 15:11:52 +02:00
|
|
|
char *ptr= X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
|
|
|
|
DBUG_PRINT("info",("comparing subjects: '%s' and '%s'",
|
|
|
|
acl_user->x509_subject, ptr));
|
|
|
|
if (strcmp(acl_user->x509_subject,ptr))
|
2003-07-01 21:40:59 +02:00
|
|
|
{
|
2003-07-31 15:11:52 +02:00
|
|
|
if (global_system_variables.log_warnings)
|
2006-08-22 14:29:48 +02:00
|
|
|
sql_print_information("X509 subject mismatch: should be '%s' but is '%s'",
|
2003-07-31 15:11:52 +02:00
|
|
|
acl_user->x509_subject, ptr);
|
2006-08-22 14:29:48 +02:00
|
|
|
free(ptr);
|
2009-05-25 15:00:18 +02:00
|
|
|
X509_free(cert);
|
2006-08-22 14:29:48 +02:00
|
|
|
user_access=NO_ACCESS;
|
|
|
|
break;
|
2003-07-01 21:40:59 +02:00
|
|
|
}
|
2006-08-22 14:29:48 +02:00
|
|
|
user_access= acl_user->access;
|
2003-07-31 15:11:52 +02:00
|
|
|
free(ptr);
|
2002-12-06 21:01:12 +01:00
|
|
|
}
|
2009-05-25 15:00:18 +02:00
|
|
|
/* Deallocate the X509 certificate. */
|
|
|
|
X509_free(cert);
|
2002-12-06 21:01:12 +01:00
|
|
|
break;
|
2002-11-30 14:31:58 +01:00
|
|
|
#else /* HAVE_OPENSSL */
|
2003-08-11 21:44:43 +02:00
|
|
|
default:
|
2003-07-23 16:50:18 +02:00
|
|
|
/*
|
2003-07-31 15:11:52 +02:00
|
|
|
If we don't have SSL but SSL is required for this user the
|
|
|
|
authentication should fail.
|
|
|
|
*/
|
2003-07-23 16:50:18 +02:00
|
|
|
break;
|
|
|
|
#endif /* HAVE_OPENSSL */
|
2002-11-30 14:31:58 +01:00
|
|
|
}
|
2005-09-15 21:29:07 +02:00
|
|
|
sctx->master_access= user_access;
|
|
|
|
sctx->priv_user= acl_user->user ? sctx->user : (char *) "";
|
2003-07-01 21:40:59 +02:00
|
|
|
*mqh= acl_user->user_resource;
|
2003-07-23 16:50:18 +02:00
|
|
|
|
2003-07-01 21:40:59 +02:00
|
|
|
if (acl_user->host.hostname)
|
2005-09-15 21:29:07 +02:00
|
|
|
strmake(sctx->priv_host, acl_user->host.hostname, MAX_HOSTNAME);
|
2003-07-01 21:40:59 +02:00
|
|
|
else
|
2005-09-15 21:29:07 +02:00
|
|
|
*sctx->priv_host= 0;
|
2003-07-01 21:40:59 +02:00
|
|
|
}
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_unlock(&acl_cache->lock);
|
2003-07-01 21:40:59 +02:00
|
|
|
DBUG_RETURN(res);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-12-13 16:40:52 +01:00
|
|
|
/*
|
2005-09-20 20:20:38 +02:00
|
|
|
This is like acl_getroot() above, but it doesn't check password,
|
|
|
|
and we don't care about the user resources.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
acl_getroot_no_password()
|
|
|
|
sctx Context which should be initialized
|
|
|
|
user user name
|
|
|
|
host host name
|
|
|
|
ip IP
|
|
|
|
db current data base name
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
FALSE OK
|
|
|
|
TRUE Error
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool acl_getroot_no_password(Security_context *sctx, char *user, char *host,
|
|
|
|
char *ip, char *db)
|
2003-12-13 16:40:52 +01:00
|
|
|
{
|
|
|
|
int res= 1;
|
2004-03-02 11:52:19 +01:00
|
|
|
uint i;
|
2003-12-13 16:40:52 +01:00
|
|
|
ACL_USER *acl_user= 0;
|
|
|
|
DBUG_ENTER("acl_getroot_no_password");
|
|
|
|
|
2005-10-27 23:18:23 +02:00
|
|
|
DBUG_PRINT("enter", ("Host: '%s', Ip: '%s', User: '%s', db: '%s'",
|
|
|
|
(host ? host : "(NULL)"), (ip ? ip : "(NULL)"),
|
2006-01-03 17:54:54 +01:00
|
|
|
user, (db ? db : "(NULL)")));
|
2005-09-15 21:29:07 +02:00
|
|
|
sctx->user= user;
|
|
|
|
sctx->host= host;
|
|
|
|
sctx->ip= ip;
|
|
|
|
sctx->host_or_ip= host ? host : (ip ? ip : "");
|
|
|
|
|
2003-12-13 16:40:52 +01:00
|
|
|
if (!initialized)
|
|
|
|
{
|
2005-09-15 21:29:07 +02:00
|
|
|
/*
|
2003-12-13 16:40:52 +01:00
|
|
|
here if mysqld's been started with --skip-grant-tables option.
|
|
|
|
*/
|
2005-09-15 21:29:07 +02:00
|
|
|
sctx->skip_grants();
|
2005-09-20 20:20:38 +02:00
|
|
|
DBUG_RETURN(FALSE);
|
2003-12-13 16:40:52 +01:00
|
|
|
}
|
|
|
|
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_lock(&acl_cache->lock);
|
2003-12-13 16:40:52 +01:00
|
|
|
|
2005-09-15 21:29:07 +02:00
|
|
|
sctx->master_access= 0;
|
|
|
|
sctx->db_access= 0;
|
2006-05-26 10:49:39 +02:00
|
|
|
sctx->priv_user= (char *) "";
|
|
|
|
*sctx->priv_host= 0;
|
2004-03-02 11:52:19 +01:00
|
|
|
|
2003-12-13 16:40:52 +01:00
|
|
|
/*
|
|
|
|
Find acl entry in user database.
|
|
|
|
This is specially tailored to suit the check we do for CALL of
|
2005-09-15 21:29:07 +02:00
|
|
|
a stored procedure; user is set to what is actually a
|
2003-12-13 16:40:52 +01:00
|
|
|
priv_user, which can be ''.
|
|
|
|
*/
|
2004-03-02 11:52:19 +01:00
|
|
|
for (i=0 ; i < acl_users.elements ; i++)
|
2003-12-13 16:40:52 +01:00
|
|
|
{
|
2007-06-05 20:18:07 +02:00
|
|
|
ACL_USER *acl_user_tmp= dynamic_element(&acl_users,i,ACL_USER*);
|
|
|
|
if ((!acl_user_tmp->user && !user[0]) ||
|
|
|
|
(acl_user_tmp->user && strcmp(user, acl_user_tmp->user) == 0))
|
2003-12-13 16:40:52 +01:00
|
|
|
{
|
2007-06-05 20:18:07 +02:00
|
|
|
if (compare_hostname(&acl_user_tmp->host, host, ip))
|
2003-12-13 16:40:52 +01:00
|
|
|
{
|
2007-06-05 20:18:07 +02:00
|
|
|
acl_user= acl_user_tmp;
|
|
|
|
res= 0;
|
|
|
|
break;
|
2003-12-13 16:40:52 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (acl_user)
|
|
|
|
{
|
2004-03-02 11:52:19 +01:00
|
|
|
for (i=0 ; i < acl_dbs.elements ; i++)
|
|
|
|
{
|
|
|
|
ACL_DB *acl_db= dynamic_element(&acl_dbs, i, ACL_DB*);
|
|
|
|
if (!acl_db->user ||
|
2005-09-15 21:29:07 +02:00
|
|
|
(user && user[0] && !strcmp(user, acl_db->user)))
|
2004-03-02 11:52:19 +01:00
|
|
|
{
|
2005-09-15 21:29:07 +02:00
|
|
|
if (compare_hostname(&acl_db->host, host, ip))
|
2004-03-02 11:52:19 +01:00
|
|
|
{
|
2005-12-15 15:23:16 +01:00
|
|
|
if (!acl_db->db || (db && !wild_compare(db, acl_db->db, 0)))
|
2004-03-02 11:52:19 +01:00
|
|
|
{
|
2005-09-15 21:29:07 +02:00
|
|
|
sctx->db_access= acl_db->access;
|
2004-03-02 11:52:19 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-09-15 21:29:07 +02:00
|
|
|
sctx->master_access= acl_user->access;
|
|
|
|
sctx->priv_user= acl_user->user ? user : (char *) "";
|
2003-12-13 16:40:52 +01:00
|
|
|
|
|
|
|
if (acl_user->host.hostname)
|
2005-09-15 21:29:07 +02:00
|
|
|
strmake(sctx->priv_host, acl_user->host.hostname, MAX_HOSTNAME);
|
2003-12-13 16:40:52 +01:00
|
|
|
else
|
2005-09-15 21:29:07 +02:00
|
|
|
*sctx->priv_host= 0;
|
2003-12-13 16:40:52 +01:00
|
|
|
}
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_unlock(&acl_cache->lock);
|
2003-12-13 16:40:52 +01:00
|
|
|
DBUG_RETURN(res);
|
|
|
|
}
|
|
|
|
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
static uchar* check_get_key(ACL_USER *buff, size_t *length,
|
|
|
|
my_bool not_used __attribute__((unused)))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
*length=buff->hostname_length;
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
return (uchar*) buff->host.hostname;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2003-07-01 21:40:59 +02:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
static void acl_update_user(const char *user, const char *host,
|
2003-07-01 21:40:59 +02:00
|
|
|
const char *password, uint password_len,
|
2001-09-30 04:46:20 +02:00
|
|
|
enum SSL_type ssl_type,
|
|
|
|
const char *ssl_cipher,
|
|
|
|
const char *x509_issuer,
|
|
|
|
const char *x509_subject,
|
2002-11-30 18:58:53 +01:00
|
|
|
USER_RESOURCES *mqh,
|
2002-06-12 14:04:18 +02:00
|
|
|
ulong privileges)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2006-05-06 09:25:59 +02:00
|
|
|
safe_mutex_assert_owner(&acl_cache->lock);
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
for (uint i=0 ; i < acl_users.elements ; i++)
|
|
|
|
{
|
|
|
|
ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*);
|
2009-06-10 16:04:07 +02:00
|
|
|
if ((!acl_user->user && !user[0]) ||
|
|
|
|
(acl_user->user && !strcmp(user,acl_user->user)))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2009-06-10 16:04:07 +02:00
|
|
|
if ((!acl_user->host.hostname && !host[0]) ||
|
|
|
|
(acl_user->host.hostname &&
|
|
|
|
!my_strcasecmp(system_charset_info, host, acl_user->host.hostname)))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
acl_user->access=privileges;
|
2004-12-29 18:30:37 +01:00
|
|
|
if (mqh->specified_limits & USER_RESOURCES::QUERIES_PER_HOUR)
|
2002-06-20 15:46:25 +02:00
|
|
|
acl_user->user_resource.questions=mqh->questions;
|
2004-12-29 18:30:37 +01:00
|
|
|
if (mqh->specified_limits & USER_RESOURCES::UPDATES_PER_HOUR)
|
2002-06-20 15:46:25 +02:00
|
|
|
acl_user->user_resource.updates=mqh->updates;
|
2004-12-29 18:30:37 +01:00
|
|
|
if (mqh->specified_limits & USER_RESOURCES::CONNECTIONS_PER_HOUR)
|
|
|
|
acl_user->user_resource.conn_per_hour= mqh->conn_per_hour;
|
|
|
|
if (mqh->specified_limits & USER_RESOURCES::USER_CONNECTIONS)
|
|
|
|
acl_user->user_resource.user_conn= mqh->user_conn;
|
2002-09-05 15:17:08 +02:00
|
|
|
if (ssl_type != SSL_TYPE_NOT_SPECIFIED)
|
|
|
|
{
|
|
|
|
acl_user->ssl_type= ssl_type;
|
|
|
|
acl_user->ssl_cipher= (ssl_cipher ? strdup_root(&mem,ssl_cipher) :
|
|
|
|
0);
|
|
|
|
acl_user->x509_issuer= (x509_issuer ? strdup_root(&mem,x509_issuer) :
|
|
|
|
0);
|
|
|
|
acl_user->x509_subject= (x509_subject ?
|
|
|
|
strdup_root(&mem,x509_subject) : 0);
|
|
|
|
}
|
2004-03-01 20:54:08 +01:00
|
|
|
if (password)
|
|
|
|
set_user_salt(acl_user, password, password_len);
|
2003-07-01 21:40:59 +02:00
|
|
|
/* search complete: */
|
2000-07-31 21:29:14 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void acl_insert_user(const char *user, const char *host,
|
2003-07-01 21:40:59 +02:00
|
|
|
const char *password, uint password_len,
|
2001-09-30 04:46:20 +02:00
|
|
|
enum SSL_type ssl_type,
|
|
|
|
const char *ssl_cipher,
|
|
|
|
const char *x509_issuer,
|
|
|
|
const char *x509_subject,
|
2002-05-15 12:50:38 +02:00
|
|
|
USER_RESOURCES *mqh,
|
2002-06-12 14:04:18 +02:00
|
|
|
ulong privileges)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
ACL_USER acl_user;
|
2006-05-06 09:25:59 +02:00
|
|
|
|
|
|
|
safe_mutex_assert_owner(&acl_cache->lock);
|
|
|
|
|
2003-07-21 13:46:57 +02:00
|
|
|
acl_user.user=*user ? strdup_root(&mem,user) : 0;
|
2004-05-05 16:05:24 +02:00
|
|
|
update_hostname(&acl_user.host, *host ? strdup_root(&mem, host): 0);
|
2000-07-31 21:29:14 +02:00
|
|
|
acl_user.access=privileges;
|
2002-05-15 12:50:38 +02:00
|
|
|
acl_user.user_resource = *mqh;
|
2000-07-31 21:29:14 +02:00
|
|
|
acl_user.sort=get_sort(2,acl_user.host.hostname,acl_user.user);
|
2004-04-28 16:45:08 +02:00
|
|
|
acl_user.hostname_length=(uint) strlen(host);
|
2002-09-05 15:17:08 +02:00
|
|
|
acl_user.ssl_type= (ssl_type != SSL_TYPE_NOT_SPECIFIED ?
|
|
|
|
ssl_type : SSL_TYPE_NONE);
|
|
|
|
acl_user.ssl_cipher= ssl_cipher ? strdup_root(&mem,ssl_cipher) : 0;
|
|
|
|
acl_user.x509_issuer= x509_issuer ? strdup_root(&mem,x509_issuer) : 0;
|
|
|
|
acl_user.x509_subject=x509_subject ? strdup_root(&mem,x509_subject) : 0;
|
2003-07-01 21:40:59 +02:00
|
|
|
|
|
|
|
set_user_salt(&acl_user, password, password_len);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2009-11-24 14:54:59 +01:00
|
|
|
(void) push_dynamic(&acl_users,(uchar*) &acl_user);
|
2006-06-06 13:21:07 +02:00
|
|
|
if (!acl_user.host.hostname ||
|
|
|
|
(acl_user.host.hostname[0] == wild_many && !acl_user.host.hostname[1]))
|
2003-05-19 15:35:49 +02:00
|
|
|
allow_all_hosts=1; // Anyone can connect /* purecov: tested */
|
2007-10-18 12:32:43 +02:00
|
|
|
my_qsort((uchar*) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements,
|
|
|
|
sizeof(ACL_USER),(qsort_cmp) acl_compare);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2005-12-28 14:43:50 +01:00
|
|
|
/* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */
|
|
|
|
rebuild_check_host();
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void acl_update_db(const char *user, const char *host, const char *db,
|
2002-06-12 14:04:18 +02:00
|
|
|
ulong privileges)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2006-05-06 09:25:59 +02:00
|
|
|
safe_mutex_assert_owner(&acl_cache->lock);
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
for (uint i=0 ; i < acl_dbs.elements ; i++)
|
|
|
|
{
|
|
|
|
ACL_DB *acl_db=dynamic_element(&acl_dbs,i,ACL_DB*);
|
2009-06-10 16:04:07 +02:00
|
|
|
if ((!acl_db->user && !user[0]) ||
|
|
|
|
(acl_db->user &&
|
|
|
|
!strcmp(user,acl_db->user)))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2009-06-10 16:04:07 +02:00
|
|
|
if ((!acl_db->host.hostname && !host[0]) ||
|
|
|
|
(acl_db->host.hostname &&
|
|
|
|
!strcmp(host, acl_db->host.hostname)))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2009-06-10 16:04:07 +02:00
|
|
|
if ((!acl_db->db && !db[0]) ||
|
|
|
|
(acl_db->db && !strcmp(db,acl_db->db)))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
if (privileges)
|
|
|
|
acl_db->access=privileges;
|
|
|
|
else
|
|
|
|
delete_dynamic_element(&acl_dbs,i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-09-22 09:35:15 +02:00
|
|
|
/*
|
|
|
|
Insert a user/db/host combination into the global acl_cache
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
acl_insert_db()
|
|
|
|
user User name
|
|
|
|
host Host name
|
|
|
|
db Database name
|
|
|
|
privileges Bitmap of privileges
|
|
|
|
|
|
|
|
NOTES
|
|
|
|
acl_cache->lock must be locked when calling this
|
|
|
|
*/
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
static void acl_insert_db(const char *user, const char *host, const char *db,
|
2002-06-12 14:04:18 +02:00
|
|
|
ulong privileges)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
ACL_DB acl_db;
|
2002-09-22 09:35:15 +02:00
|
|
|
safe_mutex_assert_owner(&acl_cache->lock);
|
2000-07-31 21:29:14 +02:00
|
|
|
acl_db.user=strdup_root(&mem,user);
|
2006-06-06 13:21:07 +02:00
|
|
|
update_hostname(&acl_db.host, *host ? strdup_root(&mem,host) : 0);
|
2000-07-31 21:29:14 +02:00
|
|
|
acl_db.db=strdup_root(&mem,db);
|
|
|
|
acl_db.access=privileges;
|
|
|
|
acl_db.sort=get_sort(3,acl_db.host.hostname,acl_db.db,acl_db.user);
|
2009-11-24 14:54:59 +01:00
|
|
|
(void) push_dynamic(&acl_dbs,(uchar*) &acl_db);
|
2007-10-18 12:32:43 +02:00
|
|
|
my_qsort((uchar*) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements,
|
|
|
|
sizeof(ACL_DB),(qsort_cmp) acl_compare);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-06-23 19:03:59 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
Get privilege for a host, user and db combination
|
2005-03-26 19:46:42 +01:00
|
|
|
|
|
|
|
as db_is_pattern changes the semantics of comparison,
|
|
|
|
acl_cache is not used if db_is_pattern is set.
|
2003-06-23 19:03:59 +02:00
|
|
|
*/
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2003-10-24 23:27:21 +02:00
|
|
|
ulong acl_get(const char *host, const char *ip,
|
2004-06-01 23:09:14 +02:00
|
|
|
const char *user, const char *db, my_bool db_is_pattern)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2005-06-02 06:56:30 +02:00
|
|
|
ulong host_access= ~(ulong)0, db_access= 0;
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
uint i;
|
|
|
|
size_t key_length;
|
2001-12-13 01:31:19 +01:00
|
|
|
char key[ACL_KEY_LENGTH],*tmp_db,*end;
|
2000-07-31 21:29:14 +02:00
|
|
|
acl_entry *entry;
|
2004-11-12 16:44:17 +01:00
|
|
|
DBUG_ENTER("acl_get");
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_lock(&acl_cache->lock);
|
2003-10-24 23:27:21 +02:00
|
|
|
end=strmov((tmp_db=strmov(strmov(key, ip ? ip : "")+1,user)+1),db);
|
2001-12-13 01:31:19 +01:00
|
|
|
if (lower_case_table_names)
|
|
|
|
{
|
2004-05-22 21:41:58 +02:00
|
|
|
my_casedn_str(files_charset_info, tmp_db);
|
2001-12-13 01:31:19 +01:00
|
|
|
db=tmp_db;
|
|
|
|
}
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
key_length= (size_t) (end-key);
|
|
|
|
if (!db_is_pattern && (entry=(acl_entry*) acl_cache->search((uchar*) key,
|
|
|
|
key_length)))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
db_access=entry->access;
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_unlock(&acl_cache->lock);
|
2004-11-12 16:44:17 +01:00
|
|
|
DBUG_PRINT("exit", ("access: 0x%lx", db_access));
|
|
|
|
DBUG_RETURN(db_access);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Check if there are some access rights for database and user
|
|
|
|
*/
|
|
|
|
for (i=0 ; i < acl_dbs.elements ; i++)
|
|
|
|
{
|
|
|
|
ACL_DB *acl_db=dynamic_element(&acl_dbs,i,ACL_DB*);
|
|
|
|
if (!acl_db->user || !strcmp(user,acl_db->user))
|
|
|
|
{
|
|
|
|
if (compare_hostname(&acl_db->host,host,ip))
|
|
|
|
{
|
2003-07-22 22:21:23 +02:00
|
|
|
if (!acl_db->db || !wild_compare(db,acl_db->db,db_is_pattern))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
db_access=acl_db->access;
|
|
|
|
if (acl_db->host.hostname)
|
|
|
|
goto exit; // Fully specified. Take it
|
|
|
|
break; /* purecov: tested */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!db_access)
|
|
|
|
goto exit; // Can't be better
|
|
|
|
|
|
|
|
/*
|
|
|
|
No host specified for user. Get hostdata from host table
|
|
|
|
*/
|
|
|
|
host_access=0; // Host must be found
|
|
|
|
for (i=0 ; i < acl_hosts.elements ; i++)
|
|
|
|
{
|
|
|
|
ACL_HOST *acl_host=dynamic_element(&acl_hosts,i,ACL_HOST*);
|
|
|
|
if (compare_hostname(&acl_host->host,host,ip))
|
|
|
|
{
|
2003-07-22 22:21:23 +02:00
|
|
|
if (!acl_host->db || !wild_compare(db,acl_host->db,db_is_pattern))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
host_access=acl_host->access; // Fully specified. Take it
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
exit:
|
|
|
|
/* Save entry in cache for quick retrieval */
|
2005-03-26 19:46:42 +01:00
|
|
|
if (!db_is_pattern &&
|
|
|
|
(entry= (acl_entry*) malloc(sizeof(acl_entry)+key_length)))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
entry->access=(db_access & host_access);
|
|
|
|
entry->length=key_length;
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
memcpy((uchar*) entry->key,key,key_length);
|
2000-07-31 21:29:14 +02:00
|
|
|
acl_cache->add(entry);
|
|
|
|
}
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_unlock(&acl_cache->lock);
|
2004-11-12 16:44:17 +01:00
|
|
|
DBUG_PRINT("exit", ("access: 0x%lx", db_access & host_access));
|
|
|
|
DBUG_RETURN(db_access & host_access);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2003-06-23 19:03:59 +02:00
|
|
|
/*
|
|
|
|
Check if there are any possible matching entries for this host
|
|
|
|
|
|
|
|
NOTES
|
|
|
|
All host names without wild cards are stored in a hash table,
|
|
|
|
entries with wildcards are stored in a dynamic array
|
|
|
|
*/
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
static void init_check_host(void)
|
|
|
|
{
|
|
|
|
DBUG_ENTER("init_check_host");
|
2009-11-24 14:54:59 +01:00
|
|
|
(void) my_init_dynamic_array(&acl_wild_hosts,sizeof(struct acl_host_and_ip),
|
|
|
|
acl_users.elements,1);
|
|
|
|
(void) my_hash_init(&acl_check_hosts,system_charset_info,
|
|
|
|
acl_users.elements, 0, 0,
|
|
|
|
(my_hash_get_key) check_get_key, 0, 0);
|
2000-07-31 21:29:14 +02:00
|
|
|
if (!allow_all_hosts)
|
|
|
|
{
|
|
|
|
for (uint i=0 ; i < acl_users.elements ; i++)
|
|
|
|
{
|
|
|
|
ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*);
|
|
|
|
if (strchr(acl_user->host.hostname,wild_many) ||
|
|
|
|
strchr(acl_user->host.hostname,wild_one) ||
|
|
|
|
acl_user->host.ip_mask)
|
|
|
|
{ // Has wildcard
|
|
|
|
uint j;
|
|
|
|
for (j=0 ; j < acl_wild_hosts.elements ; j++)
|
|
|
|
{ // Check if host already exists
|
|
|
|
acl_host_and_ip *acl=dynamic_element(&acl_wild_hosts,j,
|
|
|
|
acl_host_and_ip *);
|
2004-11-25 21:55:49 +01:00
|
|
|
if (!my_strcasecmp(system_charset_info,
|
2002-03-12 18:37:58 +01:00
|
|
|
acl_user->host.hostname, acl->hostname))
|
2000-07-31 21:29:14 +02:00
|
|
|
break; // already stored
|
|
|
|
}
|
|
|
|
if (j == acl_wild_hosts.elements) // If new
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
(void) push_dynamic(&acl_wild_hosts,(uchar*) &acl_user->host);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2009-10-14 18:37:38 +02:00
|
|
|
else if (!my_hash_search(&acl_check_hosts,(uchar*)
|
|
|
|
acl_user->host.hostname,
|
|
|
|
strlen(acl_user->host.hostname)))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
if (my_hash_insert(&acl_check_hosts,(uchar*) acl_user))
|
2000-07-31 21:29:14 +02:00
|
|
|
{ // End of memory
|
|
|
|
allow_all_hosts=1; // Should never happen
|
|
|
|
DBUG_VOID_RETURN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
freeze_size(&acl_wild_hosts);
|
|
|
|
freeze_size(&acl_check_hosts.array);
|
|
|
|
DBUG_VOID_RETURN;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-12-28 14:43:50 +01:00
|
|
|
/*
|
|
|
|
Rebuild lists used for checking of allowed hosts
|
|
|
|
|
|
|
|
We need to rebuild 'acl_check_hosts' and 'acl_wild_hosts' after adding,
|
|
|
|
dropping or renaming user, since they contain pointers to elements of
|
|
|
|
'acl_user' array, which are invalidated by drop operation, and use
|
|
|
|
ACL_USER::host::hostname as a key, which is changed by rename.
|
|
|
|
*/
|
|
|
|
void rebuild_check_host(void)
|
|
|
|
{
|
|
|
|
delete_dynamic(&acl_wild_hosts);
|
2009-10-14 18:37:38 +02:00
|
|
|
my_hash_free(&acl_check_hosts);
|
2005-12-28 14:43:50 +01:00
|
|
|
init_check_host();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
/* Return true if there is no users that can match the given host */
|
|
|
|
|
|
|
|
bool acl_check_host(const char *host, const char *ip)
|
|
|
|
{
|
|
|
|
if (allow_all_hosts)
|
|
|
|
return 0;
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_lock(&acl_cache->lock);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2009-10-14 18:37:38 +02:00
|
|
|
if ((host && my_hash_search(&acl_check_hosts,(uchar*) host,strlen(host))) ||
|
|
|
|
(ip && my_hash_search(&acl_check_hosts,(uchar*) ip, strlen(ip))))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_unlock(&acl_cache->lock);
|
2000-07-31 21:29:14 +02:00
|
|
|
return 0; // Found host
|
|
|
|
}
|
|
|
|
for (uint i=0 ; i < acl_wild_hosts.elements ; i++)
|
|
|
|
{
|
|
|
|
acl_host_and_ip *acl=dynamic_element(&acl_wild_hosts,i,acl_host_and_ip*);
|
|
|
|
if (compare_hostname(acl, host, ip))
|
|
|
|
{
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_unlock(&acl_cache->lock);
|
2000-07-31 21:29:14 +02:00
|
|
|
return 0; // Host ok
|
|
|
|
}
|
|
|
|
}
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_unlock(&acl_cache->lock);
|
2000-07-31 21:29:14 +02:00
|
|
|
return 1; // Host is not allowed
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-07-23 17:31:22 +02:00
|
|
|
/*
|
|
|
|
Check if the user is allowed to change password
|
|
|
|
|
|
|
|
SYNOPSIS:
|
|
|
|
check_change_password()
|
|
|
|
thd THD
|
|
|
|
host hostname for the user
|
|
|
|
user user name
|
2005-01-24 15:48:25 +01:00
|
|
|
new_password new password
|
|
|
|
|
|
|
|
NOTE:
|
|
|
|
new_password cannot be NULL
|
2002-03-12 11:21:51 +01:00
|
|
|
|
2002-07-23 17:31:22 +02:00
|
|
|
RETURN VALUE
|
2003-06-23 19:03:59 +02:00
|
|
|
0 OK
|
|
|
|
1 ERROR ; In this case the error is sent to the client.
|
2002-07-23 17:31:22 +02:00
|
|
|
*/
|
|
|
|
|
2008-03-21 16:23:17 +01:00
|
|
|
int check_change_password(THD *thd, const char *host, const char *user,
|
2005-01-24 15:48:25 +01:00
|
|
|
char *new_password, uint new_password_len)
|
2002-07-23 17:31:22 +02:00
|
|
|
{
|
2000-07-31 21:29:14 +02:00
|
|
|
if (!initialized)
|
|
|
|
{
|
2004-10-20 03:04:37 +02:00
|
|
|
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables");
|
2004-07-30 22:05:08 +02:00
|
|
|
return(1);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2002-03-12 10:38:22 +01:00
|
|
|
if (!thd->slave_thread &&
|
2005-09-15 21:29:07 +02:00
|
|
|
(strcmp(thd->security_ctx->user, user) ||
|
|
|
|
my_strcasecmp(system_charset_info, host,
|
|
|
|
thd->security_ctx->priv_host)))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2005-09-13 13:07:38 +02:00
|
|
|
if (check_access(thd, UPDATE_ACL, "mysql",0,1,0,0))
|
2002-07-23 17:31:22 +02:00
|
|
|
return(1);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2005-09-15 21:29:07 +02:00
|
|
|
if (!thd->slave_thread && !thd->security_ctx->user[0])
|
2002-03-12 10:38:22 +01:00
|
|
|
{
|
2004-11-12 13:34:00 +01:00
|
|
|
my_message(ER_PASSWORD_ANONYMOUS_USER, ER(ER_PASSWORD_ANONYMOUS_USER),
|
|
|
|
MYF(0));
|
2002-07-23 17:31:22 +02:00
|
|
|
return(1);
|
2002-03-12 10:38:22 +01:00
|
|
|
}
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
size_t len= strlen(new_password);
|
2004-08-01 17:21:55 +02:00
|
|
|
if (len && len != SCRAMBLED_PASSWORD_CHAR_LENGTH &&
|
2004-07-30 22:05:08 +02:00
|
|
|
len != SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
|
|
|
|
{
|
2004-10-20 03:04:37 +02:00
|
|
|
my_error(ER_PASSWD_LENGTH, MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH);
|
2004-07-30 22:05:08 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2002-07-23 17:31:22 +02:00
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-09-22 17:02:39 +02:00
|
|
|
/*
|
|
|
|
Change a password for a user
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
change_password()
|
|
|
|
thd Thread handle
|
|
|
|
host Hostname
|
|
|
|
user User name
|
|
|
|
new_password New password for host@user
|
|
|
|
|
|
|
|
RETURN VALUES
|
|
|
|
0 ok
|
|
|
|
1 ERROR; In this case the error is sent to the client.
|
2002-11-30 18:58:53 +01:00
|
|
|
*/
|
2002-09-22 17:02:39 +02:00
|
|
|
|
2002-07-23 17:31:22 +02:00
|
|
|
bool change_password(THD *thd, const char *host, const char *user,
|
|
|
|
char *new_password)
|
|
|
|
{
|
2005-09-01 14:52:59 +02:00
|
|
|
TABLE_LIST tables;
|
|
|
|
TABLE *table;
|
|
|
|
/* Buffer should be extended when password length is extended. */
|
|
|
|
char buff[512];
|
|
|
|
ulong query_length;
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
uint new_password_len= (uint) strlen(new_password);
|
2005-09-01 14:52:59 +02:00
|
|
|
bool result= 1;
|
2002-07-23 17:31:22 +02:00
|
|
|
DBUG_ENTER("change_password");
|
|
|
|
DBUG_PRINT("enter",("host: '%s' user: '%s' new_password: '%s'",
|
|
|
|
host,user,new_password));
|
|
|
|
DBUG_ASSERT(host != 0); // Ensured by parent
|
|
|
|
|
2005-01-24 15:48:25 +01:00
|
|
|
if (check_change_password(thd, host, user, new_password, new_password_len))
|
2002-07-23 17:31:22 +02:00
|
|
|
DBUG_RETURN(1);
|
|
|
|
|
2005-09-01 14:52:59 +02:00
|
|
|
bzero((char*) &tables, sizeof(tables));
|
2005-09-01 23:01:33 +02:00
|
|
|
tables.alias= tables.table_name= (char*) "user";
|
2005-09-01 14:52:59 +02:00
|
|
|
tables.db= (char*) "mysql";
|
|
|
|
|
|
|
|
#ifdef HAVE_REPLICATION
|
|
|
|
/*
|
|
|
|
GRANT and REVOKE are applied the slave in/exclusion rules as they are
|
|
|
|
some kind of updates to the mysql.% tables.
|
|
|
|
*/
|
2005-09-02 08:59:59 +02:00
|
|
|
if (thd->slave_thread && rpl_filter->is_on())
|
2005-09-01 14:52:59 +02:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
The tables must be marked "updating" so that tables_ok() takes them into
|
|
|
|
account in tests. It's ok to leave 'updating' set after tables_ok.
|
|
|
|
*/
|
|
|
|
tables.updating= 1;
|
|
|
|
/* Thanks to bzero, tables.next==0 */
|
2005-11-19 15:56:55 +01:00
|
|
|
if (!(thd->spcont || rpl_filter->tables_ok(0, &tables)))
|
2005-09-01 14:52:59 +02:00
|
|
|
DBUG_RETURN(0);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
WL#3984 (Revise locking of mysql.general_log and mysql.slow_log)
Bug#25422 (Hang with log tables)
Bug 17876 (Truncating mysql.slow_log in a SP after using cursor locks the
thread)
Bug 23044 (Warnings on flush of a log table)
Bug 29129 (Resetting general_log while the GLOBAL READ LOCK is set causes
a deadlock)
Prior to this fix, the server would hang when performing concurrent
ALTER TABLE or TRUNCATE TABLE statements against the LOG TABLES,
which are mysql.general_log and mysql.slow_log.
The root cause traces to the following code:
in sql_base.cc, open_table()
if (table->in_use != thd)
{
/* wait_for_condition will unlock LOCK_open for us */
wait_for_condition(thd, &LOCK_open, &COND_refresh);
}
The problem with this code is that the current implementation of the
LOGGER creates 'fake' THD objects, like
- Log_to_csv_event_handler::general_log_thd
- Log_to_csv_event_handler::slow_log_thd
which are not associated to a real thread running in the server,
so that waiting for these non-existing threads to release table locks
cause the dead lock.
In general, the design of Log_to_csv_event_handler does not fit into the
general architecture of the server, so that the concept of general_log_thd
and slow_log_thd has to be abandoned:
- this implementation does not work with table locking
- it will not work with commands like SHOW PROCESSLIST
- having the log tables always opened does not integrate well with DDL
operations / FLUSH TABLES / SET GLOBAL READ_ONLY
With this patch, the fundamental design of the LOGGER has been changed to:
- always open and close a log table when writing a log
- remove totally the usage of fake THD objects
- clarify how locking of log tables is implemented in general.
See WL#3984 for details related to the new locking design.
Additional changes (misc bugs exposed and fixed):
1)
mysqldump which would ignore some tables in dump_all_tables_in_db(),
but forget to ignore the same in dump_all_views_in_db().
2)
mysqldump would also issue an empty "LOCK TABLE" command when all the tables
to lock are to be ignored (numrows == 0), instead of not issuing the query.
3)
Internal errors handlers could intercept errors but not warnings
(see sql_error.cc).
4)
Implementing a nested call to open tables, for the performance schema tables,
exposed an existing bug in remove_table_from_cache(), which would perform:
in_use->some_tables_deleted=1;
against another thread, without any consideration about thread locking.
This call inside remove_table_from_cache() was not required anyway,
since calling mysql_lock_abort() takes care of aborting -- cleanly -- threads
that might hold a lock on a table.
This line (in_use->some_tables_deleted=1) has been removed.
2007-07-27 08:31:06 +02:00
|
|
|
if (!(table= open_ltable(thd, &tables, TL_WRITE, 0)))
|
2005-09-01 14:52:59 +02:00
|
|
|
DBUG_RETURN(1);
|
|
|
|
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_lock(&acl_cache->lock);
|
2000-07-31 21:29:14 +02:00
|
|
|
ACL_USER *acl_user;
|
2005-08-23 00:48:50 +02:00
|
|
|
if (!(acl_user= find_acl_user(host, user, TRUE)))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_unlock(&acl_cache->lock);
|
2004-11-12 13:34:00 +01:00
|
|
|
my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH), MYF(0));
|
2005-09-01 14:52:59 +02:00
|
|
|
goto end;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2003-07-01 21:40:59 +02:00
|
|
|
/* update loaded acl entry: */
|
|
|
|
set_user_salt(acl_user, new_password, new_password_len);
|
|
|
|
|
2005-09-01 14:52:59 +02:00
|
|
|
if (update_user_table(thd, table,
|
2000-07-31 21:29:14 +02:00
|
|
|
acl_user->host.hostname ? acl_user->host.hostname : "",
|
2002-03-12 10:38:22 +01:00
|
|
|
acl_user->user ? acl_user->user : "",
|
2003-07-01 21:40:59 +02:00
|
|
|
new_password, new_password_len))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_unlock(&acl_cache->lock); /* purecov: deadcode */
|
2005-09-01 14:52:59 +02:00
|
|
|
goto end;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2002-11-30 18:58:53 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
acl_cache->clear(1); // Clear locked hostname cache
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_unlock(&acl_cache->lock);
|
2005-09-01 14:52:59 +02:00
|
|
|
result= 0;
|
|
|
|
if (mysql_bin_log.is_open())
|
|
|
|
{
|
2005-09-01 23:01:33 +02:00
|
|
|
query_length=
|
|
|
|
my_sprintf(buff,
|
2006-11-30 08:08:23 +01:00
|
|
|
(buff,"SET PASSWORD FOR '%-.120s'@'%-.120s'='%-.120s'",
|
2005-09-01 23:01:33 +02:00
|
|
|
acl_user->user ? acl_user->user : "",
|
|
|
|
acl_user->host.hostname ? acl_user->host.hostname : "",
|
|
|
|
new_password));
|
2005-09-01 14:52:59 +02:00
|
|
|
thd->clear_error();
|
2009-11-21 05:28:01 +01:00
|
|
|
result= thd->binlog_query(THD::MYSQL_QUERY_TYPE, buff, query_length,
|
|
|
|
FALSE, FALSE, 0);
|
2005-09-01 14:52:59 +02:00
|
|
|
}
|
|
|
|
end:
|
|
|
|
close_thread_tables(thd);
|
|
|
|
DBUG_RETURN(result);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-14 09:53:09 +02:00
|
|
|
/*
|
|
|
|
Find user in ACL
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
is_acl_user()
|
|
|
|
host host name
|
|
|
|
user user name
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
FALSE user not fond
|
|
|
|
TRUE there are such user
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool is_acl_user(const char *host, const char *user)
|
|
|
|
{
|
|
|
|
bool res;
|
2005-10-18 20:42:26 +02:00
|
|
|
|
|
|
|
/* --skip-grants */
|
|
|
|
if (!initialized)
|
|
|
|
return TRUE;
|
|
|
|
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_lock(&acl_cache->lock);
|
2005-09-15 21:32:01 +02:00
|
|
|
res= find_acl_user(host, user, TRUE) != NULL;
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_unlock(&acl_cache->lock);
|
2005-09-14 09:53:09 +02:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
/*
|
|
|
|
Find first entry that matches the current user
|
|
|
|
*/
|
|
|
|
|
|
|
|
static ACL_USER *
|
2005-08-23 00:48:50 +02:00
|
|
|
find_acl_user(const char *host, const char *user, my_bool exact)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2001-11-27 01:21:44 +01:00
|
|
|
DBUG_ENTER("find_acl_user");
|
2002-06-11 10:20:31 +02:00
|
|
|
DBUG_PRINT("enter",("host: '%s' user: '%s'",host,user));
|
2006-05-06 09:25:59 +02:00
|
|
|
|
|
|
|
safe_mutex_assert_owner(&acl_cache->lock);
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
for (uint i=0 ; i < acl_users.elements ; i++)
|
|
|
|
{
|
|
|
|
ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*);
|
2001-11-27 01:21:44 +01:00
|
|
|
DBUG_PRINT("info",("strcmp('%s','%s'), compare_hostname('%s','%s'),",
|
2006-06-06 13:21:07 +02:00
|
|
|
user, acl_user->user ? acl_user->user : "",
|
|
|
|
host,
|
|
|
|
acl_user->host.hostname ? acl_user->host.hostname :
|
|
|
|
""));
|
2009-06-10 16:04:07 +02:00
|
|
|
if ((!acl_user->user && !user[0]) ||
|
|
|
|
(acl_user->user && !strcmp(user,acl_user->user)))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2006-05-06 09:25:59 +02:00
|
|
|
if (exact ? !my_strcasecmp(system_charset_info, host,
|
2006-01-09 10:31:07 +01:00
|
|
|
acl_user->host.hostname ?
|
|
|
|
acl_user->host.hostname : "") :
|
2005-08-23 00:48:50 +02:00
|
|
|
compare_hostname(&acl_user->host,host,host))
|
2001-11-27 01:21:44 +01:00
|
|
|
{
|
|
|
|
DBUG_RETURN(acl_user);
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
}
|
2001-11-27 01:21:44 +01:00
|
|
|
DBUG_RETURN(0);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-06-23 19:03:59 +02:00
|
|
|
/*
|
|
|
|
Comparing of hostnames
|
|
|
|
|
|
|
|
NOTES
|
|
|
|
A hostname may be of type:
|
|
|
|
hostname (May include wildcards); monty.pp.sci.fi
|
|
|
|
ip (May include wildcards); 192.168.0.0
|
|
|
|
ip/netmask 192.168.0.0/255.255.255.0
|
|
|
|
|
|
|
|
A net mask of 0.0.0.0 is not allowed.
|
|
|
|
*/
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
static const char *calc_ip(const char *ip, long *val, char end)
|
|
|
|
{
|
|
|
|
long ip_val,tmp;
|
|
|
|
if (!(ip=str2int(ip,10,0,255,&ip_val)) || *ip != '.')
|
|
|
|
return 0;
|
|
|
|
ip_val<<=24;
|
|
|
|
if (!(ip=str2int(ip+1,10,0,255,&tmp)) || *ip != '.')
|
|
|
|
return 0;
|
|
|
|
ip_val+=tmp<<16;
|
|
|
|
if (!(ip=str2int(ip+1,10,0,255,&tmp)) || *ip != '.')
|
|
|
|
return 0;
|
|
|
|
ip_val+=tmp<<8;
|
|
|
|
if (!(ip=str2int(ip+1,10,0,255,&tmp)) || *ip != end)
|
|
|
|
return 0;
|
|
|
|
*val=ip_val+tmp;
|
|
|
|
return ip;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void update_hostname(acl_host_and_ip *host, const char *hostname)
|
|
|
|
{
|
2006-06-06 13:21:07 +02:00
|
|
|
host->hostname=(char*) hostname; // This will not be modified!
|
2003-12-12 21:26:58 +01:00
|
|
|
if (!hostname ||
|
2000-07-31 21:29:14 +02:00
|
|
|
(!(hostname=calc_ip(hostname,&host->ip,'/')) ||
|
|
|
|
!(hostname=calc_ip(hostname+1,&host->ip_mask,'\0'))))
|
|
|
|
{
|
2003-12-12 21:26:58 +01:00
|
|
|
host->ip= host->ip_mask=0; // Not a masked ip
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static bool compare_hostname(const acl_host_and_ip *host, const char *hostname,
|
|
|
|
const char *ip)
|
|
|
|
{
|
|
|
|
long tmp;
|
|
|
|
if (host->ip_mask && ip && calc_ip(ip,&tmp,'\0'))
|
|
|
|
{
|
|
|
|
return (tmp & host->ip_mask) == host->ip;
|
|
|
|
}
|
|
|
|
return (!host->hostname ||
|
2004-11-25 21:55:49 +01:00
|
|
|
(hostname && !wild_case_compare(system_charset_info,
|
2006-06-06 13:21:07 +02:00
|
|
|
hostname, host->hostname)) ||
|
|
|
|
(ip && !wild_compare(ip, host->hostname, 0)));
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2009-11-25 11:53:23 +01:00
|
|
|
/**
|
|
|
|
Check if the given host name needs to be resolved or not.
|
|
|
|
Host name has to be resolved if it actually contains *name*.
|
|
|
|
|
|
|
|
For example:
|
|
|
|
192.168.1.1 --> FALSE
|
|
|
|
192.168.1.0/255.255.255.0 --> FALSE
|
|
|
|
% --> FALSE
|
|
|
|
192.168.1.% --> FALSE
|
|
|
|
AB% --> FALSE
|
|
|
|
|
|
|
|
AAAAFFFF --> TRUE (Hostname)
|
|
|
|
AAAA:FFFF:1234:5678 --> FALSE
|
|
|
|
::1 --> FALSE
|
|
|
|
|
|
|
|
This function does not check if the given string is a valid host name or
|
|
|
|
not. It assumes that the argument is a valid host name.
|
|
|
|
|
|
|
|
@param hostname the string to check.
|
|
|
|
|
|
|
|
@return a flag telling if the argument needs to be resolved or not.
|
|
|
|
@retval TRUE the argument is a host name and needs to be resolved.
|
|
|
|
@retval FALSE the argument is either an IP address, or a patter and
|
|
|
|
should not be resolved.
|
|
|
|
*/
|
|
|
|
|
2003-11-20 09:55:48 +01:00
|
|
|
bool hostname_requires_resolving(const char *hostname)
|
|
|
|
{
|
|
|
|
if (!hostname)
|
2004-03-30 01:32:41 +02:00
|
|
|
return FALSE;
|
2009-11-25 11:53:23 +01:00
|
|
|
|
|
|
|
/* Check if hostname is the localhost. */
|
|
|
|
|
|
|
|
size_t hostname_len= strlen(hostname);
|
|
|
|
size_t localhost_len= strlen(my_localhost);
|
|
|
|
|
|
|
|
if (hostname == my_localhost ||
|
|
|
|
(hostname_len == localhost_len &&
|
|
|
|
!my_strnncoll(system_charset_info,
|
|
|
|
(const uchar *) hostname, hostname_len,
|
|
|
|
(const uchar *) my_localhost, strlen(my_localhost))))
|
|
|
|
{
|
2004-03-30 01:32:41 +02:00
|
|
|
return FALSE;
|
2009-11-25 11:53:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
If the string contains any of {':', '%', '_', '/'}, it is definitely
|
|
|
|
not a host name:
|
|
|
|
- ':' means that the string is an IPv6 address;
|
|
|
|
- '%' or '_' means that the string is a pattern;
|
|
|
|
- '/' means that the string is an IPv4 network address;
|
|
|
|
*/
|
|
|
|
|
|
|
|
for (const char *p= hostname; *p; ++p)
|
2003-11-20 09:55:48 +01:00
|
|
|
{
|
2009-11-25 11:53:23 +01:00
|
|
|
switch (*p) {
|
|
|
|
case ':':
|
|
|
|
case '%':
|
|
|
|
case '_':
|
|
|
|
case '/':
|
|
|
|
return FALSE;
|
|
|
|
}
|
2003-11-20 09:55:48 +01:00
|
|
|
}
|
2009-11-25 11:53:23 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
Now we have to tell a host name (ab.cd, 12.ab) from an IPv4 address
|
|
|
|
(12.34.56.78). The assumption is that if the string contains only
|
|
|
|
digits and dots, it is an IPv4 address. Otherwise -- a host name.
|
|
|
|
*/
|
|
|
|
|
|
|
|
for (const char *p= hostname; *p; ++p)
|
|
|
|
{
|
|
|
|
if (*p != '.' && !my_isdigit(&my_charset_latin1, *p))
|
|
|
|
return TRUE; /* a "letter" has been found. */
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE; /* all characters are either dots or digits. */
|
2003-11-20 09:55:48 +01:00
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2005-09-01 14:52:59 +02:00
|
|
|
|
2003-06-23 19:03:59 +02:00
|
|
|
/*
|
2005-09-01 14:52:59 +02:00
|
|
|
Update record for user in mysql.user privilege table with new password.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
update_user_table()
|
|
|
|
thd Thread handle
|
|
|
|
table Pointer to TABLE object for open mysql.user table
|
|
|
|
host/user Hostname/username pair identifying user for which
|
|
|
|
new password should be set
|
|
|
|
new_password New password
|
|
|
|
new_password_len Length of new password
|
2003-06-23 19:03:59 +02:00
|
|
|
*/
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2005-09-01 14:52:59 +02:00
|
|
|
static bool update_user_table(THD *thd, TABLE *table,
|
|
|
|
const char *host, const char *user,
|
2003-07-01 21:40:59 +02:00
|
|
|
const char *new_password, uint new_password_len)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-12-06 01:00:37 +01:00
|
|
|
char user_key[MAX_KEY_LENGTH];
|
2005-09-01 14:52:59 +02:00
|
|
|
int error;
|
2000-07-31 21:29:14 +02:00
|
|
|
DBUG_ENTER("update_user_table");
|
|
|
|
DBUG_PRINT("enter",("user: %s host: %s",user,host));
|
|
|
|
|
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes
Changes that requires code changes in other code of other storage engines.
(Note that all changes are very straightforward and one should find all issues
by compiling a --debug build and fixing all compiler errors and all
asserts in field.cc while running the test suite),
- New optional handler function introduced: reset()
This is called after every DML statement to make it easy for a handler to
statement specific cleanups.
(The only case it's not called is if force the file to be closed)
- handler::extra(HA_EXTRA_RESET) is removed. Code that was there before
should be moved to handler::reset()
- table->read_set contains a bitmap over all columns that are needed
in the query. read_row() and similar functions only needs to read these
columns
- table->write_set contains a bitmap over all columns that will be updated
in the query. write_row() and update_row() only needs to update these
columns.
The above bitmaps should now be up to date in all context
(including ALTER TABLE, filesort()).
The handler is informed of any changes to the bitmap after
fix_fields() by calling the virtual function
handler::column_bitmaps_signal(). If the handler does caching of
these bitmaps (instead of using table->read_set, table->write_set),
it should redo the caching in this code. as the signal() may be sent
several times, it's probably best to set a variable in the signal
and redo the caching on read_row() / write_row() if the variable was
set.
- Removed the read_set and write_set bitmap objects from the handler class
- Removed all column bit handling functions from the handler class.
(Now one instead uses the normal bitmap functions in my_bitmap.c instead
of handler dedicated bitmap functions)
- field->query_id is removed. One should instead instead check
table->read_set and table->write_set if a field is used in the query.
- handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and
handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now
instead use table->read_set to check for which columns to retrieve.
- If a handler needs to call Field->val() or Field->store() on columns
that are not used in the query, one should install a temporary
all-columns-used map while doing so. For this, we provide the following
functions:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
field->val();
dbug_tmp_restore_column_map(table->read_set, old_map);
and similar for the write map:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
field->val();
dbug_tmp_restore_column_map(table->write_set, old_map);
If this is not done, you will sooner or later hit a DBUG_ASSERT
in the field store() / val() functions.
(For not DBUG binaries, the dbug_tmp_restore_column_map() and
dbug_tmp_restore_column_map() are inline dummy functions and should
be optimized away be the compiler).
- If one needs to temporary set the column map for all binaries (and not
just to avoid the DBUG_ASSERT() in the Field::store() / Field::val()
methods) one should use the functions tmp_use_all_columns() and
tmp_restore_column_map() instead of the above dbug_ variants.
- All 'status' fields in the handler base class (like records,
data_file_length etc) are now stored in a 'stats' struct. This makes
it easier to know what status variables are provided by the base
handler. This requires some trivial variable names in the extra()
function.
- New virtual function handler::records(). This is called to optimize
COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true.
(stats.records is not supposed to be an exact value. It's only has to
be 'reasonable enough' for the optimizer to be able to choose a good
optimization path).
- Non virtual handler::init() function added for caching of virtual
constants from engine.
- Removed has_transactions() virtual method. Now one should instead return
HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support
transactions.
- The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument
that is to be used with 'new handler_name()' to allocate the handler
in the right area. The xxxx_create_handler() function is also
responsible for any initialization of the object before returning.
For example, one should change:
static handler *myisam_create_handler(TABLE_SHARE *table)
{
return new ha_myisam(table);
}
->
static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisam(table);
}
- New optional virtual function: use_hidden_primary_key().
This is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key. This allows the handler to take precisions
in remembering any hidden primary key to able to update/delete any
found row. The default handler marks all columns to be read.
- handler::table_flags() now returns a ulonglong (to allow for more flags).
- New/changed table_flags()
- HA_HAS_RECORDS Set if ::records() is supported
- HA_NO_TRANSACTIONS Set if engine doesn't support transactions
- HA_PRIMARY_KEY_REQUIRED_FOR_DELETE
Set if we should mark all primary key columns for
read when reading rows as part of a DELETE
statement. If there is no primary key,
all columns are marked for read.
- HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some
cases (based on table->read_set)
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
- HA_DUPP_POS Renamed to HA_DUPLICATE_POS
- HA_REQUIRES_KEY_COLUMNS_FOR_DELETE
Set this if we should mark ALL key columns for
read when when reading rows as part of a DELETE
statement. In case of an update we will mark
all keys for read for which key part changed
value.
- HA_STATS_RECORDS_IS_EXACT
Set this if stats.records is exact.
(This saves us some extra records() calls
when optimizing COUNT(*))
- Removed table_flags()
- HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if
handler::records() gives an exact count() and
HA_STATS_RECORDS_IS_EXACT if stats.records is exact.
- HA_READ_RND_SAME Removed (no one supported this one)
- Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk()
- Renamed handler::dupp_pos to handler::dup_pos
- Removed not used variable handler::sortkey
Upper level handler changes:
- ha_reset() now does some overall checks and calls ::reset()
- ha_table_flags() added. This is a cached version of table_flags(). The
cache is updated on engine creation time and updated on open.
MySQL level changes (not obvious from the above):
- DBUG_ASSERT() added to check that column usage matches what is set
in the column usage bit maps. (This found a LOT of bugs in current
column marking code).
- In 5.1 before, all used columns was marked in read_set and only updated
columns was marked in write_set. Now we only mark columns for which we
need a value in read_set.
- Column bitmaps are created in open_binary_frm() and open_table_from_share().
(Before this was in table.cc)
- handler::table_flags() calls are replaced with handler::ha_table_flags()
- For calling field->val() you must have the corresponding bit set in
table->read_set. For calling field->store() you must have the
corresponding bit set in table->write_set. (There are asserts in
all store()/val() functions to catch wrong usage)
- thd->set_query_id is renamed to thd->mark_used_columns and instead
of setting this to an integer value, this has now the values:
MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE
Changed also all variables named 'set_query_id' to mark_used_columns.
- In filesort() we now inform the handler of exactly which columns are needed
doing the sort and choosing the rows.
- The TABLE_SHARE object has a 'all_set' column bitmap one can use
when one needs a column bitmap with all columns set.
(This is used for table->use_all_columns() and other places)
- The TABLE object has 3 column bitmaps:
- def_read_set Default bitmap for columns to be read
- def_write_set Default bitmap for columns to be written
- tmp_set Can be used as a temporary bitmap when needed.
The table object has also two pointer to bitmaps read_set and write_set
that the handler should use to find out which columns are used in which way.
- count() optimization now calls handler::records() instead of using
handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true).
- Added extra argument to Item::walk() to indicate if we should also
traverse sub queries.
- Added TABLE parameter to cp_buffer_from_ref()
- Don't close tables created with CREATE ... SELECT but keep them in
the table cache. (Faster usage of newly created tables).
New interfaces:
- table->clear_column_bitmaps() to initialize the bitmaps for tables
at start of new statements.
- table->column_bitmaps_set() to set up new column bitmaps and signal
the handler about this.
- table->column_bitmaps_set_no_signal() for some few cases where we need
to setup new column bitmaps but don't signal the handler (as the handler
has already been signaled about these before). Used for the momement
only in opt_range.cc when doing ROR scans.
- table->use_all_columns() to install a bitmap where all columns are marked
as use in the read and the write set.
- table->default_column_bitmaps() to install the normal read and write
column bitmaps, but not signaling the handler about this.
This is mainly used when creating TABLE instances.
- table->mark_columns_needed_for_delete(),
table->mark_columns_needed_for_delete() and
table->mark_columns_needed_for_insert() to allow us to put additional
columns in column usage maps if handler so requires.
(The handler indicates what it neads in handler->table_flags())
- table->prepare_for_position() to allow us to tell handler that it
needs to read primary key parts to be able to store them in
future table->position() calls.
(This replaces the table->file->ha_retrieve_all_pk function)
- table->mark_auto_increment_column() to tell handler are going to update
columns part of any auto_increment key.
- table->mark_columns_used_by_index() to mark all columns that is part of
an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow
it to quickly know that it only needs to read colums that are part
of the key. (The handler can also use the column map for detecting this,
but simpler/faster handler can just monitor the extra() call).
- table->mark_columns_used_by_index_no_reset() to in addition to other columns,
also mark all columns that is used by the given key.
- table->restore_column_maps_after_mark_index() to restore to default
column maps after a call to table->mark_columns_used_by_index().
- New item function register_field_in_read_map(), for marking used columns
in table->read_map. Used by filesort() to mark all used columns
- Maintain in TABLE->merge_keys set of all keys that are used in query.
(Simplices some optimization loops)
- Maintain Field->part_of_key_not_clustered which is like Field->part_of_key
but the field in the clustered key is not assumed to be part of all index.
(used in opt_range.cc for faster loops)
- dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map()
tmp_use_all_columns() and tmp_restore_column_map() functions to temporally
mark all columns as usable. The 'dbug_' version is primarily intended
inside a handler when it wants to just call Field:store() & Field::val()
functions, but don't need the column maps set for any other usage.
(ie:: bitmap_is_set() is never called)
- We can't use compare_records() to skip updates for handlers that returns
a partial column set and the read_set doesn't cover all columns in the
write set. The reason for this is that if we have a column marked only for
write we can't in the MySQL level know if the value changed or not.
The reason this worked before was that MySQL marked all to be written
columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden
bug'.
- open_table_from_share() does not anymore setup temporary MEM_ROOT
object as a thread specific variable for the handler. Instead we
send the to-be-used MEMROOT to get_new_handler().
(Simpler, faster code)
Bugs fixed:
- Column marking was not done correctly in a lot of cases.
(ALTER TABLE, when using triggers, auto_increment fields etc)
(Could potentially result in wrong values inserted in table handlers
relying on that the old column maps or field->set_query_id was correct)
Especially when it comes to triggers, there may be cases where the
old code would cause lost/wrong values for NDB and/or InnoDB tables.
- Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags:
OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG.
This allowed me to remove some wrong warnings about:
"Some non-transactional changed tables couldn't be rolled back"
- Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset
(thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose
some warnings about
"Some non-transactional changed tables couldn't be rolled back")
- Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table()
which could cause delete_table to report random failures.
- Fixed core dumps for some tests when running with --debug
- Added missing FN_LIBCHAR in mysql_rm_tmp_tables()
(This has probably caused us to not properly remove temporary files after
crash)
- slow_logs was not properly initialized, which could maybe cause
extra/lost entries in slow log.
- If we get an duplicate row on insert, change column map to read and
write all columns while retrying the operation. This is required by
the definition of REPLACE and also ensures that fields that are only
part of UPDATE are properly handled. This fixed a bug in NDB and
REPLACE where REPLACE wrongly copied some column values from the replaced
row.
- For table handler that doesn't support NULL in keys, we would give an error
when creating a primary key with NULL fields, even after the fields has been
automaticly converted to NOT NULL.
- Creating a primary key on a SPATIAL key, would fail if field was not
declared as NOT NULL.
Cleanups:
- Removed not used condition argument to setup_tables
- Removed not needed item function reset_query_id_processor().
- Field->add_index is removed. Now this is instead maintained in
(field->flags & FIELD_IN_ADD_INDEX)
- Field->fieldnr is removed (use field->field_index instead)
- New argument to filesort() to indicate that it should return a set of
row pointers (not used columns). This allowed me to remove some references
to sql_command in filesort and should also enable us to return column
results in some cases where we couldn't before.
- Changed column bitmap handling in opt_range.cc to be aligned with TABLE
bitmap, which allowed me to use bitmap functions instead of looping over
all fields to create some needed bitmaps. (Faster and smaller code)
- Broke up found too long lines
- Moved some variable declaration at start of function for better code
readability.
- Removed some not used arguments from functions.
(setup_fields(), mysql_prepare_insert_check_table())
- setup_fields() now takes an enum instead of an int for marking columns
usage.
- For internal temporary tables, use handler::write_row(),
handler::delete_row() and handler::update_row() instead of
handler::ha_xxxx() for faster execution.
- Changed some constants to enum's and define's.
- Using separate column read and write sets allows for easier checking
of timestamp field was set by statement.
- Remove calls to free_io_cache() as this is now done automaticly in ha_reset()
- Don't build table->normalized_path as this is now identical to table->path
(after bar's fixes to convert filenames)
- Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to
do comparision with the 'convert-dbug-for-diff' tool.
Things left to do in 5.1:
- We wrongly log failed CREATE TABLE ... SELECT in some cases when using
row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result)
Mats has promised to look into this.
- Test that my fix for CREATE TABLE ... SELECT is indeed correct.
(I added several test cases for this, but in this case it's better that
someone else also tests this throughly).
Lars has promosed to do this.
2006-06-04 17:52:22 +02:00
|
|
|
table->use_all_columns();
|
2004-11-25 21:55:49 +01:00
|
|
|
table->field[0]->store(host,(uint) strlen(host), system_charset_info);
|
|
|
|
table->field[1]->store(user,(uint) strlen(user), system_charset_info);
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
key_copy((uchar *) user_key, table->record[0], table->key_info,
|
2004-12-06 01:00:37 +01:00
|
|
|
table->key_info->key_length);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2007-08-13 15:11:25 +02:00
|
|
|
if (table->file->index_read_idx_map(table->record[0], 0,
|
|
|
|
(uchar *) user_key, HA_WHOLE_KEY,
|
|
|
|
HA_READ_KEY_EXACT))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-11-12 13:34:00 +01:00
|
|
|
my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH),
|
|
|
|
MYF(0)); /* purecov: deadcode */
|
2000-07-31 21:29:14 +02:00
|
|
|
DBUG_RETURN(1); /* purecov: deadcode */
|
|
|
|
}
|
2003-05-03 01:16:56 +02:00
|
|
|
store_record(table,record[1]);
|
2004-11-25 21:55:49 +01:00
|
|
|
table->field[2]->store(new_password, new_password_len, system_charset_info);
|
2007-06-28 15:07:55 +02:00
|
|
|
if ((error=table->file->ha_update_row(table->record[1],table->record[0])) &&
|
|
|
|
error != HA_ERR_RECORD_IS_THE_SAME)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
table->file->print_error(error,MYF(0)); /* purecov: deadcode */
|
2005-09-01 14:52:59 +02:00
|
|
|
DBUG_RETURN(1);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2005-09-01 14:52:59 +02:00
|
|
|
DBUG_RETURN(0);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2001-08-10 16:37:37 +02:00
|
|
|
|
2005-03-22 15:54:18 +01:00
|
|
|
/*
|
|
|
|
Return 1 if we are allowed to create new users
|
|
|
|
the logic here is: INSERT_ACL is sufficient.
|
|
|
|
It's also a requirement in opt_safe_user_create,
|
|
|
|
otherwise CREATE_USER_ACL is enough.
|
|
|
|
*/
|
2001-08-10 16:37:37 +02:00
|
|
|
|
|
|
|
static bool test_if_create_new_users(THD *thd)
|
|
|
|
{
|
2005-09-20 20:20:38 +02:00
|
|
|
Security_context *sctx= thd->security_ctx;
|
2005-09-15 21:29:07 +02:00
|
|
|
bool create_new_users= test(sctx->master_access & INSERT_ACL) ||
|
2005-03-22 15:54:18 +01:00
|
|
|
(!opt_safe_user_create &&
|
2005-09-15 21:29:07 +02:00
|
|
|
test(sctx->master_access & CREATE_USER_ACL));
|
2005-03-22 15:54:18 +01:00
|
|
|
if (!create_new_users)
|
2001-08-10 16:37:37 +02:00
|
|
|
{
|
|
|
|
TABLE_LIST tl;
|
2002-06-12 14:04:18 +02:00
|
|
|
ulong db_access;
|
2001-08-10 16:37:37 +02:00
|
|
|
bzero((char*) &tl,sizeof(tl));
|
|
|
|
tl.db= (char*) "mysql";
|
2005-01-06 12:00:13 +01:00
|
|
|
tl.table_name= (char*) "user";
|
2005-03-22 15:54:18 +01:00
|
|
|
create_new_users= 1;
|
2004-04-07 12:25:24 +02:00
|
|
|
|
2005-09-15 21:29:07 +02:00
|
|
|
db_access=acl_get(sctx->host, sctx->ip,
|
|
|
|
sctx->priv_user, tl.db, 0);
|
2001-08-10 16:37:37 +02:00
|
|
|
if (!(db_access & INSERT_ACL))
|
|
|
|
{
|
2009-10-19 14:58:13 +02:00
|
|
|
if (check_grant(thd, INSERT_ACL, &tl, FALSE, UINT_MAX, TRUE))
|
2001-08-10 16:37:37 +02:00
|
|
|
create_new_users=0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return create_new_users;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
/****************************************************************************
|
2003-06-23 19:03:59 +02:00
|
|
|
Handle GRANT commands
|
2000-07-31 21:29:14 +02:00
|
|
|
****************************************************************************/
|
|
|
|
|
2001-09-30 04:46:20 +02:00
|
|
|
static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
|
2002-06-12 14:04:18 +02:00
|
|
|
ulong rights, bool revoke_grant,
|
2005-03-23 19:18:25 +01:00
|
|
|
bool can_create_user, bool no_auto_create)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
int error = -1;
|
2001-08-10 16:37:37 +02:00
|
|
|
bool old_row_exists=0;
|
2003-07-18 16:25:54 +02:00
|
|
|
const char *password= "";
|
2003-07-01 21:40:59 +02:00
|
|
|
uint password_len= 0;
|
2002-06-12 14:04:18 +02:00
|
|
|
char what= (revoke_grant) ? 'N' : 'Y';
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
uchar user_key[MAX_KEY_LENGTH];
|
2004-11-11 19:57:55 +01:00
|
|
|
LEX *lex= thd->lex;
|
2000-07-31 21:29:14 +02:00
|
|
|
DBUG_ENTER("replace_user_table");
|
2004-12-06 18:18:35 +01:00
|
|
|
|
2002-09-22 09:35:15 +02:00
|
|
|
safe_mutex_assert_owner(&acl_cache->lock);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
if (combo.password.str && combo.password.str[0])
|
2002-05-15 12:50:38 +02:00
|
|
|
{
|
2003-07-01 21:40:59 +02:00
|
|
|
if (combo.password.length != SCRAMBLED_PASSWORD_CHAR_LENGTH &&
|
|
|
|
combo.password.length != SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
|
2002-05-15 12:50:38 +02:00
|
|
|
{
|
2004-11-13 18:35:51 +01:00
|
|
|
my_error(ER_PASSWD_LENGTH, MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH);
|
2002-05-16 15:32:51 +02:00
|
|
|
DBUG_RETURN(-1);
|
2002-05-15 12:50:38 +02:00
|
|
|
}
|
2003-07-01 21:40:59 +02:00
|
|
|
password_len= combo.password.length;
|
2000-07-31 21:29:14 +02:00
|
|
|
password=combo.password.str;
|
2002-05-15 12:50:38 +02:00
|
|
|
}
|
2002-11-30 18:58:53 +01:00
|
|
|
|
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes
Changes that requires code changes in other code of other storage engines.
(Note that all changes are very straightforward and one should find all issues
by compiling a --debug build and fixing all compiler errors and all
asserts in field.cc while running the test suite),
- New optional handler function introduced: reset()
This is called after every DML statement to make it easy for a handler to
statement specific cleanups.
(The only case it's not called is if force the file to be closed)
- handler::extra(HA_EXTRA_RESET) is removed. Code that was there before
should be moved to handler::reset()
- table->read_set contains a bitmap over all columns that are needed
in the query. read_row() and similar functions only needs to read these
columns
- table->write_set contains a bitmap over all columns that will be updated
in the query. write_row() and update_row() only needs to update these
columns.
The above bitmaps should now be up to date in all context
(including ALTER TABLE, filesort()).
The handler is informed of any changes to the bitmap after
fix_fields() by calling the virtual function
handler::column_bitmaps_signal(). If the handler does caching of
these bitmaps (instead of using table->read_set, table->write_set),
it should redo the caching in this code. as the signal() may be sent
several times, it's probably best to set a variable in the signal
and redo the caching on read_row() / write_row() if the variable was
set.
- Removed the read_set and write_set bitmap objects from the handler class
- Removed all column bit handling functions from the handler class.
(Now one instead uses the normal bitmap functions in my_bitmap.c instead
of handler dedicated bitmap functions)
- field->query_id is removed. One should instead instead check
table->read_set and table->write_set if a field is used in the query.
- handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and
handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now
instead use table->read_set to check for which columns to retrieve.
- If a handler needs to call Field->val() or Field->store() on columns
that are not used in the query, one should install a temporary
all-columns-used map while doing so. For this, we provide the following
functions:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
field->val();
dbug_tmp_restore_column_map(table->read_set, old_map);
and similar for the write map:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
field->val();
dbug_tmp_restore_column_map(table->write_set, old_map);
If this is not done, you will sooner or later hit a DBUG_ASSERT
in the field store() / val() functions.
(For not DBUG binaries, the dbug_tmp_restore_column_map() and
dbug_tmp_restore_column_map() are inline dummy functions and should
be optimized away be the compiler).
- If one needs to temporary set the column map for all binaries (and not
just to avoid the DBUG_ASSERT() in the Field::store() / Field::val()
methods) one should use the functions tmp_use_all_columns() and
tmp_restore_column_map() instead of the above dbug_ variants.
- All 'status' fields in the handler base class (like records,
data_file_length etc) are now stored in a 'stats' struct. This makes
it easier to know what status variables are provided by the base
handler. This requires some trivial variable names in the extra()
function.
- New virtual function handler::records(). This is called to optimize
COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true.
(stats.records is not supposed to be an exact value. It's only has to
be 'reasonable enough' for the optimizer to be able to choose a good
optimization path).
- Non virtual handler::init() function added for caching of virtual
constants from engine.
- Removed has_transactions() virtual method. Now one should instead return
HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support
transactions.
- The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument
that is to be used with 'new handler_name()' to allocate the handler
in the right area. The xxxx_create_handler() function is also
responsible for any initialization of the object before returning.
For example, one should change:
static handler *myisam_create_handler(TABLE_SHARE *table)
{
return new ha_myisam(table);
}
->
static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisam(table);
}
- New optional virtual function: use_hidden_primary_key().
This is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key. This allows the handler to take precisions
in remembering any hidden primary key to able to update/delete any
found row. The default handler marks all columns to be read.
- handler::table_flags() now returns a ulonglong (to allow for more flags).
- New/changed table_flags()
- HA_HAS_RECORDS Set if ::records() is supported
- HA_NO_TRANSACTIONS Set if engine doesn't support transactions
- HA_PRIMARY_KEY_REQUIRED_FOR_DELETE
Set if we should mark all primary key columns for
read when reading rows as part of a DELETE
statement. If there is no primary key,
all columns are marked for read.
- HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some
cases (based on table->read_set)
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
- HA_DUPP_POS Renamed to HA_DUPLICATE_POS
- HA_REQUIRES_KEY_COLUMNS_FOR_DELETE
Set this if we should mark ALL key columns for
read when when reading rows as part of a DELETE
statement. In case of an update we will mark
all keys for read for which key part changed
value.
- HA_STATS_RECORDS_IS_EXACT
Set this if stats.records is exact.
(This saves us some extra records() calls
when optimizing COUNT(*))
- Removed table_flags()
- HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if
handler::records() gives an exact count() and
HA_STATS_RECORDS_IS_EXACT if stats.records is exact.
- HA_READ_RND_SAME Removed (no one supported this one)
- Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk()
- Renamed handler::dupp_pos to handler::dup_pos
- Removed not used variable handler::sortkey
Upper level handler changes:
- ha_reset() now does some overall checks and calls ::reset()
- ha_table_flags() added. This is a cached version of table_flags(). The
cache is updated on engine creation time and updated on open.
MySQL level changes (not obvious from the above):
- DBUG_ASSERT() added to check that column usage matches what is set
in the column usage bit maps. (This found a LOT of bugs in current
column marking code).
- In 5.1 before, all used columns was marked in read_set and only updated
columns was marked in write_set. Now we only mark columns for which we
need a value in read_set.
- Column bitmaps are created in open_binary_frm() and open_table_from_share().
(Before this was in table.cc)
- handler::table_flags() calls are replaced with handler::ha_table_flags()
- For calling field->val() you must have the corresponding bit set in
table->read_set. For calling field->store() you must have the
corresponding bit set in table->write_set. (There are asserts in
all store()/val() functions to catch wrong usage)
- thd->set_query_id is renamed to thd->mark_used_columns and instead
of setting this to an integer value, this has now the values:
MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE
Changed also all variables named 'set_query_id' to mark_used_columns.
- In filesort() we now inform the handler of exactly which columns are needed
doing the sort and choosing the rows.
- The TABLE_SHARE object has a 'all_set' column bitmap one can use
when one needs a column bitmap with all columns set.
(This is used for table->use_all_columns() and other places)
- The TABLE object has 3 column bitmaps:
- def_read_set Default bitmap for columns to be read
- def_write_set Default bitmap for columns to be written
- tmp_set Can be used as a temporary bitmap when needed.
The table object has also two pointer to bitmaps read_set and write_set
that the handler should use to find out which columns are used in which way.
- count() optimization now calls handler::records() instead of using
handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true).
- Added extra argument to Item::walk() to indicate if we should also
traverse sub queries.
- Added TABLE parameter to cp_buffer_from_ref()
- Don't close tables created with CREATE ... SELECT but keep them in
the table cache. (Faster usage of newly created tables).
New interfaces:
- table->clear_column_bitmaps() to initialize the bitmaps for tables
at start of new statements.
- table->column_bitmaps_set() to set up new column bitmaps and signal
the handler about this.
- table->column_bitmaps_set_no_signal() for some few cases where we need
to setup new column bitmaps but don't signal the handler (as the handler
has already been signaled about these before). Used for the momement
only in opt_range.cc when doing ROR scans.
- table->use_all_columns() to install a bitmap where all columns are marked
as use in the read and the write set.
- table->default_column_bitmaps() to install the normal read and write
column bitmaps, but not signaling the handler about this.
This is mainly used when creating TABLE instances.
- table->mark_columns_needed_for_delete(),
table->mark_columns_needed_for_delete() and
table->mark_columns_needed_for_insert() to allow us to put additional
columns in column usage maps if handler so requires.
(The handler indicates what it neads in handler->table_flags())
- table->prepare_for_position() to allow us to tell handler that it
needs to read primary key parts to be able to store them in
future table->position() calls.
(This replaces the table->file->ha_retrieve_all_pk function)
- table->mark_auto_increment_column() to tell handler are going to update
columns part of any auto_increment key.
- table->mark_columns_used_by_index() to mark all columns that is part of
an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow
it to quickly know that it only needs to read colums that are part
of the key. (The handler can also use the column map for detecting this,
but simpler/faster handler can just monitor the extra() call).
- table->mark_columns_used_by_index_no_reset() to in addition to other columns,
also mark all columns that is used by the given key.
- table->restore_column_maps_after_mark_index() to restore to default
column maps after a call to table->mark_columns_used_by_index().
- New item function register_field_in_read_map(), for marking used columns
in table->read_map. Used by filesort() to mark all used columns
- Maintain in TABLE->merge_keys set of all keys that are used in query.
(Simplices some optimization loops)
- Maintain Field->part_of_key_not_clustered which is like Field->part_of_key
but the field in the clustered key is not assumed to be part of all index.
(used in opt_range.cc for faster loops)
- dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map()
tmp_use_all_columns() and tmp_restore_column_map() functions to temporally
mark all columns as usable. The 'dbug_' version is primarily intended
inside a handler when it wants to just call Field:store() & Field::val()
functions, but don't need the column maps set for any other usage.
(ie:: bitmap_is_set() is never called)
- We can't use compare_records() to skip updates for handlers that returns
a partial column set and the read_set doesn't cover all columns in the
write set. The reason for this is that if we have a column marked only for
write we can't in the MySQL level know if the value changed or not.
The reason this worked before was that MySQL marked all to be written
columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden
bug'.
- open_table_from_share() does not anymore setup temporary MEM_ROOT
object as a thread specific variable for the handler. Instead we
send the to-be-used MEMROOT to get_new_handler().
(Simpler, faster code)
Bugs fixed:
- Column marking was not done correctly in a lot of cases.
(ALTER TABLE, when using triggers, auto_increment fields etc)
(Could potentially result in wrong values inserted in table handlers
relying on that the old column maps or field->set_query_id was correct)
Especially when it comes to triggers, there may be cases where the
old code would cause lost/wrong values for NDB and/or InnoDB tables.
- Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags:
OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG.
This allowed me to remove some wrong warnings about:
"Some non-transactional changed tables couldn't be rolled back"
- Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset
(thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose
some warnings about
"Some non-transactional changed tables couldn't be rolled back")
- Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table()
which could cause delete_table to report random failures.
- Fixed core dumps for some tests when running with --debug
- Added missing FN_LIBCHAR in mysql_rm_tmp_tables()
(This has probably caused us to not properly remove temporary files after
crash)
- slow_logs was not properly initialized, which could maybe cause
extra/lost entries in slow log.
- If we get an duplicate row on insert, change column map to read and
write all columns while retrying the operation. This is required by
the definition of REPLACE and also ensures that fields that are only
part of UPDATE are properly handled. This fixed a bug in NDB and
REPLACE where REPLACE wrongly copied some column values from the replaced
row.
- For table handler that doesn't support NULL in keys, we would give an error
when creating a primary key with NULL fields, even after the fields has been
automaticly converted to NOT NULL.
- Creating a primary key on a SPATIAL key, would fail if field was not
declared as NOT NULL.
Cleanups:
- Removed not used condition argument to setup_tables
- Removed not needed item function reset_query_id_processor().
- Field->add_index is removed. Now this is instead maintained in
(field->flags & FIELD_IN_ADD_INDEX)
- Field->fieldnr is removed (use field->field_index instead)
- New argument to filesort() to indicate that it should return a set of
row pointers (not used columns). This allowed me to remove some references
to sql_command in filesort and should also enable us to return column
results in some cases where we couldn't before.
- Changed column bitmap handling in opt_range.cc to be aligned with TABLE
bitmap, which allowed me to use bitmap functions instead of looping over
all fields to create some needed bitmaps. (Faster and smaller code)
- Broke up found too long lines
- Moved some variable declaration at start of function for better code
readability.
- Removed some not used arguments from functions.
(setup_fields(), mysql_prepare_insert_check_table())
- setup_fields() now takes an enum instead of an int for marking columns
usage.
- For internal temporary tables, use handler::write_row(),
handler::delete_row() and handler::update_row() instead of
handler::ha_xxxx() for faster execution.
- Changed some constants to enum's and define's.
- Using separate column read and write sets allows for easier checking
of timestamp field was set by statement.
- Remove calls to free_io_cache() as this is now done automaticly in ha_reset()
- Don't build table->normalized_path as this is now identical to table->path
(after bar's fixes to convert filenames)
- Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to
do comparision with the 'convert-dbug-for-diff' tool.
Things left to do in 5.1:
- We wrongly log failed CREATE TABLE ... SELECT in some cases when using
row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result)
Mats has promised to look into this.
- Test that my fix for CREATE TABLE ... SELECT is indeed correct.
(I added several test cases for this, but in this case it's better that
someone else also tests this throughly).
Lars has promosed to do this.
2006-06-04 17:52:22 +02:00
|
|
|
table->use_all_columns();
|
|
|
|
table->field[0]->store(combo.host.str,combo.host.length,
|
|
|
|
system_charset_info);
|
|
|
|
table->field[1]->store(combo.user.str,combo.user.length,
|
|
|
|
system_charset_info);
|
2004-12-06 01:00:37 +01:00
|
|
|
key_copy(user_key, table->record[0], table->key_info,
|
|
|
|
table->key_info->key_length);
|
|
|
|
|
2007-08-13 15:11:25 +02:00
|
|
|
if (table->file->index_read_idx_map(table->record[0], 0, user_key,
|
|
|
|
HA_WHOLE_KEY,
|
|
|
|
HA_READ_KEY_EXACT))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-11-02 15:45:26 +01:00
|
|
|
/* what == 'N' means revoke */
|
|
|
|
if (what == 'N')
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-11-02 15:45:26 +01:00
|
|
|
my_error(ER_NONEXISTING_GRANT, MYF(0), combo.user.str, combo.host.str);
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
/*
|
2005-03-22 15:54:18 +01:00
|
|
|
There are four options which affect the process of creation of
|
|
|
|
a new user (mysqld option --safe-create-user, 'insert' privilege
|
2004-11-02 15:45:26 +01:00
|
|
|
on 'mysql.user' table, using 'GRANT' with 'IDENTIFIED BY' and
|
|
|
|
SQL_MODE flag NO_AUTO_CREATE_USER). Below is the simplified rule
|
|
|
|
how it should work.
|
|
|
|
if (safe-user-create && ! INSERT_priv) => reject
|
|
|
|
else if (identified_by) => create
|
|
|
|
else if (no_auto_create_user) => reject
|
|
|
|
else create
|
2005-03-22 15:54:18 +01:00
|
|
|
|
|
|
|
see also test_if_create_new_users()
|
2004-11-02 15:45:26 +01:00
|
|
|
*/
|
2005-03-23 19:18:25 +01:00
|
|
|
else if (!password_len && no_auto_create)
|
|
|
|
{
|
|
|
|
my_error(ER_PASSWORD_NO_MATCH, MYF(0), combo.user.str, combo.host.str);
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
else if (!can_create_user)
|
2004-11-02 15:45:26 +01:00
|
|
|
{
|
2005-03-22 14:57:24 +01:00
|
|
|
my_error(ER_CANT_CREATE_USER_WITH_GRANT, MYF(0),
|
2005-09-15 21:29:07 +02:00
|
|
|
thd->security_ctx->user, thd->security_ctx->host_or_ip);
|
2000-07-31 21:29:14 +02:00
|
|
|
goto end;
|
|
|
|
}
|
2001-08-10 16:37:37 +02:00
|
|
|
old_row_exists = 0;
|
2005-01-06 12:00:13 +01:00
|
|
|
restore_record(table,s->default_values);
|
2003-07-01 21:40:59 +02:00
|
|
|
table->field[0]->store(combo.host.str,combo.host.length,
|
2004-11-25 21:55:49 +01:00
|
|
|
system_charset_info);
|
2003-07-01 21:40:59 +02:00
|
|
|
table->field[1]->store(combo.user.str,combo.user.length,
|
2004-11-25 21:55:49 +01:00
|
|
|
system_charset_info);
|
2003-07-01 21:40:59 +02:00
|
|
|
table->field[2]->store(password, password_len,
|
2004-11-25 21:55:49 +01:00
|
|
|
system_charset_info);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-08-10 16:37:37 +02:00
|
|
|
old_row_exists = 1;
|
2003-05-03 01:16:56 +02:00
|
|
|
store_record(table,record[1]); // Save copy for update
|
2000-07-31 21:29:14 +02:00
|
|
|
if (combo.password.str) // If password given
|
2004-11-25 21:55:49 +01:00
|
|
|
table->field[2]->store(password, password_len, system_charset_info);
|
2004-11-11 19:57:55 +01:00
|
|
|
else if (!rights && !revoke_grant &&
|
2004-12-29 18:30:37 +01:00
|
|
|
lex->ssl_type == SSL_TYPE_NOT_SPECIFIED &&
|
|
|
|
!lex->mqh.specified_limits)
|
2004-03-01 20:54:08 +01:00
|
|
|
{
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2002-06-12 14:04:18 +02:00
|
|
|
/* Update table columns with new privileges */
|
|
|
|
|
|
|
|
Field **tmp_field;
|
|
|
|
ulong priv;
|
2004-12-23 19:59:36 +01:00
|
|
|
uint next_field;
|
2002-06-12 14:04:18 +02:00
|
|
|
for (tmp_field= table->field+3, priv = SELECT_ACL;
|
2006-12-02 02:26:52 +01:00
|
|
|
*tmp_field && (*tmp_field)->real_type() == MYSQL_TYPE_ENUM &&
|
2002-06-12 14:04:18 +02:00
|
|
|
((Field_enum*) (*tmp_field))->typelib->count == 2 ;
|
|
|
|
tmp_field++, priv <<= 1)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2002-06-12 14:04:18 +02:00
|
|
|
if (priv & rights) // set requested privileges
|
2003-01-29 14:31:20 +01:00
|
|
|
(*tmp_field)->store(&what, 1, &my_charset_latin1);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2004-12-23 19:59:36 +01:00
|
|
|
rights= get_access(table, 3, &next_field);
|
2005-01-06 12:00:13 +01:00
|
|
|
DBUG_PRINT("info",("table fields: %d",table->s->fields));
|
|
|
|
if (table->s->fields >= 31) /* From 4.0.0 we have more fields */
|
2002-02-18 22:54:45 +01:00
|
|
|
{
|
2002-06-12 14:04:18 +02:00
|
|
|
/* We write down SSL related ACL stuff */
|
2004-11-11 19:57:55 +01:00
|
|
|
switch (lex->ssl_type) {
|
2001-09-30 04:47:34 +02:00
|
|
|
case SSL_TYPE_ANY:
|
2005-11-20 19:47:07 +01:00
|
|
|
table->field[next_field]->store(STRING_WITH_LEN("ANY"),
|
|
|
|
&my_charset_latin1);
|
2004-12-23 20:16:43 +01:00
|
|
|
table->field[next_field+1]->store("", 0, &my_charset_latin1);
|
|
|
|
table->field[next_field+2]->store("", 0, &my_charset_latin1);
|
|
|
|
table->field[next_field+3]->store("", 0, &my_charset_latin1);
|
2001-09-30 04:47:34 +02:00
|
|
|
break;
|
|
|
|
case SSL_TYPE_X509:
|
2005-11-20 19:47:07 +01:00
|
|
|
table->field[next_field]->store(STRING_WITH_LEN("X509"),
|
|
|
|
&my_charset_latin1);
|
2004-12-23 20:16:43 +01:00
|
|
|
table->field[next_field+1]->store("", 0, &my_charset_latin1);
|
|
|
|
table->field[next_field+2]->store("", 0, &my_charset_latin1);
|
|
|
|
table->field[next_field+3]->store("", 0, &my_charset_latin1);
|
2001-09-30 04:47:34 +02:00
|
|
|
break;
|
|
|
|
case SSL_TYPE_SPECIFIED:
|
2005-11-20 19:47:07 +01:00
|
|
|
table->field[next_field]->store(STRING_WITH_LEN("SPECIFIED"),
|
|
|
|
&my_charset_latin1);
|
2004-12-23 20:16:43 +01:00
|
|
|
table->field[next_field+1]->store("", 0, &my_charset_latin1);
|
|
|
|
table->field[next_field+2]->store("", 0, &my_charset_latin1);
|
|
|
|
table->field[next_field+3]->store("", 0, &my_charset_latin1);
|
2004-11-11 19:57:55 +01:00
|
|
|
if (lex->ssl_cipher)
|
2004-12-31 15:26:24 +01:00
|
|
|
table->field[next_field+1]->store(lex->ssl_cipher,
|
|
|
|
strlen(lex->ssl_cipher), system_charset_info);
|
2004-11-11 19:57:55 +01:00
|
|
|
if (lex->x509_issuer)
|
2004-12-31 15:26:24 +01:00
|
|
|
table->field[next_field+2]->store(lex->x509_issuer,
|
|
|
|
strlen(lex->x509_issuer), system_charset_info);
|
2004-11-11 19:57:55 +01:00
|
|
|
if (lex->x509_subject)
|
2004-12-31 15:26:24 +01:00
|
|
|
table->field[next_field+3]->store(lex->x509_subject,
|
|
|
|
strlen(lex->x509_subject), system_charset_info);
|
2001-09-30 04:47:34 +02:00
|
|
|
break;
|
2002-09-11 05:40:08 +02:00
|
|
|
case SSL_TYPE_NOT_SPECIFIED:
|
2002-10-30 15:27:15 +01:00
|
|
|
break;
|
|
|
|
case SSL_TYPE_NONE:
|
2004-12-23 20:16:43 +01:00
|
|
|
table->field[next_field]->store("", 0, &my_charset_latin1);
|
|
|
|
table->field[next_field+1]->store("", 0, &my_charset_latin1);
|
|
|
|
table->field[next_field+2]->store("", 0, &my_charset_latin1);
|
|
|
|
table->field[next_field+3]->store("", 0, &my_charset_latin1);
|
2002-10-30 15:27:15 +01:00
|
|
|
break;
|
2001-09-30 04:46:20 +02:00
|
|
|
}
|
2004-12-31 15:26:24 +01:00
|
|
|
next_field+=4;
|
2002-06-12 14:04:18 +02:00
|
|
|
|
2004-11-11 19:57:55 +01:00
|
|
|
USER_RESOURCES mqh= lex->mqh;
|
2004-12-29 18:30:37 +01:00
|
|
|
if (mqh.specified_limits & USER_RESOURCES::QUERIES_PER_HOUR)
|
2005-09-14 00:41:44 +02:00
|
|
|
table->field[next_field]->store((longlong) mqh.questions, TRUE);
|
2004-12-29 18:30:37 +01:00
|
|
|
if (mqh.specified_limits & USER_RESOURCES::UPDATES_PER_HOUR)
|
2005-09-14 00:41:44 +02:00
|
|
|
table->field[next_field+1]->store((longlong) mqh.updates, TRUE);
|
2004-12-29 18:30:37 +01:00
|
|
|
if (mqh.specified_limits & USER_RESOURCES::CONNECTIONS_PER_HOUR)
|
2005-09-14 00:41:44 +02:00
|
|
|
table->field[next_field+2]->store((longlong) mqh.conn_per_hour, TRUE);
|
2005-01-06 12:00:13 +01:00
|
|
|
if (table->s->fields >= 36 &&
|
2004-12-29 18:30:37 +01:00
|
|
|
(mqh.specified_limits & USER_RESOURCES::USER_CONNECTIONS))
|
2006-06-16 12:17:20 +02:00
|
|
|
table->field[next_field+3]->store((longlong) mqh.user_conn, TRUE);
|
2004-12-29 18:30:37 +01:00
|
|
|
mqh_used= mqh_used || mqh.questions || mqh.updates || mqh.conn_per_hour;
|
2001-12-26 15:49:10 +01:00
|
|
|
}
|
2001-08-10 16:37:37 +02:00
|
|
|
if (old_row_exists)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
We should NEVER delete from the user table, as a uses can still
|
|
|
|
use mysqld even if he doesn't have any privileges in the user table!
|
|
|
|
*/
|
2007-06-28 15:07:55 +02:00
|
|
|
if (cmp_record(table,record[1]))
|
|
|
|
{
|
|
|
|
if ((error=
|
|
|
|
table->file->ha_update_row(table->record[1],table->record[0])) &&
|
|
|
|
error != HA_ERR_RECORD_IS_THE_SAME)
|
|
|
|
{ // This should never happen
|
|
|
|
table->file->print_error(error,MYF(0)); /* purecov: deadcode */
|
|
|
|
error= -1; /* purecov: deadcode */
|
|
|
|
goto end; /* purecov: deadcode */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
error= 0;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
}
|
2005-12-22 06:39:02 +01:00
|
|
|
else if ((error=table->file->ha_write_row(table->record[0]))) // insert
|
2000-07-31 21:29:14 +02:00
|
|
|
{ // This should never happen
|
2006-07-01 06:01:37 +02:00
|
|
|
if (table->file->is_fatal_error(error, HA_CHECK_DUP))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
table->file->print_error(error,MYF(0)); /* purecov: deadcode */
|
|
|
|
error= -1; /* purecov: deadcode */
|
|
|
|
goto end; /* purecov: deadcode */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
error=0; // Privileges granted / revoked
|
|
|
|
|
2001-09-30 04:47:34 +02:00
|
|
|
end:
|
2000-07-31 21:29:14 +02:00
|
|
|
if (!error)
|
|
|
|
{
|
|
|
|
acl_cache->clear(1); // Clear privilege cache
|
2001-08-10 16:37:37 +02:00
|
|
|
if (old_row_exists)
|
2004-05-04 14:02:38 +02:00
|
|
|
acl_update_user(combo.user.str, combo.host.str,
|
|
|
|
combo.password.str, password_len,
|
2004-11-11 19:57:55 +01:00
|
|
|
lex->ssl_type,
|
|
|
|
lex->ssl_cipher,
|
|
|
|
lex->x509_issuer,
|
|
|
|
lex->x509_subject,
|
|
|
|
&lex->mqh,
|
2001-09-30 04:47:34 +02:00
|
|
|
rights);
|
2000-07-31 21:29:14 +02:00
|
|
|
else
|
2003-07-01 21:40:59 +02:00
|
|
|
acl_insert_user(combo.user.str, combo.host.str, password, password_len,
|
2004-11-11 19:57:55 +01:00
|
|
|
lex->ssl_type,
|
|
|
|
lex->ssl_cipher,
|
|
|
|
lex->x509_issuer,
|
|
|
|
lex->x509_subject,
|
|
|
|
&lex->mqh,
|
2001-09-30 04:47:34 +02:00
|
|
|
rights);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
DBUG_RETURN(error);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2002-06-12 14:04:18 +02:00
|
|
|
change grants in the mysql.db table
|
2000-07-31 21:29:14 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
static int replace_db_table(TABLE *table, const char *db,
|
|
|
|
const LEX_USER &combo,
|
2002-06-12 14:04:18 +02:00
|
|
|
ulong rights, bool revoke_grant)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2002-06-12 14:04:18 +02:00
|
|
|
uint i;
|
|
|
|
ulong priv,store_rights;
|
2001-08-10 16:37:37 +02:00
|
|
|
bool old_row_exists=0;
|
2000-07-31 21:29:14 +02:00
|
|
|
int error;
|
2002-06-12 14:04:18 +02:00
|
|
|
char what= (revoke_grant) ? 'N' : 'Y';
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
uchar user_key[MAX_KEY_LENGTH];
|
2000-07-31 21:29:14 +02:00
|
|
|
DBUG_ENTER("replace_db_table");
|
|
|
|
|
2004-01-26 17:31:38 +01:00
|
|
|
if (!initialized)
|
|
|
|
{
|
2004-02-21 15:15:26 +01:00
|
|
|
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables");
|
2004-01-26 17:31:38 +01:00
|
|
|
DBUG_RETURN(-1);
|
|
|
|
}
|
|
|
|
|
2003-06-23 19:03:59 +02:00
|
|
|
/* Check if there is such a user in user table in memory? */
|
2005-08-23 00:48:50 +02:00
|
|
|
if (!find_acl_user(combo.host.str,combo.user.str, FALSE))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-11-12 13:34:00 +01:00
|
|
|
my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH), MYF(0));
|
2000-07-31 21:29:14 +02:00
|
|
|
DBUG_RETURN(-1);
|
|
|
|
}
|
|
|
|
|
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes
Changes that requires code changes in other code of other storage engines.
(Note that all changes are very straightforward and one should find all issues
by compiling a --debug build and fixing all compiler errors and all
asserts in field.cc while running the test suite),
- New optional handler function introduced: reset()
This is called after every DML statement to make it easy for a handler to
statement specific cleanups.
(The only case it's not called is if force the file to be closed)
- handler::extra(HA_EXTRA_RESET) is removed. Code that was there before
should be moved to handler::reset()
- table->read_set contains a bitmap over all columns that are needed
in the query. read_row() and similar functions only needs to read these
columns
- table->write_set contains a bitmap over all columns that will be updated
in the query. write_row() and update_row() only needs to update these
columns.
The above bitmaps should now be up to date in all context
(including ALTER TABLE, filesort()).
The handler is informed of any changes to the bitmap after
fix_fields() by calling the virtual function
handler::column_bitmaps_signal(). If the handler does caching of
these bitmaps (instead of using table->read_set, table->write_set),
it should redo the caching in this code. as the signal() may be sent
several times, it's probably best to set a variable in the signal
and redo the caching on read_row() / write_row() if the variable was
set.
- Removed the read_set and write_set bitmap objects from the handler class
- Removed all column bit handling functions from the handler class.
(Now one instead uses the normal bitmap functions in my_bitmap.c instead
of handler dedicated bitmap functions)
- field->query_id is removed. One should instead instead check
table->read_set and table->write_set if a field is used in the query.
- handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and
handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now
instead use table->read_set to check for which columns to retrieve.
- If a handler needs to call Field->val() or Field->store() on columns
that are not used in the query, one should install a temporary
all-columns-used map while doing so. For this, we provide the following
functions:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
field->val();
dbug_tmp_restore_column_map(table->read_set, old_map);
and similar for the write map:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
field->val();
dbug_tmp_restore_column_map(table->write_set, old_map);
If this is not done, you will sooner or later hit a DBUG_ASSERT
in the field store() / val() functions.
(For not DBUG binaries, the dbug_tmp_restore_column_map() and
dbug_tmp_restore_column_map() are inline dummy functions and should
be optimized away be the compiler).
- If one needs to temporary set the column map for all binaries (and not
just to avoid the DBUG_ASSERT() in the Field::store() / Field::val()
methods) one should use the functions tmp_use_all_columns() and
tmp_restore_column_map() instead of the above dbug_ variants.
- All 'status' fields in the handler base class (like records,
data_file_length etc) are now stored in a 'stats' struct. This makes
it easier to know what status variables are provided by the base
handler. This requires some trivial variable names in the extra()
function.
- New virtual function handler::records(). This is called to optimize
COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true.
(stats.records is not supposed to be an exact value. It's only has to
be 'reasonable enough' for the optimizer to be able to choose a good
optimization path).
- Non virtual handler::init() function added for caching of virtual
constants from engine.
- Removed has_transactions() virtual method. Now one should instead return
HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support
transactions.
- The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument
that is to be used with 'new handler_name()' to allocate the handler
in the right area. The xxxx_create_handler() function is also
responsible for any initialization of the object before returning.
For example, one should change:
static handler *myisam_create_handler(TABLE_SHARE *table)
{
return new ha_myisam(table);
}
->
static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisam(table);
}
- New optional virtual function: use_hidden_primary_key().
This is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key. This allows the handler to take precisions
in remembering any hidden primary key to able to update/delete any
found row. The default handler marks all columns to be read.
- handler::table_flags() now returns a ulonglong (to allow for more flags).
- New/changed table_flags()
- HA_HAS_RECORDS Set if ::records() is supported
- HA_NO_TRANSACTIONS Set if engine doesn't support transactions
- HA_PRIMARY_KEY_REQUIRED_FOR_DELETE
Set if we should mark all primary key columns for
read when reading rows as part of a DELETE
statement. If there is no primary key,
all columns are marked for read.
- HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some
cases (based on table->read_set)
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
- HA_DUPP_POS Renamed to HA_DUPLICATE_POS
- HA_REQUIRES_KEY_COLUMNS_FOR_DELETE
Set this if we should mark ALL key columns for
read when when reading rows as part of a DELETE
statement. In case of an update we will mark
all keys for read for which key part changed
value.
- HA_STATS_RECORDS_IS_EXACT
Set this if stats.records is exact.
(This saves us some extra records() calls
when optimizing COUNT(*))
- Removed table_flags()
- HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if
handler::records() gives an exact count() and
HA_STATS_RECORDS_IS_EXACT if stats.records is exact.
- HA_READ_RND_SAME Removed (no one supported this one)
- Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk()
- Renamed handler::dupp_pos to handler::dup_pos
- Removed not used variable handler::sortkey
Upper level handler changes:
- ha_reset() now does some overall checks and calls ::reset()
- ha_table_flags() added. This is a cached version of table_flags(). The
cache is updated on engine creation time and updated on open.
MySQL level changes (not obvious from the above):
- DBUG_ASSERT() added to check that column usage matches what is set
in the column usage bit maps. (This found a LOT of bugs in current
column marking code).
- In 5.1 before, all used columns was marked in read_set and only updated
columns was marked in write_set. Now we only mark columns for which we
need a value in read_set.
- Column bitmaps are created in open_binary_frm() and open_table_from_share().
(Before this was in table.cc)
- handler::table_flags() calls are replaced with handler::ha_table_flags()
- For calling field->val() you must have the corresponding bit set in
table->read_set. For calling field->store() you must have the
corresponding bit set in table->write_set. (There are asserts in
all store()/val() functions to catch wrong usage)
- thd->set_query_id is renamed to thd->mark_used_columns and instead
of setting this to an integer value, this has now the values:
MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE
Changed also all variables named 'set_query_id' to mark_used_columns.
- In filesort() we now inform the handler of exactly which columns are needed
doing the sort and choosing the rows.
- The TABLE_SHARE object has a 'all_set' column bitmap one can use
when one needs a column bitmap with all columns set.
(This is used for table->use_all_columns() and other places)
- The TABLE object has 3 column bitmaps:
- def_read_set Default bitmap for columns to be read
- def_write_set Default bitmap for columns to be written
- tmp_set Can be used as a temporary bitmap when needed.
The table object has also two pointer to bitmaps read_set and write_set
that the handler should use to find out which columns are used in which way.
- count() optimization now calls handler::records() instead of using
handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true).
- Added extra argument to Item::walk() to indicate if we should also
traverse sub queries.
- Added TABLE parameter to cp_buffer_from_ref()
- Don't close tables created with CREATE ... SELECT but keep them in
the table cache. (Faster usage of newly created tables).
New interfaces:
- table->clear_column_bitmaps() to initialize the bitmaps for tables
at start of new statements.
- table->column_bitmaps_set() to set up new column bitmaps and signal
the handler about this.
- table->column_bitmaps_set_no_signal() for some few cases where we need
to setup new column bitmaps but don't signal the handler (as the handler
has already been signaled about these before). Used for the momement
only in opt_range.cc when doing ROR scans.
- table->use_all_columns() to install a bitmap where all columns are marked
as use in the read and the write set.
- table->default_column_bitmaps() to install the normal read and write
column bitmaps, but not signaling the handler about this.
This is mainly used when creating TABLE instances.
- table->mark_columns_needed_for_delete(),
table->mark_columns_needed_for_delete() and
table->mark_columns_needed_for_insert() to allow us to put additional
columns in column usage maps if handler so requires.
(The handler indicates what it neads in handler->table_flags())
- table->prepare_for_position() to allow us to tell handler that it
needs to read primary key parts to be able to store them in
future table->position() calls.
(This replaces the table->file->ha_retrieve_all_pk function)
- table->mark_auto_increment_column() to tell handler are going to update
columns part of any auto_increment key.
- table->mark_columns_used_by_index() to mark all columns that is part of
an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow
it to quickly know that it only needs to read colums that are part
of the key. (The handler can also use the column map for detecting this,
but simpler/faster handler can just monitor the extra() call).
- table->mark_columns_used_by_index_no_reset() to in addition to other columns,
also mark all columns that is used by the given key.
- table->restore_column_maps_after_mark_index() to restore to default
column maps after a call to table->mark_columns_used_by_index().
- New item function register_field_in_read_map(), for marking used columns
in table->read_map. Used by filesort() to mark all used columns
- Maintain in TABLE->merge_keys set of all keys that are used in query.
(Simplices some optimization loops)
- Maintain Field->part_of_key_not_clustered which is like Field->part_of_key
but the field in the clustered key is not assumed to be part of all index.
(used in opt_range.cc for faster loops)
- dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map()
tmp_use_all_columns() and tmp_restore_column_map() functions to temporally
mark all columns as usable. The 'dbug_' version is primarily intended
inside a handler when it wants to just call Field:store() & Field::val()
functions, but don't need the column maps set for any other usage.
(ie:: bitmap_is_set() is never called)
- We can't use compare_records() to skip updates for handlers that returns
a partial column set and the read_set doesn't cover all columns in the
write set. The reason for this is that if we have a column marked only for
write we can't in the MySQL level know if the value changed or not.
The reason this worked before was that MySQL marked all to be written
columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden
bug'.
- open_table_from_share() does not anymore setup temporary MEM_ROOT
object as a thread specific variable for the handler. Instead we
send the to-be-used MEMROOT to get_new_handler().
(Simpler, faster code)
Bugs fixed:
- Column marking was not done correctly in a lot of cases.
(ALTER TABLE, when using triggers, auto_increment fields etc)
(Could potentially result in wrong values inserted in table handlers
relying on that the old column maps or field->set_query_id was correct)
Especially when it comes to triggers, there may be cases where the
old code would cause lost/wrong values for NDB and/or InnoDB tables.
- Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags:
OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG.
This allowed me to remove some wrong warnings about:
"Some non-transactional changed tables couldn't be rolled back"
- Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset
(thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose
some warnings about
"Some non-transactional changed tables couldn't be rolled back")
- Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table()
which could cause delete_table to report random failures.
- Fixed core dumps for some tests when running with --debug
- Added missing FN_LIBCHAR in mysql_rm_tmp_tables()
(This has probably caused us to not properly remove temporary files after
crash)
- slow_logs was not properly initialized, which could maybe cause
extra/lost entries in slow log.
- If we get an duplicate row on insert, change column map to read and
write all columns while retrying the operation. This is required by
the definition of REPLACE and also ensures that fields that are only
part of UPDATE are properly handled. This fixed a bug in NDB and
REPLACE where REPLACE wrongly copied some column values from the replaced
row.
- For table handler that doesn't support NULL in keys, we would give an error
when creating a primary key with NULL fields, even after the fields has been
automaticly converted to NOT NULL.
- Creating a primary key on a SPATIAL key, would fail if field was not
declared as NOT NULL.
Cleanups:
- Removed not used condition argument to setup_tables
- Removed not needed item function reset_query_id_processor().
- Field->add_index is removed. Now this is instead maintained in
(field->flags & FIELD_IN_ADD_INDEX)
- Field->fieldnr is removed (use field->field_index instead)
- New argument to filesort() to indicate that it should return a set of
row pointers (not used columns). This allowed me to remove some references
to sql_command in filesort and should also enable us to return column
results in some cases where we couldn't before.
- Changed column bitmap handling in opt_range.cc to be aligned with TABLE
bitmap, which allowed me to use bitmap functions instead of looping over
all fields to create some needed bitmaps. (Faster and smaller code)
- Broke up found too long lines
- Moved some variable declaration at start of function for better code
readability.
- Removed some not used arguments from functions.
(setup_fields(), mysql_prepare_insert_check_table())
- setup_fields() now takes an enum instead of an int for marking columns
usage.
- For internal temporary tables, use handler::write_row(),
handler::delete_row() and handler::update_row() instead of
handler::ha_xxxx() for faster execution.
- Changed some constants to enum's and define's.
- Using separate column read and write sets allows for easier checking
of timestamp field was set by statement.
- Remove calls to free_io_cache() as this is now done automaticly in ha_reset()
- Don't build table->normalized_path as this is now identical to table->path
(after bar's fixes to convert filenames)
- Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to
do comparision with the 'convert-dbug-for-diff' tool.
Things left to do in 5.1:
- We wrongly log failed CREATE TABLE ... SELECT in some cases when using
row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result)
Mats has promised to look into this.
- Test that my fix for CREATE TABLE ... SELECT is indeed correct.
(I added several test cases for this, but in this case it's better that
someone else also tests this throughly).
Lars has promosed to do this.
2006-06-04 17:52:22 +02:00
|
|
|
table->use_all_columns();
|
|
|
|
table->field[0]->store(combo.host.str,combo.host.length,
|
|
|
|
system_charset_info);
|
2004-11-25 21:55:49 +01:00
|
|
|
table->field[1]->store(db,(uint) strlen(db), system_charset_info);
|
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes
Changes that requires code changes in other code of other storage engines.
(Note that all changes are very straightforward and one should find all issues
by compiling a --debug build and fixing all compiler errors and all
asserts in field.cc while running the test suite),
- New optional handler function introduced: reset()
This is called after every DML statement to make it easy for a handler to
statement specific cleanups.
(The only case it's not called is if force the file to be closed)
- handler::extra(HA_EXTRA_RESET) is removed. Code that was there before
should be moved to handler::reset()
- table->read_set contains a bitmap over all columns that are needed
in the query. read_row() and similar functions only needs to read these
columns
- table->write_set contains a bitmap over all columns that will be updated
in the query. write_row() and update_row() only needs to update these
columns.
The above bitmaps should now be up to date in all context
(including ALTER TABLE, filesort()).
The handler is informed of any changes to the bitmap after
fix_fields() by calling the virtual function
handler::column_bitmaps_signal(). If the handler does caching of
these bitmaps (instead of using table->read_set, table->write_set),
it should redo the caching in this code. as the signal() may be sent
several times, it's probably best to set a variable in the signal
and redo the caching on read_row() / write_row() if the variable was
set.
- Removed the read_set and write_set bitmap objects from the handler class
- Removed all column bit handling functions from the handler class.
(Now one instead uses the normal bitmap functions in my_bitmap.c instead
of handler dedicated bitmap functions)
- field->query_id is removed. One should instead instead check
table->read_set and table->write_set if a field is used in the query.
- handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and
handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now
instead use table->read_set to check for which columns to retrieve.
- If a handler needs to call Field->val() or Field->store() on columns
that are not used in the query, one should install a temporary
all-columns-used map while doing so. For this, we provide the following
functions:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
field->val();
dbug_tmp_restore_column_map(table->read_set, old_map);
and similar for the write map:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
field->val();
dbug_tmp_restore_column_map(table->write_set, old_map);
If this is not done, you will sooner or later hit a DBUG_ASSERT
in the field store() / val() functions.
(For not DBUG binaries, the dbug_tmp_restore_column_map() and
dbug_tmp_restore_column_map() are inline dummy functions and should
be optimized away be the compiler).
- If one needs to temporary set the column map for all binaries (and not
just to avoid the DBUG_ASSERT() in the Field::store() / Field::val()
methods) one should use the functions tmp_use_all_columns() and
tmp_restore_column_map() instead of the above dbug_ variants.
- All 'status' fields in the handler base class (like records,
data_file_length etc) are now stored in a 'stats' struct. This makes
it easier to know what status variables are provided by the base
handler. This requires some trivial variable names in the extra()
function.
- New virtual function handler::records(). This is called to optimize
COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true.
(stats.records is not supposed to be an exact value. It's only has to
be 'reasonable enough' for the optimizer to be able to choose a good
optimization path).
- Non virtual handler::init() function added for caching of virtual
constants from engine.
- Removed has_transactions() virtual method. Now one should instead return
HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support
transactions.
- The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument
that is to be used with 'new handler_name()' to allocate the handler
in the right area. The xxxx_create_handler() function is also
responsible for any initialization of the object before returning.
For example, one should change:
static handler *myisam_create_handler(TABLE_SHARE *table)
{
return new ha_myisam(table);
}
->
static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisam(table);
}
- New optional virtual function: use_hidden_primary_key().
This is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key. This allows the handler to take precisions
in remembering any hidden primary key to able to update/delete any
found row. The default handler marks all columns to be read.
- handler::table_flags() now returns a ulonglong (to allow for more flags).
- New/changed table_flags()
- HA_HAS_RECORDS Set if ::records() is supported
- HA_NO_TRANSACTIONS Set if engine doesn't support transactions
- HA_PRIMARY_KEY_REQUIRED_FOR_DELETE
Set if we should mark all primary key columns for
read when reading rows as part of a DELETE
statement. If there is no primary key,
all columns are marked for read.
- HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some
cases (based on table->read_set)
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
- HA_DUPP_POS Renamed to HA_DUPLICATE_POS
- HA_REQUIRES_KEY_COLUMNS_FOR_DELETE
Set this if we should mark ALL key columns for
read when when reading rows as part of a DELETE
statement. In case of an update we will mark
all keys for read for which key part changed
value.
- HA_STATS_RECORDS_IS_EXACT
Set this if stats.records is exact.
(This saves us some extra records() calls
when optimizing COUNT(*))
- Removed table_flags()
- HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if
handler::records() gives an exact count() and
HA_STATS_RECORDS_IS_EXACT if stats.records is exact.
- HA_READ_RND_SAME Removed (no one supported this one)
- Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk()
- Renamed handler::dupp_pos to handler::dup_pos
- Removed not used variable handler::sortkey
Upper level handler changes:
- ha_reset() now does some overall checks and calls ::reset()
- ha_table_flags() added. This is a cached version of table_flags(). The
cache is updated on engine creation time and updated on open.
MySQL level changes (not obvious from the above):
- DBUG_ASSERT() added to check that column usage matches what is set
in the column usage bit maps. (This found a LOT of bugs in current
column marking code).
- In 5.1 before, all used columns was marked in read_set and only updated
columns was marked in write_set. Now we only mark columns for which we
need a value in read_set.
- Column bitmaps are created in open_binary_frm() and open_table_from_share().
(Before this was in table.cc)
- handler::table_flags() calls are replaced with handler::ha_table_flags()
- For calling field->val() you must have the corresponding bit set in
table->read_set. For calling field->store() you must have the
corresponding bit set in table->write_set. (There are asserts in
all store()/val() functions to catch wrong usage)
- thd->set_query_id is renamed to thd->mark_used_columns and instead
of setting this to an integer value, this has now the values:
MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE
Changed also all variables named 'set_query_id' to mark_used_columns.
- In filesort() we now inform the handler of exactly which columns are needed
doing the sort and choosing the rows.
- The TABLE_SHARE object has a 'all_set' column bitmap one can use
when one needs a column bitmap with all columns set.
(This is used for table->use_all_columns() and other places)
- The TABLE object has 3 column bitmaps:
- def_read_set Default bitmap for columns to be read
- def_write_set Default bitmap for columns to be written
- tmp_set Can be used as a temporary bitmap when needed.
The table object has also two pointer to bitmaps read_set and write_set
that the handler should use to find out which columns are used in which way.
- count() optimization now calls handler::records() instead of using
handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true).
- Added extra argument to Item::walk() to indicate if we should also
traverse sub queries.
- Added TABLE parameter to cp_buffer_from_ref()
- Don't close tables created with CREATE ... SELECT but keep them in
the table cache. (Faster usage of newly created tables).
New interfaces:
- table->clear_column_bitmaps() to initialize the bitmaps for tables
at start of new statements.
- table->column_bitmaps_set() to set up new column bitmaps and signal
the handler about this.
- table->column_bitmaps_set_no_signal() for some few cases where we need
to setup new column bitmaps but don't signal the handler (as the handler
has already been signaled about these before). Used for the momement
only in opt_range.cc when doing ROR scans.
- table->use_all_columns() to install a bitmap where all columns are marked
as use in the read and the write set.
- table->default_column_bitmaps() to install the normal read and write
column bitmaps, but not signaling the handler about this.
This is mainly used when creating TABLE instances.
- table->mark_columns_needed_for_delete(),
table->mark_columns_needed_for_delete() and
table->mark_columns_needed_for_insert() to allow us to put additional
columns in column usage maps if handler so requires.
(The handler indicates what it neads in handler->table_flags())
- table->prepare_for_position() to allow us to tell handler that it
needs to read primary key parts to be able to store them in
future table->position() calls.
(This replaces the table->file->ha_retrieve_all_pk function)
- table->mark_auto_increment_column() to tell handler are going to update
columns part of any auto_increment key.
- table->mark_columns_used_by_index() to mark all columns that is part of
an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow
it to quickly know that it only needs to read colums that are part
of the key. (The handler can also use the column map for detecting this,
but simpler/faster handler can just monitor the extra() call).
- table->mark_columns_used_by_index_no_reset() to in addition to other columns,
also mark all columns that is used by the given key.
- table->restore_column_maps_after_mark_index() to restore to default
column maps after a call to table->mark_columns_used_by_index().
- New item function register_field_in_read_map(), for marking used columns
in table->read_map. Used by filesort() to mark all used columns
- Maintain in TABLE->merge_keys set of all keys that are used in query.
(Simplices some optimization loops)
- Maintain Field->part_of_key_not_clustered which is like Field->part_of_key
but the field in the clustered key is not assumed to be part of all index.
(used in opt_range.cc for faster loops)
- dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map()
tmp_use_all_columns() and tmp_restore_column_map() functions to temporally
mark all columns as usable. The 'dbug_' version is primarily intended
inside a handler when it wants to just call Field:store() & Field::val()
functions, but don't need the column maps set for any other usage.
(ie:: bitmap_is_set() is never called)
- We can't use compare_records() to skip updates for handlers that returns
a partial column set and the read_set doesn't cover all columns in the
write set. The reason for this is that if we have a column marked only for
write we can't in the MySQL level know if the value changed or not.
The reason this worked before was that MySQL marked all to be written
columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden
bug'.
- open_table_from_share() does not anymore setup temporary MEM_ROOT
object as a thread specific variable for the handler. Instead we
send the to-be-used MEMROOT to get_new_handler().
(Simpler, faster code)
Bugs fixed:
- Column marking was not done correctly in a lot of cases.
(ALTER TABLE, when using triggers, auto_increment fields etc)
(Could potentially result in wrong values inserted in table handlers
relying on that the old column maps or field->set_query_id was correct)
Especially when it comes to triggers, there may be cases where the
old code would cause lost/wrong values for NDB and/or InnoDB tables.
- Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags:
OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG.
This allowed me to remove some wrong warnings about:
"Some non-transactional changed tables couldn't be rolled back"
- Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset
(thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose
some warnings about
"Some non-transactional changed tables couldn't be rolled back")
- Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table()
which could cause delete_table to report random failures.
- Fixed core dumps for some tests when running with --debug
- Added missing FN_LIBCHAR in mysql_rm_tmp_tables()
(This has probably caused us to not properly remove temporary files after
crash)
- slow_logs was not properly initialized, which could maybe cause
extra/lost entries in slow log.
- If we get an duplicate row on insert, change column map to read and
write all columns while retrying the operation. This is required by
the definition of REPLACE and also ensures that fields that are only
part of UPDATE are properly handled. This fixed a bug in NDB and
REPLACE where REPLACE wrongly copied some column values from the replaced
row.
- For table handler that doesn't support NULL in keys, we would give an error
when creating a primary key with NULL fields, even after the fields has been
automaticly converted to NOT NULL.
- Creating a primary key on a SPATIAL key, would fail if field was not
declared as NOT NULL.
Cleanups:
- Removed not used condition argument to setup_tables
- Removed not needed item function reset_query_id_processor().
- Field->add_index is removed. Now this is instead maintained in
(field->flags & FIELD_IN_ADD_INDEX)
- Field->fieldnr is removed (use field->field_index instead)
- New argument to filesort() to indicate that it should return a set of
row pointers (not used columns). This allowed me to remove some references
to sql_command in filesort and should also enable us to return column
results in some cases where we couldn't before.
- Changed column bitmap handling in opt_range.cc to be aligned with TABLE
bitmap, which allowed me to use bitmap functions instead of looping over
all fields to create some needed bitmaps. (Faster and smaller code)
- Broke up found too long lines
- Moved some variable declaration at start of function for better code
readability.
- Removed some not used arguments from functions.
(setup_fields(), mysql_prepare_insert_check_table())
- setup_fields() now takes an enum instead of an int for marking columns
usage.
- For internal temporary tables, use handler::write_row(),
handler::delete_row() and handler::update_row() instead of
handler::ha_xxxx() for faster execution.
- Changed some constants to enum's and define's.
- Using separate column read and write sets allows for easier checking
of timestamp field was set by statement.
- Remove calls to free_io_cache() as this is now done automaticly in ha_reset()
- Don't build table->normalized_path as this is now identical to table->path
(after bar's fixes to convert filenames)
- Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to
do comparision with the 'convert-dbug-for-diff' tool.
Things left to do in 5.1:
- We wrongly log failed CREATE TABLE ... SELECT in some cases when using
row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result)
Mats has promised to look into this.
- Test that my fix for CREATE TABLE ... SELECT is indeed correct.
(I added several test cases for this, but in this case it's better that
someone else also tests this throughly).
Lars has promosed to do this.
2006-06-04 17:52:22 +02:00
|
|
|
table->field[2]->store(combo.user.str,combo.user.length,
|
|
|
|
system_charset_info);
|
2004-12-06 01:00:37 +01:00
|
|
|
key_copy(user_key, table->record[0], table->key_info,
|
|
|
|
table->key_info->key_length);
|
|
|
|
|
2007-08-13 15:11:25 +02:00
|
|
|
if (table->file->index_read_idx_map(table->record[0],0, user_key,
|
|
|
|
HA_WHOLE_KEY,
|
|
|
|
HA_READ_KEY_EXACT))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
if (what == 'N')
|
|
|
|
{ // no row, no revoke
|
2004-02-21 15:15:26 +01:00
|
|
|
my_error(ER_NONEXISTING_GRANT, MYF(0), combo.user.str, combo.host.str);
|
2000-07-31 21:29:14 +02:00
|
|
|
goto abort;
|
|
|
|
}
|
2001-08-10 16:37:37 +02:00
|
|
|
old_row_exists = 0;
|
2005-01-06 12:00:13 +01:00
|
|
|
restore_record(table, s->default_values);
|
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes
Changes that requires code changes in other code of other storage engines.
(Note that all changes are very straightforward and one should find all issues
by compiling a --debug build and fixing all compiler errors and all
asserts in field.cc while running the test suite),
- New optional handler function introduced: reset()
This is called after every DML statement to make it easy for a handler to
statement specific cleanups.
(The only case it's not called is if force the file to be closed)
- handler::extra(HA_EXTRA_RESET) is removed. Code that was there before
should be moved to handler::reset()
- table->read_set contains a bitmap over all columns that are needed
in the query. read_row() and similar functions only needs to read these
columns
- table->write_set contains a bitmap over all columns that will be updated
in the query. write_row() and update_row() only needs to update these
columns.
The above bitmaps should now be up to date in all context
(including ALTER TABLE, filesort()).
The handler is informed of any changes to the bitmap after
fix_fields() by calling the virtual function
handler::column_bitmaps_signal(). If the handler does caching of
these bitmaps (instead of using table->read_set, table->write_set),
it should redo the caching in this code. as the signal() may be sent
several times, it's probably best to set a variable in the signal
and redo the caching on read_row() / write_row() if the variable was
set.
- Removed the read_set and write_set bitmap objects from the handler class
- Removed all column bit handling functions from the handler class.
(Now one instead uses the normal bitmap functions in my_bitmap.c instead
of handler dedicated bitmap functions)
- field->query_id is removed. One should instead instead check
table->read_set and table->write_set if a field is used in the query.
- handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and
handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now
instead use table->read_set to check for which columns to retrieve.
- If a handler needs to call Field->val() or Field->store() on columns
that are not used in the query, one should install a temporary
all-columns-used map while doing so. For this, we provide the following
functions:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
field->val();
dbug_tmp_restore_column_map(table->read_set, old_map);
and similar for the write map:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
field->val();
dbug_tmp_restore_column_map(table->write_set, old_map);
If this is not done, you will sooner or later hit a DBUG_ASSERT
in the field store() / val() functions.
(For not DBUG binaries, the dbug_tmp_restore_column_map() and
dbug_tmp_restore_column_map() are inline dummy functions and should
be optimized away be the compiler).
- If one needs to temporary set the column map for all binaries (and not
just to avoid the DBUG_ASSERT() in the Field::store() / Field::val()
methods) one should use the functions tmp_use_all_columns() and
tmp_restore_column_map() instead of the above dbug_ variants.
- All 'status' fields in the handler base class (like records,
data_file_length etc) are now stored in a 'stats' struct. This makes
it easier to know what status variables are provided by the base
handler. This requires some trivial variable names in the extra()
function.
- New virtual function handler::records(). This is called to optimize
COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true.
(stats.records is not supposed to be an exact value. It's only has to
be 'reasonable enough' for the optimizer to be able to choose a good
optimization path).
- Non virtual handler::init() function added for caching of virtual
constants from engine.
- Removed has_transactions() virtual method. Now one should instead return
HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support
transactions.
- The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument
that is to be used with 'new handler_name()' to allocate the handler
in the right area. The xxxx_create_handler() function is also
responsible for any initialization of the object before returning.
For example, one should change:
static handler *myisam_create_handler(TABLE_SHARE *table)
{
return new ha_myisam(table);
}
->
static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisam(table);
}
- New optional virtual function: use_hidden_primary_key().
This is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key. This allows the handler to take precisions
in remembering any hidden primary key to able to update/delete any
found row. The default handler marks all columns to be read.
- handler::table_flags() now returns a ulonglong (to allow for more flags).
- New/changed table_flags()
- HA_HAS_RECORDS Set if ::records() is supported
- HA_NO_TRANSACTIONS Set if engine doesn't support transactions
- HA_PRIMARY_KEY_REQUIRED_FOR_DELETE
Set if we should mark all primary key columns for
read when reading rows as part of a DELETE
statement. If there is no primary key,
all columns are marked for read.
- HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some
cases (based on table->read_set)
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
- HA_DUPP_POS Renamed to HA_DUPLICATE_POS
- HA_REQUIRES_KEY_COLUMNS_FOR_DELETE
Set this if we should mark ALL key columns for
read when when reading rows as part of a DELETE
statement. In case of an update we will mark
all keys for read for which key part changed
value.
- HA_STATS_RECORDS_IS_EXACT
Set this if stats.records is exact.
(This saves us some extra records() calls
when optimizing COUNT(*))
- Removed table_flags()
- HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if
handler::records() gives an exact count() and
HA_STATS_RECORDS_IS_EXACT if stats.records is exact.
- HA_READ_RND_SAME Removed (no one supported this one)
- Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk()
- Renamed handler::dupp_pos to handler::dup_pos
- Removed not used variable handler::sortkey
Upper level handler changes:
- ha_reset() now does some overall checks and calls ::reset()
- ha_table_flags() added. This is a cached version of table_flags(). The
cache is updated on engine creation time and updated on open.
MySQL level changes (not obvious from the above):
- DBUG_ASSERT() added to check that column usage matches what is set
in the column usage bit maps. (This found a LOT of bugs in current
column marking code).
- In 5.1 before, all used columns was marked in read_set and only updated
columns was marked in write_set. Now we only mark columns for which we
need a value in read_set.
- Column bitmaps are created in open_binary_frm() and open_table_from_share().
(Before this was in table.cc)
- handler::table_flags() calls are replaced with handler::ha_table_flags()
- For calling field->val() you must have the corresponding bit set in
table->read_set. For calling field->store() you must have the
corresponding bit set in table->write_set. (There are asserts in
all store()/val() functions to catch wrong usage)
- thd->set_query_id is renamed to thd->mark_used_columns and instead
of setting this to an integer value, this has now the values:
MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE
Changed also all variables named 'set_query_id' to mark_used_columns.
- In filesort() we now inform the handler of exactly which columns are needed
doing the sort and choosing the rows.
- The TABLE_SHARE object has a 'all_set' column bitmap one can use
when one needs a column bitmap with all columns set.
(This is used for table->use_all_columns() and other places)
- The TABLE object has 3 column bitmaps:
- def_read_set Default bitmap for columns to be read
- def_write_set Default bitmap for columns to be written
- tmp_set Can be used as a temporary bitmap when needed.
The table object has also two pointer to bitmaps read_set and write_set
that the handler should use to find out which columns are used in which way.
- count() optimization now calls handler::records() instead of using
handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true).
- Added extra argument to Item::walk() to indicate if we should also
traverse sub queries.
- Added TABLE parameter to cp_buffer_from_ref()
- Don't close tables created with CREATE ... SELECT but keep them in
the table cache. (Faster usage of newly created tables).
New interfaces:
- table->clear_column_bitmaps() to initialize the bitmaps for tables
at start of new statements.
- table->column_bitmaps_set() to set up new column bitmaps and signal
the handler about this.
- table->column_bitmaps_set_no_signal() for some few cases where we need
to setup new column bitmaps but don't signal the handler (as the handler
has already been signaled about these before). Used for the momement
only in opt_range.cc when doing ROR scans.
- table->use_all_columns() to install a bitmap where all columns are marked
as use in the read and the write set.
- table->default_column_bitmaps() to install the normal read and write
column bitmaps, but not signaling the handler about this.
This is mainly used when creating TABLE instances.
- table->mark_columns_needed_for_delete(),
table->mark_columns_needed_for_delete() and
table->mark_columns_needed_for_insert() to allow us to put additional
columns in column usage maps if handler so requires.
(The handler indicates what it neads in handler->table_flags())
- table->prepare_for_position() to allow us to tell handler that it
needs to read primary key parts to be able to store them in
future table->position() calls.
(This replaces the table->file->ha_retrieve_all_pk function)
- table->mark_auto_increment_column() to tell handler are going to update
columns part of any auto_increment key.
- table->mark_columns_used_by_index() to mark all columns that is part of
an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow
it to quickly know that it only needs to read colums that are part
of the key. (The handler can also use the column map for detecting this,
but simpler/faster handler can just monitor the extra() call).
- table->mark_columns_used_by_index_no_reset() to in addition to other columns,
also mark all columns that is used by the given key.
- table->restore_column_maps_after_mark_index() to restore to default
column maps after a call to table->mark_columns_used_by_index().
- New item function register_field_in_read_map(), for marking used columns
in table->read_map. Used by filesort() to mark all used columns
- Maintain in TABLE->merge_keys set of all keys that are used in query.
(Simplices some optimization loops)
- Maintain Field->part_of_key_not_clustered which is like Field->part_of_key
but the field in the clustered key is not assumed to be part of all index.
(used in opt_range.cc for faster loops)
- dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map()
tmp_use_all_columns() and tmp_restore_column_map() functions to temporally
mark all columns as usable. The 'dbug_' version is primarily intended
inside a handler when it wants to just call Field:store() & Field::val()
functions, but don't need the column maps set for any other usage.
(ie:: bitmap_is_set() is never called)
- We can't use compare_records() to skip updates for handlers that returns
a partial column set and the read_set doesn't cover all columns in the
write set. The reason for this is that if we have a column marked only for
write we can't in the MySQL level know if the value changed or not.
The reason this worked before was that MySQL marked all to be written
columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden
bug'.
- open_table_from_share() does not anymore setup temporary MEM_ROOT
object as a thread specific variable for the handler. Instead we
send the to-be-used MEMROOT to get_new_handler().
(Simpler, faster code)
Bugs fixed:
- Column marking was not done correctly in a lot of cases.
(ALTER TABLE, when using triggers, auto_increment fields etc)
(Could potentially result in wrong values inserted in table handlers
relying on that the old column maps or field->set_query_id was correct)
Especially when it comes to triggers, there may be cases where the
old code would cause lost/wrong values for NDB and/or InnoDB tables.
- Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags:
OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG.
This allowed me to remove some wrong warnings about:
"Some non-transactional changed tables couldn't be rolled back"
- Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset
(thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose
some warnings about
"Some non-transactional changed tables couldn't be rolled back")
- Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table()
which could cause delete_table to report random failures.
- Fixed core dumps for some tests when running with --debug
- Added missing FN_LIBCHAR in mysql_rm_tmp_tables()
(This has probably caused us to not properly remove temporary files after
crash)
- slow_logs was not properly initialized, which could maybe cause
extra/lost entries in slow log.
- If we get an duplicate row on insert, change column map to read and
write all columns while retrying the operation. This is required by
the definition of REPLACE and also ensures that fields that are only
part of UPDATE are properly handled. This fixed a bug in NDB and
REPLACE where REPLACE wrongly copied some column values from the replaced
row.
- For table handler that doesn't support NULL in keys, we would give an error
when creating a primary key with NULL fields, even after the fields has been
automaticly converted to NOT NULL.
- Creating a primary key on a SPATIAL key, would fail if field was not
declared as NOT NULL.
Cleanups:
- Removed not used condition argument to setup_tables
- Removed not needed item function reset_query_id_processor().
- Field->add_index is removed. Now this is instead maintained in
(field->flags & FIELD_IN_ADD_INDEX)
- Field->fieldnr is removed (use field->field_index instead)
- New argument to filesort() to indicate that it should return a set of
row pointers (not used columns). This allowed me to remove some references
to sql_command in filesort and should also enable us to return column
results in some cases where we couldn't before.
- Changed column bitmap handling in opt_range.cc to be aligned with TABLE
bitmap, which allowed me to use bitmap functions instead of looping over
all fields to create some needed bitmaps. (Faster and smaller code)
- Broke up found too long lines
- Moved some variable declaration at start of function for better code
readability.
- Removed some not used arguments from functions.
(setup_fields(), mysql_prepare_insert_check_table())
- setup_fields() now takes an enum instead of an int for marking columns
usage.
- For internal temporary tables, use handler::write_row(),
handler::delete_row() and handler::update_row() instead of
handler::ha_xxxx() for faster execution.
- Changed some constants to enum's and define's.
- Using separate column read and write sets allows for easier checking
of timestamp field was set by statement.
- Remove calls to free_io_cache() as this is now done automaticly in ha_reset()
- Don't build table->normalized_path as this is now identical to table->path
(after bar's fixes to convert filenames)
- Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to
do comparision with the 'convert-dbug-for-diff' tool.
Things left to do in 5.1:
- We wrongly log failed CREATE TABLE ... SELECT in some cases when using
row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result)
Mats has promised to look into this.
- Test that my fix for CREATE TABLE ... SELECT is indeed correct.
(I added several test cases for this, but in this case it's better that
someone else also tests this throughly).
Lars has promosed to do this.
2006-06-04 17:52:22 +02:00
|
|
|
table->field[0]->store(combo.host.str,combo.host.length,
|
|
|
|
system_charset_info);
|
2004-11-25 21:55:49 +01:00
|
|
|
table->field[1]->store(db,(uint) strlen(db), system_charset_info);
|
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes
Changes that requires code changes in other code of other storage engines.
(Note that all changes are very straightforward and one should find all issues
by compiling a --debug build and fixing all compiler errors and all
asserts in field.cc while running the test suite),
- New optional handler function introduced: reset()
This is called after every DML statement to make it easy for a handler to
statement specific cleanups.
(The only case it's not called is if force the file to be closed)
- handler::extra(HA_EXTRA_RESET) is removed. Code that was there before
should be moved to handler::reset()
- table->read_set contains a bitmap over all columns that are needed
in the query. read_row() and similar functions only needs to read these
columns
- table->write_set contains a bitmap over all columns that will be updated
in the query. write_row() and update_row() only needs to update these
columns.
The above bitmaps should now be up to date in all context
(including ALTER TABLE, filesort()).
The handler is informed of any changes to the bitmap after
fix_fields() by calling the virtual function
handler::column_bitmaps_signal(). If the handler does caching of
these bitmaps (instead of using table->read_set, table->write_set),
it should redo the caching in this code. as the signal() may be sent
several times, it's probably best to set a variable in the signal
and redo the caching on read_row() / write_row() if the variable was
set.
- Removed the read_set and write_set bitmap objects from the handler class
- Removed all column bit handling functions from the handler class.
(Now one instead uses the normal bitmap functions in my_bitmap.c instead
of handler dedicated bitmap functions)
- field->query_id is removed. One should instead instead check
table->read_set and table->write_set if a field is used in the query.
- handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and
handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now
instead use table->read_set to check for which columns to retrieve.
- If a handler needs to call Field->val() or Field->store() on columns
that are not used in the query, one should install a temporary
all-columns-used map while doing so. For this, we provide the following
functions:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
field->val();
dbug_tmp_restore_column_map(table->read_set, old_map);
and similar for the write map:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
field->val();
dbug_tmp_restore_column_map(table->write_set, old_map);
If this is not done, you will sooner or later hit a DBUG_ASSERT
in the field store() / val() functions.
(For not DBUG binaries, the dbug_tmp_restore_column_map() and
dbug_tmp_restore_column_map() are inline dummy functions and should
be optimized away be the compiler).
- If one needs to temporary set the column map for all binaries (and not
just to avoid the DBUG_ASSERT() in the Field::store() / Field::val()
methods) one should use the functions tmp_use_all_columns() and
tmp_restore_column_map() instead of the above dbug_ variants.
- All 'status' fields in the handler base class (like records,
data_file_length etc) are now stored in a 'stats' struct. This makes
it easier to know what status variables are provided by the base
handler. This requires some trivial variable names in the extra()
function.
- New virtual function handler::records(). This is called to optimize
COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true.
(stats.records is not supposed to be an exact value. It's only has to
be 'reasonable enough' for the optimizer to be able to choose a good
optimization path).
- Non virtual handler::init() function added for caching of virtual
constants from engine.
- Removed has_transactions() virtual method. Now one should instead return
HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support
transactions.
- The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument
that is to be used with 'new handler_name()' to allocate the handler
in the right area. The xxxx_create_handler() function is also
responsible for any initialization of the object before returning.
For example, one should change:
static handler *myisam_create_handler(TABLE_SHARE *table)
{
return new ha_myisam(table);
}
->
static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisam(table);
}
- New optional virtual function: use_hidden_primary_key().
This is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key. This allows the handler to take precisions
in remembering any hidden primary key to able to update/delete any
found row. The default handler marks all columns to be read.
- handler::table_flags() now returns a ulonglong (to allow for more flags).
- New/changed table_flags()
- HA_HAS_RECORDS Set if ::records() is supported
- HA_NO_TRANSACTIONS Set if engine doesn't support transactions
- HA_PRIMARY_KEY_REQUIRED_FOR_DELETE
Set if we should mark all primary key columns for
read when reading rows as part of a DELETE
statement. If there is no primary key,
all columns are marked for read.
- HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some
cases (based on table->read_set)
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
- HA_DUPP_POS Renamed to HA_DUPLICATE_POS
- HA_REQUIRES_KEY_COLUMNS_FOR_DELETE
Set this if we should mark ALL key columns for
read when when reading rows as part of a DELETE
statement. In case of an update we will mark
all keys for read for which key part changed
value.
- HA_STATS_RECORDS_IS_EXACT
Set this if stats.records is exact.
(This saves us some extra records() calls
when optimizing COUNT(*))
- Removed table_flags()
- HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if
handler::records() gives an exact count() and
HA_STATS_RECORDS_IS_EXACT if stats.records is exact.
- HA_READ_RND_SAME Removed (no one supported this one)
- Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk()
- Renamed handler::dupp_pos to handler::dup_pos
- Removed not used variable handler::sortkey
Upper level handler changes:
- ha_reset() now does some overall checks and calls ::reset()
- ha_table_flags() added. This is a cached version of table_flags(). The
cache is updated on engine creation time and updated on open.
MySQL level changes (not obvious from the above):
- DBUG_ASSERT() added to check that column usage matches what is set
in the column usage bit maps. (This found a LOT of bugs in current
column marking code).
- In 5.1 before, all used columns was marked in read_set and only updated
columns was marked in write_set. Now we only mark columns for which we
need a value in read_set.
- Column bitmaps are created in open_binary_frm() and open_table_from_share().
(Before this was in table.cc)
- handler::table_flags() calls are replaced with handler::ha_table_flags()
- For calling field->val() you must have the corresponding bit set in
table->read_set. For calling field->store() you must have the
corresponding bit set in table->write_set. (There are asserts in
all store()/val() functions to catch wrong usage)
- thd->set_query_id is renamed to thd->mark_used_columns and instead
of setting this to an integer value, this has now the values:
MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE
Changed also all variables named 'set_query_id' to mark_used_columns.
- In filesort() we now inform the handler of exactly which columns are needed
doing the sort and choosing the rows.
- The TABLE_SHARE object has a 'all_set' column bitmap one can use
when one needs a column bitmap with all columns set.
(This is used for table->use_all_columns() and other places)
- The TABLE object has 3 column bitmaps:
- def_read_set Default bitmap for columns to be read
- def_write_set Default bitmap for columns to be written
- tmp_set Can be used as a temporary bitmap when needed.
The table object has also two pointer to bitmaps read_set and write_set
that the handler should use to find out which columns are used in which way.
- count() optimization now calls handler::records() instead of using
handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true).
- Added extra argument to Item::walk() to indicate if we should also
traverse sub queries.
- Added TABLE parameter to cp_buffer_from_ref()
- Don't close tables created with CREATE ... SELECT but keep them in
the table cache. (Faster usage of newly created tables).
New interfaces:
- table->clear_column_bitmaps() to initialize the bitmaps for tables
at start of new statements.
- table->column_bitmaps_set() to set up new column bitmaps and signal
the handler about this.
- table->column_bitmaps_set_no_signal() for some few cases where we need
to setup new column bitmaps but don't signal the handler (as the handler
has already been signaled about these before). Used for the momement
only in opt_range.cc when doing ROR scans.
- table->use_all_columns() to install a bitmap where all columns are marked
as use in the read and the write set.
- table->default_column_bitmaps() to install the normal read and write
column bitmaps, but not signaling the handler about this.
This is mainly used when creating TABLE instances.
- table->mark_columns_needed_for_delete(),
table->mark_columns_needed_for_delete() and
table->mark_columns_needed_for_insert() to allow us to put additional
columns in column usage maps if handler so requires.
(The handler indicates what it neads in handler->table_flags())
- table->prepare_for_position() to allow us to tell handler that it
needs to read primary key parts to be able to store them in
future table->position() calls.
(This replaces the table->file->ha_retrieve_all_pk function)
- table->mark_auto_increment_column() to tell handler are going to update
columns part of any auto_increment key.
- table->mark_columns_used_by_index() to mark all columns that is part of
an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow
it to quickly know that it only needs to read colums that are part
of the key. (The handler can also use the column map for detecting this,
but simpler/faster handler can just monitor the extra() call).
- table->mark_columns_used_by_index_no_reset() to in addition to other columns,
also mark all columns that is used by the given key.
- table->restore_column_maps_after_mark_index() to restore to default
column maps after a call to table->mark_columns_used_by_index().
- New item function register_field_in_read_map(), for marking used columns
in table->read_map. Used by filesort() to mark all used columns
- Maintain in TABLE->merge_keys set of all keys that are used in query.
(Simplices some optimization loops)
- Maintain Field->part_of_key_not_clustered which is like Field->part_of_key
but the field in the clustered key is not assumed to be part of all index.
(used in opt_range.cc for faster loops)
- dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map()
tmp_use_all_columns() and tmp_restore_column_map() functions to temporally
mark all columns as usable. The 'dbug_' version is primarily intended
inside a handler when it wants to just call Field:store() & Field::val()
functions, but don't need the column maps set for any other usage.
(ie:: bitmap_is_set() is never called)
- We can't use compare_records() to skip updates for handlers that returns
a partial column set and the read_set doesn't cover all columns in the
write set. The reason for this is that if we have a column marked only for
write we can't in the MySQL level know if the value changed or not.
The reason this worked before was that MySQL marked all to be written
columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden
bug'.
- open_table_from_share() does not anymore setup temporary MEM_ROOT
object as a thread specific variable for the handler. Instead we
send the to-be-used MEMROOT to get_new_handler().
(Simpler, faster code)
Bugs fixed:
- Column marking was not done correctly in a lot of cases.
(ALTER TABLE, when using triggers, auto_increment fields etc)
(Could potentially result in wrong values inserted in table handlers
relying on that the old column maps or field->set_query_id was correct)
Especially when it comes to triggers, there may be cases where the
old code would cause lost/wrong values for NDB and/or InnoDB tables.
- Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags:
OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG.
This allowed me to remove some wrong warnings about:
"Some non-transactional changed tables couldn't be rolled back"
- Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset
(thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose
some warnings about
"Some non-transactional changed tables couldn't be rolled back")
- Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table()
which could cause delete_table to report random failures.
- Fixed core dumps for some tests when running with --debug
- Added missing FN_LIBCHAR in mysql_rm_tmp_tables()
(This has probably caused us to not properly remove temporary files after
crash)
- slow_logs was not properly initialized, which could maybe cause
extra/lost entries in slow log.
- If we get an duplicate row on insert, change column map to read and
write all columns while retrying the operation. This is required by
the definition of REPLACE and also ensures that fields that are only
part of UPDATE are properly handled. This fixed a bug in NDB and
REPLACE where REPLACE wrongly copied some column values from the replaced
row.
- For table handler that doesn't support NULL in keys, we would give an error
when creating a primary key with NULL fields, even after the fields has been
automaticly converted to NOT NULL.
- Creating a primary key on a SPATIAL key, would fail if field was not
declared as NOT NULL.
Cleanups:
- Removed not used condition argument to setup_tables
- Removed not needed item function reset_query_id_processor().
- Field->add_index is removed. Now this is instead maintained in
(field->flags & FIELD_IN_ADD_INDEX)
- Field->fieldnr is removed (use field->field_index instead)
- New argument to filesort() to indicate that it should return a set of
row pointers (not used columns). This allowed me to remove some references
to sql_command in filesort and should also enable us to return column
results in some cases where we couldn't before.
- Changed column bitmap handling in opt_range.cc to be aligned with TABLE
bitmap, which allowed me to use bitmap functions instead of looping over
all fields to create some needed bitmaps. (Faster and smaller code)
- Broke up found too long lines
- Moved some variable declaration at start of function for better code
readability.
- Removed some not used arguments from functions.
(setup_fields(), mysql_prepare_insert_check_table())
- setup_fields() now takes an enum instead of an int for marking columns
usage.
- For internal temporary tables, use handler::write_row(),
handler::delete_row() and handler::update_row() instead of
handler::ha_xxxx() for faster execution.
- Changed some constants to enum's and define's.
- Using separate column read and write sets allows for easier checking
of timestamp field was set by statement.
- Remove calls to free_io_cache() as this is now done automaticly in ha_reset()
- Don't build table->normalized_path as this is now identical to table->path
(after bar's fixes to convert filenames)
- Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to
do comparision with the 'convert-dbug-for-diff' tool.
Things left to do in 5.1:
- We wrongly log failed CREATE TABLE ... SELECT in some cases when using
row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result)
Mats has promised to look into this.
- Test that my fix for CREATE TABLE ... SELECT is indeed correct.
(I added several test cases for this, but in this case it's better that
someone else also tests this throughly).
Lars has promosed to do this.
2006-06-04 17:52:22 +02:00
|
|
|
table->field[2]->store(combo.user.str,combo.user.length,
|
|
|
|
system_charset_info);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-08-10 16:37:37 +02:00
|
|
|
old_row_exists = 1;
|
2003-05-03 01:16:56 +02:00
|
|
|
store_record(table,record[1]);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
store_rights=get_rights_for_db(rights);
|
2005-01-06 12:00:13 +01:00
|
|
|
for (i= 3, priv= 1; i < table->s->fields; i++, priv <<= 1)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2002-06-12 14:04:18 +02:00
|
|
|
if (priv & store_rights) // do it if priv is chosen
|
2003-01-29 14:31:20 +01:00
|
|
|
table->field [i]->store(&what,1, &my_charset_latin1);// set requested privileges
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
rights=get_access(table,3);
|
|
|
|
rights=fix_rights_for_db(rights);
|
|
|
|
|
2001-08-10 16:37:37 +02:00
|
|
|
if (old_row_exists)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2003-06-23 19:03:59 +02:00
|
|
|
/* update old existing row */
|
2000-07-31 21:29:14 +02:00
|
|
|
if (rights)
|
|
|
|
{
|
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes
Changes that requires code changes in other code of other storage engines.
(Note that all changes are very straightforward and one should find all issues
by compiling a --debug build and fixing all compiler errors and all
asserts in field.cc while running the test suite),
- New optional handler function introduced: reset()
This is called after every DML statement to make it easy for a handler to
statement specific cleanups.
(The only case it's not called is if force the file to be closed)
- handler::extra(HA_EXTRA_RESET) is removed. Code that was there before
should be moved to handler::reset()
- table->read_set contains a bitmap over all columns that are needed
in the query. read_row() and similar functions only needs to read these
columns
- table->write_set contains a bitmap over all columns that will be updated
in the query. write_row() and update_row() only needs to update these
columns.
The above bitmaps should now be up to date in all context
(including ALTER TABLE, filesort()).
The handler is informed of any changes to the bitmap after
fix_fields() by calling the virtual function
handler::column_bitmaps_signal(). If the handler does caching of
these bitmaps (instead of using table->read_set, table->write_set),
it should redo the caching in this code. as the signal() may be sent
several times, it's probably best to set a variable in the signal
and redo the caching on read_row() / write_row() if the variable was
set.
- Removed the read_set and write_set bitmap objects from the handler class
- Removed all column bit handling functions from the handler class.
(Now one instead uses the normal bitmap functions in my_bitmap.c instead
of handler dedicated bitmap functions)
- field->query_id is removed. One should instead instead check
table->read_set and table->write_set if a field is used in the query.
- handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and
handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now
instead use table->read_set to check for which columns to retrieve.
- If a handler needs to call Field->val() or Field->store() on columns
that are not used in the query, one should install a temporary
all-columns-used map while doing so. For this, we provide the following
functions:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
field->val();
dbug_tmp_restore_column_map(table->read_set, old_map);
and similar for the write map:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
field->val();
dbug_tmp_restore_column_map(table->write_set, old_map);
If this is not done, you will sooner or later hit a DBUG_ASSERT
in the field store() / val() functions.
(For not DBUG binaries, the dbug_tmp_restore_column_map() and
dbug_tmp_restore_column_map() are inline dummy functions and should
be optimized away be the compiler).
- If one needs to temporary set the column map for all binaries (and not
just to avoid the DBUG_ASSERT() in the Field::store() / Field::val()
methods) one should use the functions tmp_use_all_columns() and
tmp_restore_column_map() instead of the above dbug_ variants.
- All 'status' fields in the handler base class (like records,
data_file_length etc) are now stored in a 'stats' struct. This makes
it easier to know what status variables are provided by the base
handler. This requires some trivial variable names in the extra()
function.
- New virtual function handler::records(). This is called to optimize
COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true.
(stats.records is not supposed to be an exact value. It's only has to
be 'reasonable enough' for the optimizer to be able to choose a good
optimization path).
- Non virtual handler::init() function added for caching of virtual
constants from engine.
- Removed has_transactions() virtual method. Now one should instead return
HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support
transactions.
- The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument
that is to be used with 'new handler_name()' to allocate the handler
in the right area. The xxxx_create_handler() function is also
responsible for any initialization of the object before returning.
For example, one should change:
static handler *myisam_create_handler(TABLE_SHARE *table)
{
return new ha_myisam(table);
}
->
static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisam(table);
}
- New optional virtual function: use_hidden_primary_key().
This is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key. This allows the handler to take precisions
in remembering any hidden primary key to able to update/delete any
found row. The default handler marks all columns to be read.
- handler::table_flags() now returns a ulonglong (to allow for more flags).
- New/changed table_flags()
- HA_HAS_RECORDS Set if ::records() is supported
- HA_NO_TRANSACTIONS Set if engine doesn't support transactions
- HA_PRIMARY_KEY_REQUIRED_FOR_DELETE
Set if we should mark all primary key columns for
read when reading rows as part of a DELETE
statement. If there is no primary key,
all columns are marked for read.
- HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some
cases (based on table->read_set)
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
- HA_DUPP_POS Renamed to HA_DUPLICATE_POS
- HA_REQUIRES_KEY_COLUMNS_FOR_DELETE
Set this if we should mark ALL key columns for
read when when reading rows as part of a DELETE
statement. In case of an update we will mark
all keys for read for which key part changed
value.
- HA_STATS_RECORDS_IS_EXACT
Set this if stats.records is exact.
(This saves us some extra records() calls
when optimizing COUNT(*))
- Removed table_flags()
- HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if
handler::records() gives an exact count() and
HA_STATS_RECORDS_IS_EXACT if stats.records is exact.
- HA_READ_RND_SAME Removed (no one supported this one)
- Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk()
- Renamed handler::dupp_pos to handler::dup_pos
- Removed not used variable handler::sortkey
Upper level handler changes:
- ha_reset() now does some overall checks and calls ::reset()
- ha_table_flags() added. This is a cached version of table_flags(). The
cache is updated on engine creation time and updated on open.
MySQL level changes (not obvious from the above):
- DBUG_ASSERT() added to check that column usage matches what is set
in the column usage bit maps. (This found a LOT of bugs in current
column marking code).
- In 5.1 before, all used columns was marked in read_set and only updated
columns was marked in write_set. Now we only mark columns for which we
need a value in read_set.
- Column bitmaps are created in open_binary_frm() and open_table_from_share().
(Before this was in table.cc)
- handler::table_flags() calls are replaced with handler::ha_table_flags()
- For calling field->val() you must have the corresponding bit set in
table->read_set. For calling field->store() you must have the
corresponding bit set in table->write_set. (There are asserts in
all store()/val() functions to catch wrong usage)
- thd->set_query_id is renamed to thd->mark_used_columns and instead
of setting this to an integer value, this has now the values:
MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE
Changed also all variables named 'set_query_id' to mark_used_columns.
- In filesort() we now inform the handler of exactly which columns are needed
doing the sort and choosing the rows.
- The TABLE_SHARE object has a 'all_set' column bitmap one can use
when one needs a column bitmap with all columns set.
(This is used for table->use_all_columns() and other places)
- The TABLE object has 3 column bitmaps:
- def_read_set Default bitmap for columns to be read
- def_write_set Default bitmap for columns to be written
- tmp_set Can be used as a temporary bitmap when needed.
The table object has also two pointer to bitmaps read_set and write_set
that the handler should use to find out which columns are used in which way.
- count() optimization now calls handler::records() instead of using
handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true).
- Added extra argument to Item::walk() to indicate if we should also
traverse sub queries.
- Added TABLE parameter to cp_buffer_from_ref()
- Don't close tables created with CREATE ... SELECT but keep them in
the table cache. (Faster usage of newly created tables).
New interfaces:
- table->clear_column_bitmaps() to initialize the bitmaps for tables
at start of new statements.
- table->column_bitmaps_set() to set up new column bitmaps and signal
the handler about this.
- table->column_bitmaps_set_no_signal() for some few cases where we need
to setup new column bitmaps but don't signal the handler (as the handler
has already been signaled about these before). Used for the momement
only in opt_range.cc when doing ROR scans.
- table->use_all_columns() to install a bitmap where all columns are marked
as use in the read and the write set.
- table->default_column_bitmaps() to install the normal read and write
column bitmaps, but not signaling the handler about this.
This is mainly used when creating TABLE instances.
- table->mark_columns_needed_for_delete(),
table->mark_columns_needed_for_delete() and
table->mark_columns_needed_for_insert() to allow us to put additional
columns in column usage maps if handler so requires.
(The handler indicates what it neads in handler->table_flags())
- table->prepare_for_position() to allow us to tell handler that it
needs to read primary key parts to be able to store them in
future table->position() calls.
(This replaces the table->file->ha_retrieve_all_pk function)
- table->mark_auto_increment_column() to tell handler are going to update
columns part of any auto_increment key.
- table->mark_columns_used_by_index() to mark all columns that is part of
an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow
it to quickly know that it only needs to read colums that are part
of the key. (The handler can also use the column map for detecting this,
but simpler/faster handler can just monitor the extra() call).
- table->mark_columns_used_by_index_no_reset() to in addition to other columns,
also mark all columns that is used by the given key.
- table->restore_column_maps_after_mark_index() to restore to default
column maps after a call to table->mark_columns_used_by_index().
- New item function register_field_in_read_map(), for marking used columns
in table->read_map. Used by filesort() to mark all used columns
- Maintain in TABLE->merge_keys set of all keys that are used in query.
(Simplices some optimization loops)
- Maintain Field->part_of_key_not_clustered which is like Field->part_of_key
but the field in the clustered key is not assumed to be part of all index.
(used in opt_range.cc for faster loops)
- dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map()
tmp_use_all_columns() and tmp_restore_column_map() functions to temporally
mark all columns as usable. The 'dbug_' version is primarily intended
inside a handler when it wants to just call Field:store() & Field::val()
functions, but don't need the column maps set for any other usage.
(ie:: bitmap_is_set() is never called)
- We can't use compare_records() to skip updates for handlers that returns
a partial column set and the read_set doesn't cover all columns in the
write set. The reason for this is that if we have a column marked only for
write we can't in the MySQL level know if the value changed or not.
The reason this worked before was that MySQL marked all to be written
columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden
bug'.
- open_table_from_share() does not anymore setup temporary MEM_ROOT
object as a thread specific variable for the handler. Instead we
send the to-be-used MEMROOT to get_new_handler().
(Simpler, faster code)
Bugs fixed:
- Column marking was not done correctly in a lot of cases.
(ALTER TABLE, when using triggers, auto_increment fields etc)
(Could potentially result in wrong values inserted in table handlers
relying on that the old column maps or field->set_query_id was correct)
Especially when it comes to triggers, there may be cases where the
old code would cause lost/wrong values for NDB and/or InnoDB tables.
- Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags:
OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG.
This allowed me to remove some wrong warnings about:
"Some non-transactional changed tables couldn't be rolled back"
- Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset
(thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose
some warnings about
"Some non-transactional changed tables couldn't be rolled back")
- Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table()
which could cause delete_table to report random failures.
- Fixed core dumps for some tests when running with --debug
- Added missing FN_LIBCHAR in mysql_rm_tmp_tables()
(This has probably caused us to not properly remove temporary files after
crash)
- slow_logs was not properly initialized, which could maybe cause
extra/lost entries in slow log.
- If we get an duplicate row on insert, change column map to read and
write all columns while retrying the operation. This is required by
the definition of REPLACE and also ensures that fields that are only
part of UPDATE are properly handled. This fixed a bug in NDB and
REPLACE where REPLACE wrongly copied some column values from the replaced
row.
- For table handler that doesn't support NULL in keys, we would give an error
when creating a primary key with NULL fields, even after the fields has been
automaticly converted to NOT NULL.
- Creating a primary key on a SPATIAL key, would fail if field was not
declared as NOT NULL.
Cleanups:
- Removed not used condition argument to setup_tables
- Removed not needed item function reset_query_id_processor().
- Field->add_index is removed. Now this is instead maintained in
(field->flags & FIELD_IN_ADD_INDEX)
- Field->fieldnr is removed (use field->field_index instead)
- New argument to filesort() to indicate that it should return a set of
row pointers (not used columns). This allowed me to remove some references
to sql_command in filesort and should also enable us to return column
results in some cases where we couldn't before.
- Changed column bitmap handling in opt_range.cc to be aligned with TABLE
bitmap, which allowed me to use bitmap functions instead of looping over
all fields to create some needed bitmaps. (Faster and smaller code)
- Broke up found too long lines
- Moved some variable declaration at start of function for better code
readability.
- Removed some not used arguments from functions.
(setup_fields(), mysql_prepare_insert_check_table())
- setup_fields() now takes an enum instead of an int for marking columns
usage.
- For internal temporary tables, use handler::write_row(),
handler::delete_row() and handler::update_row() instead of
handler::ha_xxxx() for faster execution.
- Changed some constants to enum's and define's.
- Using separate column read and write sets allows for easier checking
of timestamp field was set by statement.
- Remove calls to free_io_cache() as this is now done automaticly in ha_reset()
- Don't build table->normalized_path as this is now identical to table->path
(after bar's fixes to convert filenames)
- Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to
do comparision with the 'convert-dbug-for-diff' tool.
Things left to do in 5.1:
- We wrongly log failed CREATE TABLE ... SELECT in some cases when using
row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result)
Mats has promised to look into this.
- Test that my fix for CREATE TABLE ... SELECT is indeed correct.
(I added several test cases for this, but in this case it's better that
someone else also tests this throughly).
Lars has promosed to do this.
2006-06-04 17:52:22 +02:00
|
|
|
if ((error= table->file->ha_update_row(table->record[1],
|
2007-06-28 15:07:55 +02:00
|
|
|
table->record[0])) &&
|
|
|
|
error != HA_ERR_RECORD_IS_THE_SAME)
|
2000-07-31 21:29:14 +02:00
|
|
|
goto table_error; /* purecov: deadcode */
|
|
|
|
}
|
|
|
|
else /* must have been a revoke of all privileges */
|
|
|
|
{
|
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes
Changes that requires code changes in other code of other storage engines.
(Note that all changes are very straightforward and one should find all issues
by compiling a --debug build and fixing all compiler errors and all
asserts in field.cc while running the test suite),
- New optional handler function introduced: reset()
This is called after every DML statement to make it easy for a handler to
statement specific cleanups.
(The only case it's not called is if force the file to be closed)
- handler::extra(HA_EXTRA_RESET) is removed. Code that was there before
should be moved to handler::reset()
- table->read_set contains a bitmap over all columns that are needed
in the query. read_row() and similar functions only needs to read these
columns
- table->write_set contains a bitmap over all columns that will be updated
in the query. write_row() and update_row() only needs to update these
columns.
The above bitmaps should now be up to date in all context
(including ALTER TABLE, filesort()).
The handler is informed of any changes to the bitmap after
fix_fields() by calling the virtual function
handler::column_bitmaps_signal(). If the handler does caching of
these bitmaps (instead of using table->read_set, table->write_set),
it should redo the caching in this code. as the signal() may be sent
several times, it's probably best to set a variable in the signal
and redo the caching on read_row() / write_row() if the variable was
set.
- Removed the read_set and write_set bitmap objects from the handler class
- Removed all column bit handling functions from the handler class.
(Now one instead uses the normal bitmap functions in my_bitmap.c instead
of handler dedicated bitmap functions)
- field->query_id is removed. One should instead instead check
table->read_set and table->write_set if a field is used in the query.
- handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and
handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now
instead use table->read_set to check for which columns to retrieve.
- If a handler needs to call Field->val() or Field->store() on columns
that are not used in the query, one should install a temporary
all-columns-used map while doing so. For this, we provide the following
functions:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
field->val();
dbug_tmp_restore_column_map(table->read_set, old_map);
and similar for the write map:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
field->val();
dbug_tmp_restore_column_map(table->write_set, old_map);
If this is not done, you will sooner or later hit a DBUG_ASSERT
in the field store() / val() functions.
(For not DBUG binaries, the dbug_tmp_restore_column_map() and
dbug_tmp_restore_column_map() are inline dummy functions and should
be optimized away be the compiler).
- If one needs to temporary set the column map for all binaries (and not
just to avoid the DBUG_ASSERT() in the Field::store() / Field::val()
methods) one should use the functions tmp_use_all_columns() and
tmp_restore_column_map() instead of the above dbug_ variants.
- All 'status' fields in the handler base class (like records,
data_file_length etc) are now stored in a 'stats' struct. This makes
it easier to know what status variables are provided by the base
handler. This requires some trivial variable names in the extra()
function.
- New virtual function handler::records(). This is called to optimize
COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true.
(stats.records is not supposed to be an exact value. It's only has to
be 'reasonable enough' for the optimizer to be able to choose a good
optimization path).
- Non virtual handler::init() function added for caching of virtual
constants from engine.
- Removed has_transactions() virtual method. Now one should instead return
HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support
transactions.
- The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument
that is to be used with 'new handler_name()' to allocate the handler
in the right area. The xxxx_create_handler() function is also
responsible for any initialization of the object before returning.
For example, one should change:
static handler *myisam_create_handler(TABLE_SHARE *table)
{
return new ha_myisam(table);
}
->
static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisam(table);
}
- New optional virtual function: use_hidden_primary_key().
This is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key. This allows the handler to take precisions
in remembering any hidden primary key to able to update/delete any
found row. The default handler marks all columns to be read.
- handler::table_flags() now returns a ulonglong (to allow for more flags).
- New/changed table_flags()
- HA_HAS_RECORDS Set if ::records() is supported
- HA_NO_TRANSACTIONS Set if engine doesn't support transactions
- HA_PRIMARY_KEY_REQUIRED_FOR_DELETE
Set if we should mark all primary key columns for
read when reading rows as part of a DELETE
statement. If there is no primary key,
all columns are marked for read.
- HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some
cases (based on table->read_set)
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
- HA_DUPP_POS Renamed to HA_DUPLICATE_POS
- HA_REQUIRES_KEY_COLUMNS_FOR_DELETE
Set this if we should mark ALL key columns for
read when when reading rows as part of a DELETE
statement. In case of an update we will mark
all keys for read for which key part changed
value.
- HA_STATS_RECORDS_IS_EXACT
Set this if stats.records is exact.
(This saves us some extra records() calls
when optimizing COUNT(*))
- Removed table_flags()
- HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if
handler::records() gives an exact count() and
HA_STATS_RECORDS_IS_EXACT if stats.records is exact.
- HA_READ_RND_SAME Removed (no one supported this one)
- Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk()
- Renamed handler::dupp_pos to handler::dup_pos
- Removed not used variable handler::sortkey
Upper level handler changes:
- ha_reset() now does some overall checks and calls ::reset()
- ha_table_flags() added. This is a cached version of table_flags(). The
cache is updated on engine creation time and updated on open.
MySQL level changes (not obvious from the above):
- DBUG_ASSERT() added to check that column usage matches what is set
in the column usage bit maps. (This found a LOT of bugs in current
column marking code).
- In 5.1 before, all used columns was marked in read_set and only updated
columns was marked in write_set. Now we only mark columns for which we
need a value in read_set.
- Column bitmaps are created in open_binary_frm() and open_table_from_share().
(Before this was in table.cc)
- handler::table_flags() calls are replaced with handler::ha_table_flags()
- For calling field->val() you must have the corresponding bit set in
table->read_set. For calling field->store() you must have the
corresponding bit set in table->write_set. (There are asserts in
all store()/val() functions to catch wrong usage)
- thd->set_query_id is renamed to thd->mark_used_columns and instead
of setting this to an integer value, this has now the values:
MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE
Changed also all variables named 'set_query_id' to mark_used_columns.
- In filesort() we now inform the handler of exactly which columns are needed
doing the sort and choosing the rows.
- The TABLE_SHARE object has a 'all_set' column bitmap one can use
when one needs a column bitmap with all columns set.
(This is used for table->use_all_columns() and other places)
- The TABLE object has 3 column bitmaps:
- def_read_set Default bitmap for columns to be read
- def_write_set Default bitmap for columns to be written
- tmp_set Can be used as a temporary bitmap when needed.
The table object has also two pointer to bitmaps read_set and write_set
that the handler should use to find out which columns are used in which way.
- count() optimization now calls handler::records() instead of using
handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true).
- Added extra argument to Item::walk() to indicate if we should also
traverse sub queries.
- Added TABLE parameter to cp_buffer_from_ref()
- Don't close tables created with CREATE ... SELECT but keep them in
the table cache. (Faster usage of newly created tables).
New interfaces:
- table->clear_column_bitmaps() to initialize the bitmaps for tables
at start of new statements.
- table->column_bitmaps_set() to set up new column bitmaps and signal
the handler about this.
- table->column_bitmaps_set_no_signal() for some few cases where we need
to setup new column bitmaps but don't signal the handler (as the handler
has already been signaled about these before). Used for the momement
only in opt_range.cc when doing ROR scans.
- table->use_all_columns() to install a bitmap where all columns are marked
as use in the read and the write set.
- table->default_column_bitmaps() to install the normal read and write
column bitmaps, but not signaling the handler about this.
This is mainly used when creating TABLE instances.
- table->mark_columns_needed_for_delete(),
table->mark_columns_needed_for_delete() and
table->mark_columns_needed_for_insert() to allow us to put additional
columns in column usage maps if handler so requires.
(The handler indicates what it neads in handler->table_flags())
- table->prepare_for_position() to allow us to tell handler that it
needs to read primary key parts to be able to store them in
future table->position() calls.
(This replaces the table->file->ha_retrieve_all_pk function)
- table->mark_auto_increment_column() to tell handler are going to update
columns part of any auto_increment key.
- table->mark_columns_used_by_index() to mark all columns that is part of
an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow
it to quickly know that it only needs to read colums that are part
of the key. (The handler can also use the column map for detecting this,
but simpler/faster handler can just monitor the extra() call).
- table->mark_columns_used_by_index_no_reset() to in addition to other columns,
also mark all columns that is used by the given key.
- table->restore_column_maps_after_mark_index() to restore to default
column maps after a call to table->mark_columns_used_by_index().
- New item function register_field_in_read_map(), for marking used columns
in table->read_map. Used by filesort() to mark all used columns
- Maintain in TABLE->merge_keys set of all keys that are used in query.
(Simplices some optimization loops)
- Maintain Field->part_of_key_not_clustered which is like Field->part_of_key
but the field in the clustered key is not assumed to be part of all index.
(used in opt_range.cc for faster loops)
- dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map()
tmp_use_all_columns() and tmp_restore_column_map() functions to temporally
mark all columns as usable. The 'dbug_' version is primarily intended
inside a handler when it wants to just call Field:store() & Field::val()
functions, but don't need the column maps set for any other usage.
(ie:: bitmap_is_set() is never called)
- We can't use compare_records() to skip updates for handlers that returns
a partial column set and the read_set doesn't cover all columns in the
write set. The reason for this is that if we have a column marked only for
write we can't in the MySQL level know if the value changed or not.
The reason this worked before was that MySQL marked all to be written
columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden
bug'.
- open_table_from_share() does not anymore setup temporary MEM_ROOT
object as a thread specific variable for the handler. Instead we
send the to-be-used MEMROOT to get_new_handler().
(Simpler, faster code)
Bugs fixed:
- Column marking was not done correctly in a lot of cases.
(ALTER TABLE, when using triggers, auto_increment fields etc)
(Could potentially result in wrong values inserted in table handlers
relying on that the old column maps or field->set_query_id was correct)
Especially when it comes to triggers, there may be cases where the
old code would cause lost/wrong values for NDB and/or InnoDB tables.
- Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags:
OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG.
This allowed me to remove some wrong warnings about:
"Some non-transactional changed tables couldn't be rolled back"
- Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset
(thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose
some warnings about
"Some non-transactional changed tables couldn't be rolled back")
- Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table()
which could cause delete_table to report random failures.
- Fixed core dumps for some tests when running with --debug
- Added missing FN_LIBCHAR in mysql_rm_tmp_tables()
(This has probably caused us to not properly remove temporary files after
crash)
- slow_logs was not properly initialized, which could maybe cause
extra/lost entries in slow log.
- If we get an duplicate row on insert, change column map to read and
write all columns while retrying the operation. This is required by
the definition of REPLACE and also ensures that fields that are only
part of UPDATE are properly handled. This fixed a bug in NDB and
REPLACE where REPLACE wrongly copied some column values from the replaced
row.
- For table handler that doesn't support NULL in keys, we would give an error
when creating a primary key with NULL fields, even after the fields has been
automaticly converted to NOT NULL.
- Creating a primary key on a SPATIAL key, would fail if field was not
declared as NOT NULL.
Cleanups:
- Removed not used condition argument to setup_tables
- Removed not needed item function reset_query_id_processor().
- Field->add_index is removed. Now this is instead maintained in
(field->flags & FIELD_IN_ADD_INDEX)
- Field->fieldnr is removed (use field->field_index instead)
- New argument to filesort() to indicate that it should return a set of
row pointers (not used columns). This allowed me to remove some references
to sql_command in filesort and should also enable us to return column
results in some cases where we couldn't before.
- Changed column bitmap handling in opt_range.cc to be aligned with TABLE
bitmap, which allowed me to use bitmap functions instead of looping over
all fields to create some needed bitmaps. (Faster and smaller code)
- Broke up found too long lines
- Moved some variable declaration at start of function for better code
readability.
- Removed some not used arguments from functions.
(setup_fields(), mysql_prepare_insert_check_table())
- setup_fields() now takes an enum instead of an int for marking columns
usage.
- For internal temporary tables, use handler::write_row(),
handler::delete_row() and handler::update_row() instead of
handler::ha_xxxx() for faster execution.
- Changed some constants to enum's and define's.
- Using separate column read and write sets allows for easier checking
of timestamp field was set by statement.
- Remove calls to free_io_cache() as this is now done automaticly in ha_reset()
- Don't build table->normalized_path as this is now identical to table->path
(after bar's fixes to convert filenames)
- Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to
do comparision with the 'convert-dbug-for-diff' tool.
Things left to do in 5.1:
- We wrongly log failed CREATE TABLE ... SELECT in some cases when using
row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result)
Mats has promised to look into this.
- Test that my fix for CREATE TABLE ... SELECT is indeed correct.
(I added several test cases for this, but in this case it's better that
someone else also tests this throughly).
Lars has promosed to do this.
2006-06-04 17:52:22 +02:00
|
|
|
if ((error= table->file->ha_delete_row(table->record[1])))
|
2000-07-31 21:29:14 +02:00
|
|
|
goto table_error; /* purecov: deadcode */
|
|
|
|
}
|
|
|
|
}
|
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes
Changes that requires code changes in other code of other storage engines.
(Note that all changes are very straightforward and one should find all issues
by compiling a --debug build and fixing all compiler errors and all
asserts in field.cc while running the test suite),
- New optional handler function introduced: reset()
This is called after every DML statement to make it easy for a handler to
statement specific cleanups.
(The only case it's not called is if force the file to be closed)
- handler::extra(HA_EXTRA_RESET) is removed. Code that was there before
should be moved to handler::reset()
- table->read_set contains a bitmap over all columns that are needed
in the query. read_row() and similar functions only needs to read these
columns
- table->write_set contains a bitmap over all columns that will be updated
in the query. write_row() and update_row() only needs to update these
columns.
The above bitmaps should now be up to date in all context
(including ALTER TABLE, filesort()).
The handler is informed of any changes to the bitmap after
fix_fields() by calling the virtual function
handler::column_bitmaps_signal(). If the handler does caching of
these bitmaps (instead of using table->read_set, table->write_set),
it should redo the caching in this code. as the signal() may be sent
several times, it's probably best to set a variable in the signal
and redo the caching on read_row() / write_row() if the variable was
set.
- Removed the read_set and write_set bitmap objects from the handler class
- Removed all column bit handling functions from the handler class.
(Now one instead uses the normal bitmap functions in my_bitmap.c instead
of handler dedicated bitmap functions)
- field->query_id is removed. One should instead instead check
table->read_set and table->write_set if a field is used in the query.
- handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and
handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now
instead use table->read_set to check for which columns to retrieve.
- If a handler needs to call Field->val() or Field->store() on columns
that are not used in the query, one should install a temporary
all-columns-used map while doing so. For this, we provide the following
functions:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
field->val();
dbug_tmp_restore_column_map(table->read_set, old_map);
and similar for the write map:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
field->val();
dbug_tmp_restore_column_map(table->write_set, old_map);
If this is not done, you will sooner or later hit a DBUG_ASSERT
in the field store() / val() functions.
(For not DBUG binaries, the dbug_tmp_restore_column_map() and
dbug_tmp_restore_column_map() are inline dummy functions and should
be optimized away be the compiler).
- If one needs to temporary set the column map for all binaries (and not
just to avoid the DBUG_ASSERT() in the Field::store() / Field::val()
methods) one should use the functions tmp_use_all_columns() and
tmp_restore_column_map() instead of the above dbug_ variants.
- All 'status' fields in the handler base class (like records,
data_file_length etc) are now stored in a 'stats' struct. This makes
it easier to know what status variables are provided by the base
handler. This requires some trivial variable names in the extra()
function.
- New virtual function handler::records(). This is called to optimize
COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true.
(stats.records is not supposed to be an exact value. It's only has to
be 'reasonable enough' for the optimizer to be able to choose a good
optimization path).
- Non virtual handler::init() function added for caching of virtual
constants from engine.
- Removed has_transactions() virtual method. Now one should instead return
HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support
transactions.
- The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument
that is to be used with 'new handler_name()' to allocate the handler
in the right area. The xxxx_create_handler() function is also
responsible for any initialization of the object before returning.
For example, one should change:
static handler *myisam_create_handler(TABLE_SHARE *table)
{
return new ha_myisam(table);
}
->
static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisam(table);
}
- New optional virtual function: use_hidden_primary_key().
This is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key. This allows the handler to take precisions
in remembering any hidden primary key to able to update/delete any
found row. The default handler marks all columns to be read.
- handler::table_flags() now returns a ulonglong (to allow for more flags).
- New/changed table_flags()
- HA_HAS_RECORDS Set if ::records() is supported
- HA_NO_TRANSACTIONS Set if engine doesn't support transactions
- HA_PRIMARY_KEY_REQUIRED_FOR_DELETE
Set if we should mark all primary key columns for
read when reading rows as part of a DELETE
statement. If there is no primary key,
all columns are marked for read.
- HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some
cases (based on table->read_set)
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
- HA_DUPP_POS Renamed to HA_DUPLICATE_POS
- HA_REQUIRES_KEY_COLUMNS_FOR_DELETE
Set this if we should mark ALL key columns for
read when when reading rows as part of a DELETE
statement. In case of an update we will mark
all keys for read for which key part changed
value.
- HA_STATS_RECORDS_IS_EXACT
Set this if stats.records is exact.
(This saves us some extra records() calls
when optimizing COUNT(*))
- Removed table_flags()
- HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if
handler::records() gives an exact count() and
HA_STATS_RECORDS_IS_EXACT if stats.records is exact.
- HA_READ_RND_SAME Removed (no one supported this one)
- Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk()
- Renamed handler::dupp_pos to handler::dup_pos
- Removed not used variable handler::sortkey
Upper level handler changes:
- ha_reset() now does some overall checks and calls ::reset()
- ha_table_flags() added. This is a cached version of table_flags(). The
cache is updated on engine creation time and updated on open.
MySQL level changes (not obvious from the above):
- DBUG_ASSERT() added to check that column usage matches what is set
in the column usage bit maps. (This found a LOT of bugs in current
column marking code).
- In 5.1 before, all used columns was marked in read_set and only updated
columns was marked in write_set. Now we only mark columns for which we
need a value in read_set.
- Column bitmaps are created in open_binary_frm() and open_table_from_share().
(Before this was in table.cc)
- handler::table_flags() calls are replaced with handler::ha_table_flags()
- For calling field->val() you must have the corresponding bit set in
table->read_set. For calling field->store() you must have the
corresponding bit set in table->write_set. (There are asserts in
all store()/val() functions to catch wrong usage)
- thd->set_query_id is renamed to thd->mark_used_columns and instead
of setting this to an integer value, this has now the values:
MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE
Changed also all variables named 'set_query_id' to mark_used_columns.
- In filesort() we now inform the handler of exactly which columns are needed
doing the sort and choosing the rows.
- The TABLE_SHARE object has a 'all_set' column bitmap one can use
when one needs a column bitmap with all columns set.
(This is used for table->use_all_columns() and other places)
- The TABLE object has 3 column bitmaps:
- def_read_set Default bitmap for columns to be read
- def_write_set Default bitmap for columns to be written
- tmp_set Can be used as a temporary bitmap when needed.
The table object has also two pointer to bitmaps read_set and write_set
that the handler should use to find out which columns are used in which way.
- count() optimization now calls handler::records() instead of using
handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true).
- Added extra argument to Item::walk() to indicate if we should also
traverse sub queries.
- Added TABLE parameter to cp_buffer_from_ref()
- Don't close tables created with CREATE ... SELECT but keep them in
the table cache. (Faster usage of newly created tables).
New interfaces:
- table->clear_column_bitmaps() to initialize the bitmaps for tables
at start of new statements.
- table->column_bitmaps_set() to set up new column bitmaps and signal
the handler about this.
- table->column_bitmaps_set_no_signal() for some few cases where we need
to setup new column bitmaps but don't signal the handler (as the handler
has already been signaled about these before). Used for the momement
only in opt_range.cc when doing ROR scans.
- table->use_all_columns() to install a bitmap where all columns are marked
as use in the read and the write set.
- table->default_column_bitmaps() to install the normal read and write
column bitmaps, but not signaling the handler about this.
This is mainly used when creating TABLE instances.
- table->mark_columns_needed_for_delete(),
table->mark_columns_needed_for_delete() and
table->mark_columns_needed_for_insert() to allow us to put additional
columns in column usage maps if handler so requires.
(The handler indicates what it neads in handler->table_flags())
- table->prepare_for_position() to allow us to tell handler that it
needs to read primary key parts to be able to store them in
future table->position() calls.
(This replaces the table->file->ha_retrieve_all_pk function)
- table->mark_auto_increment_column() to tell handler are going to update
columns part of any auto_increment key.
- table->mark_columns_used_by_index() to mark all columns that is part of
an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow
it to quickly know that it only needs to read colums that are part
of the key. (The handler can also use the column map for detecting this,
but simpler/faster handler can just monitor the extra() call).
- table->mark_columns_used_by_index_no_reset() to in addition to other columns,
also mark all columns that is used by the given key.
- table->restore_column_maps_after_mark_index() to restore to default
column maps after a call to table->mark_columns_used_by_index().
- New item function register_field_in_read_map(), for marking used columns
in table->read_map. Used by filesort() to mark all used columns
- Maintain in TABLE->merge_keys set of all keys that are used in query.
(Simplices some optimization loops)
- Maintain Field->part_of_key_not_clustered which is like Field->part_of_key
but the field in the clustered key is not assumed to be part of all index.
(used in opt_range.cc for faster loops)
- dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map()
tmp_use_all_columns() and tmp_restore_column_map() functions to temporally
mark all columns as usable. The 'dbug_' version is primarily intended
inside a handler when it wants to just call Field:store() & Field::val()
functions, but don't need the column maps set for any other usage.
(ie:: bitmap_is_set() is never called)
- We can't use compare_records() to skip updates for handlers that returns
a partial column set and the read_set doesn't cover all columns in the
write set. The reason for this is that if we have a column marked only for
write we can't in the MySQL level know if the value changed or not.
The reason this worked before was that MySQL marked all to be written
columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden
bug'.
- open_table_from_share() does not anymore setup temporary MEM_ROOT
object as a thread specific variable for the handler. Instead we
send the to-be-used MEMROOT to get_new_handler().
(Simpler, faster code)
Bugs fixed:
- Column marking was not done correctly in a lot of cases.
(ALTER TABLE, when using triggers, auto_increment fields etc)
(Could potentially result in wrong values inserted in table handlers
relying on that the old column maps or field->set_query_id was correct)
Especially when it comes to triggers, there may be cases where the
old code would cause lost/wrong values for NDB and/or InnoDB tables.
- Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags:
OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG.
This allowed me to remove some wrong warnings about:
"Some non-transactional changed tables couldn't be rolled back"
- Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset
(thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose
some warnings about
"Some non-transactional changed tables couldn't be rolled back")
- Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table()
which could cause delete_table to report random failures.
- Fixed core dumps for some tests when running with --debug
- Added missing FN_LIBCHAR in mysql_rm_tmp_tables()
(This has probably caused us to not properly remove temporary files after
crash)
- slow_logs was not properly initialized, which could maybe cause
extra/lost entries in slow log.
- If we get an duplicate row on insert, change column map to read and
write all columns while retrying the operation. This is required by
the definition of REPLACE and also ensures that fields that are only
part of UPDATE are properly handled. This fixed a bug in NDB and
REPLACE where REPLACE wrongly copied some column values from the replaced
row.
- For table handler that doesn't support NULL in keys, we would give an error
when creating a primary key with NULL fields, even after the fields has been
automaticly converted to NOT NULL.
- Creating a primary key on a SPATIAL key, would fail if field was not
declared as NOT NULL.
Cleanups:
- Removed not used condition argument to setup_tables
- Removed not needed item function reset_query_id_processor().
- Field->add_index is removed. Now this is instead maintained in
(field->flags & FIELD_IN_ADD_INDEX)
- Field->fieldnr is removed (use field->field_index instead)
- New argument to filesort() to indicate that it should return a set of
row pointers (not used columns). This allowed me to remove some references
to sql_command in filesort and should also enable us to return column
results in some cases where we couldn't before.
- Changed column bitmap handling in opt_range.cc to be aligned with TABLE
bitmap, which allowed me to use bitmap functions instead of looping over
all fields to create some needed bitmaps. (Faster and smaller code)
- Broke up found too long lines
- Moved some variable declaration at start of function for better code
readability.
- Removed some not used arguments from functions.
(setup_fields(), mysql_prepare_insert_check_table())
- setup_fields() now takes an enum instead of an int for marking columns
usage.
- For internal temporary tables, use handler::write_row(),
handler::delete_row() and handler::update_row() instead of
handler::ha_xxxx() for faster execution.
- Changed some constants to enum's and define's.
- Using separate column read and write sets allows for easier checking
of timestamp field was set by statement.
- Remove calls to free_io_cache() as this is now done automaticly in ha_reset()
- Don't build table->normalized_path as this is now identical to table->path
(after bar's fixes to convert filenames)
- Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to
do comparision with the 'convert-dbug-for-diff' tool.
Things left to do in 5.1:
- We wrongly log failed CREATE TABLE ... SELECT in some cases when using
row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result)
Mats has promised to look into this.
- Test that my fix for CREATE TABLE ... SELECT is indeed correct.
(I added several test cases for this, but in this case it's better that
someone else also tests this throughly).
Lars has promosed to do this.
2006-06-04 17:52:22 +02:00
|
|
|
else if (rights && (error= table->file->ha_write_row(table->record[0])))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2006-07-01 06:01:37 +02:00
|
|
|
if (table->file->is_fatal_error(error, HA_CHECK_DUP_KEY))
|
2000-07-31 21:29:14 +02:00
|
|
|
goto table_error; /* purecov: deadcode */
|
|
|
|
}
|
|
|
|
|
|
|
|
acl_cache->clear(1); // Clear privilege cache
|
2001-08-10 16:37:37 +02:00
|
|
|
if (old_row_exists)
|
2000-07-31 21:29:14 +02:00
|
|
|
acl_update_db(combo.user.str,combo.host.str,db,rights);
|
|
|
|
else
|
2004-11-11 21:59:03 +01:00
|
|
|
if (rights)
|
2000-07-31 21:29:14 +02:00
|
|
|
acl_insert_db(combo.user.str,combo.host.str,db,rights);
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
|
|
|
|
/* This could only happen if the grant tables got corrupted */
|
2003-06-23 19:03:59 +02:00
|
|
|
table_error:
|
2000-07-31 21:29:14 +02:00
|
|
|
table->file->print_error(error,MYF(0)); /* purecov: deadcode */
|
|
|
|
|
2003-06-23 19:03:59 +02:00
|
|
|
abort:
|
2000-07-31 21:29:14 +02:00
|
|
|
DBUG_RETURN(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class GRANT_COLUMN :public Sql_alloc
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
char *column;
|
2002-06-12 14:04:18 +02:00
|
|
|
ulong rights;
|
|
|
|
uint key_length;
|
|
|
|
GRANT_COLUMN(String &c, ulong y) :rights (y)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
column= (char*) memdup_root(&memex,c.ptr(), key_length=c.length());
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2002-06-12 14:04:18 +02:00
|
|
|
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
static uchar* get_key_column(GRANT_COLUMN *buff, size_t *length,
|
2000-07-31 21:29:14 +02:00
|
|
|
my_bool not_used __attribute__((unused)))
|
|
|
|
{
|
|
|
|
*length=buff->key_length;
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
return (uchar*) buff->column;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2002-06-12 14:04:18 +02:00
|
|
|
|
2004-12-23 11:46:24 +01:00
|
|
|
class GRANT_NAME :public Sql_alloc
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
public:
|
2005-03-03 01:30:24 +01:00
|
|
|
acl_host_and_ip host;
|
|
|
|
char *db, *user, *tname, *hash_key;
|
2004-12-23 11:46:24 +01:00
|
|
|
ulong privs;
|
2003-09-02 11:18:13 +02:00
|
|
|
ulong sort;
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
size_t key_length;
|
2004-12-23 11:46:24 +01:00
|
|
|
GRANT_NAME(const char *h, const char *d,const char *u,
|
2009-10-27 09:09:19 +01:00
|
|
|
const char *t, ulong p, bool is_routine);
|
|
|
|
GRANT_NAME (TABLE *form, bool is_routine);
|
2004-12-23 11:46:24 +01:00
|
|
|
virtual ~GRANT_NAME() {};
|
|
|
|
virtual bool ok() { return privs != 0; }
|
2009-10-20 08:17:57 +02:00
|
|
|
void set_user_details(const char *h, const char *d,
|
2009-10-27 09:09:19 +01:00
|
|
|
const char *u, const char *t,
|
|
|
|
bool is_routine);
|
2004-12-23 11:46:24 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class GRANT_TABLE :public GRANT_NAME
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
ulong cols;
|
2000-07-31 21:29:14 +02:00
|
|
|
HASH hash_columns;
|
2004-05-05 16:05:24 +02:00
|
|
|
|
|
|
|
GRANT_TABLE(const char *h, const char *d,const char *u,
|
|
|
|
const char *t, ulong p, ulong c);
|
|
|
|
GRANT_TABLE (TABLE *form, TABLE *col_privs);
|
2004-11-25 21:55:49 +01:00
|
|
|
~GRANT_TABLE();
|
2004-04-28 16:45:08 +02:00
|
|
|
bool ok() { return privs != 0 || cols != 0; }
|
|
|
|
};
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2004-04-28 16:45:08 +02:00
|
|
|
|
2009-10-20 08:17:57 +02:00
|
|
|
void GRANT_NAME::set_user_details(const char *h, const char *d,
|
2009-10-27 09:09:19 +01:00
|
|
|
const char *u, const char *t,
|
|
|
|
bool is_routine)
|
2004-04-28 16:45:08 +02:00
|
|
|
{
|
|
|
|
/* Host given by user */
|
2005-03-03 01:30:24 +01:00
|
|
|
update_hostname(&host, strdup_root(&memex, h));
|
2009-10-20 08:17:57 +02:00
|
|
|
if (db != d)
|
|
|
|
{
|
|
|
|
db= strdup_root(&memex, d);
|
|
|
|
if (lower_case_table_names)
|
|
|
|
my_casedn_str(files_charset_info, db);
|
|
|
|
}
|
2004-04-28 16:45:08 +02:00
|
|
|
user = strdup_root(&memex,u);
|
2005-03-03 01:30:24 +01:00
|
|
|
sort= get_sort(3,host.hostname,db,user);
|
2009-10-20 08:17:57 +02:00
|
|
|
if (tname != t)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2009-10-20 08:17:57 +02:00
|
|
|
tname= strdup_root(&memex, t);
|
2009-10-27 09:09:19 +01:00
|
|
|
if (lower_case_table_names || is_routine)
|
2009-10-20 08:17:57 +02:00
|
|
|
my_casedn_str(files_charset_info, tname);
|
2004-04-28 16:45:08 +02:00
|
|
|
}
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
key_length= strlen(d) + strlen(u)+ strlen(t)+3;
|
|
|
|
hash_key= (char*) alloc_root(&memex,key_length);
|
2004-04-28 16:45:08 +02:00
|
|
|
strmov(strmov(strmov(hash_key,user)+1,db)+1,tname);
|
2004-12-23 11:46:24 +01:00
|
|
|
}
|
|
|
|
|
2009-10-20 08:17:57 +02:00
|
|
|
GRANT_NAME::GRANT_NAME(const char *h, const char *d,const char *u,
|
2009-10-27 09:09:19 +01:00
|
|
|
const char *t, ulong p, bool is_routine)
|
2009-10-20 08:17:57 +02:00
|
|
|
:db(0), tname(0), privs(p)
|
|
|
|
{
|
2009-10-27 09:09:19 +01:00
|
|
|
set_user_details(h, d, u, t, is_routine);
|
2009-10-20 08:17:57 +02:00
|
|
|
}
|
2004-12-23 11:46:24 +01:00
|
|
|
|
|
|
|
GRANT_TABLE::GRANT_TABLE(const char *h, const char *d,const char *u,
|
|
|
|
const char *t, ulong p, ulong c)
|
2009-10-27 09:09:19 +01:00
|
|
|
:GRANT_NAME(h,d,u,t,p, FALSE), cols(c)
|
2004-12-23 11:46:24 +01:00
|
|
|
{
|
2009-10-14 18:37:38 +02:00
|
|
|
(void) my_hash_init2(&hash_columns,4,system_charset_info,
|
|
|
|
0,0,0, (my_hash_get_key) get_key_column,0,0);
|
2004-04-28 16:45:08 +02:00
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2004-04-28 16:45:08 +02:00
|
|
|
|
2009-10-27 09:09:19 +01:00
|
|
|
GRANT_NAME::GRANT_NAME(TABLE *form, bool is_routine)
|
2004-04-28 16:45:08 +02:00
|
|
|
{
|
2005-03-03 01:30:24 +01:00
|
|
|
update_hostname(&host, get_field(&memex, form->field[0]));
|
2004-05-05 16:05:24 +02:00
|
|
|
db= get_field(&memex,form->field[1]);
|
|
|
|
user= get_field(&memex,form->field[2]);
|
2004-04-28 16:45:08 +02:00
|
|
|
if (!user)
|
|
|
|
user= (char*) "";
|
2005-03-03 01:30:24 +01:00
|
|
|
sort= get_sort(3, host.hostname, db, user);
|
2004-05-05 16:05:24 +02:00
|
|
|
tname= get_field(&memex,form->field[3]);
|
2004-04-28 16:45:08 +02:00
|
|
|
if (!db || !tname)
|
|
|
|
{
|
|
|
|
/* Wrong table row; Ignore it */
|
2004-12-23 11:46:24 +01:00
|
|
|
privs= 0;
|
2004-04-28 16:45:08 +02:00
|
|
|
return; /* purecov: inspected */
|
|
|
|
}
|
|
|
|
if (lower_case_table_names)
|
|
|
|
{
|
2004-05-22 21:41:58 +02:00
|
|
|
my_casedn_str(files_charset_info, db);
|
2009-10-27 09:09:19 +01:00
|
|
|
}
|
|
|
|
if (lower_case_table_names || is_routine)
|
|
|
|
{
|
2004-05-22 21:41:58 +02:00
|
|
|
my_casedn_str(files_charset_info, tname);
|
2004-04-28 16:45:08 +02:00
|
|
|
}
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
key_length= (strlen(db) + strlen(user) + strlen(tname) + 3);
|
|
|
|
hash_key= (char*) alloc_root(&memex, key_length);
|
2004-04-28 16:45:08 +02:00
|
|
|
strmov(strmov(strmov(hash_key,user)+1,db)+1,tname);
|
|
|
|
privs = (ulong) form->field[6]->val_int();
|
|
|
|
privs = fix_rights_for_table(privs);
|
2004-12-23 11:46:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs)
|
2009-10-27 09:09:19 +01:00
|
|
|
:GRANT_NAME(form, FALSE)
|
2004-12-23 11:46:24 +01:00
|
|
|
{
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
uchar key[MAX_KEY_LENGTH];
|
2004-12-23 11:46:24 +01:00
|
|
|
|
|
|
|
if (!db || !tname)
|
|
|
|
{
|
|
|
|
/* Wrong table row; Ignore it */
|
2009-10-14 18:37:38 +02:00
|
|
|
my_hash_clear(&hash_columns); /* allow for destruction */
|
2004-12-23 11:46:24 +01:00
|
|
|
cols= 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
cols= (ulong) form->field[7]->val_int();
|
2004-04-28 16:45:08 +02:00
|
|
|
cols = fix_rights_for_column(cols);
|
|
|
|
|
2009-10-14 18:37:38 +02:00
|
|
|
(void) my_hash_init2(&hash_columns,4,system_charset_info,
|
|
|
|
0,0,0, (my_hash_get_key) get_key_column,0,0);
|
2004-04-28 16:45:08 +02:00
|
|
|
if (cols)
|
|
|
|
{
|
2004-12-06 01:00:37 +01:00
|
|
|
uint key_prefix_len;
|
|
|
|
KEY_PART_INFO *key_part= col_privs->key_info->key_part;
|
2005-06-20 19:21:35 +02:00
|
|
|
col_privs->field[0]->store(host.hostname,
|
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes
Changes that requires code changes in other code of other storage engines.
(Note that all changes are very straightforward and one should find all issues
by compiling a --debug build and fixing all compiler errors and all
asserts in field.cc while running the test suite),
- New optional handler function introduced: reset()
This is called after every DML statement to make it easy for a handler to
statement specific cleanups.
(The only case it's not called is if force the file to be closed)
- handler::extra(HA_EXTRA_RESET) is removed. Code that was there before
should be moved to handler::reset()
- table->read_set contains a bitmap over all columns that are needed
in the query. read_row() and similar functions only needs to read these
columns
- table->write_set contains a bitmap over all columns that will be updated
in the query. write_row() and update_row() only needs to update these
columns.
The above bitmaps should now be up to date in all context
(including ALTER TABLE, filesort()).
The handler is informed of any changes to the bitmap after
fix_fields() by calling the virtual function
handler::column_bitmaps_signal(). If the handler does caching of
these bitmaps (instead of using table->read_set, table->write_set),
it should redo the caching in this code. as the signal() may be sent
several times, it's probably best to set a variable in the signal
and redo the caching on read_row() / write_row() if the variable was
set.
- Removed the read_set and write_set bitmap objects from the handler class
- Removed all column bit handling functions from the handler class.
(Now one instead uses the normal bitmap functions in my_bitmap.c instead
of handler dedicated bitmap functions)
- field->query_id is removed. One should instead instead check
table->read_set and table->write_set if a field is used in the query.
- handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and
handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now
instead use table->read_set to check for which columns to retrieve.
- If a handler needs to call Field->val() or Field->store() on columns
that are not used in the query, one should install a temporary
all-columns-used map while doing so. For this, we provide the following
functions:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
field->val();
dbug_tmp_restore_column_map(table->read_set, old_map);
and similar for the write map:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
field->val();
dbug_tmp_restore_column_map(table->write_set, old_map);
If this is not done, you will sooner or later hit a DBUG_ASSERT
in the field store() / val() functions.
(For not DBUG binaries, the dbug_tmp_restore_column_map() and
dbug_tmp_restore_column_map() are inline dummy functions and should
be optimized away be the compiler).
- If one needs to temporary set the column map for all binaries (and not
just to avoid the DBUG_ASSERT() in the Field::store() / Field::val()
methods) one should use the functions tmp_use_all_columns() and
tmp_restore_column_map() instead of the above dbug_ variants.
- All 'status' fields in the handler base class (like records,
data_file_length etc) are now stored in a 'stats' struct. This makes
it easier to know what status variables are provided by the base
handler. This requires some trivial variable names in the extra()
function.
- New virtual function handler::records(). This is called to optimize
COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true.
(stats.records is not supposed to be an exact value. It's only has to
be 'reasonable enough' for the optimizer to be able to choose a good
optimization path).
- Non virtual handler::init() function added for caching of virtual
constants from engine.
- Removed has_transactions() virtual method. Now one should instead return
HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support
transactions.
- The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument
that is to be used with 'new handler_name()' to allocate the handler
in the right area. The xxxx_create_handler() function is also
responsible for any initialization of the object before returning.
For example, one should change:
static handler *myisam_create_handler(TABLE_SHARE *table)
{
return new ha_myisam(table);
}
->
static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisam(table);
}
- New optional virtual function: use_hidden_primary_key().
This is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key. This allows the handler to take precisions
in remembering any hidden primary key to able to update/delete any
found row. The default handler marks all columns to be read.
- handler::table_flags() now returns a ulonglong (to allow for more flags).
- New/changed table_flags()
- HA_HAS_RECORDS Set if ::records() is supported
- HA_NO_TRANSACTIONS Set if engine doesn't support transactions
- HA_PRIMARY_KEY_REQUIRED_FOR_DELETE
Set if we should mark all primary key columns for
read when reading rows as part of a DELETE
statement. If there is no primary key,
all columns are marked for read.
- HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some
cases (based on table->read_set)
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
- HA_DUPP_POS Renamed to HA_DUPLICATE_POS
- HA_REQUIRES_KEY_COLUMNS_FOR_DELETE
Set this if we should mark ALL key columns for
read when when reading rows as part of a DELETE
statement. In case of an update we will mark
all keys for read for which key part changed
value.
- HA_STATS_RECORDS_IS_EXACT
Set this if stats.records is exact.
(This saves us some extra records() calls
when optimizing COUNT(*))
- Removed table_flags()
- HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if
handler::records() gives an exact count() and
HA_STATS_RECORDS_IS_EXACT if stats.records is exact.
- HA_READ_RND_SAME Removed (no one supported this one)
- Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk()
- Renamed handler::dupp_pos to handler::dup_pos
- Removed not used variable handler::sortkey
Upper level handler changes:
- ha_reset() now does some overall checks and calls ::reset()
- ha_table_flags() added. This is a cached version of table_flags(). The
cache is updated on engine creation time and updated on open.
MySQL level changes (not obvious from the above):
- DBUG_ASSERT() added to check that column usage matches what is set
in the column usage bit maps. (This found a LOT of bugs in current
column marking code).
- In 5.1 before, all used columns was marked in read_set and only updated
columns was marked in write_set. Now we only mark columns for which we
need a value in read_set.
- Column bitmaps are created in open_binary_frm() and open_table_from_share().
(Before this was in table.cc)
- handler::table_flags() calls are replaced with handler::ha_table_flags()
- For calling field->val() you must have the corresponding bit set in
table->read_set. For calling field->store() you must have the
corresponding bit set in table->write_set. (There are asserts in
all store()/val() functions to catch wrong usage)
- thd->set_query_id is renamed to thd->mark_used_columns and instead
of setting this to an integer value, this has now the values:
MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE
Changed also all variables named 'set_query_id' to mark_used_columns.
- In filesort() we now inform the handler of exactly which columns are needed
doing the sort and choosing the rows.
- The TABLE_SHARE object has a 'all_set' column bitmap one can use
when one needs a column bitmap with all columns set.
(This is used for table->use_all_columns() and other places)
- The TABLE object has 3 column bitmaps:
- def_read_set Default bitmap for columns to be read
- def_write_set Default bitmap for columns to be written
- tmp_set Can be used as a temporary bitmap when needed.
The table object has also two pointer to bitmaps read_set and write_set
that the handler should use to find out which columns are used in which way.
- count() optimization now calls handler::records() instead of using
handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true).
- Added extra argument to Item::walk() to indicate if we should also
traverse sub queries.
- Added TABLE parameter to cp_buffer_from_ref()
- Don't close tables created with CREATE ... SELECT but keep them in
the table cache. (Faster usage of newly created tables).
New interfaces:
- table->clear_column_bitmaps() to initialize the bitmaps for tables
at start of new statements.
- table->column_bitmaps_set() to set up new column bitmaps and signal
the handler about this.
- table->column_bitmaps_set_no_signal() for some few cases where we need
to setup new column bitmaps but don't signal the handler (as the handler
has already been signaled about these before). Used for the momement
only in opt_range.cc when doing ROR scans.
- table->use_all_columns() to install a bitmap where all columns are marked
as use in the read and the write set.
- table->default_column_bitmaps() to install the normal read and write
column bitmaps, but not signaling the handler about this.
This is mainly used when creating TABLE instances.
- table->mark_columns_needed_for_delete(),
table->mark_columns_needed_for_delete() and
table->mark_columns_needed_for_insert() to allow us to put additional
columns in column usage maps if handler so requires.
(The handler indicates what it neads in handler->table_flags())
- table->prepare_for_position() to allow us to tell handler that it
needs to read primary key parts to be able to store them in
future table->position() calls.
(This replaces the table->file->ha_retrieve_all_pk function)
- table->mark_auto_increment_column() to tell handler are going to update
columns part of any auto_increment key.
- table->mark_columns_used_by_index() to mark all columns that is part of
an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow
it to quickly know that it only needs to read colums that are part
of the key. (The handler can also use the column map for detecting this,
but simpler/faster handler can just monitor the extra() call).
- table->mark_columns_used_by_index_no_reset() to in addition to other columns,
also mark all columns that is used by the given key.
- table->restore_column_maps_after_mark_index() to restore to default
column maps after a call to table->mark_columns_used_by_index().
- New item function register_field_in_read_map(), for marking used columns
in table->read_map. Used by filesort() to mark all used columns
- Maintain in TABLE->merge_keys set of all keys that are used in query.
(Simplices some optimization loops)
- Maintain Field->part_of_key_not_clustered which is like Field->part_of_key
but the field in the clustered key is not assumed to be part of all index.
(used in opt_range.cc for faster loops)
- dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map()
tmp_use_all_columns() and tmp_restore_column_map() functions to temporally
mark all columns as usable. The 'dbug_' version is primarily intended
inside a handler when it wants to just call Field:store() & Field::val()
functions, but don't need the column maps set for any other usage.
(ie:: bitmap_is_set() is never called)
- We can't use compare_records() to skip updates for handlers that returns
a partial column set and the read_set doesn't cover all columns in the
write set. The reason for this is that if we have a column marked only for
write we can't in the MySQL level know if the value changed or not.
The reason this worked before was that MySQL marked all to be written
columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden
bug'.
- open_table_from_share() does not anymore setup temporary MEM_ROOT
object as a thread specific variable for the handler. Instead we
send the to-be-used MEMROOT to get_new_handler().
(Simpler, faster code)
Bugs fixed:
- Column marking was not done correctly in a lot of cases.
(ALTER TABLE, when using triggers, auto_increment fields etc)
(Could potentially result in wrong values inserted in table handlers
relying on that the old column maps or field->set_query_id was correct)
Especially when it comes to triggers, there may be cases where the
old code would cause lost/wrong values for NDB and/or InnoDB tables.
- Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags:
OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG.
This allowed me to remove some wrong warnings about:
"Some non-transactional changed tables couldn't be rolled back"
- Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset
(thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose
some warnings about
"Some non-transactional changed tables couldn't be rolled back")
- Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table()
which could cause delete_table to report random failures.
- Fixed core dumps for some tests when running with --debug
- Added missing FN_LIBCHAR in mysql_rm_tmp_tables()
(This has probably caused us to not properly remove temporary files after
crash)
- slow_logs was not properly initialized, which could maybe cause
extra/lost entries in slow log.
- If we get an duplicate row on insert, change column map to read and
write all columns while retrying the operation. This is required by
the definition of REPLACE and also ensures that fields that are only
part of UPDATE are properly handled. This fixed a bug in NDB and
REPLACE where REPLACE wrongly copied some column values from the replaced
row.
- For table handler that doesn't support NULL in keys, we would give an error
when creating a primary key with NULL fields, even after the fields has been
automaticly converted to NOT NULL.
- Creating a primary key on a SPATIAL key, would fail if field was not
declared as NOT NULL.
Cleanups:
- Removed not used condition argument to setup_tables
- Removed not needed item function reset_query_id_processor().
- Field->add_index is removed. Now this is instead maintained in
(field->flags & FIELD_IN_ADD_INDEX)
- Field->fieldnr is removed (use field->field_index instead)
- New argument to filesort() to indicate that it should return a set of
row pointers (not used columns). This allowed me to remove some references
to sql_command in filesort and should also enable us to return column
results in some cases where we couldn't before.
- Changed column bitmap handling in opt_range.cc to be aligned with TABLE
bitmap, which allowed me to use bitmap functions instead of looping over
all fields to create some needed bitmaps. (Faster and smaller code)
- Broke up found too long lines
- Moved some variable declaration at start of function for better code
readability.
- Removed some not used arguments from functions.
(setup_fields(), mysql_prepare_insert_check_table())
- setup_fields() now takes an enum instead of an int for marking columns
usage.
- For internal temporary tables, use handler::write_row(),
handler::delete_row() and handler::update_row() instead of
handler::ha_xxxx() for faster execution.
- Changed some constants to enum's and define's.
- Using separate column read and write sets allows for easier checking
of timestamp field was set by statement.
- Remove calls to free_io_cache() as this is now done automaticly in ha_reset()
- Don't build table->normalized_path as this is now identical to table->path
(after bar's fixes to convert filenames)
- Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to
do comparision with the 'convert-dbug-for-diff' tool.
Things left to do in 5.1:
- We wrongly log failed CREATE TABLE ... SELECT in some cases when using
row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result)
Mats has promised to look into this.
- Test that my fix for CREATE TABLE ... SELECT is indeed correct.
(I added several test cases for this, but in this case it's better that
someone else also tests this throughly).
Lars has promosed to do this.
2006-06-04 17:52:22 +02:00
|
|
|
host.hostname ? (uint) strlen(host.hostname) :
|
|
|
|
0,
|
2004-11-25 21:55:49 +01:00
|
|
|
system_charset_info);
|
|
|
|
col_privs->field[1]->store(db,(uint) strlen(db), system_charset_info);
|
|
|
|
col_privs->field[2]->store(user,(uint) strlen(user), system_charset_info);
|
|
|
|
col_privs->field[3]->store(tname,(uint) strlen(tname), system_charset_info);
|
2004-12-06 01:00:37 +01:00
|
|
|
|
|
|
|
key_prefix_len= (key_part[0].store_length +
|
|
|
|
key_part[1].store_length +
|
|
|
|
key_part[2].store_length +
|
|
|
|
key_part[3].store_length);
|
|
|
|
key_copy(key, col_privs->record[0], col_privs->key_info, key_prefix_len);
|
2004-05-05 16:05:24 +02:00
|
|
|
col_privs->field[4]->store("",0, &my_charset_latin1);
|
2004-12-06 01:00:37 +01:00
|
|
|
|
2005-07-18 13:31:02 +02:00
|
|
|
col_privs->file->ha_index_init(0, 1);
|
2007-08-13 15:11:25 +02:00
|
|
|
if (col_privs->file->index_read_map(col_privs->record[0], (uchar*) key,
|
|
|
|
(key_part_map)15, HA_READ_KEY_EXACT))
|
2001-12-13 01:31:19 +01:00
|
|
|
{
|
2004-04-28 16:45:08 +02:00
|
|
|
cols = 0; /* purecov: deadcode */
|
2004-07-06 17:30:50 +02:00
|
|
|
col_privs->file->ha_index_end();
|
2004-04-28 16:45:08 +02:00
|
|
|
return;
|
2001-12-13 01:31:19 +01:00
|
|
|
}
|
2004-04-28 16:45:08 +02:00
|
|
|
do
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-04-28 16:45:08 +02:00
|
|
|
String *res,column_name;
|
|
|
|
GRANT_COLUMN *mem_check;
|
|
|
|
/* As column name is a string, we don't have to supply a buffer */
|
2004-05-05 16:05:24 +02:00
|
|
|
res=col_privs->field[4]->val_str(&column_name);
|
2004-04-28 16:45:08 +02:00
|
|
|
ulong priv= (ulong) col_privs->field[6]->val_int();
|
|
|
|
if (!(mem_check = new GRANT_COLUMN(*res,
|
|
|
|
fix_rights_for_column(priv))))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-04-28 16:45:08 +02:00
|
|
|
/* Don't use this entry */
|
|
|
|
privs = cols = 0; /* purecov: deadcode */
|
|
|
|
return; /* purecov: deadcode */
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2009-11-20 16:18:01 +01:00
|
|
|
if (my_hash_insert(&hash_columns, (uchar *) mem_check))
|
|
|
|
{
|
|
|
|
/* Invalidate this entry */
|
|
|
|
privs= cols= 0;
|
|
|
|
return;
|
|
|
|
}
|
2004-04-28 16:45:08 +02:00
|
|
|
} while (!col_privs->file->index_next(col_privs->record[0]) &&
|
2004-12-06 01:00:37 +01:00
|
|
|
!key_cmp_if_same(col_privs,key,0,key_prefix_len));
|
2004-07-06 17:30:50 +02:00
|
|
|
col_privs->file->ha_index_end();
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2004-04-28 16:45:08 +02:00
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2002-06-12 14:04:18 +02:00
|
|
|
|
2004-11-25 21:55:49 +01:00
|
|
|
GRANT_TABLE::~GRANT_TABLE()
|
|
|
|
{
|
2009-10-14 18:37:38 +02:00
|
|
|
my_hash_free(&hash_columns);
|
2004-11-25 21:55:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
static uchar* get_grant_table(GRANT_NAME *buff, size_t *length,
|
2000-07-31 21:29:14 +02:00
|
|
|
my_bool not_used __attribute__((unused)))
|
|
|
|
{
|
|
|
|
*length=buff->key_length;
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
return (uchar*) buff->hash_key;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2002-06-12 14:04:18 +02:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
void free_grant_table(GRANT_TABLE *grant_table)
|
|
|
|
{
|
2009-10-14 18:37:38 +02:00
|
|
|
my_hash_free(&grant_table->hash_columns);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2002-06-12 14:04:18 +02:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
/* Search after a matching grant. Prefer exact grants before not exact ones */
|
|
|
|
|
2004-12-23 11:46:24 +01:00
|
|
|
static GRANT_NAME *name_hash_search(HASH *name_hash,
|
2005-11-23 21:45:02 +01:00
|
|
|
const char *host,const char* ip,
|
|
|
|
const char *db,
|
|
|
|
const char *user, const char *tname,
|
2009-11-27 11:32:15 +01:00
|
|
|
bool exact, bool name_tolower)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2009-11-27 10:59:44 +01:00
|
|
|
char helping [NAME_LEN*2+USERNAME_LENGTH+3], *name_ptr;
|
2000-07-31 21:29:14 +02:00
|
|
|
uint len;
|
2004-12-23 11:46:24 +01:00
|
|
|
GRANT_NAME *grant_name,*found=0;
|
2006-01-04 15:35:30 +01:00
|
|
|
HASH_SEARCH_STATE state;
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2009-11-27 10:59:44 +01:00
|
|
|
name_ptr= strmov(strmov(helping, user) + 1, db) + 1;
|
|
|
|
len = (uint) (strmov(name_ptr, tname) - helping) + 1;
|
|
|
|
if (name_tolower)
|
|
|
|
my_casedn_str(files_charset_info, name_ptr);
|
2009-10-14 18:37:38 +02:00
|
|
|
for (grant_name= (GRANT_NAME*) my_hash_first(name_hash, (uchar*) helping,
|
|
|
|
len, &state);
|
2004-12-23 11:46:24 +01:00
|
|
|
grant_name ;
|
2009-10-14 18:37:38 +02:00
|
|
|
grant_name= (GRANT_NAME*) my_hash_next(name_hash,(uchar*) helping,
|
|
|
|
len, &state))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
if (exact)
|
|
|
|
{
|
2006-06-06 13:21:07 +02:00
|
|
|
if (!grant_name->host.hostname ||
|
|
|
|
(host &&
|
2006-03-06 11:03:40 +01:00
|
|
|
!my_strcasecmp(system_charset_info, host,
|
2006-03-06 11:38:31 +01:00
|
|
|
grant_name->host.hostname)) ||
|
|
|
|
(ip && !strcmp(ip, grant_name->host.hostname)))
|
2004-12-23 11:46:24 +01:00
|
|
|
return grant_name;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-03-04 02:44:28 +01:00
|
|
|
if (compare_hostname(&grant_name->host, host, ip) &&
|
2004-12-23 11:46:24 +01:00
|
|
|
(!found || found->sort < grant_name->sort))
|
|
|
|
found=grant_name; // Host ok
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return found;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-12-23 11:46:24 +01:00
|
|
|
inline GRANT_NAME *
|
2005-05-17 20:54:20 +02:00
|
|
|
routine_hash_search(const char *host, const char *ip, const char *db,
|
|
|
|
const char *user, const char *tname, bool proc, bool exact)
|
2004-12-23 11:46:24 +01:00
|
|
|
{
|
2005-05-17 20:54:20 +02:00
|
|
|
return (GRANT_TABLE*)
|
|
|
|
name_hash_search(proc ? &proc_priv_hash : &func_priv_hash,
|
2009-11-27 10:59:44 +01:00
|
|
|
host, ip, db, user, tname, exact, TRUE);
|
2004-12-23 11:46:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
inline GRANT_TABLE *
|
|
|
|
table_hash_search(const char *host, const char *ip, const char *db,
|
|
|
|
const char *user, const char *tname, bool exact)
|
|
|
|
{
|
|
|
|
return (GRANT_TABLE*) name_hash_search(&column_priv_hash, host, ip, db,
|
2009-11-27 10:59:44 +01:00
|
|
|
user, tname, exact, FALSE);
|
2004-12-23 11:46:24 +01:00
|
|
|
}
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2001-01-25 21:38:26 +01:00
|
|
|
inline GRANT_COLUMN *
|
2002-06-12 14:04:18 +02:00
|
|
|
column_hash_search(GRANT_TABLE *t, const char *cname, uint length)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2009-10-14 18:37:38 +02:00
|
|
|
return (GRANT_COLUMN*) my_hash_search(&t->hash_columns,
|
|
|
|
(uchar*) cname, length);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int replace_column_table(GRANT_TABLE *g_t,
|
|
|
|
TABLE *table, const LEX_USER &combo,
|
|
|
|
List <LEX_COLUMN> &columns,
|
|
|
|
const char *db, const char *table_name,
|
2002-06-12 14:04:18 +02:00
|
|
|
ulong rights, bool revoke_grant)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
int error=0,result=0;
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
uchar key[MAX_KEY_LENGTH];
|
2004-12-06 01:00:37 +01:00
|
|
|
uint key_prefix_length;
|
|
|
|
KEY_PART_INFO *key_part= table->key_info->key_part;
|
2000-07-31 21:29:14 +02:00
|
|
|
DBUG_ENTER("replace_column_table");
|
|
|
|
|
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes
Changes that requires code changes in other code of other storage engines.
(Note that all changes are very straightforward and one should find all issues
by compiling a --debug build and fixing all compiler errors and all
asserts in field.cc while running the test suite),
- New optional handler function introduced: reset()
This is called after every DML statement to make it easy for a handler to
statement specific cleanups.
(The only case it's not called is if force the file to be closed)
- handler::extra(HA_EXTRA_RESET) is removed. Code that was there before
should be moved to handler::reset()
- table->read_set contains a bitmap over all columns that are needed
in the query. read_row() and similar functions only needs to read these
columns
- table->write_set contains a bitmap over all columns that will be updated
in the query. write_row() and update_row() only needs to update these
columns.
The above bitmaps should now be up to date in all context
(including ALTER TABLE, filesort()).
The handler is informed of any changes to the bitmap after
fix_fields() by calling the virtual function
handler::column_bitmaps_signal(). If the handler does caching of
these bitmaps (instead of using table->read_set, table->write_set),
it should redo the caching in this code. as the signal() may be sent
several times, it's probably best to set a variable in the signal
and redo the caching on read_row() / write_row() if the variable was
set.
- Removed the read_set and write_set bitmap objects from the handler class
- Removed all column bit handling functions from the handler class.
(Now one instead uses the normal bitmap functions in my_bitmap.c instead
of handler dedicated bitmap functions)
- field->query_id is removed. One should instead instead check
table->read_set and table->write_set if a field is used in the query.
- handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and
handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now
instead use table->read_set to check for which columns to retrieve.
- If a handler needs to call Field->val() or Field->store() on columns
that are not used in the query, one should install a temporary
all-columns-used map while doing so. For this, we provide the following
functions:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
field->val();
dbug_tmp_restore_column_map(table->read_set, old_map);
and similar for the write map:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
field->val();
dbug_tmp_restore_column_map(table->write_set, old_map);
If this is not done, you will sooner or later hit a DBUG_ASSERT
in the field store() / val() functions.
(For not DBUG binaries, the dbug_tmp_restore_column_map() and
dbug_tmp_restore_column_map() are inline dummy functions and should
be optimized away be the compiler).
- If one needs to temporary set the column map for all binaries (and not
just to avoid the DBUG_ASSERT() in the Field::store() / Field::val()
methods) one should use the functions tmp_use_all_columns() and
tmp_restore_column_map() instead of the above dbug_ variants.
- All 'status' fields in the handler base class (like records,
data_file_length etc) are now stored in a 'stats' struct. This makes
it easier to know what status variables are provided by the base
handler. This requires some trivial variable names in the extra()
function.
- New virtual function handler::records(). This is called to optimize
COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true.
(stats.records is not supposed to be an exact value. It's only has to
be 'reasonable enough' for the optimizer to be able to choose a good
optimization path).
- Non virtual handler::init() function added for caching of virtual
constants from engine.
- Removed has_transactions() virtual method. Now one should instead return
HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support
transactions.
- The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument
that is to be used with 'new handler_name()' to allocate the handler
in the right area. The xxxx_create_handler() function is also
responsible for any initialization of the object before returning.
For example, one should change:
static handler *myisam_create_handler(TABLE_SHARE *table)
{
return new ha_myisam(table);
}
->
static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisam(table);
}
- New optional virtual function: use_hidden_primary_key().
This is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key. This allows the handler to take precisions
in remembering any hidden primary key to able to update/delete any
found row. The default handler marks all columns to be read.
- handler::table_flags() now returns a ulonglong (to allow for more flags).
- New/changed table_flags()
- HA_HAS_RECORDS Set if ::records() is supported
- HA_NO_TRANSACTIONS Set if engine doesn't support transactions
- HA_PRIMARY_KEY_REQUIRED_FOR_DELETE
Set if we should mark all primary key columns for
read when reading rows as part of a DELETE
statement. If there is no primary key,
all columns are marked for read.
- HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some
cases (based on table->read_set)
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
- HA_DUPP_POS Renamed to HA_DUPLICATE_POS
- HA_REQUIRES_KEY_COLUMNS_FOR_DELETE
Set this if we should mark ALL key columns for
read when when reading rows as part of a DELETE
statement. In case of an update we will mark
all keys for read for which key part changed
value.
- HA_STATS_RECORDS_IS_EXACT
Set this if stats.records is exact.
(This saves us some extra records() calls
when optimizing COUNT(*))
- Removed table_flags()
- HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if
handler::records() gives an exact count() and
HA_STATS_RECORDS_IS_EXACT if stats.records is exact.
- HA_READ_RND_SAME Removed (no one supported this one)
- Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk()
- Renamed handler::dupp_pos to handler::dup_pos
- Removed not used variable handler::sortkey
Upper level handler changes:
- ha_reset() now does some overall checks and calls ::reset()
- ha_table_flags() added. This is a cached version of table_flags(). The
cache is updated on engine creation time and updated on open.
MySQL level changes (not obvious from the above):
- DBUG_ASSERT() added to check that column usage matches what is set
in the column usage bit maps. (This found a LOT of bugs in current
column marking code).
- In 5.1 before, all used columns was marked in read_set and only updated
columns was marked in write_set. Now we only mark columns for which we
need a value in read_set.
- Column bitmaps are created in open_binary_frm() and open_table_from_share().
(Before this was in table.cc)
- handler::table_flags() calls are replaced with handler::ha_table_flags()
- For calling field->val() you must have the corresponding bit set in
table->read_set. For calling field->store() you must have the
corresponding bit set in table->write_set. (There are asserts in
all store()/val() functions to catch wrong usage)
- thd->set_query_id is renamed to thd->mark_used_columns and instead
of setting this to an integer value, this has now the values:
MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE
Changed also all variables named 'set_query_id' to mark_used_columns.
- In filesort() we now inform the handler of exactly which columns are needed
doing the sort and choosing the rows.
- The TABLE_SHARE object has a 'all_set' column bitmap one can use
when one needs a column bitmap with all columns set.
(This is used for table->use_all_columns() and other places)
- The TABLE object has 3 column bitmaps:
- def_read_set Default bitmap for columns to be read
- def_write_set Default bitmap for columns to be written
- tmp_set Can be used as a temporary bitmap when needed.
The table object has also two pointer to bitmaps read_set and write_set
that the handler should use to find out which columns are used in which way.
- count() optimization now calls handler::records() instead of using
handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true).
- Added extra argument to Item::walk() to indicate if we should also
traverse sub queries.
- Added TABLE parameter to cp_buffer_from_ref()
- Don't close tables created with CREATE ... SELECT but keep them in
the table cache. (Faster usage of newly created tables).
New interfaces:
- table->clear_column_bitmaps() to initialize the bitmaps for tables
at start of new statements.
- table->column_bitmaps_set() to set up new column bitmaps and signal
the handler about this.
- table->column_bitmaps_set_no_signal() for some few cases where we need
to setup new column bitmaps but don't signal the handler (as the handler
has already been signaled about these before). Used for the momement
only in opt_range.cc when doing ROR scans.
- table->use_all_columns() to install a bitmap where all columns are marked
as use in the read and the write set.
- table->default_column_bitmaps() to install the normal read and write
column bitmaps, but not signaling the handler about this.
This is mainly used when creating TABLE instances.
- table->mark_columns_needed_for_delete(),
table->mark_columns_needed_for_delete() and
table->mark_columns_needed_for_insert() to allow us to put additional
columns in column usage maps if handler so requires.
(The handler indicates what it neads in handler->table_flags())
- table->prepare_for_position() to allow us to tell handler that it
needs to read primary key parts to be able to store them in
future table->position() calls.
(This replaces the table->file->ha_retrieve_all_pk function)
- table->mark_auto_increment_column() to tell handler are going to update
columns part of any auto_increment key.
- table->mark_columns_used_by_index() to mark all columns that is part of
an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow
it to quickly know that it only needs to read colums that are part
of the key. (The handler can also use the column map for detecting this,
but simpler/faster handler can just monitor the extra() call).
- table->mark_columns_used_by_index_no_reset() to in addition to other columns,
also mark all columns that is used by the given key.
- table->restore_column_maps_after_mark_index() to restore to default
column maps after a call to table->mark_columns_used_by_index().
- New item function register_field_in_read_map(), for marking used columns
in table->read_map. Used by filesort() to mark all used columns
- Maintain in TABLE->merge_keys set of all keys that are used in query.
(Simplices some optimization loops)
- Maintain Field->part_of_key_not_clustered which is like Field->part_of_key
but the field in the clustered key is not assumed to be part of all index.
(used in opt_range.cc for faster loops)
- dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map()
tmp_use_all_columns() and tmp_restore_column_map() functions to temporally
mark all columns as usable. The 'dbug_' version is primarily intended
inside a handler when it wants to just call Field:store() & Field::val()
functions, but don't need the column maps set for any other usage.
(ie:: bitmap_is_set() is never called)
- We can't use compare_records() to skip updates for handlers that returns
a partial column set and the read_set doesn't cover all columns in the
write set. The reason for this is that if we have a column marked only for
write we can't in the MySQL level know if the value changed or not.
The reason this worked before was that MySQL marked all to be written
columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden
bug'.
- open_table_from_share() does not anymore setup temporary MEM_ROOT
object as a thread specific variable for the handler. Instead we
send the to-be-used MEMROOT to get_new_handler().
(Simpler, faster code)
Bugs fixed:
- Column marking was not done correctly in a lot of cases.
(ALTER TABLE, when using triggers, auto_increment fields etc)
(Could potentially result in wrong values inserted in table handlers
relying on that the old column maps or field->set_query_id was correct)
Especially when it comes to triggers, there may be cases where the
old code would cause lost/wrong values for NDB and/or InnoDB tables.
- Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags:
OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG.
This allowed me to remove some wrong warnings about:
"Some non-transactional changed tables couldn't be rolled back"
- Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset
(thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose
some warnings about
"Some non-transactional changed tables couldn't be rolled back")
- Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table()
which could cause delete_table to report random failures.
- Fixed core dumps for some tests when running with --debug
- Added missing FN_LIBCHAR in mysql_rm_tmp_tables()
(This has probably caused us to not properly remove temporary files after
crash)
- slow_logs was not properly initialized, which could maybe cause
extra/lost entries in slow log.
- If we get an duplicate row on insert, change column map to read and
write all columns while retrying the operation. This is required by
the definition of REPLACE and also ensures that fields that are only
part of UPDATE are properly handled. This fixed a bug in NDB and
REPLACE where REPLACE wrongly copied some column values from the replaced
row.
- For table handler that doesn't support NULL in keys, we would give an error
when creating a primary key with NULL fields, even after the fields has been
automaticly converted to NOT NULL.
- Creating a primary key on a SPATIAL key, would fail if field was not
declared as NOT NULL.
Cleanups:
- Removed not used condition argument to setup_tables
- Removed not needed item function reset_query_id_processor().
- Field->add_index is removed. Now this is instead maintained in
(field->flags & FIELD_IN_ADD_INDEX)
- Field->fieldnr is removed (use field->field_index instead)
- New argument to filesort() to indicate that it should return a set of
row pointers (not used columns). This allowed me to remove some references
to sql_command in filesort and should also enable us to return column
results in some cases where we couldn't before.
- Changed column bitmap handling in opt_range.cc to be aligned with TABLE
bitmap, which allowed me to use bitmap functions instead of looping over
all fields to create some needed bitmaps. (Faster and smaller code)
- Broke up found too long lines
- Moved some variable declaration at start of function for better code
readability.
- Removed some not used arguments from functions.
(setup_fields(), mysql_prepare_insert_check_table())
- setup_fields() now takes an enum instead of an int for marking columns
usage.
- For internal temporary tables, use handler::write_row(),
handler::delete_row() and handler::update_row() instead of
handler::ha_xxxx() for faster execution.
- Changed some constants to enum's and define's.
- Using separate column read and write sets allows for easier checking
of timestamp field was set by statement.
- Remove calls to free_io_cache() as this is now done automaticly in ha_reset()
- Don't build table->normalized_path as this is now identical to table->path
(after bar's fixes to convert filenames)
- Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to
do comparision with the 'convert-dbug-for-diff' tool.
Things left to do in 5.1:
- We wrongly log failed CREATE TABLE ... SELECT in some cases when using
row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result)
Mats has promised to look into this.
- Test that my fix for CREATE TABLE ... SELECT is indeed correct.
(I added several test cases for this, but in this case it's better that
someone else also tests this throughly).
Lars has promosed to do this.
2006-06-04 17:52:22 +02:00
|
|
|
table->use_all_columns();
|
2005-05-06 10:39:30 +02:00
|
|
|
table->field[0]->store(combo.host.str,combo.host.length,
|
|
|
|
system_charset_info);
|
|
|
|
table->field[1]->store(db,(uint) strlen(db),
|
|
|
|
system_charset_info);
|
|
|
|
table->field[2]->store(combo.user.str,combo.user.length,
|
|
|
|
system_charset_info);
|
|
|
|
table->field[3]->store(table_name,(uint) strlen(table_name),
|
|
|
|
system_charset_info);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2007-01-29 10:40:26 +01:00
|
|
|
/* Get length of 4 first key parts */
|
2004-12-06 01:00:37 +01:00
|
|
|
key_prefix_length= (key_part[0].store_length + key_part[1].store_length +
|
|
|
|
key_part[2].store_length + key_part[3].store_length);
|
|
|
|
key_copy(key, table->record[0], table->key_info, key_prefix_length);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2004-12-06 01:00:37 +01:00
|
|
|
rights&= COL_ACLS; // Only ACL for columns
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
/* first fix privileges for all columns in column list */
|
|
|
|
|
|
|
|
List_iterator <LEX_COLUMN> iter(columns);
|
2005-05-06 10:39:30 +02:00
|
|
|
class LEX_COLUMN *column;
|
2005-07-18 13:31:02 +02:00
|
|
|
table->file->ha_index_init(0, 1);
|
2005-05-06 10:39:30 +02:00
|
|
|
while ((column= iter++))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2005-05-06 10:39:30 +02:00
|
|
|
ulong privileges= column->rights;
|
2001-08-10 16:37:37 +02:00
|
|
|
bool old_row_exists=0;
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
uchar user_key[MAX_KEY_LENGTH];
|
2004-12-06 01:00:37 +01:00
|
|
|
|
|
|
|
key_restore(table->record[0],key,table->key_info,
|
|
|
|
key_prefix_length);
|
2005-05-06 10:39:30 +02:00
|
|
|
table->field[4]->store(column->column.ptr(), column->column.length(),
|
2004-11-25 21:55:49 +01:00
|
|
|
system_charset_info);
|
2004-12-06 01:00:37 +01:00
|
|
|
/* Get key for the first 4 columns */
|
|
|
|
key_copy(user_key, table->record[0], table->key_info,
|
|
|
|
table->key_info->key_length);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2007-08-13 15:11:25 +02:00
|
|
|
if (table->file->index_read_map(table->record[0], user_key, HA_WHOLE_KEY,
|
|
|
|
HA_READ_KEY_EXACT))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
if (revoke_grant)
|
|
|
|
{
|
2004-02-21 15:15:26 +01:00
|
|
|
my_error(ER_NONEXISTING_TABLE_GRANT, MYF(0),
|
2004-11-13 18:35:51 +01:00
|
|
|
combo.user.str, combo.host.str,
|
2005-05-06 10:39:30 +02:00
|
|
|
table_name); /* purecov: inspected */
|
|
|
|
result= -1; /* purecov: inspected */
|
|
|
|
continue; /* purecov: inspected */
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2001-08-10 16:37:37 +02:00
|
|
|
old_row_exists = 0;
|
2005-01-06 12:00:13 +01:00
|
|
|
restore_record(table, s->default_values); // Get empty record
|
2004-12-06 01:00:37 +01:00
|
|
|
key_restore(table->record[0],key,table->key_info,
|
|
|
|
key_prefix_length);
|
2005-05-06 10:39:30 +02:00
|
|
|
table->field[4]->store(column->column.ptr(),column->column.length(),
|
2004-11-25 21:55:49 +01:00
|
|
|
system_charset_info);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2002-06-12 14:04:18 +02:00
|
|
|
ulong tmp= (ulong) table->field[6]->val_int();
|
2000-07-31 21:29:14 +02:00
|
|
|
tmp=fix_rights_for_column(tmp);
|
|
|
|
|
|
|
|
if (revoke_grant)
|
|
|
|
privileges = tmp & ~(privileges | rights);
|
|
|
|
else
|
|
|
|
privileges |= tmp;
|
2001-08-10 16:37:37 +02:00
|
|
|
old_row_exists = 1;
|
2003-05-03 01:16:56 +02:00
|
|
|
store_record(table,record[1]); // copy original row
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2005-09-14 00:41:44 +02:00
|
|
|
table->field[6]->store((longlong) get_rights_for_column(privileges), TRUE);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2001-08-10 16:37:37 +02:00
|
|
|
if (old_row_exists)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2005-05-06 10:39:30 +02:00
|
|
|
GRANT_COLUMN *grant_column;
|
2000-07-31 21:29:14 +02:00
|
|
|
if (privileges)
|
2005-12-22 06:39:02 +01:00
|
|
|
error=table->file->ha_update_row(table->record[1],table->record[0]);
|
2000-07-31 21:29:14 +02:00
|
|
|
else
|
2005-12-22 06:39:02 +01:00
|
|
|
error=table->file->ha_delete_row(table->record[1]);
|
2007-06-28 15:07:55 +02:00
|
|
|
if (error && error != HA_ERR_RECORD_IS_THE_SAME)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
table->file->print_error(error,MYF(0)); /* purecov: inspected */
|
|
|
|
result= -1; /* purecov: inspected */
|
|
|
|
goto end; /* purecov: inspected */
|
|
|
|
}
|
2007-06-28 15:07:55 +02:00
|
|
|
else
|
|
|
|
error= 0;
|
2005-05-06 10:39:30 +02:00
|
|
|
grant_column= column_hash_search(g_t, column->column.ptr(),
|
|
|
|
column->column.length());
|
2000-07-31 21:29:14 +02:00
|
|
|
if (grant_column) // Should always be true
|
2005-05-06 10:39:30 +02:00
|
|
|
grant_column->rights= privileges; // Update hash
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
else // new grant
|
|
|
|
{
|
2005-05-06 10:39:30 +02:00
|
|
|
GRANT_COLUMN *grant_column;
|
2005-12-22 06:39:02 +01:00
|
|
|
if ((error=table->file->ha_write_row(table->record[0])))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
table->file->print_error(error,MYF(0)); /* purecov: inspected */
|
|
|
|
result= -1; /* purecov: inspected */
|
|
|
|
goto end; /* purecov: inspected */
|
|
|
|
}
|
2005-05-06 10:39:30 +02:00
|
|
|
grant_column= new GRANT_COLUMN(column->column,privileges);
|
2009-11-20 16:18:01 +01:00
|
|
|
if (my_hash_insert(&g_t->hash_columns,(uchar*) grant_column))
|
|
|
|
{
|
|
|
|
result= -1;
|
|
|
|
goto end;
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
If revoke of privileges on the table level, remove all such privileges
|
|
|
|
for all columns
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (revoke_grant)
|
|
|
|
{
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
uchar user_key[MAX_KEY_LENGTH];
|
2004-12-06 01:00:37 +01:00
|
|
|
key_copy(user_key, table->record[0], table->key_info,
|
2004-12-06 18:18:35 +01:00
|
|
|
key_prefix_length);
|
|
|
|
|
2007-08-13 15:11:25 +02:00
|
|
|
if (table->file->index_read_map(table->record[0], user_key,
|
|
|
|
(key_part_map)15,
|
|
|
|
HA_READ_KEY_EXACT))
|
2000-07-31 21:29:14 +02:00
|
|
|
goto end;
|
|
|
|
|
2003-06-23 19:03:59 +02:00
|
|
|
/* Scan through all rows with the same host,db,user and table */
|
2000-07-31 21:29:14 +02:00
|
|
|
do
|
|
|
|
{
|
2002-06-12 14:04:18 +02:00
|
|
|
ulong privileges = (ulong) table->field[6]->val_int();
|
2000-07-31 21:29:14 +02:00
|
|
|
privileges=fix_rights_for_column(privileges);
|
2003-05-03 01:16:56 +02:00
|
|
|
store_record(table,record[1]);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
if (privileges & rights) // is in this record the priv to be revoked ??
|
|
|
|
{
|
|
|
|
GRANT_COLUMN *grant_column = NULL;
|
|
|
|
char colum_name_buf[HOSTNAME_LENGTH+1];
|
2004-12-06 01:00:37 +01:00
|
|
|
String column_name(colum_name_buf,sizeof(colum_name_buf),
|
2004-12-06 18:18:35 +01:00
|
|
|
system_charset_info);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
privileges&= ~rights;
|
|
|
|
table->field[6]->store((longlong)
|
2005-09-14 00:41:44 +02:00
|
|
|
get_rights_for_column(privileges), TRUE);
|
2004-04-06 21:35:26 +02:00
|
|
|
table->field[4]->val_str(&column_name);
|
2000-07-31 21:29:14 +02:00
|
|
|
grant_column = column_hash_search(g_t,
|
|
|
|
column_name.ptr(),
|
|
|
|
column_name.length());
|
|
|
|
if (privileges)
|
|
|
|
{
|
|
|
|
int tmp_error;
|
2005-12-22 06:39:02 +01:00
|
|
|
if ((tmp_error=table->file->ha_update_row(table->record[1],
|
2007-06-28 15:07:55 +02:00
|
|
|
table->record[0])) &&
|
|
|
|
tmp_error != HA_ERR_RECORD_IS_THE_SAME)
|
2000-07-31 21:29:14 +02:00
|
|
|
{ /* purecov: deadcode */
|
|
|
|
table->file->print_error(tmp_error,MYF(0)); /* purecov: deadcode */
|
|
|
|
result= -1; /* purecov: deadcode */
|
|
|
|
goto end; /* purecov: deadcode */
|
|
|
|
}
|
|
|
|
if (grant_column)
|
|
|
|
grant_column->rights = privileges; // Update hash
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int tmp_error;
|
2005-12-22 06:39:02 +01:00
|
|
|
if ((tmp_error = table->file->ha_delete_row(table->record[1])))
|
2000-07-31 21:29:14 +02:00
|
|
|
{ /* purecov: deadcode */
|
|
|
|
table->file->print_error(tmp_error,MYF(0)); /* purecov: deadcode */
|
|
|
|
result= -1; /* purecov: deadcode */
|
|
|
|
goto end; /* purecov: deadcode */
|
|
|
|
}
|
|
|
|
if (grant_column)
|
2009-10-14 18:37:38 +02:00
|
|
|
my_hash_delete(&g_t->hash_columns,(uchar*) grant_column);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} while (!table->file->index_next(table->record[0]) &&
|
2004-12-06 01:00:37 +01:00
|
|
|
!key_cmp_if_same(table, key, 0, key_prefix_length));
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2003-06-23 19:03:59 +02:00
|
|
|
end:
|
2004-06-23 12:29:05 +02:00
|
|
|
table->file->ha_index_end();
|
2000-07-31 21:29:14 +02:00
|
|
|
DBUG_RETURN(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
|
|
|
|
TABLE *table, const LEX_USER &combo,
|
|
|
|
const char *db, const char *table_name,
|
2002-06-12 14:04:18 +02:00
|
|
|
ulong rights, ulong col_rights,
|
|
|
|
bool revoke_grant)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2006-01-11 00:07:40 +01:00
|
|
|
char grantor[USER_HOST_BUFF_SIZE];
|
2001-08-10 16:37:37 +02:00
|
|
|
int old_row_exists = 1;
|
2000-07-31 21:29:14 +02:00
|
|
|
int error=0;
|
2002-06-12 14:04:18 +02:00
|
|
|
ulong store_table_rights, store_col_rights;
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
uchar user_key[MAX_KEY_LENGTH];
|
2000-07-31 21:29:14 +02:00
|
|
|
DBUG_ENTER("replace_table_table");
|
|
|
|
|
2005-09-15 21:29:07 +02:00
|
|
|
strxmov(grantor, thd->security_ctx->user, "@",
|
|
|
|
thd->security_ctx->host_or_ip, NullS);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2002-06-12 14:04:18 +02:00
|
|
|
/*
|
|
|
|
The following should always succeed as new users are created before
|
|
|
|
this function is called!
|
|
|
|
*/
|
2005-08-23 00:48:50 +02:00
|
|
|
if (!find_acl_user(combo.host.str,combo.user.str, FALSE))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-11-12 13:34:00 +01:00
|
|
|
my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH),
|
|
|
|
MYF(0)); /* purecov: deadcode */
|
2000-07-31 21:29:14 +02:00
|
|
|
DBUG_RETURN(-1); /* purecov: deadcode */
|
|
|
|
}
|
|
|
|
|
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes
Changes that requires code changes in other code of other storage engines.
(Note that all changes are very straightforward and one should find all issues
by compiling a --debug build and fixing all compiler errors and all
asserts in field.cc while running the test suite),
- New optional handler function introduced: reset()
This is called after every DML statement to make it easy for a handler to
statement specific cleanups.
(The only case it's not called is if force the file to be closed)
- handler::extra(HA_EXTRA_RESET) is removed. Code that was there before
should be moved to handler::reset()
- table->read_set contains a bitmap over all columns that are needed
in the query. read_row() and similar functions only needs to read these
columns
- table->write_set contains a bitmap over all columns that will be updated
in the query. write_row() and update_row() only needs to update these
columns.
The above bitmaps should now be up to date in all context
(including ALTER TABLE, filesort()).
The handler is informed of any changes to the bitmap after
fix_fields() by calling the virtual function
handler::column_bitmaps_signal(). If the handler does caching of
these bitmaps (instead of using table->read_set, table->write_set),
it should redo the caching in this code. as the signal() may be sent
several times, it's probably best to set a variable in the signal
and redo the caching on read_row() / write_row() if the variable was
set.
- Removed the read_set and write_set bitmap objects from the handler class
- Removed all column bit handling functions from the handler class.
(Now one instead uses the normal bitmap functions in my_bitmap.c instead
of handler dedicated bitmap functions)
- field->query_id is removed. One should instead instead check
table->read_set and table->write_set if a field is used in the query.
- handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and
handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now
instead use table->read_set to check for which columns to retrieve.
- If a handler needs to call Field->val() or Field->store() on columns
that are not used in the query, one should install a temporary
all-columns-used map while doing so. For this, we provide the following
functions:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
field->val();
dbug_tmp_restore_column_map(table->read_set, old_map);
and similar for the write map:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
field->val();
dbug_tmp_restore_column_map(table->write_set, old_map);
If this is not done, you will sooner or later hit a DBUG_ASSERT
in the field store() / val() functions.
(For not DBUG binaries, the dbug_tmp_restore_column_map() and
dbug_tmp_restore_column_map() are inline dummy functions and should
be optimized away be the compiler).
- If one needs to temporary set the column map for all binaries (and not
just to avoid the DBUG_ASSERT() in the Field::store() / Field::val()
methods) one should use the functions tmp_use_all_columns() and
tmp_restore_column_map() instead of the above dbug_ variants.
- All 'status' fields in the handler base class (like records,
data_file_length etc) are now stored in a 'stats' struct. This makes
it easier to know what status variables are provided by the base
handler. This requires some trivial variable names in the extra()
function.
- New virtual function handler::records(). This is called to optimize
COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true.
(stats.records is not supposed to be an exact value. It's only has to
be 'reasonable enough' for the optimizer to be able to choose a good
optimization path).
- Non virtual handler::init() function added for caching of virtual
constants from engine.
- Removed has_transactions() virtual method. Now one should instead return
HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support
transactions.
- The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument
that is to be used with 'new handler_name()' to allocate the handler
in the right area. The xxxx_create_handler() function is also
responsible for any initialization of the object before returning.
For example, one should change:
static handler *myisam_create_handler(TABLE_SHARE *table)
{
return new ha_myisam(table);
}
->
static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisam(table);
}
- New optional virtual function: use_hidden_primary_key().
This is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key. This allows the handler to take precisions
in remembering any hidden primary key to able to update/delete any
found row. The default handler marks all columns to be read.
- handler::table_flags() now returns a ulonglong (to allow for more flags).
- New/changed table_flags()
- HA_HAS_RECORDS Set if ::records() is supported
- HA_NO_TRANSACTIONS Set if engine doesn't support transactions
- HA_PRIMARY_KEY_REQUIRED_FOR_DELETE
Set if we should mark all primary key columns for
read when reading rows as part of a DELETE
statement. If there is no primary key,
all columns are marked for read.
- HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some
cases (based on table->read_set)
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
- HA_DUPP_POS Renamed to HA_DUPLICATE_POS
- HA_REQUIRES_KEY_COLUMNS_FOR_DELETE
Set this if we should mark ALL key columns for
read when when reading rows as part of a DELETE
statement. In case of an update we will mark
all keys for read for which key part changed
value.
- HA_STATS_RECORDS_IS_EXACT
Set this if stats.records is exact.
(This saves us some extra records() calls
when optimizing COUNT(*))
- Removed table_flags()
- HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if
handler::records() gives an exact count() and
HA_STATS_RECORDS_IS_EXACT if stats.records is exact.
- HA_READ_RND_SAME Removed (no one supported this one)
- Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk()
- Renamed handler::dupp_pos to handler::dup_pos
- Removed not used variable handler::sortkey
Upper level handler changes:
- ha_reset() now does some overall checks and calls ::reset()
- ha_table_flags() added. This is a cached version of table_flags(). The
cache is updated on engine creation time and updated on open.
MySQL level changes (not obvious from the above):
- DBUG_ASSERT() added to check that column usage matches what is set
in the column usage bit maps. (This found a LOT of bugs in current
column marking code).
- In 5.1 before, all used columns was marked in read_set and only updated
columns was marked in write_set. Now we only mark columns for which we
need a value in read_set.
- Column bitmaps are created in open_binary_frm() and open_table_from_share().
(Before this was in table.cc)
- handler::table_flags() calls are replaced with handler::ha_table_flags()
- For calling field->val() you must have the corresponding bit set in
table->read_set. For calling field->store() you must have the
corresponding bit set in table->write_set. (There are asserts in
all store()/val() functions to catch wrong usage)
- thd->set_query_id is renamed to thd->mark_used_columns and instead
of setting this to an integer value, this has now the values:
MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE
Changed also all variables named 'set_query_id' to mark_used_columns.
- In filesort() we now inform the handler of exactly which columns are needed
doing the sort and choosing the rows.
- The TABLE_SHARE object has a 'all_set' column bitmap one can use
when one needs a column bitmap with all columns set.
(This is used for table->use_all_columns() and other places)
- The TABLE object has 3 column bitmaps:
- def_read_set Default bitmap for columns to be read
- def_write_set Default bitmap for columns to be written
- tmp_set Can be used as a temporary bitmap when needed.
The table object has also two pointer to bitmaps read_set and write_set
that the handler should use to find out which columns are used in which way.
- count() optimization now calls handler::records() instead of using
handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true).
- Added extra argument to Item::walk() to indicate if we should also
traverse sub queries.
- Added TABLE parameter to cp_buffer_from_ref()
- Don't close tables created with CREATE ... SELECT but keep them in
the table cache. (Faster usage of newly created tables).
New interfaces:
- table->clear_column_bitmaps() to initialize the bitmaps for tables
at start of new statements.
- table->column_bitmaps_set() to set up new column bitmaps and signal
the handler about this.
- table->column_bitmaps_set_no_signal() for some few cases where we need
to setup new column bitmaps but don't signal the handler (as the handler
has already been signaled about these before). Used for the momement
only in opt_range.cc when doing ROR scans.
- table->use_all_columns() to install a bitmap where all columns are marked
as use in the read and the write set.
- table->default_column_bitmaps() to install the normal read and write
column bitmaps, but not signaling the handler about this.
This is mainly used when creating TABLE instances.
- table->mark_columns_needed_for_delete(),
table->mark_columns_needed_for_delete() and
table->mark_columns_needed_for_insert() to allow us to put additional
columns in column usage maps if handler so requires.
(The handler indicates what it neads in handler->table_flags())
- table->prepare_for_position() to allow us to tell handler that it
needs to read primary key parts to be able to store them in
future table->position() calls.
(This replaces the table->file->ha_retrieve_all_pk function)
- table->mark_auto_increment_column() to tell handler are going to update
columns part of any auto_increment key.
- table->mark_columns_used_by_index() to mark all columns that is part of
an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow
it to quickly know that it only needs to read colums that are part
of the key. (The handler can also use the column map for detecting this,
but simpler/faster handler can just monitor the extra() call).
- table->mark_columns_used_by_index_no_reset() to in addition to other columns,
also mark all columns that is used by the given key.
- table->restore_column_maps_after_mark_index() to restore to default
column maps after a call to table->mark_columns_used_by_index().
- New item function register_field_in_read_map(), for marking used columns
in table->read_map. Used by filesort() to mark all used columns
- Maintain in TABLE->merge_keys set of all keys that are used in query.
(Simplices some optimization loops)
- Maintain Field->part_of_key_not_clustered which is like Field->part_of_key
but the field in the clustered key is not assumed to be part of all index.
(used in opt_range.cc for faster loops)
- dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map()
tmp_use_all_columns() and tmp_restore_column_map() functions to temporally
mark all columns as usable. The 'dbug_' version is primarily intended
inside a handler when it wants to just call Field:store() & Field::val()
functions, but don't need the column maps set for any other usage.
(ie:: bitmap_is_set() is never called)
- We can't use compare_records() to skip updates for handlers that returns
a partial column set and the read_set doesn't cover all columns in the
write set. The reason for this is that if we have a column marked only for
write we can't in the MySQL level know if the value changed or not.
The reason this worked before was that MySQL marked all to be written
columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden
bug'.
- open_table_from_share() does not anymore setup temporary MEM_ROOT
object as a thread specific variable for the handler. Instead we
send the to-be-used MEMROOT to get_new_handler().
(Simpler, faster code)
Bugs fixed:
- Column marking was not done correctly in a lot of cases.
(ALTER TABLE, when using triggers, auto_increment fields etc)
(Could potentially result in wrong values inserted in table handlers
relying on that the old column maps or field->set_query_id was correct)
Especially when it comes to triggers, there may be cases where the
old code would cause lost/wrong values for NDB and/or InnoDB tables.
- Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags:
OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG.
This allowed me to remove some wrong warnings about:
"Some non-transactional changed tables couldn't be rolled back"
- Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset
(thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose
some warnings about
"Some non-transactional changed tables couldn't be rolled back")
- Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table()
which could cause delete_table to report random failures.
- Fixed core dumps for some tests when running with --debug
- Added missing FN_LIBCHAR in mysql_rm_tmp_tables()
(This has probably caused us to not properly remove temporary files after
crash)
- slow_logs was not properly initialized, which could maybe cause
extra/lost entries in slow log.
- If we get an duplicate row on insert, change column map to read and
write all columns while retrying the operation. This is required by
the definition of REPLACE and also ensures that fields that are only
part of UPDATE are properly handled. This fixed a bug in NDB and
REPLACE where REPLACE wrongly copied some column values from the replaced
row.
- For table handler that doesn't support NULL in keys, we would give an error
when creating a primary key with NULL fields, even after the fields has been
automaticly converted to NOT NULL.
- Creating a primary key on a SPATIAL key, would fail if field was not
declared as NOT NULL.
Cleanups:
- Removed not used condition argument to setup_tables
- Removed not needed item function reset_query_id_processor().
- Field->add_index is removed. Now this is instead maintained in
(field->flags & FIELD_IN_ADD_INDEX)
- Field->fieldnr is removed (use field->field_index instead)
- New argument to filesort() to indicate that it should return a set of
row pointers (not used columns). This allowed me to remove some references
to sql_command in filesort and should also enable us to return column
results in some cases where we couldn't before.
- Changed column bitmap handling in opt_range.cc to be aligned with TABLE
bitmap, which allowed me to use bitmap functions instead of looping over
all fields to create some needed bitmaps. (Faster and smaller code)
- Broke up found too long lines
- Moved some variable declaration at start of function for better code
readability.
- Removed some not used arguments from functions.
(setup_fields(), mysql_prepare_insert_check_table())
- setup_fields() now takes an enum instead of an int for marking columns
usage.
- For internal temporary tables, use handler::write_row(),
handler::delete_row() and handler::update_row() instead of
handler::ha_xxxx() for faster execution.
- Changed some constants to enum's and define's.
- Using separate column read and write sets allows for easier checking
of timestamp field was set by statement.
- Remove calls to free_io_cache() as this is now done automaticly in ha_reset()
- Don't build table->normalized_path as this is now identical to table->path
(after bar's fixes to convert filenames)
- Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to
do comparision with the 'convert-dbug-for-diff' tool.
Things left to do in 5.1:
- We wrongly log failed CREATE TABLE ... SELECT in some cases when using
row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result)
Mats has promised to look into this.
- Test that my fix for CREATE TABLE ... SELECT is indeed correct.
(I added several test cases for this, but in this case it's better that
someone else also tests this throughly).
Lars has promosed to do this.
2006-06-04 17:52:22 +02:00
|
|
|
table->use_all_columns();
|
2005-01-06 12:00:13 +01:00
|
|
|
restore_record(table, s->default_values); // Get empty record
|
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes
Changes that requires code changes in other code of other storage engines.
(Note that all changes are very straightforward and one should find all issues
by compiling a --debug build and fixing all compiler errors and all
asserts in field.cc while running the test suite),
- New optional handler function introduced: reset()
This is called after every DML statement to make it easy for a handler to
statement specific cleanups.
(The only case it's not called is if force the file to be closed)
- handler::extra(HA_EXTRA_RESET) is removed. Code that was there before
should be moved to handler::reset()
- table->read_set contains a bitmap over all columns that are needed
in the query. read_row() and similar functions only needs to read these
columns
- table->write_set contains a bitmap over all columns that will be updated
in the query. write_row() and update_row() only needs to update these
columns.
The above bitmaps should now be up to date in all context
(including ALTER TABLE, filesort()).
The handler is informed of any changes to the bitmap after
fix_fields() by calling the virtual function
handler::column_bitmaps_signal(). If the handler does caching of
these bitmaps (instead of using table->read_set, table->write_set),
it should redo the caching in this code. as the signal() may be sent
several times, it's probably best to set a variable in the signal
and redo the caching on read_row() / write_row() if the variable was
set.
- Removed the read_set and write_set bitmap objects from the handler class
- Removed all column bit handling functions from the handler class.
(Now one instead uses the normal bitmap functions in my_bitmap.c instead
of handler dedicated bitmap functions)
- field->query_id is removed. One should instead instead check
table->read_set and table->write_set if a field is used in the query.
- handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and
handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now
instead use table->read_set to check for which columns to retrieve.
- If a handler needs to call Field->val() or Field->store() on columns
that are not used in the query, one should install a temporary
all-columns-used map while doing so. For this, we provide the following
functions:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
field->val();
dbug_tmp_restore_column_map(table->read_set, old_map);
and similar for the write map:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
field->val();
dbug_tmp_restore_column_map(table->write_set, old_map);
If this is not done, you will sooner or later hit a DBUG_ASSERT
in the field store() / val() functions.
(For not DBUG binaries, the dbug_tmp_restore_column_map() and
dbug_tmp_restore_column_map() are inline dummy functions and should
be optimized away be the compiler).
- If one needs to temporary set the column map for all binaries (and not
just to avoid the DBUG_ASSERT() in the Field::store() / Field::val()
methods) one should use the functions tmp_use_all_columns() and
tmp_restore_column_map() instead of the above dbug_ variants.
- All 'status' fields in the handler base class (like records,
data_file_length etc) are now stored in a 'stats' struct. This makes
it easier to know what status variables are provided by the base
handler. This requires some trivial variable names in the extra()
function.
- New virtual function handler::records(). This is called to optimize
COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true.
(stats.records is not supposed to be an exact value. It's only has to
be 'reasonable enough' for the optimizer to be able to choose a good
optimization path).
- Non virtual handler::init() function added for caching of virtual
constants from engine.
- Removed has_transactions() virtual method. Now one should instead return
HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support
transactions.
- The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument
that is to be used with 'new handler_name()' to allocate the handler
in the right area. The xxxx_create_handler() function is also
responsible for any initialization of the object before returning.
For example, one should change:
static handler *myisam_create_handler(TABLE_SHARE *table)
{
return new ha_myisam(table);
}
->
static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisam(table);
}
- New optional virtual function: use_hidden_primary_key().
This is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key. This allows the handler to take precisions
in remembering any hidden primary key to able to update/delete any
found row. The default handler marks all columns to be read.
- handler::table_flags() now returns a ulonglong (to allow for more flags).
- New/changed table_flags()
- HA_HAS_RECORDS Set if ::records() is supported
- HA_NO_TRANSACTIONS Set if engine doesn't support transactions
- HA_PRIMARY_KEY_REQUIRED_FOR_DELETE
Set if we should mark all primary key columns for
read when reading rows as part of a DELETE
statement. If there is no primary key,
all columns are marked for read.
- HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some
cases (based on table->read_set)
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
- HA_DUPP_POS Renamed to HA_DUPLICATE_POS
- HA_REQUIRES_KEY_COLUMNS_FOR_DELETE
Set this if we should mark ALL key columns for
read when when reading rows as part of a DELETE
statement. In case of an update we will mark
all keys for read for which key part changed
value.
- HA_STATS_RECORDS_IS_EXACT
Set this if stats.records is exact.
(This saves us some extra records() calls
when optimizing COUNT(*))
- Removed table_flags()
- HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if
handler::records() gives an exact count() and
HA_STATS_RECORDS_IS_EXACT if stats.records is exact.
- HA_READ_RND_SAME Removed (no one supported this one)
- Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk()
- Renamed handler::dupp_pos to handler::dup_pos
- Removed not used variable handler::sortkey
Upper level handler changes:
- ha_reset() now does some overall checks and calls ::reset()
- ha_table_flags() added. This is a cached version of table_flags(). The
cache is updated on engine creation time and updated on open.
MySQL level changes (not obvious from the above):
- DBUG_ASSERT() added to check that column usage matches what is set
in the column usage bit maps. (This found a LOT of bugs in current
column marking code).
- In 5.1 before, all used columns was marked in read_set and only updated
columns was marked in write_set. Now we only mark columns for which we
need a value in read_set.
- Column bitmaps are created in open_binary_frm() and open_table_from_share().
(Before this was in table.cc)
- handler::table_flags() calls are replaced with handler::ha_table_flags()
- For calling field->val() you must have the corresponding bit set in
table->read_set. For calling field->store() you must have the
corresponding bit set in table->write_set. (There are asserts in
all store()/val() functions to catch wrong usage)
- thd->set_query_id is renamed to thd->mark_used_columns and instead
of setting this to an integer value, this has now the values:
MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE
Changed also all variables named 'set_query_id' to mark_used_columns.
- In filesort() we now inform the handler of exactly which columns are needed
doing the sort and choosing the rows.
- The TABLE_SHARE object has a 'all_set' column bitmap one can use
when one needs a column bitmap with all columns set.
(This is used for table->use_all_columns() and other places)
- The TABLE object has 3 column bitmaps:
- def_read_set Default bitmap for columns to be read
- def_write_set Default bitmap for columns to be written
- tmp_set Can be used as a temporary bitmap when needed.
The table object has also two pointer to bitmaps read_set and write_set
that the handler should use to find out which columns are used in which way.
- count() optimization now calls handler::records() instead of using
handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true).
- Added extra argument to Item::walk() to indicate if we should also
traverse sub queries.
- Added TABLE parameter to cp_buffer_from_ref()
- Don't close tables created with CREATE ... SELECT but keep them in
the table cache. (Faster usage of newly created tables).
New interfaces:
- table->clear_column_bitmaps() to initialize the bitmaps for tables
at start of new statements.
- table->column_bitmaps_set() to set up new column bitmaps and signal
the handler about this.
- table->column_bitmaps_set_no_signal() for some few cases where we need
to setup new column bitmaps but don't signal the handler (as the handler
has already been signaled about these before). Used for the momement
only in opt_range.cc when doing ROR scans.
- table->use_all_columns() to install a bitmap where all columns are marked
as use in the read and the write set.
- table->default_column_bitmaps() to install the normal read and write
column bitmaps, but not signaling the handler about this.
This is mainly used when creating TABLE instances.
- table->mark_columns_needed_for_delete(),
table->mark_columns_needed_for_delete() and
table->mark_columns_needed_for_insert() to allow us to put additional
columns in column usage maps if handler so requires.
(The handler indicates what it neads in handler->table_flags())
- table->prepare_for_position() to allow us to tell handler that it
needs to read primary key parts to be able to store them in
future table->position() calls.
(This replaces the table->file->ha_retrieve_all_pk function)
- table->mark_auto_increment_column() to tell handler are going to update
columns part of any auto_increment key.
- table->mark_columns_used_by_index() to mark all columns that is part of
an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow
it to quickly know that it only needs to read colums that are part
of the key. (The handler can also use the column map for detecting this,
but simpler/faster handler can just monitor the extra() call).
- table->mark_columns_used_by_index_no_reset() to in addition to other columns,
also mark all columns that is used by the given key.
- table->restore_column_maps_after_mark_index() to restore to default
column maps after a call to table->mark_columns_used_by_index().
- New item function register_field_in_read_map(), for marking used columns
in table->read_map. Used by filesort() to mark all used columns
- Maintain in TABLE->merge_keys set of all keys that are used in query.
(Simplices some optimization loops)
- Maintain Field->part_of_key_not_clustered which is like Field->part_of_key
but the field in the clustered key is not assumed to be part of all index.
(used in opt_range.cc for faster loops)
- dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map()
tmp_use_all_columns() and tmp_restore_column_map() functions to temporally
mark all columns as usable. The 'dbug_' version is primarily intended
inside a handler when it wants to just call Field:store() & Field::val()
functions, but don't need the column maps set for any other usage.
(ie:: bitmap_is_set() is never called)
- We can't use compare_records() to skip updates for handlers that returns
a partial column set and the read_set doesn't cover all columns in the
write set. The reason for this is that if we have a column marked only for
write we can't in the MySQL level know if the value changed or not.
The reason this worked before was that MySQL marked all to be written
columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden
bug'.
- open_table_from_share() does not anymore setup temporary MEM_ROOT
object as a thread specific variable for the handler. Instead we
send the to-be-used MEMROOT to get_new_handler().
(Simpler, faster code)
Bugs fixed:
- Column marking was not done correctly in a lot of cases.
(ALTER TABLE, when using triggers, auto_increment fields etc)
(Could potentially result in wrong values inserted in table handlers
relying on that the old column maps or field->set_query_id was correct)
Especially when it comes to triggers, there may be cases where the
old code would cause lost/wrong values for NDB and/or InnoDB tables.
- Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags:
OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG.
This allowed me to remove some wrong warnings about:
"Some non-transactional changed tables couldn't be rolled back"
- Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset
(thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose
some warnings about
"Some non-transactional changed tables couldn't be rolled back")
- Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table()
which could cause delete_table to report random failures.
- Fixed core dumps for some tests when running with --debug
- Added missing FN_LIBCHAR in mysql_rm_tmp_tables()
(This has probably caused us to not properly remove temporary files after
crash)
- slow_logs was not properly initialized, which could maybe cause
extra/lost entries in slow log.
- If we get an duplicate row on insert, change column map to read and
write all columns while retrying the operation. This is required by
the definition of REPLACE and also ensures that fields that are only
part of UPDATE are properly handled. This fixed a bug in NDB and
REPLACE where REPLACE wrongly copied some column values from the replaced
row.
- For table handler that doesn't support NULL in keys, we would give an error
when creating a primary key with NULL fields, even after the fields has been
automaticly converted to NOT NULL.
- Creating a primary key on a SPATIAL key, would fail if field was not
declared as NOT NULL.
Cleanups:
- Removed not used condition argument to setup_tables
- Removed not needed item function reset_query_id_processor().
- Field->add_index is removed. Now this is instead maintained in
(field->flags & FIELD_IN_ADD_INDEX)
- Field->fieldnr is removed (use field->field_index instead)
- New argument to filesort() to indicate that it should return a set of
row pointers (not used columns). This allowed me to remove some references
to sql_command in filesort and should also enable us to return column
results in some cases where we couldn't before.
- Changed column bitmap handling in opt_range.cc to be aligned with TABLE
bitmap, which allowed me to use bitmap functions instead of looping over
all fields to create some needed bitmaps. (Faster and smaller code)
- Broke up found too long lines
- Moved some variable declaration at start of function for better code
readability.
- Removed some not used arguments from functions.
(setup_fields(), mysql_prepare_insert_check_table())
- setup_fields() now takes an enum instead of an int for marking columns
usage.
- For internal temporary tables, use handler::write_row(),
handler::delete_row() and handler::update_row() instead of
handler::ha_xxxx() for faster execution.
- Changed some constants to enum's and define's.
- Using separate column read and write sets allows for easier checking
of timestamp field was set by statement.
- Remove calls to free_io_cache() as this is now done automaticly in ha_reset()
- Don't build table->normalized_path as this is now identical to table->path
(after bar's fixes to convert filenames)
- Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to
do comparision with the 'convert-dbug-for-diff' tool.
Things left to do in 5.1:
- We wrongly log failed CREATE TABLE ... SELECT in some cases when using
row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result)
Mats has promised to look into this.
- Test that my fix for CREATE TABLE ... SELECT is indeed correct.
(I added several test cases for this, but in this case it's better that
someone else also tests this throughly).
Lars has promosed to do this.
2006-06-04 17:52:22 +02:00
|
|
|
table->field[0]->store(combo.host.str,combo.host.length,
|
|
|
|
system_charset_info);
|
2004-11-25 21:55:49 +01:00
|
|
|
table->field[1]->store(db,(uint) strlen(db), system_charset_info);
|
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes
Changes that requires code changes in other code of other storage engines.
(Note that all changes are very straightforward and one should find all issues
by compiling a --debug build and fixing all compiler errors and all
asserts in field.cc while running the test suite),
- New optional handler function introduced: reset()
This is called after every DML statement to make it easy for a handler to
statement specific cleanups.
(The only case it's not called is if force the file to be closed)
- handler::extra(HA_EXTRA_RESET) is removed. Code that was there before
should be moved to handler::reset()
- table->read_set contains a bitmap over all columns that are needed
in the query. read_row() and similar functions only needs to read these
columns
- table->write_set contains a bitmap over all columns that will be updated
in the query. write_row() and update_row() only needs to update these
columns.
The above bitmaps should now be up to date in all context
(including ALTER TABLE, filesort()).
The handler is informed of any changes to the bitmap after
fix_fields() by calling the virtual function
handler::column_bitmaps_signal(). If the handler does caching of
these bitmaps (instead of using table->read_set, table->write_set),
it should redo the caching in this code. as the signal() may be sent
several times, it's probably best to set a variable in the signal
and redo the caching on read_row() / write_row() if the variable was
set.
- Removed the read_set and write_set bitmap objects from the handler class
- Removed all column bit handling functions from the handler class.
(Now one instead uses the normal bitmap functions in my_bitmap.c instead
of handler dedicated bitmap functions)
- field->query_id is removed. One should instead instead check
table->read_set and table->write_set if a field is used in the query.
- handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and
handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now
instead use table->read_set to check for which columns to retrieve.
- If a handler needs to call Field->val() or Field->store() on columns
that are not used in the query, one should install a temporary
all-columns-used map while doing so. For this, we provide the following
functions:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
field->val();
dbug_tmp_restore_column_map(table->read_set, old_map);
and similar for the write map:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
field->val();
dbug_tmp_restore_column_map(table->write_set, old_map);
If this is not done, you will sooner or later hit a DBUG_ASSERT
in the field store() / val() functions.
(For not DBUG binaries, the dbug_tmp_restore_column_map() and
dbug_tmp_restore_column_map() are inline dummy functions and should
be optimized away be the compiler).
- If one needs to temporary set the column map for all binaries (and not
just to avoid the DBUG_ASSERT() in the Field::store() / Field::val()
methods) one should use the functions tmp_use_all_columns() and
tmp_restore_column_map() instead of the above dbug_ variants.
- All 'status' fields in the handler base class (like records,
data_file_length etc) are now stored in a 'stats' struct. This makes
it easier to know what status variables are provided by the base
handler. This requires some trivial variable names in the extra()
function.
- New virtual function handler::records(). This is called to optimize
COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true.
(stats.records is not supposed to be an exact value. It's only has to
be 'reasonable enough' for the optimizer to be able to choose a good
optimization path).
- Non virtual handler::init() function added for caching of virtual
constants from engine.
- Removed has_transactions() virtual method. Now one should instead return
HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support
transactions.
- The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument
that is to be used with 'new handler_name()' to allocate the handler
in the right area. The xxxx_create_handler() function is also
responsible for any initialization of the object before returning.
For example, one should change:
static handler *myisam_create_handler(TABLE_SHARE *table)
{
return new ha_myisam(table);
}
->
static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisam(table);
}
- New optional virtual function: use_hidden_primary_key().
This is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key. This allows the handler to take precisions
in remembering any hidden primary key to able to update/delete any
found row. The default handler marks all columns to be read.
- handler::table_flags() now returns a ulonglong (to allow for more flags).
- New/changed table_flags()
- HA_HAS_RECORDS Set if ::records() is supported
- HA_NO_TRANSACTIONS Set if engine doesn't support transactions
- HA_PRIMARY_KEY_REQUIRED_FOR_DELETE
Set if we should mark all primary key columns for
read when reading rows as part of a DELETE
statement. If there is no primary key,
all columns are marked for read.
- HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some
cases (based on table->read_set)
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
- HA_DUPP_POS Renamed to HA_DUPLICATE_POS
- HA_REQUIRES_KEY_COLUMNS_FOR_DELETE
Set this if we should mark ALL key columns for
read when when reading rows as part of a DELETE
statement. In case of an update we will mark
all keys for read for which key part changed
value.
- HA_STATS_RECORDS_IS_EXACT
Set this if stats.records is exact.
(This saves us some extra records() calls
when optimizing COUNT(*))
- Removed table_flags()
- HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if
handler::records() gives an exact count() and
HA_STATS_RECORDS_IS_EXACT if stats.records is exact.
- HA_READ_RND_SAME Removed (no one supported this one)
- Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk()
- Renamed handler::dupp_pos to handler::dup_pos
- Removed not used variable handler::sortkey
Upper level handler changes:
- ha_reset() now does some overall checks and calls ::reset()
- ha_table_flags() added. This is a cached version of table_flags(). The
cache is updated on engine creation time and updated on open.
MySQL level changes (not obvious from the above):
- DBUG_ASSERT() added to check that column usage matches what is set
in the column usage bit maps. (This found a LOT of bugs in current
column marking code).
- In 5.1 before, all used columns was marked in read_set and only updated
columns was marked in write_set. Now we only mark columns for which we
need a value in read_set.
- Column bitmaps are created in open_binary_frm() and open_table_from_share().
(Before this was in table.cc)
- handler::table_flags() calls are replaced with handler::ha_table_flags()
- For calling field->val() you must have the corresponding bit set in
table->read_set. For calling field->store() you must have the
corresponding bit set in table->write_set. (There are asserts in
all store()/val() functions to catch wrong usage)
- thd->set_query_id is renamed to thd->mark_used_columns and instead
of setting this to an integer value, this has now the values:
MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE
Changed also all variables named 'set_query_id' to mark_used_columns.
- In filesort() we now inform the handler of exactly which columns are needed
doing the sort and choosing the rows.
- The TABLE_SHARE object has a 'all_set' column bitmap one can use
when one needs a column bitmap with all columns set.
(This is used for table->use_all_columns() and other places)
- The TABLE object has 3 column bitmaps:
- def_read_set Default bitmap for columns to be read
- def_write_set Default bitmap for columns to be written
- tmp_set Can be used as a temporary bitmap when needed.
The table object has also two pointer to bitmaps read_set and write_set
that the handler should use to find out which columns are used in which way.
- count() optimization now calls handler::records() instead of using
handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true).
- Added extra argument to Item::walk() to indicate if we should also
traverse sub queries.
- Added TABLE parameter to cp_buffer_from_ref()
- Don't close tables created with CREATE ... SELECT but keep them in
the table cache. (Faster usage of newly created tables).
New interfaces:
- table->clear_column_bitmaps() to initialize the bitmaps for tables
at start of new statements.
- table->column_bitmaps_set() to set up new column bitmaps and signal
the handler about this.
- table->column_bitmaps_set_no_signal() for some few cases where we need
to setup new column bitmaps but don't signal the handler (as the handler
has already been signaled about these before). Used for the momement
only in opt_range.cc when doing ROR scans.
- table->use_all_columns() to install a bitmap where all columns are marked
as use in the read and the write set.
- table->default_column_bitmaps() to install the normal read and write
column bitmaps, but not signaling the handler about this.
This is mainly used when creating TABLE instances.
- table->mark_columns_needed_for_delete(),
table->mark_columns_needed_for_delete() and
table->mark_columns_needed_for_insert() to allow us to put additional
columns in column usage maps if handler so requires.
(The handler indicates what it neads in handler->table_flags())
- table->prepare_for_position() to allow us to tell handler that it
needs to read primary key parts to be able to store them in
future table->position() calls.
(This replaces the table->file->ha_retrieve_all_pk function)
- table->mark_auto_increment_column() to tell handler are going to update
columns part of any auto_increment key.
- table->mark_columns_used_by_index() to mark all columns that is part of
an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow
it to quickly know that it only needs to read colums that are part
of the key. (The handler can also use the column map for detecting this,
but simpler/faster handler can just monitor the extra() call).
- table->mark_columns_used_by_index_no_reset() to in addition to other columns,
also mark all columns that is used by the given key.
- table->restore_column_maps_after_mark_index() to restore to default
column maps after a call to table->mark_columns_used_by_index().
- New item function register_field_in_read_map(), for marking used columns
in table->read_map. Used by filesort() to mark all used columns
- Maintain in TABLE->merge_keys set of all keys that are used in query.
(Simplices some optimization loops)
- Maintain Field->part_of_key_not_clustered which is like Field->part_of_key
but the field in the clustered key is not assumed to be part of all index.
(used in opt_range.cc for faster loops)
- dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map()
tmp_use_all_columns() and tmp_restore_column_map() functions to temporally
mark all columns as usable. The 'dbug_' version is primarily intended
inside a handler when it wants to just call Field:store() & Field::val()
functions, but don't need the column maps set for any other usage.
(ie:: bitmap_is_set() is never called)
- We can't use compare_records() to skip updates for handlers that returns
a partial column set and the read_set doesn't cover all columns in the
write set. The reason for this is that if we have a column marked only for
write we can't in the MySQL level know if the value changed or not.
The reason this worked before was that MySQL marked all to be written
columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden
bug'.
- open_table_from_share() does not anymore setup temporary MEM_ROOT
object as a thread specific variable for the handler. Instead we
send the to-be-used MEMROOT to get_new_handler().
(Simpler, faster code)
Bugs fixed:
- Column marking was not done correctly in a lot of cases.
(ALTER TABLE, when using triggers, auto_increment fields etc)
(Could potentially result in wrong values inserted in table handlers
relying on that the old column maps or field->set_query_id was correct)
Especially when it comes to triggers, there may be cases where the
old code would cause lost/wrong values for NDB and/or InnoDB tables.
- Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags:
OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG.
This allowed me to remove some wrong warnings about:
"Some non-transactional changed tables couldn't be rolled back"
- Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset
(thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose
some warnings about
"Some non-transactional changed tables couldn't be rolled back")
- Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table()
which could cause delete_table to report random failures.
- Fixed core dumps for some tests when running with --debug
- Added missing FN_LIBCHAR in mysql_rm_tmp_tables()
(This has probably caused us to not properly remove temporary files after
crash)
- slow_logs was not properly initialized, which could maybe cause
extra/lost entries in slow log.
- If we get an duplicate row on insert, change column map to read and
write all columns while retrying the operation. This is required by
the definition of REPLACE and also ensures that fields that are only
part of UPDATE are properly handled. This fixed a bug in NDB and
REPLACE where REPLACE wrongly copied some column values from the replaced
row.
- For table handler that doesn't support NULL in keys, we would give an error
when creating a primary key with NULL fields, even after the fields has been
automaticly converted to NOT NULL.
- Creating a primary key on a SPATIAL key, would fail if field was not
declared as NOT NULL.
Cleanups:
- Removed not used condition argument to setup_tables
- Removed not needed item function reset_query_id_processor().
- Field->add_index is removed. Now this is instead maintained in
(field->flags & FIELD_IN_ADD_INDEX)
- Field->fieldnr is removed (use field->field_index instead)
- New argument to filesort() to indicate that it should return a set of
row pointers (not used columns). This allowed me to remove some references
to sql_command in filesort and should also enable us to return column
results in some cases where we couldn't before.
- Changed column bitmap handling in opt_range.cc to be aligned with TABLE
bitmap, which allowed me to use bitmap functions instead of looping over
all fields to create some needed bitmaps. (Faster and smaller code)
- Broke up found too long lines
- Moved some variable declaration at start of function for better code
readability.
- Removed some not used arguments from functions.
(setup_fields(), mysql_prepare_insert_check_table())
- setup_fields() now takes an enum instead of an int for marking columns
usage.
- For internal temporary tables, use handler::write_row(),
handler::delete_row() and handler::update_row() instead of
handler::ha_xxxx() for faster execution.
- Changed some constants to enum's and define's.
- Using separate column read and write sets allows for easier checking
of timestamp field was set by statement.
- Remove calls to free_io_cache() as this is now done automaticly in ha_reset()
- Don't build table->normalized_path as this is now identical to table->path
(after bar's fixes to convert filenames)
- Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to
do comparision with the 'convert-dbug-for-diff' tool.
Things left to do in 5.1:
- We wrongly log failed CREATE TABLE ... SELECT in some cases when using
row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result)
Mats has promised to look into this.
- Test that my fix for CREATE TABLE ... SELECT is indeed correct.
(I added several test cases for this, but in this case it's better that
someone else also tests this throughly).
Lars has promosed to do this.
2006-06-04 17:52:22 +02:00
|
|
|
table->field[2]->store(combo.user.str,combo.user.length,
|
|
|
|
system_charset_info);
|
|
|
|
table->field[3]->store(table_name,(uint) strlen(table_name),
|
|
|
|
system_charset_info);
|
2003-05-03 01:16:56 +02:00
|
|
|
store_record(table,record[1]); // store at pos 1
|
2004-12-06 01:00:37 +01:00
|
|
|
key_copy(user_key, table->record[0], table->key_info,
|
|
|
|
table->key_info->key_length);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2007-08-13 15:11:25 +02:00
|
|
|
if (table->file->index_read_idx_map(table->record[0], 0, user_key,
|
|
|
|
HA_WHOLE_KEY,
|
|
|
|
HA_READ_KEY_EXACT))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
The following should never happen as we first check the in memory
|
|
|
|
grant tables for the user. There is however always a small change that
|
|
|
|
the user has modified the grant tables directly.
|
|
|
|
*/
|
|
|
|
if (revoke_grant)
|
|
|
|
{ // no row, no revoke
|
2004-02-21 15:15:26 +01:00
|
|
|
my_error(ER_NONEXISTING_TABLE_GRANT, MYF(0),
|
|
|
|
combo.user.str, combo.host.str,
|
2004-11-13 18:35:51 +01:00
|
|
|
table_name); /* purecov: deadcode */
|
2000-07-31 21:29:14 +02:00
|
|
|
DBUG_RETURN(-1); /* purecov: deadcode */
|
|
|
|
}
|
2001-08-10 16:37:37 +02:00
|
|
|
old_row_exists = 0;
|
2003-05-03 01:16:56 +02:00
|
|
|
restore_record(table,record[1]); // Get saved record
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2002-06-12 14:04:18 +02:00
|
|
|
store_table_rights= get_rights_for_table(rights);
|
|
|
|
store_col_rights= get_rights_for_column(col_rights);
|
2001-08-10 16:37:37 +02:00
|
|
|
if (old_row_exists)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2002-06-12 14:04:18 +02:00
|
|
|
ulong j,k;
|
2003-05-03 01:16:56 +02:00
|
|
|
store_record(table,record[1]);
|
2002-06-12 14:04:18 +02:00
|
|
|
j = (ulong) table->field[6]->val_int();
|
|
|
|
k = (ulong) table->field[7]->val_int();
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
if (revoke_grant)
|
|
|
|
{
|
2003-06-23 19:03:59 +02:00
|
|
|
/* column rights are already fixed in mysql_table_grant */
|
2000-07-31 21:29:14 +02:00
|
|
|
store_table_rights=j & ~store_table_rights;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2002-06-12 14:04:18 +02:00
|
|
|
store_table_rights|= j;
|
|
|
|
store_col_rights|= k;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-11-25 21:55:49 +01:00
|
|
|
table->field[4]->store(grantor,(uint) strlen(grantor), system_charset_info);
|
2005-09-14 00:41:44 +02:00
|
|
|
table->field[6]->store((longlong) store_table_rights, TRUE);
|
|
|
|
table->field[7]->store((longlong) store_col_rights, TRUE);
|
2000-07-31 21:29:14 +02:00
|
|
|
rights=fix_rights_for_table(store_table_rights);
|
2002-06-12 14:04:18 +02:00
|
|
|
col_rights=fix_rights_for_column(store_col_rights);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2001-08-10 16:37:37 +02:00
|
|
|
if (old_row_exists)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
if (store_table_rights || store_col_rights)
|
|
|
|
{
|
2007-06-28 15:07:55 +02:00
|
|
|
if ((error=table->file->ha_update_row(table->record[1],
|
|
|
|
table->record[0])) &&
|
|
|
|
error != HA_ERR_RECORD_IS_THE_SAME)
|
2000-07-31 21:29:14 +02:00
|
|
|
goto table_error; /* purecov: deadcode */
|
|
|
|
}
|
2005-12-22 06:39:02 +01:00
|
|
|
else if ((error = table->file->ha_delete_row(table->record[1])))
|
2000-07-31 21:29:14 +02:00
|
|
|
goto table_error; /* purecov: deadcode */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-12-22 06:39:02 +01:00
|
|
|
error=table->file->ha_write_row(table->record[0]);
|
2006-07-01 06:01:37 +02:00
|
|
|
if (table->file->is_fatal_error(error, HA_CHECK_DUP_KEY))
|
2000-07-31 21:29:14 +02:00
|
|
|
goto table_error; /* purecov: deadcode */
|
|
|
|
}
|
|
|
|
|
2002-06-12 14:04:18 +02:00
|
|
|
if (rights | col_rights)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2002-06-12 14:04:18 +02:00
|
|
|
grant_table->privs= rights;
|
2003-06-23 19:03:59 +02:00
|
|
|
grant_table->cols= col_rights;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-10-14 18:37:38 +02:00
|
|
|
my_hash_delete(&column_priv_hash,(uchar*) grant_table);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
|
2003-06-23 19:03:59 +02:00
|
|
|
/* This should never happen */
|
|
|
|
table_error:
|
2000-07-31 21:29:14 +02:00
|
|
|
table->file->print_error(error,MYF(0)); /* purecov: deadcode */
|
|
|
|
DBUG_RETURN(-1); /* purecov: deadcode */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-03-05 15:33:32 +01:00
|
|
|
/**
|
|
|
|
@retval 0 success
|
|
|
|
@retval -1 error
|
|
|
|
*/
|
2005-05-17 20:54:20 +02:00
|
|
|
static int replace_routine_table(THD *thd, GRANT_NAME *grant_name,
|
2004-12-23 11:46:24 +01:00
|
|
|
TABLE *table, const LEX_USER &combo,
|
2005-05-17 20:54:20 +02:00
|
|
|
const char *db, const char *routine_name,
|
|
|
|
bool is_proc, ulong rights, bool revoke_grant)
|
2004-12-23 11:46:24 +01:00
|
|
|
{
|
2006-01-11 00:07:40 +01:00
|
|
|
char grantor[USER_HOST_BUFF_SIZE];
|
2004-12-23 11:46:24 +01:00
|
|
|
int old_row_exists= 1;
|
|
|
|
int error=0;
|
|
|
|
ulong store_proc_rights;
|
2005-05-17 20:54:20 +02:00
|
|
|
DBUG_ENTER("replace_routine_table");
|
2004-12-23 11:46:24 +01:00
|
|
|
|
|
|
|
if (!initialized)
|
|
|
|
{
|
|
|
|
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables");
|
|
|
|
DBUG_RETURN(-1);
|
|
|
|
}
|
|
|
|
|
2005-09-15 21:29:07 +02:00
|
|
|
strxmov(grantor, thd->security_ctx->user, "@",
|
|
|
|
thd->security_ctx->host_or_ip, NullS);
|
2004-12-23 11:46:24 +01:00
|
|
|
|
|
|
|
/*
|
2008-03-05 15:33:32 +01:00
|
|
|
New users are created before this function is called.
|
|
|
|
|
|
|
|
There may be some cases where a routine's definer is removed but the
|
|
|
|
routine remains.
|
2004-12-23 11:46:24 +01:00
|
|
|
*/
|
|
|
|
|
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes
Changes that requires code changes in other code of other storage engines.
(Note that all changes are very straightforward and one should find all issues
by compiling a --debug build and fixing all compiler errors and all
asserts in field.cc while running the test suite),
- New optional handler function introduced: reset()
This is called after every DML statement to make it easy for a handler to
statement specific cleanups.
(The only case it's not called is if force the file to be closed)
- handler::extra(HA_EXTRA_RESET) is removed. Code that was there before
should be moved to handler::reset()
- table->read_set contains a bitmap over all columns that are needed
in the query. read_row() and similar functions only needs to read these
columns
- table->write_set contains a bitmap over all columns that will be updated
in the query. write_row() and update_row() only needs to update these
columns.
The above bitmaps should now be up to date in all context
(including ALTER TABLE, filesort()).
The handler is informed of any changes to the bitmap after
fix_fields() by calling the virtual function
handler::column_bitmaps_signal(). If the handler does caching of
these bitmaps (instead of using table->read_set, table->write_set),
it should redo the caching in this code. as the signal() may be sent
several times, it's probably best to set a variable in the signal
and redo the caching on read_row() / write_row() if the variable was
set.
- Removed the read_set and write_set bitmap objects from the handler class
- Removed all column bit handling functions from the handler class.
(Now one instead uses the normal bitmap functions in my_bitmap.c instead
of handler dedicated bitmap functions)
- field->query_id is removed. One should instead instead check
table->read_set and table->write_set if a field is used in the query.
- handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and
handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now
instead use table->read_set to check for which columns to retrieve.
- If a handler needs to call Field->val() or Field->store() on columns
that are not used in the query, one should install a temporary
all-columns-used map while doing so. For this, we provide the following
functions:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
field->val();
dbug_tmp_restore_column_map(table->read_set, old_map);
and similar for the write map:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
field->val();
dbug_tmp_restore_column_map(table->write_set, old_map);
If this is not done, you will sooner or later hit a DBUG_ASSERT
in the field store() / val() functions.
(For not DBUG binaries, the dbug_tmp_restore_column_map() and
dbug_tmp_restore_column_map() are inline dummy functions and should
be optimized away be the compiler).
- If one needs to temporary set the column map for all binaries (and not
just to avoid the DBUG_ASSERT() in the Field::store() / Field::val()
methods) one should use the functions tmp_use_all_columns() and
tmp_restore_column_map() instead of the above dbug_ variants.
- All 'status' fields in the handler base class (like records,
data_file_length etc) are now stored in a 'stats' struct. This makes
it easier to know what status variables are provided by the base
handler. This requires some trivial variable names in the extra()
function.
- New virtual function handler::records(). This is called to optimize
COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true.
(stats.records is not supposed to be an exact value. It's only has to
be 'reasonable enough' for the optimizer to be able to choose a good
optimization path).
- Non virtual handler::init() function added for caching of virtual
constants from engine.
- Removed has_transactions() virtual method. Now one should instead return
HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support
transactions.
- The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument
that is to be used with 'new handler_name()' to allocate the handler
in the right area. The xxxx_create_handler() function is also
responsible for any initialization of the object before returning.
For example, one should change:
static handler *myisam_create_handler(TABLE_SHARE *table)
{
return new ha_myisam(table);
}
->
static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisam(table);
}
- New optional virtual function: use_hidden_primary_key().
This is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key. This allows the handler to take precisions
in remembering any hidden primary key to able to update/delete any
found row. The default handler marks all columns to be read.
- handler::table_flags() now returns a ulonglong (to allow for more flags).
- New/changed table_flags()
- HA_HAS_RECORDS Set if ::records() is supported
- HA_NO_TRANSACTIONS Set if engine doesn't support transactions
- HA_PRIMARY_KEY_REQUIRED_FOR_DELETE
Set if we should mark all primary key columns for
read when reading rows as part of a DELETE
statement. If there is no primary key,
all columns are marked for read.
- HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some
cases (based on table->read_set)
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
- HA_DUPP_POS Renamed to HA_DUPLICATE_POS
- HA_REQUIRES_KEY_COLUMNS_FOR_DELETE
Set this if we should mark ALL key columns for
read when when reading rows as part of a DELETE
statement. In case of an update we will mark
all keys for read for which key part changed
value.
- HA_STATS_RECORDS_IS_EXACT
Set this if stats.records is exact.
(This saves us some extra records() calls
when optimizing COUNT(*))
- Removed table_flags()
- HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if
handler::records() gives an exact count() and
HA_STATS_RECORDS_IS_EXACT if stats.records is exact.
- HA_READ_RND_SAME Removed (no one supported this one)
- Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk()
- Renamed handler::dupp_pos to handler::dup_pos
- Removed not used variable handler::sortkey
Upper level handler changes:
- ha_reset() now does some overall checks and calls ::reset()
- ha_table_flags() added. This is a cached version of table_flags(). The
cache is updated on engine creation time and updated on open.
MySQL level changes (not obvious from the above):
- DBUG_ASSERT() added to check that column usage matches what is set
in the column usage bit maps. (This found a LOT of bugs in current
column marking code).
- In 5.1 before, all used columns was marked in read_set and only updated
columns was marked in write_set. Now we only mark columns for which we
need a value in read_set.
- Column bitmaps are created in open_binary_frm() and open_table_from_share().
(Before this was in table.cc)
- handler::table_flags() calls are replaced with handler::ha_table_flags()
- For calling field->val() you must have the corresponding bit set in
table->read_set. For calling field->store() you must have the
corresponding bit set in table->write_set. (There are asserts in
all store()/val() functions to catch wrong usage)
- thd->set_query_id is renamed to thd->mark_used_columns and instead
of setting this to an integer value, this has now the values:
MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE
Changed also all variables named 'set_query_id' to mark_used_columns.
- In filesort() we now inform the handler of exactly which columns are needed
doing the sort and choosing the rows.
- The TABLE_SHARE object has a 'all_set' column bitmap one can use
when one needs a column bitmap with all columns set.
(This is used for table->use_all_columns() and other places)
- The TABLE object has 3 column bitmaps:
- def_read_set Default bitmap for columns to be read
- def_write_set Default bitmap for columns to be written
- tmp_set Can be used as a temporary bitmap when needed.
The table object has also two pointer to bitmaps read_set and write_set
that the handler should use to find out which columns are used in which way.
- count() optimization now calls handler::records() instead of using
handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true).
- Added extra argument to Item::walk() to indicate if we should also
traverse sub queries.
- Added TABLE parameter to cp_buffer_from_ref()
- Don't close tables created with CREATE ... SELECT but keep them in
the table cache. (Faster usage of newly created tables).
New interfaces:
- table->clear_column_bitmaps() to initialize the bitmaps for tables
at start of new statements.
- table->column_bitmaps_set() to set up new column bitmaps and signal
the handler about this.
- table->column_bitmaps_set_no_signal() for some few cases where we need
to setup new column bitmaps but don't signal the handler (as the handler
has already been signaled about these before). Used for the momement
only in opt_range.cc when doing ROR scans.
- table->use_all_columns() to install a bitmap where all columns are marked
as use in the read and the write set.
- table->default_column_bitmaps() to install the normal read and write
column bitmaps, but not signaling the handler about this.
This is mainly used when creating TABLE instances.
- table->mark_columns_needed_for_delete(),
table->mark_columns_needed_for_delete() and
table->mark_columns_needed_for_insert() to allow us to put additional
columns in column usage maps if handler so requires.
(The handler indicates what it neads in handler->table_flags())
- table->prepare_for_position() to allow us to tell handler that it
needs to read primary key parts to be able to store them in
future table->position() calls.
(This replaces the table->file->ha_retrieve_all_pk function)
- table->mark_auto_increment_column() to tell handler are going to update
columns part of any auto_increment key.
- table->mark_columns_used_by_index() to mark all columns that is part of
an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow
it to quickly know that it only needs to read colums that are part
of the key. (The handler can also use the column map for detecting this,
but simpler/faster handler can just monitor the extra() call).
- table->mark_columns_used_by_index_no_reset() to in addition to other columns,
also mark all columns that is used by the given key.
- table->restore_column_maps_after_mark_index() to restore to default
column maps after a call to table->mark_columns_used_by_index().
- New item function register_field_in_read_map(), for marking used columns
in table->read_map. Used by filesort() to mark all used columns
- Maintain in TABLE->merge_keys set of all keys that are used in query.
(Simplices some optimization loops)
- Maintain Field->part_of_key_not_clustered which is like Field->part_of_key
but the field in the clustered key is not assumed to be part of all index.
(used in opt_range.cc for faster loops)
- dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map()
tmp_use_all_columns() and tmp_restore_column_map() functions to temporally
mark all columns as usable. The 'dbug_' version is primarily intended
inside a handler when it wants to just call Field:store() & Field::val()
functions, but don't need the column maps set for any other usage.
(ie:: bitmap_is_set() is never called)
- We can't use compare_records() to skip updates for handlers that returns
a partial column set and the read_set doesn't cover all columns in the
write set. The reason for this is that if we have a column marked only for
write we can't in the MySQL level know if the value changed or not.
The reason this worked before was that MySQL marked all to be written
columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden
bug'.
- open_table_from_share() does not anymore setup temporary MEM_ROOT
object as a thread specific variable for the handler. Instead we
send the to-be-used MEMROOT to get_new_handler().
(Simpler, faster code)
Bugs fixed:
- Column marking was not done correctly in a lot of cases.
(ALTER TABLE, when using triggers, auto_increment fields etc)
(Could potentially result in wrong values inserted in table handlers
relying on that the old column maps or field->set_query_id was correct)
Especially when it comes to triggers, there may be cases where the
old code would cause lost/wrong values for NDB and/or InnoDB tables.
- Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags:
OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG.
This allowed me to remove some wrong warnings about:
"Some non-transactional changed tables couldn't be rolled back"
- Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset
(thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose
some warnings about
"Some non-transactional changed tables couldn't be rolled back")
- Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table()
which could cause delete_table to report random failures.
- Fixed core dumps for some tests when running with --debug
- Added missing FN_LIBCHAR in mysql_rm_tmp_tables()
(This has probably caused us to not properly remove temporary files after
crash)
- slow_logs was not properly initialized, which could maybe cause
extra/lost entries in slow log.
- If we get an duplicate row on insert, change column map to read and
write all columns while retrying the operation. This is required by
the definition of REPLACE and also ensures that fields that are only
part of UPDATE are properly handled. This fixed a bug in NDB and
REPLACE where REPLACE wrongly copied some column values from the replaced
row.
- For table handler that doesn't support NULL in keys, we would give an error
when creating a primary key with NULL fields, even after the fields has been
automaticly converted to NOT NULL.
- Creating a primary key on a SPATIAL key, would fail if field was not
declared as NOT NULL.
Cleanups:
- Removed not used condition argument to setup_tables
- Removed not needed item function reset_query_id_processor().
- Field->add_index is removed. Now this is instead maintained in
(field->flags & FIELD_IN_ADD_INDEX)
- Field->fieldnr is removed (use field->field_index instead)
- New argument to filesort() to indicate that it should return a set of
row pointers (not used columns). This allowed me to remove some references
to sql_command in filesort and should also enable us to return column
results in some cases where we couldn't before.
- Changed column bitmap handling in opt_range.cc to be aligned with TABLE
bitmap, which allowed me to use bitmap functions instead of looping over
all fields to create some needed bitmaps. (Faster and smaller code)
- Broke up found too long lines
- Moved some variable declaration at start of function for better code
readability.
- Removed some not used arguments from functions.
(setup_fields(), mysql_prepare_insert_check_table())
- setup_fields() now takes an enum instead of an int for marking columns
usage.
- For internal temporary tables, use handler::write_row(),
handler::delete_row() and handler::update_row() instead of
handler::ha_xxxx() for faster execution.
- Changed some constants to enum's and define's.
- Using separate column read and write sets allows for easier checking
of timestamp field was set by statement.
- Remove calls to free_io_cache() as this is now done automaticly in ha_reset()
- Don't build table->normalized_path as this is now identical to table->path
(after bar's fixes to convert filenames)
- Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to
do comparision with the 'convert-dbug-for-diff' tool.
Things left to do in 5.1:
- We wrongly log failed CREATE TABLE ... SELECT in some cases when using
row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result)
Mats has promised to look into this.
- Test that my fix for CREATE TABLE ... SELECT is indeed correct.
(I added several test cases for this, but in this case it's better that
someone else also tests this throughly).
Lars has promosed to do this.
2006-06-04 17:52:22 +02:00
|
|
|
table->use_all_columns();
|
2005-01-06 12:00:13 +01:00
|
|
|
restore_record(table, s->default_values); // Get empty record
|
2004-12-23 11:46:24 +01:00
|
|
|
table->field[0]->store(combo.host.str,combo.host.length, &my_charset_latin1);
|
|
|
|
table->field[1]->store(db,(uint) strlen(db), &my_charset_latin1);
|
|
|
|
table->field[2]->store(combo.user.str,combo.user.length, &my_charset_latin1);
|
2005-05-17 20:54:20 +02:00
|
|
|
table->field[3]->store(routine_name,(uint) strlen(routine_name),
|
|
|
|
&my_charset_latin1);
|
2007-03-17 00:13:25 +01:00
|
|
|
table->field[4]->store((longlong)(is_proc ?
|
2005-09-14 00:41:44 +02:00
|
|
|
TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION),
|
|
|
|
TRUE);
|
2004-12-23 11:46:24 +01:00
|
|
|
store_record(table,record[1]); // store at pos 1
|
|
|
|
|
2007-08-13 15:11:25 +02:00
|
|
|
if (table->file->index_read_idx_map(table->record[0], 0,
|
|
|
|
(uchar*) table->field[0]->ptr,
|
|
|
|
HA_WHOLE_KEY,
|
|
|
|
HA_READ_KEY_EXACT))
|
2004-12-23 11:46:24 +01:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
The following should never happen as we first check the in memory
|
|
|
|
grant tables for the user. There is however always a small change that
|
|
|
|
the user has modified the grant tables directly.
|
|
|
|
*/
|
|
|
|
if (revoke_grant)
|
|
|
|
{ // no row, no revoke
|
|
|
|
my_error(ER_NONEXISTING_PROC_GRANT, MYF(0),
|
2005-05-17 20:54:20 +02:00
|
|
|
combo.user.str, combo.host.str, routine_name);
|
2004-12-23 11:46:24 +01:00
|
|
|
DBUG_RETURN(-1);
|
|
|
|
}
|
|
|
|
old_row_exists= 0;
|
|
|
|
restore_record(table,record[1]); // Get saved record
|
|
|
|
}
|
|
|
|
|
|
|
|
store_proc_rights= get_rights_for_procedure(rights);
|
|
|
|
if (old_row_exists)
|
|
|
|
{
|
|
|
|
ulong j;
|
|
|
|
store_record(table,record[1]);
|
|
|
|
j= (ulong) table->field[6]->val_int();
|
|
|
|
|
|
|
|
if (revoke_grant)
|
|
|
|
{
|
|
|
|
/* column rights are already fixed in mysql_table_grant */
|
|
|
|
store_proc_rights=j & ~store_proc_rights;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
store_proc_rights|= j;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-05-17 20:54:20 +02:00
|
|
|
table->field[5]->store(grantor,(uint) strlen(grantor), &my_charset_latin1);
|
2005-09-14 00:41:44 +02:00
|
|
|
table->field[6]->store((longlong) store_proc_rights, TRUE);
|
2004-12-23 11:46:24 +01:00
|
|
|
rights=fix_rights_for_procedure(store_proc_rights);
|
|
|
|
|
|
|
|
if (old_row_exists)
|
|
|
|
{
|
|
|
|
if (store_proc_rights)
|
|
|
|
{
|
2007-06-28 15:07:55 +02:00
|
|
|
if ((error=table->file->ha_update_row(table->record[1],
|
|
|
|
table->record[0])) &&
|
|
|
|
error != HA_ERR_RECORD_IS_THE_SAME)
|
2004-12-23 11:46:24 +01:00
|
|
|
goto table_error;
|
|
|
|
}
|
2005-12-22 06:39:02 +01:00
|
|
|
else if ((error= table->file->ha_delete_row(table->record[1])))
|
2004-12-23 11:46:24 +01:00
|
|
|
goto table_error;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-12-22 06:39:02 +01:00
|
|
|
error=table->file->ha_write_row(table->record[0]);
|
2006-07-01 06:01:37 +02:00
|
|
|
if (table->file->is_fatal_error(error, HA_CHECK_DUP_KEY))
|
2004-12-23 11:46:24 +01:00
|
|
|
goto table_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rights)
|
|
|
|
{
|
|
|
|
grant_name->privs= rights;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-10-14 18:37:38 +02:00
|
|
|
my_hash_delete(is_proc ? &proc_priv_hash : &func_priv_hash,(uchar*)
|
|
|
|
grant_name);
|
2004-12-23 11:46:24 +01:00
|
|
|
}
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
|
|
|
|
/* This should never happen */
|
|
|
|
table_error:
|
|
|
|
table->file->print_error(error,MYF(0));
|
|
|
|
DBUG_RETURN(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-06-23 19:03:59 +02:00
|
|
|
/*
|
|
|
|
Store table level and column level grants in the privilege tables
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
mysql_table_grant()
|
|
|
|
thd Thread handle
|
|
|
|
table_list List of tables to give grant
|
|
|
|
user_list List of users to give grant
|
|
|
|
columns List of columns to give grant
|
|
|
|
rights Table level grant
|
|
|
|
revoke_grant Set to 1 if this is a REVOKE command
|
|
|
|
|
|
|
|
RETURN
|
2004-10-20 03:04:37 +02:00
|
|
|
FALSE ok
|
|
|
|
TRUE error
|
2003-06-23 19:03:59 +02:00
|
|
|
*/
|
|
|
|
|
2008-03-21 16:23:17 +01:00
|
|
|
int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
|
2003-04-28 09:32:56 +02:00
|
|
|
List <LEX_USER> &user_list,
|
|
|
|
List <LEX_COLUMN> &columns, ulong rights,
|
|
|
|
bool revoke_grant)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2003-06-23 19:03:59 +02:00
|
|
|
ulong column_priv= 0;
|
2000-07-31 21:29:14 +02:00
|
|
|
List_iterator <LEX_USER> str_list (user_list);
|
2006-06-29 12:50:44 +02:00
|
|
|
LEX_USER *Str, *tmp_Str;
|
2000-07-31 21:29:14 +02:00
|
|
|
TABLE_LIST tables[3];
|
2001-09-15 14:24:56 +02:00
|
|
|
bool create_new_users=0;
|
2005-01-06 12:00:13 +01:00
|
|
|
char *db_name, *table_name;
|
2000-07-31 21:29:14 +02:00
|
|
|
DBUG_ENTER("mysql_table_grant");
|
|
|
|
|
|
|
|
if (!initialized)
|
|
|
|
{
|
2004-02-21 15:15:26 +01:00
|
|
|
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0),
|
|
|
|
"--skip-grant-tables"); /* purecov: inspected */
|
2004-10-20 03:04:37 +02:00
|
|
|
DBUG_RETURN(TRUE); /* purecov: inspected */
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
if (rights & ~TABLE_ACLS)
|
|
|
|
{
|
2004-11-12 13:34:00 +01:00
|
|
|
my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER(ER_ILLEGAL_GRANT_FOR_TABLE),
|
|
|
|
MYF(0));
|
2004-10-20 03:04:37 +02:00
|
|
|
DBUG_RETURN(TRUE);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2004-12-30 21:01:11 +01:00
|
|
|
if (!revoke_grant)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-12-31 15:26:24 +01:00
|
|
|
if (columns.elements)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-12-30 21:01:11 +01:00
|
|
|
class LEX_COLUMN *column;
|
|
|
|
List_iterator <LEX_COLUMN> column_iter(columns);
|
2004-12-31 15:26:24 +01:00
|
|
|
|
|
|
|
if (open_and_lock_tables(thd, table_list))
|
|
|
|
DBUG_RETURN(TRUE);
|
2004-12-30 21:01:11 +01:00
|
|
|
|
|
|
|
while ((column = column_iter++))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-12-30 21:11:40 +01:00
|
|
|
uint unused_field_idx= NO_CACHED_FIELD_INDEX;
|
2005-08-12 16:57:19 +02:00
|
|
|
TABLE_LIST *dummy;
|
|
|
|
Field *f=find_field_in_table_ref(thd, table_list, column->column.ptr(),
|
2005-11-28 20:57:50 +01:00
|
|
|
column->column.length(),
|
2005-08-12 16:57:19 +02:00
|
|
|
column->column.ptr(), NULL, NULL,
|
2005-11-30 20:27:11 +01:00
|
|
|
NULL, TRUE, FALSE,
|
2005-08-12 16:57:19 +02:00
|
|
|
&unused_field_idx, FALSE, &dummy);
|
2004-12-31 15:26:24 +01:00
|
|
|
if (f == (Field*)0)
|
2004-12-30 21:01:11 +01:00
|
|
|
{
|
2004-12-30 21:11:40 +01:00
|
|
|
my_error(ER_BAD_FIELD_ERROR, MYF(0),
|
|
|
|
column->column.c_ptr(), table_list->alias);
|
2004-12-31 15:26:24 +01:00
|
|
|
DBUG_RETURN(TRUE);
|
2004-12-30 21:01:11 +01:00
|
|
|
}
|
2004-12-31 15:26:24 +01:00
|
|
|
if (f == (Field *)-1)
|
|
|
|
DBUG_RETURN(TRUE);
|
2004-12-30 21:01:11 +01:00
|
|
|
column_priv|= column->rights;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2004-12-30 21:01:11 +01:00
|
|
|
close_thread_tables(thd);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2004-12-30 21:01:11 +01:00
|
|
|
else
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-12-30 21:01:11 +01:00
|
|
|
if (!(rights & CREATE_ACL))
|
|
|
|
{
|
2009-06-19 10:24:43 +02:00
|
|
|
char buf[FN_REFLEN + 1];
|
|
|
|
build_table_filename(buf, sizeof(buf) - 1, table_list->db,
|
2006-08-02 17:57:06 +02:00
|
|
|
table_list->table_name, reg_ext, 0);
|
2005-12-31 06:01:26 +01:00
|
|
|
fn_format(buf, buf, "", "", MY_UNPACK_FILENAME | MY_RESOLVE_SYMLINKS |
|
|
|
|
MY_RETURN_REAL_PATH | MY_APPEND_EXT);
|
2004-12-30 21:01:11 +01:00
|
|
|
if (access(buf,F_OK))
|
|
|
|
{
|
2004-12-30 21:11:40 +01:00
|
|
|
my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, table_list->alias);
|
2004-12-31 15:26:24 +01:00
|
|
|
DBUG_RETURN(TRUE);
|
2004-12-30 21:01:11 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (table_list->grant.want_privilege)
|
|
|
|
{
|
|
|
|
char command[128];
|
|
|
|
get_privilege_desc(command, sizeof(command),
|
|
|
|
table_list->grant.want_privilege);
|
|
|
|
my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0),
|
2005-09-15 21:29:07 +02:00
|
|
|
command, thd->security_ctx->priv_user,
|
|
|
|
thd->security_ctx->host_or_ip, table_list->alias);
|
2004-12-30 21:01:11 +01:00
|
|
|
DBUG_RETURN(-1);
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* open the mysql.tables_priv and mysql.columns_priv tables */
|
|
|
|
|
|
|
|
bzero((char*) &tables,sizeof(tables));
|
2005-01-06 12:00:13 +01:00
|
|
|
tables[0].alias=tables[0].table_name= (char*) "user";
|
|
|
|
tables[1].alias=tables[1].table_name= (char*) "tables_priv";
|
|
|
|
tables[2].alias=tables[2].table_name= (char*) "columns_priv";
|
2004-07-16 00:15:55 +02:00
|
|
|
tables[0].next_local= tables[0].next_global= tables+1;
|
2000-07-31 21:29:14 +02:00
|
|
|
/* Don't open column table if we don't need it ! */
|
2004-07-16 00:15:55 +02:00
|
|
|
tables[1].next_local=
|
|
|
|
tables[1].next_global= ((column_priv ||
|
|
|
|
(revoke_grant &&
|
|
|
|
((rights & COL_ACLS) || columns.elements)))
|
|
|
|
? tables+2 : 0);
|
2000-07-31 21:29:14 +02:00
|
|
|
tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_WRITE;
|
|
|
|
tables[0].db=tables[1].db=tables[2].db=(char*) "mysql";
|
|
|
|
|
BUG#25091 (A DELETE statement to mysql database is not logged in ROW format):
With this patch, statements that change metadata (in the mysql database)
is logged as statements, while normal changes (e.g., using INSERT, DELETE,
and/or UPDATE) is logged according to the format in effect.
The log tables (i.e., general_log and slow_log) are not replicated at all.
With this patch, the following statements are replicated as statements:
GRANT, REVOKE (ALL), CREATE USER, DROP USER, and RENAME USER.
2007-02-26 10:19:08 +01:00
|
|
|
/*
|
|
|
|
This statement will be replicated as a statement, even when using
|
|
|
|
row-based replication. The flag will be reset at the end of the
|
|
|
|
statement.
|
|
|
|
*/
|
|
|
|
thd->clear_current_stmt_binlog_row_based();
|
|
|
|
|
2003-04-01 22:49:40 +02:00
|
|
|
#ifdef HAVE_REPLICATION
|
|
|
|
/*
|
|
|
|
GRANT and REVOKE are applied the slave in/exclusion rules as they are
|
|
|
|
some kind of updates to the mysql.% tables.
|
|
|
|
*/
|
2005-03-08 21:12:35 +01:00
|
|
|
if (thd->slave_thread && rpl_filter->is_on())
|
2003-08-02 16:10:26 +02:00
|
|
|
{
|
2003-08-11 21:44:43 +02:00
|
|
|
/*
|
|
|
|
The tables must be marked "updating" so that tables_ok() takes them into
|
|
|
|
account in tests.
|
2003-08-02 16:10:26 +02:00
|
|
|
*/
|
2003-08-07 19:16:37 +02:00
|
|
|
tables[0].updating= tables[1].updating= tables[2].updating= 1;
|
2005-05-09 11:43:09 +02:00
|
|
|
if (!(thd->spcont || rpl_filter->tables_ok(0, tables)))
|
2004-10-20 03:04:37 +02:00
|
|
|
DBUG_RETURN(FALSE);
|
2003-08-02 16:10:26 +02:00
|
|
|
}
|
2003-04-01 22:49:40 +02:00
|
|
|
#endif
|
|
|
|
|
2008-02-01 14:10:46 +01:00
|
|
|
/*
|
|
|
|
The lock api is depending on the thd->lex variable which needs to be
|
|
|
|
re-initialized.
|
|
|
|
*/
|
|
|
|
Query_tables_list backup;
|
|
|
|
thd->lex->reset_n_backup_query_tables_list(&backup);
|
2004-02-01 14:30:32 +01:00
|
|
|
if (simple_open_n_lock_tables(thd,tables))
|
2000-07-31 21:29:14 +02:00
|
|
|
{ // Should never happen
|
|
|
|
close_thread_tables(thd); /* purecov: deadcode */
|
2004-10-20 03:04:37 +02:00
|
|
|
DBUG_RETURN(TRUE); /* purecov: deadcode */
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2001-09-15 14:24:56 +02:00
|
|
|
if (!revoke_grant)
|
|
|
|
create_new_users= test_if_create_new_users(thd);
|
2004-10-20 03:04:37 +02:00
|
|
|
bool result= FALSE;
|
2002-10-02 12:33:08 +02:00
|
|
|
rw_wrlock(&LOCK_grant);
|
2006-05-06 09:25:59 +02:00
|
|
|
pthread_mutex_lock(&acl_cache->lock);
|
2004-11-08 00:13:54 +01:00
|
|
|
MEM_ROOT *old_root= thd->mem_root;
|
|
|
|
thd->mem_root= &memex;
|
2005-05-07 15:55:46 +02:00
|
|
|
grant_version++;
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2006-06-29 12:50:44 +02:00
|
|
|
while ((tmp_Str = str_list++))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2002-09-21 20:36:23 +02:00
|
|
|
int error;
|
2000-07-31 21:29:14 +02:00
|
|
|
GRANT_TABLE *grant_table;
|
2006-06-29 12:50:44 +02:00
|
|
|
if (!(Str= get_current_user(thd, tmp_Str)))
|
|
|
|
{
|
|
|
|
result= TRUE;
|
|
|
|
continue;
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
/* Create user if needed */
|
2002-09-22 09:59:33 +02:00
|
|
|
error=replace_user_table(thd, tables[0].table, *Str,
|
2005-03-23 19:18:25 +01:00
|
|
|
0, revoke_grant, create_new_users,
|
2005-03-29 11:37:36 +02:00
|
|
|
test(thd->variables.sql_mode &
|
|
|
|
MODE_NO_AUTO_CREATE_USER));
|
2002-09-21 20:36:23 +02:00
|
|
|
if (error)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-10-20 03:04:37 +02:00
|
|
|
result= TRUE; // Remember error
|
2000-07-31 21:29:14 +02:00
|
|
|
continue; // Add next user
|
|
|
|
}
|
|
|
|
|
2008-09-03 16:45:40 +02:00
|
|
|
db_name= table_list->get_db_name();
|
|
|
|
table_name= table_list->get_table_name();
|
2004-07-16 00:15:55 +02:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
/* Find/create cached table grant */
|
2004-07-16 00:15:55 +02:00
|
|
|
grant_table= table_hash_search(Str->host.str, NullS, db_name,
|
2005-01-06 12:00:13 +01:00
|
|
|
Str->user.str, table_name, 1);
|
2000-07-31 21:29:14 +02:00
|
|
|
if (!grant_table)
|
|
|
|
{
|
|
|
|
if (revoke_grant)
|
|
|
|
{
|
2004-02-21 15:15:26 +01:00
|
|
|
my_error(ER_NONEXISTING_TABLE_GRANT, MYF(0),
|
2005-01-06 12:00:13 +01:00
|
|
|
Str->user.str, Str->host.str, table_list->table_name);
|
2004-10-20 03:04:37 +02:00
|
|
|
result= TRUE;
|
2000-07-31 21:29:14 +02:00
|
|
|
continue;
|
|
|
|
}
|
2004-07-16 00:15:55 +02:00
|
|
|
grant_table = new GRANT_TABLE (Str->host.str, db_name,
|
2005-01-06 12:00:13 +01:00
|
|
|
Str->user.str, table_name,
|
2000-07-31 21:29:14 +02:00
|
|
|
rights,
|
|
|
|
column_priv);
|
2009-11-20 16:18:01 +01:00
|
|
|
if (!grant_table ||
|
2009-11-20 21:56:43 +01:00
|
|
|
my_hash_insert(&column_priv_hash,(uchar*) grant_table))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-10-20 03:04:37 +02:00
|
|
|
result= TRUE; /* purecov: deadcode */
|
2000-07-31 21:29:14 +02:00
|
|
|
continue; /* purecov: deadcode */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If revoke_grant, calculate the new column privilege for tables_priv */
|
|
|
|
if (revoke_grant)
|
|
|
|
{
|
2003-06-23 19:03:59 +02:00
|
|
|
class LEX_COLUMN *column;
|
|
|
|
List_iterator <LEX_COLUMN> column_iter(columns);
|
2000-07-31 21:29:14 +02:00
|
|
|
GRANT_COLUMN *grant_column;
|
|
|
|
|
|
|
|
/* Fix old grants */
|
2003-06-23 19:03:59 +02:00
|
|
|
while ((column = column_iter++))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
grant_column = column_hash_search(grant_table,
|
2003-06-23 19:03:59 +02:00
|
|
|
column->column.ptr(),
|
|
|
|
column->column.length());
|
2000-07-31 21:29:14 +02:00
|
|
|
if (grant_column)
|
2003-06-23 19:03:59 +02:00
|
|
|
grant_column->rights&= ~(column->rights | rights);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
/* scan trough all columns to get new column grant */
|
2003-06-23 19:03:59 +02:00
|
|
|
column_priv= 0;
|
2000-07-31 21:29:14 +02:00
|
|
|
for (uint idx=0 ; idx < grant_table->hash_columns.records ; idx++)
|
|
|
|
{
|
2009-10-14 18:37:38 +02:00
|
|
|
grant_column= (GRANT_COLUMN*)
|
|
|
|
my_hash_element(&grant_table->hash_columns, idx);
|
2000-07-31 21:29:14 +02:00
|
|
|
grant_column->rights&= ~rights; // Fix other columns
|
|
|
|
column_priv|= grant_column->rights;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
column_priv|= grant_table->cols;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* update table and columns */
|
|
|
|
|
2004-07-16 00:15:55 +02:00
|
|
|
if (replace_table_table(thd, grant_table, tables[1].table, *Str,
|
2005-01-06 12:00:13 +01:00
|
|
|
db_name, table_name,
|
2000-07-31 21:29:14 +02:00
|
|
|
rights, column_priv, revoke_grant))
|
2004-10-20 00:28:42 +02:00
|
|
|
{
|
|
|
|
/* Should only happen if table is crashed */
|
2004-10-20 03:04:37 +02:00
|
|
|
result= TRUE; /* purecov: deadcode */
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
else if (tables[2].table)
|
|
|
|
{
|
2004-07-16 00:15:55 +02:00
|
|
|
if ((replace_column_table(grant_table, tables[2].table, *Str,
|
2000-07-31 21:29:14 +02:00
|
|
|
columns,
|
2005-01-06 12:00:13 +01:00
|
|
|
db_name, table_name,
|
2000-07-31 21:29:14 +02:00
|
|
|
rights, revoke_grant)))
|
|
|
|
{
|
2004-10-20 03:04:37 +02:00
|
|
|
result= TRUE;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2004-11-08 00:13:54 +01:00
|
|
|
thd->mem_root= old_root;
|
2006-05-06 09:25:59 +02:00
|
|
|
pthread_mutex_unlock(&acl_cache->lock);
|
2006-10-03 19:38:25 +02:00
|
|
|
|
|
|
|
if (!result) /* success */
|
|
|
|
{
|
2009-11-21 05:28:01 +01:00
|
|
|
result= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
|
2006-10-03 19:38:25 +02:00
|
|
|
}
|
|
|
|
|
2002-10-02 12:33:08 +02:00
|
|
|
rw_unlock(&LOCK_grant);
|
2006-10-03 19:38:25 +02:00
|
|
|
|
|
|
|
if (!result) /* success */
|
2008-02-19 13:45:21 +01:00
|
|
|
my_ok(thd);
|
2006-10-03 19:38:25 +02:00
|
|
|
|
2001-09-30 04:46:20 +02:00
|
|
|
/* Tables are automatically closed */
|
2008-02-01 14:10:46 +01:00
|
|
|
thd->lex->restore_backup_query_tables_list(&backup);
|
2000-07-31 21:29:14 +02:00
|
|
|
DBUG_RETURN(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-05-29 15:37:54 +02:00
|
|
|
/**
|
2005-05-17 20:54:20 +02:00
|
|
|
Store routine level grants in the privilege tables
|
2004-12-23 11:46:24 +01:00
|
|
|
|
2009-05-29 15:37:54 +02:00
|
|
|
@param thd Thread handle
|
|
|
|
@param table_list List of routines to give grant
|
|
|
|
@param is_proc Is this a list of procedures?
|
|
|
|
@param user_list List of users to give grant
|
|
|
|
@param rights Table level grant
|
|
|
|
@param revoke_grant Is this is a REVOKE command?
|
2004-12-23 11:46:24 +01:00
|
|
|
|
2009-05-29 15:37:54 +02:00
|
|
|
@return
|
|
|
|
@retval FALSE Success.
|
|
|
|
@retval TRUE An error occurred.
|
2004-12-23 11:46:24 +01:00
|
|
|
*/
|
|
|
|
|
2005-05-17 20:54:20 +02:00
|
|
|
bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
|
|
|
|
List <LEX_USER> &user_list, ulong rights,
|
2009-05-29 15:37:54 +02:00
|
|
|
bool revoke_grant, bool write_to_binlog)
|
2004-12-23 11:46:24 +01:00
|
|
|
{
|
|
|
|
List_iterator <LEX_USER> str_list (user_list);
|
2006-06-29 12:50:44 +02:00
|
|
|
LEX_USER *Str, *tmp_Str;
|
2004-12-23 11:46:24 +01:00
|
|
|
TABLE_LIST tables[2];
|
|
|
|
bool create_new_users=0, result=0;
|
2005-01-06 12:00:13 +01:00
|
|
|
char *db_name, *table_name;
|
2005-05-17 20:54:20 +02:00
|
|
|
DBUG_ENTER("mysql_routine_grant");
|
2004-12-23 11:46:24 +01:00
|
|
|
|
|
|
|
if (!initialized)
|
|
|
|
{
|
2009-05-29 15:37:54 +02:00
|
|
|
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0),
|
|
|
|
"--skip-grant-tables");
|
2004-12-23 11:46:24 +01:00
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
if (rights & ~PROC_ACLS)
|
|
|
|
{
|
2009-05-29 15:37:54 +02:00
|
|
|
my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER(ER_ILLEGAL_GRANT_FOR_TABLE),
|
|
|
|
MYF(0));
|
2004-12-23 11:46:24 +01:00
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!revoke_grant)
|
|
|
|
{
|
2009-05-29 15:37:54 +02:00
|
|
|
if (sp_exist_routines(thd, table_list, is_proc))
|
2004-12-23 11:46:24 +01:00
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* open the mysql.user and mysql.procs_priv tables */
|
|
|
|
|
|
|
|
bzero((char*) &tables,sizeof(tables));
|
2005-01-06 12:00:13 +01:00
|
|
|
tables[0].alias=tables[0].table_name= (char*) "user";
|
|
|
|
tables[1].alias=tables[1].table_name= (char*) "procs_priv";
|
2004-12-23 11:46:24 +01:00
|
|
|
tables[0].next_local= tables[0].next_global= tables+1;
|
|
|
|
tables[0].lock_type=tables[1].lock_type=TL_WRITE;
|
|
|
|
tables[0].db=tables[1].db=(char*) "mysql";
|
|
|
|
|
BUG#25091 (A DELETE statement to mysql database is not logged in ROW format):
With this patch, statements that change metadata (in the mysql database)
is logged as statements, while normal changes (e.g., using INSERT, DELETE,
and/or UPDATE) is logged according to the format in effect.
The log tables (i.e., general_log and slow_log) are not replicated at all.
With this patch, the following statements are replicated as statements:
GRANT, REVOKE (ALL), CREATE USER, DROP USER, and RENAME USER.
2007-02-26 10:19:08 +01:00
|
|
|
/*
|
|
|
|
This statement will be replicated as a statement, even when using
|
|
|
|
row-based replication. The flag will be reset at the end of the
|
|
|
|
statement.
|
|
|
|
*/
|
|
|
|
thd->clear_current_stmt_binlog_row_based();
|
|
|
|
|
2004-12-23 11:46:24 +01:00
|
|
|
#ifdef HAVE_REPLICATION
|
|
|
|
/*
|
|
|
|
GRANT and REVOKE are applied the slave in/exclusion rules as they are
|
|
|
|
some kind of updates to the mysql.% tables.
|
|
|
|
*/
|
2005-03-08 21:12:35 +01:00
|
|
|
if (thd->slave_thread && rpl_filter->is_on())
|
2004-12-23 11:46:24 +01:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
The tables must be marked "updating" so that tables_ok() takes them into
|
|
|
|
account in tests.
|
|
|
|
*/
|
|
|
|
tables[0].updating= tables[1].updating= 1;
|
2005-05-09 11:43:09 +02:00
|
|
|
if (!(thd->spcont || rpl_filter->tables_ok(0, tables)))
|
2004-12-23 11:46:24 +01:00
|
|
|
DBUG_RETURN(FALSE);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (simple_open_n_lock_tables(thd,tables))
|
|
|
|
{ // Should never happen
|
|
|
|
close_thread_tables(thd);
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!revoke_grant)
|
|
|
|
create_new_users= test_if_create_new_users(thd);
|
|
|
|
rw_wrlock(&LOCK_grant);
|
2006-05-06 09:25:59 +02:00
|
|
|
pthread_mutex_lock(&acl_cache->lock);
|
2004-12-23 11:46:24 +01:00
|
|
|
MEM_ROOT *old_root= thd->mem_root;
|
|
|
|
thd->mem_root= &memex;
|
|
|
|
|
|
|
|
DBUG_PRINT("info",("now time to iterate and add users"));
|
|
|
|
|
2006-06-29 12:50:44 +02:00
|
|
|
while ((tmp_Str= str_list++))
|
2004-12-23 11:46:24 +01:00
|
|
|
{
|
|
|
|
int error;
|
|
|
|
GRANT_NAME *grant_name;
|
2006-06-29 12:50:44 +02:00
|
|
|
if (!(Str= get_current_user(thd, tmp_Str)))
|
|
|
|
{
|
|
|
|
result= TRUE;
|
|
|
|
continue;
|
|
|
|
}
|
2004-12-23 11:46:24 +01:00
|
|
|
/* Create user if needed */
|
|
|
|
error=replace_user_table(thd, tables[0].table, *Str,
|
2005-03-23 19:18:25 +01:00
|
|
|
0, revoke_grant, create_new_users,
|
2005-03-29 11:37:36 +02:00
|
|
|
test(thd->variables.sql_mode &
|
|
|
|
MODE_NO_AUTO_CREATE_USER));
|
2004-12-23 11:46:24 +01:00
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
result= TRUE; // Remember error
|
|
|
|
continue; // Add next user
|
|
|
|
}
|
|
|
|
|
|
|
|
db_name= table_list->db;
|
2005-01-06 12:00:13 +01:00
|
|
|
table_name= table_list->table_name;
|
2004-12-23 11:46:24 +01:00
|
|
|
|
2005-05-17 20:54:20 +02:00
|
|
|
grant_name= routine_hash_search(Str->host.str, NullS, db_name,
|
|
|
|
Str->user.str, table_name, is_proc, 1);
|
2004-12-23 11:46:24 +01:00
|
|
|
if (!grant_name)
|
|
|
|
{
|
|
|
|
if (revoke_grant)
|
|
|
|
{
|
2009-05-29 15:37:54 +02:00
|
|
|
my_error(ER_NONEXISTING_PROC_GRANT, MYF(0),
|
|
|
|
Str->user.str, Str->host.str, table_name);
|
2004-12-23 11:46:24 +01:00
|
|
|
result= TRUE;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
grant_name= new GRANT_NAME(Str->host.str, db_name,
|
2005-01-06 12:00:13 +01:00
|
|
|
Str->user.str, table_name,
|
2009-10-27 09:09:19 +01:00
|
|
|
rights, TRUE);
|
2009-11-20 16:18:01 +01:00
|
|
|
if (!grant_name ||
|
2009-11-20 21:56:43 +01:00
|
|
|
my_hash_insert(is_proc ?
|
|
|
|
&proc_priv_hash : &func_priv_hash,(uchar*) grant_name))
|
2004-12-23 11:46:24 +01:00
|
|
|
{
|
|
|
|
result= TRUE;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2005-03-22 15:54:18 +01:00
|
|
|
|
2005-05-17 20:54:20 +02:00
|
|
|
if (replace_routine_table(thd, grant_name, tables[1].table, *Str,
|
2008-03-05 15:33:32 +01:00
|
|
|
db_name, table_name, is_proc, rights,
|
|
|
|
revoke_grant) != 0)
|
2004-12-23 11:46:24 +01:00
|
|
|
{
|
|
|
|
result= TRUE;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
thd->mem_root= old_root;
|
2006-05-06 09:25:59 +02:00
|
|
|
pthread_mutex_unlock(&acl_cache->lock);
|
2009-05-29 15:37:54 +02:00
|
|
|
|
|
|
|
if (write_to_binlog)
|
2006-10-03 19:38:25 +02:00
|
|
|
{
|
2009-12-16 19:02:21 +01:00
|
|
|
if (write_bin_log(thd, FALSE, thd->query(), thd->query_length()))
|
2009-11-21 05:28:01 +01:00
|
|
|
result= TRUE;
|
2006-10-03 19:38:25 +02:00
|
|
|
}
|
|
|
|
|
2004-12-23 11:46:24 +01:00
|
|
|
rw_unlock(&LOCK_grant);
|
2006-10-03 19:38:25 +02:00
|
|
|
|
2004-12-23 11:46:24 +01:00
|
|
|
/* Tables are automatically closed */
|
|
|
|
DBUG_RETURN(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-10-20 03:04:37 +02:00
|
|
|
bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
|
|
|
|
ulong rights, bool revoke_grant)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
List_iterator <LEX_USER> str_list (list);
|
2006-06-29 12:50:44 +02:00
|
|
|
LEX_USER *Str, *tmp_Str;
|
2006-09-27 16:21:29 +02:00
|
|
|
char tmp_db[NAME_LEN+1];
|
2001-08-10 16:37:37 +02:00
|
|
|
bool create_new_users=0;
|
2000-07-31 21:29:14 +02:00
|
|
|
TABLE_LIST tables[2];
|
|
|
|
DBUG_ENTER("mysql_grant");
|
|
|
|
if (!initialized)
|
|
|
|
{
|
2004-02-21 15:15:26 +01:00
|
|
|
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0),
|
|
|
|
"--skip-grant-tables"); /* purecov: tested */
|
2004-10-20 03:04:37 +02:00
|
|
|
DBUG_RETURN(TRUE); /* purecov: tested */
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2001-12-13 01:31:19 +01:00
|
|
|
if (lower_case_table_names && db)
|
|
|
|
{
|
|
|
|
strmov(tmp_db,db);
|
2004-05-22 21:41:58 +02:00
|
|
|
my_casedn_str(files_charset_info, tmp_db);
|
2001-12-13 01:31:19 +01:00
|
|
|
db=tmp_db;
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
/* open the mysql.user and mysql.db tables */
|
2004-02-01 14:30:32 +01:00
|
|
|
bzero((char*) &tables,sizeof(tables));
|
2005-01-06 12:00:13 +01:00
|
|
|
tables[0].alias=tables[0].table_name=(char*) "user";
|
|
|
|
tables[1].alias=tables[1].table_name=(char*) "db";
|
2004-07-16 00:15:55 +02:00
|
|
|
tables[0].next_local= tables[0].next_global= tables+1;
|
2000-07-31 21:29:14 +02:00
|
|
|
tables[0].lock_type=tables[1].lock_type=TL_WRITE;
|
|
|
|
tables[0].db=tables[1].db=(char*) "mysql";
|
2003-04-01 22:49:40 +02:00
|
|
|
|
BUG#25091 (A DELETE statement to mysql database is not logged in ROW format):
With this patch, statements that change metadata (in the mysql database)
is logged as statements, while normal changes (e.g., using INSERT, DELETE,
and/or UPDATE) is logged according to the format in effect.
The log tables (i.e., general_log and slow_log) are not replicated at all.
With this patch, the following statements are replicated as statements:
GRANT, REVOKE (ALL), CREATE USER, DROP USER, and RENAME USER.
2007-02-26 10:19:08 +01:00
|
|
|
/*
|
|
|
|
This statement will be replicated as a statement, even when using
|
|
|
|
row-based replication. The flag will be reset at the end of the
|
|
|
|
statement.
|
|
|
|
*/
|
|
|
|
thd->clear_current_stmt_binlog_row_based();
|
|
|
|
|
2003-04-01 22:49:40 +02:00
|
|
|
#ifdef HAVE_REPLICATION
|
|
|
|
/*
|
|
|
|
GRANT and REVOKE are applied the slave in/exclusion rules as they are
|
|
|
|
some kind of updates to the mysql.% tables.
|
|
|
|
*/
|
2005-03-08 21:12:35 +01:00
|
|
|
if (thd->slave_thread && rpl_filter->is_on())
|
2003-08-02 16:10:26 +02:00
|
|
|
{
|
2003-08-11 21:44:43 +02:00
|
|
|
/*
|
|
|
|
The tables must be marked "updating" so that tables_ok() takes them into
|
|
|
|
account in tests.
|
2003-08-02 16:10:26 +02:00
|
|
|
*/
|
2003-08-07 19:16:37 +02:00
|
|
|
tables[0].updating= tables[1].updating= 1;
|
2005-05-09 11:43:09 +02:00
|
|
|
if (!(thd->spcont || rpl_filter->tables_ok(0, tables)))
|
2004-10-20 03:04:37 +02:00
|
|
|
DBUG_RETURN(FALSE);
|
2003-08-02 16:10:26 +02:00
|
|
|
}
|
2003-04-01 22:49:40 +02:00
|
|
|
#endif
|
|
|
|
|
2004-02-01 14:30:32 +01:00
|
|
|
if (simple_open_n_lock_tables(thd,tables))
|
2000-07-31 21:29:14 +02:00
|
|
|
{ // This should never happen
|
|
|
|
close_thread_tables(thd); /* purecov: deadcode */
|
2004-10-20 03:04:37 +02:00
|
|
|
DBUG_RETURN(TRUE); /* purecov: deadcode */
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2001-08-10 16:37:37 +02:00
|
|
|
if (!revoke_grant)
|
|
|
|
create_new_users= test_if_create_new_users(thd);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2003-06-23 19:03:59 +02:00
|
|
|
/* go through users in user_list */
|
2002-10-02 12:33:08 +02:00
|
|
|
rw_wrlock(&LOCK_grant);
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_lock(&acl_cache->lock);
|
2000-07-31 21:29:14 +02:00
|
|
|
grant_version++;
|
|
|
|
|
|
|
|
int result=0;
|
2006-06-29 12:50:44 +02:00
|
|
|
while ((tmp_Str = str_list++))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2006-06-29 12:50:44 +02:00
|
|
|
if (!(Str= get_current_user(thd, tmp_Str)))
|
|
|
|
{
|
|
|
|
result= TRUE;
|
|
|
|
continue;
|
2006-09-27 16:21:29 +02:00
|
|
|
}
|
2009-10-30 06:06:10 +01:00
|
|
|
/*
|
|
|
|
No User, but a password?
|
|
|
|
They did GRANT ... TO CURRENT_USER() IDENTIFIED BY ... !
|
|
|
|
Get the current user, and shallow-copy the new password to them!
|
|
|
|
*/
|
|
|
|
if (!tmp_Str->user.str && tmp_Str->password.str)
|
|
|
|
Str->password= tmp_Str->password;
|
2005-03-23 19:18:25 +01:00
|
|
|
if (replace_user_table(thd, tables[0].table, *Str,
|
|
|
|
(!db ? rights : 0), revoke_grant, create_new_users,
|
2005-03-29 11:37:36 +02:00
|
|
|
test(thd->variables.sql_mode &
|
|
|
|
MODE_NO_AUTO_CREATE_USER)))
|
2001-07-17 20:04:01 +02:00
|
|
|
result= -1;
|
2003-05-31 20:35:20 +02:00
|
|
|
else if (db)
|
2001-08-10 16:37:37 +02:00
|
|
|
{
|
2003-05-31 20:35:20 +02:00
|
|
|
ulong db_rights= rights & DB_ACLS;
|
|
|
|
if (db_rights == rights)
|
|
|
|
{
|
|
|
|
if (replace_db_table(tables[1].table, db, *Str, db_rights,
|
|
|
|
revoke_grant))
|
|
|
|
result= -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-02-21 15:15:26 +01:00
|
|
|
my_error(ER_WRONG_USAGE, MYF(0), "DB GRANT", "GLOBAL PRIVILEGES");
|
2003-09-11 18:06:23 +02:00
|
|
|
result= -1;
|
2003-05-31 20:35:20 +02:00
|
|
|
}
|
2001-08-10 16:37:37 +02:00
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_unlock(&acl_cache->lock);
|
2006-10-03 19:38:25 +02:00
|
|
|
|
|
|
|
if (!result)
|
|
|
|
{
|
2009-11-21 05:28:01 +01:00
|
|
|
result= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
|
2006-10-03 19:38:25 +02:00
|
|
|
}
|
|
|
|
|
2002-10-02 12:33:08 +02:00
|
|
|
rw_unlock(&LOCK_grant);
|
2000-07-31 21:29:14 +02:00
|
|
|
close_thread_tables(thd);
|
|
|
|
|
|
|
|
if (!result)
|
2008-02-19 13:45:21 +01:00
|
|
|
my_ok(thd);
|
2006-10-03 19:38:25 +02:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
DBUG_RETURN(result);
|
|
|
|
}
|
|
|
|
|
2002-06-12 14:04:18 +02:00
|
|
|
|
|
|
|
/* Free grant array if possible */
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
void grant_free(void)
|
|
|
|
{
|
|
|
|
DBUG_ENTER("grant_free");
|
2009-10-14 18:37:38 +02:00
|
|
|
my_hash_free(&column_priv_hash);
|
|
|
|
my_hash_free(&proc_priv_hash);
|
|
|
|
my_hash_free(&func_priv_hash);
|
2000-09-12 02:02:33 +02:00
|
|
|
free_root(&memex,MYF(0));
|
2000-07-31 21:29:14 +02:00
|
|
|
DBUG_VOID_RETURN;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-11-26 19:09:40 +01:00
|
|
|
/**
|
|
|
|
@brief Initialize structures responsible for table/column-level privilege
|
|
|
|
checking and load information for them from tables in the 'mysql' database.
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2007-11-26 19:09:40 +01:00
|
|
|
@return Error status
|
|
|
|
@retval 0 OK
|
|
|
|
@retval 1 Could not initialize grant subsystem.
|
2005-09-01 14:52:59 +02:00
|
|
|
*/
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2005-09-01 14:52:59 +02:00
|
|
|
my_bool grant_init()
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2002-10-29 20:59:03 +01:00
|
|
|
THD *thd;
|
2005-09-01 14:52:59 +02:00
|
|
|
my_bool return_val;
|
|
|
|
DBUG_ENTER("grant_init");
|
|
|
|
|
|
|
|
if (!(thd= new THD))
|
|
|
|
DBUG_RETURN(1); /* purecov: deadcode */
|
2005-11-23 19:18:10 +01:00
|
|
|
thd->thread_stack= (char*) &thd;
|
2005-09-01 14:52:59 +02:00
|
|
|
thd->store_globals();
|
|
|
|
return_val= grant_reload(thd);
|
|
|
|
delete thd;
|
|
|
|
/* Remember that we don't have a THD */
|
|
|
|
my_pthread_setspecific_ptr(THR_THD, 0);
|
|
|
|
DBUG_RETURN(return_val);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-11-26 19:09:40 +01:00
|
|
|
/**
|
|
|
|
@brief Helper function to grant_reload_procs_priv
|
2005-09-01 14:52:59 +02:00
|
|
|
|
2007-11-26 19:09:40 +01:00
|
|
|
Reads the procs_priv table into memory hash.
|
2005-09-01 14:52:59 +02:00
|
|
|
|
2007-11-26 19:09:40 +01:00
|
|
|
@param table A pointer to the procs_priv table structure.
|
|
|
|
|
|
|
|
@see grant_reload
|
|
|
|
@see grant_reload_procs_priv
|
|
|
|
|
|
|
|
@return Error state
|
|
|
|
@retval TRUE An error occurred
|
|
|
|
@retval FALSE Success
|
2005-09-01 14:52:59 +02:00
|
|
|
*/
|
|
|
|
|
2007-11-26 19:09:40 +01:00
|
|
|
static my_bool grant_load_procs_priv(TABLE *p_table)
|
2005-09-01 14:52:59 +02:00
|
|
|
{
|
2004-11-08 00:13:54 +01:00
|
|
|
MEM_ROOT *memex_ptr;
|
2002-09-05 15:17:08 +02:00
|
|
|
my_bool return_val= 1;
|
2003-11-20 09:55:48 +01:00
|
|
|
bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE;
|
2005-09-01 14:52:59 +02:00
|
|
|
MEM_ROOT **save_mem_root_ptr= my_pthread_getspecific_ptr(MEM_ROOT**,
|
|
|
|
THR_MALLOC);
|
2008-04-08 15:57:44 +02:00
|
|
|
DBUG_ENTER("grant_load_procs_priv");
|
2009-11-06 15:20:27 +01:00
|
|
|
(void) my_hash_init(&proc_priv_hash, &my_charset_utf8_bin,
|
2009-10-14 18:37:38 +02:00
|
|
|
0,0,0, (my_hash_get_key) get_grant_table,
|
|
|
|
0,0);
|
2009-11-06 15:20:27 +01:00
|
|
|
(void) my_hash_init(&func_priv_hash, &my_charset_utf8_bin,
|
2009-10-14 18:37:38 +02:00
|
|
|
0,0,0, (my_hash_get_key) get_grant_table,
|
|
|
|
0,0);
|
2005-07-18 13:31:02 +02:00
|
|
|
p_table->file->ha_index_init(0, 1);
|
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes
Changes that requires code changes in other code of other storage engines.
(Note that all changes are very straightforward and one should find all issues
by compiling a --debug build and fixing all compiler errors and all
asserts in field.cc while running the test suite),
- New optional handler function introduced: reset()
This is called after every DML statement to make it easy for a handler to
statement specific cleanups.
(The only case it's not called is if force the file to be closed)
- handler::extra(HA_EXTRA_RESET) is removed. Code that was there before
should be moved to handler::reset()
- table->read_set contains a bitmap over all columns that are needed
in the query. read_row() and similar functions only needs to read these
columns
- table->write_set contains a bitmap over all columns that will be updated
in the query. write_row() and update_row() only needs to update these
columns.
The above bitmaps should now be up to date in all context
(including ALTER TABLE, filesort()).
The handler is informed of any changes to the bitmap after
fix_fields() by calling the virtual function
handler::column_bitmaps_signal(). If the handler does caching of
these bitmaps (instead of using table->read_set, table->write_set),
it should redo the caching in this code. as the signal() may be sent
several times, it's probably best to set a variable in the signal
and redo the caching on read_row() / write_row() if the variable was
set.
- Removed the read_set and write_set bitmap objects from the handler class
- Removed all column bit handling functions from the handler class.
(Now one instead uses the normal bitmap functions in my_bitmap.c instead
of handler dedicated bitmap functions)
- field->query_id is removed. One should instead instead check
table->read_set and table->write_set if a field is used in the query.
- handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and
handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now
instead use table->read_set to check for which columns to retrieve.
- If a handler needs to call Field->val() or Field->store() on columns
that are not used in the query, one should install a temporary
all-columns-used map while doing so. For this, we provide the following
functions:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
field->val();
dbug_tmp_restore_column_map(table->read_set, old_map);
and similar for the write map:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
field->val();
dbug_tmp_restore_column_map(table->write_set, old_map);
If this is not done, you will sooner or later hit a DBUG_ASSERT
in the field store() / val() functions.
(For not DBUG binaries, the dbug_tmp_restore_column_map() and
dbug_tmp_restore_column_map() are inline dummy functions and should
be optimized away be the compiler).
- If one needs to temporary set the column map for all binaries (and not
just to avoid the DBUG_ASSERT() in the Field::store() / Field::val()
methods) one should use the functions tmp_use_all_columns() and
tmp_restore_column_map() instead of the above dbug_ variants.
- All 'status' fields in the handler base class (like records,
data_file_length etc) are now stored in a 'stats' struct. This makes
it easier to know what status variables are provided by the base
handler. This requires some trivial variable names in the extra()
function.
- New virtual function handler::records(). This is called to optimize
COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true.
(stats.records is not supposed to be an exact value. It's only has to
be 'reasonable enough' for the optimizer to be able to choose a good
optimization path).
- Non virtual handler::init() function added for caching of virtual
constants from engine.
- Removed has_transactions() virtual method. Now one should instead return
HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support
transactions.
- The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument
that is to be used with 'new handler_name()' to allocate the handler
in the right area. The xxxx_create_handler() function is also
responsible for any initialization of the object before returning.
For example, one should change:
static handler *myisam_create_handler(TABLE_SHARE *table)
{
return new ha_myisam(table);
}
->
static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisam(table);
}
- New optional virtual function: use_hidden_primary_key().
This is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key. This allows the handler to take precisions
in remembering any hidden primary key to able to update/delete any
found row. The default handler marks all columns to be read.
- handler::table_flags() now returns a ulonglong (to allow for more flags).
- New/changed table_flags()
- HA_HAS_RECORDS Set if ::records() is supported
- HA_NO_TRANSACTIONS Set if engine doesn't support transactions
- HA_PRIMARY_KEY_REQUIRED_FOR_DELETE
Set if we should mark all primary key columns for
read when reading rows as part of a DELETE
statement. If there is no primary key,
all columns are marked for read.
- HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some
cases (based on table->read_set)
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
- HA_DUPP_POS Renamed to HA_DUPLICATE_POS
- HA_REQUIRES_KEY_COLUMNS_FOR_DELETE
Set this if we should mark ALL key columns for
read when when reading rows as part of a DELETE
statement. In case of an update we will mark
all keys for read for which key part changed
value.
- HA_STATS_RECORDS_IS_EXACT
Set this if stats.records is exact.
(This saves us some extra records() calls
when optimizing COUNT(*))
- Removed table_flags()
- HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if
handler::records() gives an exact count() and
HA_STATS_RECORDS_IS_EXACT if stats.records is exact.
- HA_READ_RND_SAME Removed (no one supported this one)
- Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk()
- Renamed handler::dupp_pos to handler::dup_pos
- Removed not used variable handler::sortkey
Upper level handler changes:
- ha_reset() now does some overall checks and calls ::reset()
- ha_table_flags() added. This is a cached version of table_flags(). The
cache is updated on engine creation time and updated on open.
MySQL level changes (not obvious from the above):
- DBUG_ASSERT() added to check that column usage matches what is set
in the column usage bit maps. (This found a LOT of bugs in current
column marking code).
- In 5.1 before, all used columns was marked in read_set and only updated
columns was marked in write_set. Now we only mark columns for which we
need a value in read_set.
- Column bitmaps are created in open_binary_frm() and open_table_from_share().
(Before this was in table.cc)
- handler::table_flags() calls are replaced with handler::ha_table_flags()
- For calling field->val() you must have the corresponding bit set in
table->read_set. For calling field->store() you must have the
corresponding bit set in table->write_set. (There are asserts in
all store()/val() functions to catch wrong usage)
- thd->set_query_id is renamed to thd->mark_used_columns and instead
of setting this to an integer value, this has now the values:
MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE
Changed also all variables named 'set_query_id' to mark_used_columns.
- In filesort() we now inform the handler of exactly which columns are needed
doing the sort and choosing the rows.
- The TABLE_SHARE object has a 'all_set' column bitmap one can use
when one needs a column bitmap with all columns set.
(This is used for table->use_all_columns() and other places)
- The TABLE object has 3 column bitmaps:
- def_read_set Default bitmap for columns to be read
- def_write_set Default bitmap for columns to be written
- tmp_set Can be used as a temporary bitmap when needed.
The table object has also two pointer to bitmaps read_set and write_set
that the handler should use to find out which columns are used in which way.
- count() optimization now calls handler::records() instead of using
handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true).
- Added extra argument to Item::walk() to indicate if we should also
traverse sub queries.
- Added TABLE parameter to cp_buffer_from_ref()
- Don't close tables created with CREATE ... SELECT but keep them in
the table cache. (Faster usage of newly created tables).
New interfaces:
- table->clear_column_bitmaps() to initialize the bitmaps for tables
at start of new statements.
- table->column_bitmaps_set() to set up new column bitmaps and signal
the handler about this.
- table->column_bitmaps_set_no_signal() for some few cases where we need
to setup new column bitmaps but don't signal the handler (as the handler
has already been signaled about these before). Used for the momement
only in opt_range.cc when doing ROR scans.
- table->use_all_columns() to install a bitmap where all columns are marked
as use in the read and the write set.
- table->default_column_bitmaps() to install the normal read and write
column bitmaps, but not signaling the handler about this.
This is mainly used when creating TABLE instances.
- table->mark_columns_needed_for_delete(),
table->mark_columns_needed_for_delete() and
table->mark_columns_needed_for_insert() to allow us to put additional
columns in column usage maps if handler so requires.
(The handler indicates what it neads in handler->table_flags())
- table->prepare_for_position() to allow us to tell handler that it
needs to read primary key parts to be able to store them in
future table->position() calls.
(This replaces the table->file->ha_retrieve_all_pk function)
- table->mark_auto_increment_column() to tell handler are going to update
columns part of any auto_increment key.
- table->mark_columns_used_by_index() to mark all columns that is part of
an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow
it to quickly know that it only needs to read colums that are part
of the key. (The handler can also use the column map for detecting this,
but simpler/faster handler can just monitor the extra() call).
- table->mark_columns_used_by_index_no_reset() to in addition to other columns,
also mark all columns that is used by the given key.
- table->restore_column_maps_after_mark_index() to restore to default
column maps after a call to table->mark_columns_used_by_index().
- New item function register_field_in_read_map(), for marking used columns
in table->read_map. Used by filesort() to mark all used columns
- Maintain in TABLE->merge_keys set of all keys that are used in query.
(Simplices some optimization loops)
- Maintain Field->part_of_key_not_clustered which is like Field->part_of_key
but the field in the clustered key is not assumed to be part of all index.
(used in opt_range.cc for faster loops)
- dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map()
tmp_use_all_columns() and tmp_restore_column_map() functions to temporally
mark all columns as usable. The 'dbug_' version is primarily intended
inside a handler when it wants to just call Field:store() & Field::val()
functions, but don't need the column maps set for any other usage.
(ie:: bitmap_is_set() is never called)
- We can't use compare_records() to skip updates for handlers that returns
a partial column set and the read_set doesn't cover all columns in the
write set. The reason for this is that if we have a column marked only for
write we can't in the MySQL level know if the value changed or not.
The reason this worked before was that MySQL marked all to be written
columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden
bug'.
- open_table_from_share() does not anymore setup temporary MEM_ROOT
object as a thread specific variable for the handler. Instead we
send the to-be-used MEMROOT to get_new_handler().
(Simpler, faster code)
Bugs fixed:
- Column marking was not done correctly in a lot of cases.
(ALTER TABLE, when using triggers, auto_increment fields etc)
(Could potentially result in wrong values inserted in table handlers
relying on that the old column maps or field->set_query_id was correct)
Especially when it comes to triggers, there may be cases where the
old code would cause lost/wrong values for NDB and/or InnoDB tables.
- Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags:
OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG.
This allowed me to remove some wrong warnings about:
"Some non-transactional changed tables couldn't be rolled back"
- Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset
(thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose
some warnings about
"Some non-transactional changed tables couldn't be rolled back")
- Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table()
which could cause delete_table to report random failures.
- Fixed core dumps for some tests when running with --debug
- Added missing FN_LIBCHAR in mysql_rm_tmp_tables()
(This has probably caused us to not properly remove temporary files after
crash)
- slow_logs was not properly initialized, which could maybe cause
extra/lost entries in slow log.
- If we get an duplicate row on insert, change column map to read and
write all columns while retrying the operation. This is required by
the definition of REPLACE and also ensures that fields that are only
part of UPDATE are properly handled. This fixed a bug in NDB and
REPLACE where REPLACE wrongly copied some column values from the replaced
row.
- For table handler that doesn't support NULL in keys, we would give an error
when creating a primary key with NULL fields, even after the fields has been
automaticly converted to NOT NULL.
- Creating a primary key on a SPATIAL key, would fail if field was not
declared as NOT NULL.
Cleanups:
- Removed not used condition argument to setup_tables
- Removed not needed item function reset_query_id_processor().
- Field->add_index is removed. Now this is instead maintained in
(field->flags & FIELD_IN_ADD_INDEX)
- Field->fieldnr is removed (use field->field_index instead)
- New argument to filesort() to indicate that it should return a set of
row pointers (not used columns). This allowed me to remove some references
to sql_command in filesort and should also enable us to return column
results in some cases where we couldn't before.
- Changed column bitmap handling in opt_range.cc to be aligned with TABLE
bitmap, which allowed me to use bitmap functions instead of looping over
all fields to create some needed bitmaps. (Faster and smaller code)
- Broke up found too long lines
- Moved some variable declaration at start of function for better code
readability.
- Removed some not used arguments from functions.
(setup_fields(), mysql_prepare_insert_check_table())
- setup_fields() now takes an enum instead of an int for marking columns
usage.
- For internal temporary tables, use handler::write_row(),
handler::delete_row() and handler::update_row() instead of
handler::ha_xxxx() for faster execution.
- Changed some constants to enum's and define's.
- Using separate column read and write sets allows for easier checking
of timestamp field was set by statement.
- Remove calls to free_io_cache() as this is now done automaticly in ha_reset()
- Don't build table->normalized_path as this is now identical to table->path
(after bar's fixes to convert filenames)
- Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to
do comparision with the 'convert-dbug-for-diff' tool.
Things left to do in 5.1:
- We wrongly log failed CREATE TABLE ... SELECT in some cases when using
row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result)
Mats has promised to look into this.
- Test that my fix for CREATE TABLE ... SELECT is indeed correct.
(I added several test cases for this, but in this case it's better that
someone else also tests this throughly).
Lars has promosed to do this.
2006-06-04 17:52:22 +02:00
|
|
|
p_table->use_all_columns();
|
2007-11-26 19:09:40 +01:00
|
|
|
|
|
|
|
if (!p_table->file->index_first(p_table->record[0]))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-12-23 11:46:24 +01:00
|
|
|
memex_ptr= &memex;
|
|
|
|
my_pthread_setspecific_ptr(THR_MALLOC, &memex_ptr);
|
|
|
|
do
|
|
|
|
{
|
2007-11-26 19:09:40 +01:00
|
|
|
GRANT_NAME *mem_check;
|
|
|
|
HASH *hash;
|
2009-10-27 11:09:36 +01:00
|
|
|
if (!(mem_check=new (memex_ptr) GRANT_NAME(p_table, TRUE)))
|
2004-12-23 11:46:24 +01:00
|
|
|
{
|
2007-11-26 19:09:40 +01:00
|
|
|
/* This could only happen if we are out memory */
|
|
|
|
goto end_unlock;
|
2004-12-23 11:46:24 +01:00
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2004-12-23 11:46:24 +01:00
|
|
|
if (check_no_resolve)
|
|
|
|
{
|
2005-03-04 02:44:28 +01:00
|
|
|
if (hostname_requires_resolving(mem_check->host.hostname))
|
2004-12-23 11:46:24 +01:00
|
|
|
{
|
2007-11-26 19:09:40 +01:00
|
|
|
sql_print_warning("'procs_priv' entry '%s %s@%s' "
|
2004-12-23 11:46:24 +01:00
|
|
|
"ignored in --skip-name-resolve mode.",
|
2007-11-26 19:09:40 +01:00
|
|
|
mem_check->tname, mem_check->user,
|
2006-06-06 13:21:07 +02:00
|
|
|
mem_check->host.hostname ?
|
|
|
|
mem_check->host.hostname : "");
|
2007-11-26 19:09:40 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (p_table->field[4]->val_int() == TYPE_ENUM_PROCEDURE)
|
|
|
|
{
|
|
|
|
hash= &proc_priv_hash;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (p_table->field[4]->val_int() == TYPE_ENUM_FUNCTION)
|
|
|
|
{
|
|
|
|
hash= &func_priv_hash;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sql_print_warning("'procs_priv' entry '%s' "
|
|
|
|
"ignored, bad routine type",
|
|
|
|
mem_check->tname);
|
|
|
|
continue;
|
2004-12-23 11:46:24 +01:00
|
|
|
}
|
|
|
|
|
2007-11-26 19:09:40 +01:00
|
|
|
mem_check->privs= fix_rights_for_procedure(mem_check->privs);
|
2004-12-23 11:46:24 +01:00
|
|
|
if (! mem_check->ok())
|
2007-11-26 19:09:40 +01:00
|
|
|
delete mem_check;
|
|
|
|
else if (my_hash_insert(hash, (uchar*) mem_check))
|
2004-12-23 11:46:24 +01:00
|
|
|
{
|
2007-11-26 19:09:40 +01:00
|
|
|
delete mem_check;
|
|
|
|
goto end_unlock;
|
2004-12-23 11:46:24 +01:00
|
|
|
}
|
|
|
|
}
|
2007-11-26 19:09:40 +01:00
|
|
|
while (!p_table->file->index_next(p_table->record[0]));
|
2004-12-23 11:46:24 +01:00
|
|
|
}
|
2007-11-26 19:09:40 +01:00
|
|
|
/* Return ok */
|
|
|
|
return_val= 0;
|
|
|
|
|
|
|
|
end_unlock:
|
|
|
|
p_table->file->ha_index_end();
|
|
|
|
my_pthread_setspecific_ptr(THR_MALLOC, save_mem_root_ptr);
|
|
|
|
DBUG_RETURN(return_val);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@brief Initialize structures responsible for table/column-level privilege
|
|
|
|
checking and load information about grants from open privilege tables.
|
|
|
|
|
|
|
|
@param thd Current thread
|
|
|
|
@param tables List containing open "mysql.tables_priv" and
|
|
|
|
"mysql.columns_priv" tables.
|
|
|
|
|
|
|
|
@see grant_reload
|
|
|
|
|
|
|
|
@return Error state
|
|
|
|
@retval FALSE Success
|
|
|
|
@retval TRUE Error
|
|
|
|
*/
|
|
|
|
|
2008-02-24 13:58:07 +01:00
|
|
|
static my_bool grant_load(THD *thd, TABLE_LIST *tables)
|
2007-11-26 19:09:40 +01:00
|
|
|
{
|
|
|
|
MEM_ROOT *memex_ptr;
|
|
|
|
my_bool return_val= 1;
|
|
|
|
TABLE *t_table= 0, *c_table= 0;
|
|
|
|
bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE;
|
|
|
|
MEM_ROOT **save_mem_root_ptr= my_pthread_getspecific_ptr(MEM_ROOT**,
|
|
|
|
THR_MALLOC);
|
2008-02-24 13:58:07 +01:00
|
|
|
ulong old_sql_mode= thd->variables.sql_mode;
|
2007-11-26 19:09:40 +01:00
|
|
|
DBUG_ENTER("grant_load");
|
2008-02-24 13:58:07 +01:00
|
|
|
|
|
|
|
thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH;
|
|
|
|
|
2009-11-06 15:20:27 +01:00
|
|
|
(void) my_hash_init(&column_priv_hash, &my_charset_utf8_bin,
|
2009-10-14 18:37:38 +02:00
|
|
|
0,0,0, (my_hash_get_key) get_grant_table,
|
|
|
|
(my_hash_free_key) free_grant_table,0);
|
2007-11-26 19:09:40 +01:00
|
|
|
|
|
|
|
t_table = tables[0].table;
|
|
|
|
c_table = tables[1].table;
|
|
|
|
t_table->file->ha_index_init(0, 1);
|
|
|
|
t_table->use_all_columns();
|
|
|
|
c_table->use_all_columns();
|
|
|
|
|
|
|
|
if (!t_table->file->index_first(t_table->record[0]))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-12-23 11:46:24 +01:00
|
|
|
memex_ptr= &memex;
|
|
|
|
my_pthread_setspecific_ptr(THR_MALLOC, &memex_ptr);
|
|
|
|
do
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2007-11-26 19:09:40 +01:00
|
|
|
GRANT_TABLE *mem_check;
|
|
|
|
if (!(mem_check=new (memex_ptr) GRANT_TABLE(t_table,c_table)))
|
2004-12-23 11:46:24 +01:00
|
|
|
{
|
|
|
|
/* This could only happen if we are out memory */
|
|
|
|
goto end_unlock;
|
|
|
|
}
|
2003-11-20 09:55:48 +01:00
|
|
|
|
2004-12-23 11:46:24 +01:00
|
|
|
if (check_no_resolve)
|
2003-11-20 09:55:48 +01:00
|
|
|
{
|
2005-03-04 00:01:46 +01:00
|
|
|
if (hostname_requires_resolving(mem_check->host.hostname))
|
2004-12-23 11:46:24 +01:00
|
|
|
{
|
2007-11-26 19:09:40 +01:00
|
|
|
sql_print_warning("'tables_priv' entry '%s %s@%s' "
|
2004-12-23 11:46:24 +01:00
|
|
|
"ignored in --skip-name-resolve mode.",
|
2007-11-26 19:09:40 +01:00
|
|
|
mem_check->tname,
|
|
|
|
mem_check->user ? mem_check->user : "",
|
2006-06-06 13:21:07 +02:00
|
|
|
mem_check->host.hostname ?
|
|
|
|
mem_check->host.hostname : "");
|
2004-12-23 11:46:24 +01:00
|
|
|
continue;
|
|
|
|
}
|
2003-11-20 09:55:48 +01:00
|
|
|
}
|
|
|
|
|
2004-12-23 11:46:24 +01:00
|
|
|
if (! mem_check->ok())
|
|
|
|
delete mem_check;
|
2007-11-26 19:09:40 +01:00
|
|
|
else if (my_hash_insert(&column_priv_hash,(uchar*) mem_check))
|
2004-12-23 11:46:24 +01:00
|
|
|
{
|
|
|
|
delete mem_check;
|
|
|
|
goto end_unlock;
|
|
|
|
}
|
2003-11-20 09:55:48 +01:00
|
|
|
}
|
2007-11-26 19:09:40 +01:00
|
|
|
while (!t_table->file->index_next(t_table->record[0]));
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2007-11-26 19:09:40 +01:00
|
|
|
|
2002-09-05 15:17:08 +02:00
|
|
|
return_val=0; // Return ok
|
|
|
|
|
|
|
|
end_unlock:
|
2008-02-24 13:58:07 +01:00
|
|
|
thd->variables.sql_mode= old_sql_mode;
|
2004-06-23 12:29:05 +02:00
|
|
|
t_table->file->ha_index_end();
|
2005-09-01 14:52:59 +02:00
|
|
|
my_pthread_setspecific_ptr(THR_MALLOC, save_mem_root_ptr);
|
2002-09-05 15:17:08 +02:00
|
|
|
DBUG_RETURN(return_val);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-11-26 19:09:40 +01:00
|
|
|
/**
|
|
|
|
@brief Helper function to grant_reload. Reloads procs_priv table is it
|
|
|
|
exists.
|
2003-06-23 19:03:59 +02:00
|
|
|
|
2007-11-26 19:09:40 +01:00
|
|
|
@param thd A pointer to the thread handler object.
|
2003-06-23 19:03:59 +02:00
|
|
|
|
2007-11-26 19:09:40 +01:00
|
|
|
@see grant_reload
|
2005-09-01 14:52:59 +02:00
|
|
|
|
2007-11-26 19:09:40 +01:00
|
|
|
@return Error state
|
|
|
|
@retval FALSE Success
|
|
|
|
@retval TRUE An error has occurred.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static my_bool grant_reload_procs_priv(THD *thd)
|
|
|
|
{
|
|
|
|
HASH old_proc_priv_hash, old_func_priv_hash;
|
|
|
|
TABLE_LIST table;
|
|
|
|
my_bool return_val= FALSE;
|
|
|
|
DBUG_ENTER("grant_reload_procs_priv");
|
|
|
|
|
|
|
|
bzero((char*) &table, sizeof(table));
|
|
|
|
table.alias= table.table_name= (char*) "procs_priv";
|
|
|
|
table.db= (char *) "mysql";
|
|
|
|
table.lock_type= TL_READ;
|
2008-04-08 15:57:44 +02:00
|
|
|
table.skip_temporary= 1;
|
2007-11-26 19:09:40 +01:00
|
|
|
|
|
|
|
if (simple_open_n_lock_tables(thd, &table))
|
|
|
|
{
|
|
|
|
close_thread_tables(thd);
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
|
2009-12-08 13:19:38 +01:00
|
|
|
rw_wrlock(&LOCK_grant);
|
2007-11-26 19:09:40 +01:00
|
|
|
/* Save a copy of the current hash if we need to undo the grant load */
|
|
|
|
old_proc_priv_hash= proc_priv_hash;
|
|
|
|
old_func_priv_hash= func_priv_hash;
|
|
|
|
|
|
|
|
if ((return_val= grant_load_procs_priv(table.table)))
|
|
|
|
{
|
|
|
|
/* Error; Reverting to old hash */
|
|
|
|
DBUG_PRINT("error",("Reverting to old privileges"));
|
|
|
|
grant_free();
|
|
|
|
proc_priv_hash= old_proc_priv_hash;
|
|
|
|
func_priv_hash= old_func_priv_hash;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-10-14 18:37:38 +02:00
|
|
|
my_hash_free(&old_proc_priv_hash);
|
|
|
|
my_hash_free(&old_func_priv_hash);
|
2007-11-26 19:09:40 +01:00
|
|
|
}
|
|
|
|
rw_unlock(&LOCK_grant);
|
|
|
|
|
|
|
|
close_thread_tables(thd);
|
|
|
|
DBUG_RETURN(return_val);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@brief Reload information about table and column level privileges if possible
|
|
|
|
|
|
|
|
@param thd Current thread
|
|
|
|
|
|
|
|
Locked tables are checked by acl_reload() and doesn't have to be checked
|
|
|
|
in this call.
|
|
|
|
This function is also used for initialization of structures responsible
|
|
|
|
for table/column-level privilege checking.
|
|
|
|
|
|
|
|
@return Error state
|
|
|
|
@retval FALSE Success
|
|
|
|
@retval TRUE Error
|
2003-06-23 19:03:59 +02:00
|
|
|
*/
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2005-09-01 14:52:59 +02:00
|
|
|
my_bool grant_reload(THD *thd)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2007-11-26 19:09:40 +01:00
|
|
|
TABLE_LIST tables[2];
|
|
|
|
HASH old_column_priv_hash;
|
2000-07-31 21:29:14 +02:00
|
|
|
MEM_ROOT old_mem;
|
2005-09-01 14:52:59 +02:00
|
|
|
my_bool return_val= 1;
|
2000-07-31 21:29:14 +02:00
|
|
|
DBUG_ENTER("grant_reload");
|
|
|
|
|
2005-09-01 14:52:59 +02:00
|
|
|
/* Don't do anything if running with --skip-grant-tables */
|
|
|
|
if (!initialized)
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
|
|
|
|
bzero((char*) tables, sizeof(tables));
|
2005-09-01 23:01:33 +02:00
|
|
|
tables[0].alias= tables[0].table_name= (char*) "tables_priv";
|
|
|
|
tables[1].alias= tables[1].table_name= (char*) "columns_priv";
|
2007-11-26 19:09:40 +01:00
|
|
|
tables[0].db= tables[1].db= (char *) "mysql";
|
2005-09-01 23:01:33 +02:00
|
|
|
tables[0].next_local= tables[0].next_global= tables+1;
|
2007-11-26 19:09:40 +01:00
|
|
|
tables[0].lock_type= tables[1].lock_type= TL_READ;
|
2008-04-08 15:57:44 +02:00
|
|
|
tables[0].skip_temporary= tables[1].skip_temporary= TRUE;
|
2005-09-01 14:52:59 +02:00
|
|
|
/*
|
|
|
|
To avoid deadlocks we should obtain table locks before
|
|
|
|
obtaining LOCK_grant rwlock.
|
|
|
|
*/
|
|
|
|
if (simple_open_n_lock_tables(thd, tables))
|
|
|
|
goto end;
|
|
|
|
|
2002-10-02 12:33:08 +02:00
|
|
|
rw_wrlock(&LOCK_grant);
|
2003-01-18 15:39:21 +01:00
|
|
|
old_column_priv_hash= column_priv_hash;
|
2007-11-26 19:09:40 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
Create a new memory pool but save the current memory pool to make an undo
|
|
|
|
opertion possible in case of failure.
|
|
|
|
*/
|
2003-05-19 15:35:49 +02:00
|
|
|
old_mem= memex;
|
2007-11-26 19:09:40 +01:00
|
|
|
init_sql_alloc(&memex, ACL_ALLOC_BLOCK_SIZE, 0);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2008-02-24 13:58:07 +01:00
|
|
|
if ((return_val= grant_load(thd, tables)))
|
2000-07-31 21:29:14 +02:00
|
|
|
{ // Error. Revert to old hash
|
2003-01-18 15:39:21 +01:00
|
|
|
DBUG_PRINT("error",("Reverting to old privileges"));
|
2000-07-31 21:29:14 +02:00
|
|
|
grant_free(); /* purecov: deadcode */
|
2003-01-18 15:39:21 +01:00
|
|
|
column_priv_hash= old_column_priv_hash; /* purecov: deadcode */
|
2003-05-19 15:35:49 +02:00
|
|
|
memex= old_mem; /* purecov: deadcode */
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-10-14 18:37:38 +02:00
|
|
|
my_hash_free(&old_column_priv_hash);
|
2000-09-12 02:02:33 +02:00
|
|
|
free_root(&old_mem,MYF(0));
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2002-10-02 12:33:08 +02:00
|
|
|
rw_unlock(&LOCK_grant);
|
2005-09-01 14:52:59 +02:00
|
|
|
close_thread_tables(thd);
|
2007-11-26 19:09:40 +01:00
|
|
|
|
|
|
|
/*
|
2007-12-12 16:21:01 +01:00
|
|
|
It is OK failing to load procs_priv table because we may be
|
2007-11-26 19:09:40 +01:00
|
|
|
working with 4.1 privilege tables.
|
|
|
|
*/
|
|
|
|
if (grant_reload_procs_priv(thd))
|
2007-12-12 16:21:01 +01:00
|
|
|
return_val= 1;
|
2007-11-26 19:09:40 +01:00
|
|
|
|
|
|
|
rw_wrlock(&LOCK_grant);
|
|
|
|
grant_version++;
|
|
|
|
rw_unlock(&LOCK_grant);
|
|
|
|
|
|
|
|
end:
|
2005-09-01 14:52:59 +02:00
|
|
|
DBUG_RETURN(return_val);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2004-09-03 20:43:04 +02:00
|
|
|
|
2009-10-19 14:58:13 +02:00
|
|
|
/**
|
|
|
|
@brief Check table level grants
|
|
|
|
|
|
|
|
@param thd Thread handler
|
|
|
|
@param want_access Bits of privileges user needs to have.
|
|
|
|
@param tables List of tables to check. The user should have
|
|
|
|
'want_access' to all tables in list.
|
|
|
|
@param any_combination_will_do TRUE if it's enough to have any privilege for
|
|
|
|
any combination of the table columns.
|
|
|
|
@param number Check at most this number of tables.
|
|
|
|
@param no_errors TRUE if no error should be sent directly to the client.
|
|
|
|
|
|
|
|
If table->grant.want_privilege != 0 then the requested privileges where
|
|
|
|
in the set of COL_ACLS but access was not granted on the table level. As
|
|
|
|
a consequence an extra check of column privileges is required.
|
|
|
|
|
|
|
|
Specifically if this function returns FALSE the user has some kind of
|
|
|
|
privilege on a combination of columns in each table.
|
|
|
|
|
|
|
|
This function is usually preceeded by check_access which establish the
|
|
|
|
User-, Db- and Host access rights.
|
|
|
|
|
|
|
|
@see check_access
|
|
|
|
@see check_table_access
|
|
|
|
|
|
|
|
@note This functions assumes that either number of tables to be inspected
|
2006-03-20 10:42:02 +01:00
|
|
|
by it is limited explicitly (i.e. is is not UINT_MAX) or table list
|
|
|
|
used and thd->lex->query_tables_own_last value correspond to each
|
|
|
|
other (the latter should be either 0 or point to next_global member
|
|
|
|
of one of elements of this table list).
|
2009-10-19 14:58:13 +02:00
|
|
|
|
|
|
|
@return Access status
|
|
|
|
@retval FALSE Access granted; But column privileges might need to be
|
|
|
|
checked.
|
|
|
|
@retval TRUE The user did not have the requested privileges on any of the
|
|
|
|
tables.
|
|
|
|
|
|
|
|
*/
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2002-06-12 14:04:18 +02:00
|
|
|
bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
|
2009-10-19 14:58:13 +02:00
|
|
|
bool any_combination_will_do, uint number, bool no_errors)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2005-10-27 23:18:23 +02:00
|
|
|
TABLE_LIST *table, *first_not_own_table= thd->lex->first_not_own_table();
|
2005-09-20 20:20:38 +02:00
|
|
|
Security_context *sctx= thd->security_ctx;
|
2005-10-27 23:18:23 +02:00
|
|
|
uint i;
|
2004-09-03 20:43:04 +02:00
|
|
|
DBUG_ENTER("check_grant");
|
|
|
|
DBUG_ASSERT(number > 0);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2005-10-27 23:18:23 +02:00
|
|
|
/*
|
2005-10-27 23:56:44 +02:00
|
|
|
Walk through the list of tables that belong to the query and save the
|
|
|
|
requested access (orig_want_privilege) to be able to use it when
|
|
|
|
checking access rights to the underlying tables of a view. Our grant
|
|
|
|
system gradually eliminates checked bits from want_privilege and thus
|
|
|
|
after all checks are done we can no longer use it.
|
|
|
|
The check that first_not_own_table is not reached is for the case when
|
|
|
|
the given table list refers to the list for prelocking (contains tables
|
|
|
|
of other queries). For simple queries first_not_own_table is 0.
|
2005-10-27 23:18:23 +02:00
|
|
|
*/
|
|
|
|
for (i= 0, table= tables;
|
2008-01-30 16:27:41 +01:00
|
|
|
i < number && table != first_not_own_table;
|
2005-10-27 23:18:23 +02:00
|
|
|
table= table->next_global, i++)
|
|
|
|
{
|
2009-10-19 14:58:13 +02:00
|
|
|
/*
|
|
|
|
Save a copy of the privileges without the SHOW_VIEW_ACL attribute.
|
|
|
|
It will be checked during making view.
|
|
|
|
*/
|
2005-10-27 23:18:23 +02:00
|
|
|
table->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL);
|
|
|
|
}
|
|
|
|
|
2002-10-02 12:33:08 +02:00
|
|
|
rw_rdlock(&LOCK_grant);
|
2005-10-27 23:18:23 +02:00
|
|
|
for (table= tables;
|
|
|
|
table && number-- && table != first_not_own_table;
|
|
|
|
table= table->next_global)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-09-03 20:43:04 +02:00
|
|
|
GRANT_TABLE *grant_table;
|
2006-05-26 10:47:53 +02:00
|
|
|
sctx = test(table->security_ctx) ?
|
|
|
|
table->security_ctx : thd->security_ctx;
|
|
|
|
|
|
|
|
want_access&= ~sctx->master_access;
|
|
|
|
if (!want_access)
|
|
|
|
continue; // ok
|
|
|
|
|
2008-09-03 16:45:40 +02:00
|
|
|
if (!(~table->grant.privilege & want_access) ||
|
|
|
|
table->is_anonymous_derived_table() || table->schema_table)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-07-16 00:15:55 +02:00
|
|
|
/*
|
|
|
|
It is subquery in the FROM clause. VIEW set table->derived after
|
|
|
|
table opening, but this function always called before table opening.
|
|
|
|
*/
|
2005-10-27 23:18:23 +02:00
|
|
|
if (!table->referencing_view)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
If it's a temporary table created for a subquery in the FROM
|
|
|
|
clause, or an INFORMATION_SCHEMA table, drop the request for
|
|
|
|
a privilege.
|
|
|
|
*/
|
|
|
|
table->grant.want_privilege= 0;
|
|
|
|
}
|
|
|
|
continue;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2005-09-15 21:29:07 +02:00
|
|
|
if (!(grant_table= table_hash_search(sctx->host, sctx->ip,
|
2008-09-03 16:45:40 +02:00
|
|
|
table->get_db_name(), sctx->priv_user,
|
|
|
|
table->get_table_name(), FALSE)))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
want_access &= ~table->grant.privilege;
|
|
|
|
goto err; // No grants
|
|
|
|
}
|
2009-10-19 14:58:13 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
For SHOW COLUMNS, SHOW INDEX it is enough to have some
|
|
|
|
privileges on any column combination on the table.
|
|
|
|
*/
|
|
|
|
if (any_combination_will_do)
|
|
|
|
continue;
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
table->grant.grant_table=grant_table; // Remember for column test
|
|
|
|
table->grant.version=grant_version;
|
|
|
|
table->grant.privilege|= grant_table->privs;
|
|
|
|
table->grant.want_privilege= ((want_access & COL_ACLS)
|
|
|
|
& ~table->grant.privilege);
|
|
|
|
|
|
|
|
if (!(~table->grant.privilege & want_access))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (want_access & ~(grant_table->cols | table->grant.privilege))
|
|
|
|
{
|
|
|
|
want_access &= ~(grant_table->cols | table->grant.privilege);
|
|
|
|
goto err; // impossible
|
|
|
|
}
|
|
|
|
}
|
2002-10-02 12:33:08 +02:00
|
|
|
rw_unlock(&LOCK_grant);
|
2009-10-19 14:58:13 +02:00
|
|
|
DBUG_RETURN(FALSE);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2003-06-23 19:03:59 +02:00
|
|
|
err:
|
2002-10-02 12:33:08 +02:00
|
|
|
rw_unlock(&LOCK_grant);
|
2001-08-10 16:37:37 +02:00
|
|
|
if (!no_errors) // Not a silent skip of table
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-12-30 21:01:11 +01:00
|
|
|
char command[128];
|
|
|
|
get_privilege_desc(command, sizeof(command), want_access);
|
2004-11-13 18:35:51 +01:00
|
|
|
my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0),
|
|
|
|
command,
|
2005-09-15 21:29:07 +02:00
|
|
|
sctx->priv_user,
|
|
|
|
sctx->host_or_ip,
|
2008-09-03 16:45:40 +02:00
|
|
|
table ? table->get_table_name() : "unknown");
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2009-10-19 14:58:13 +02:00
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
Check if all tables in the table list has any of the requested table level
|
|
|
|
privileges matching the current user.
|
|
|
|
|
|
|
|
@param thd A pointer to the thread context.
|
|
|
|
@param required_access Set of privileges to compare against.
|
|
|
|
@param tables[in,out] A list of tables to be checked.
|
|
|
|
|
|
|
|
@note If the table grant hash contains any grant table, this table will be
|
|
|
|
attached to the corresponding TABLE_LIST object in 'tables'.
|
|
|
|
|
|
|
|
@return
|
|
|
|
@retval TRUE There is a privilege on the table level granted to the
|
|
|
|
current user.
|
|
|
|
@retval FALSE There are no privileges on the table level granted to the
|
|
|
|
current user.
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool has_any_table_level_privileges(THD *thd, ulong required_access,
|
|
|
|
TABLE_LIST *tables)
|
|
|
|
{
|
|
|
|
|
|
|
|
Security_context *sctx;
|
|
|
|
GRANT_TABLE *grant_table;
|
|
|
|
TABLE_LIST *table;
|
|
|
|
|
|
|
|
/* For each table in tables */
|
|
|
|
for (table= tables; table; table= table->next_global)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
If this table is a VIEW, then it will supply its own security context.
|
|
|
|
This is because VIEWs can have a DEFINER or an INVOKER security role.
|
|
|
|
*/
|
|
|
|
sctx= table->security_ctx ? table->security_ctx : thd->security_ctx;
|
|
|
|
|
|
|
|
/*
|
|
|
|
Get privileges from table_priv and column_priv tables by searching
|
|
|
|
the cache.
|
|
|
|
*/
|
|
|
|
rw_rdlock(&LOCK_grant);
|
|
|
|
grant_table= table_hash_search(sctx->host, sctx->ip,
|
|
|
|
table->db, sctx->priv_user,
|
|
|
|
table->table_name,0);
|
|
|
|
rw_unlock(&LOCK_grant);
|
|
|
|
|
|
|
|
/* Stop if there are no grants for the current user */
|
|
|
|
if (!grant_table)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
/*
|
|
|
|
Save a pointer to the found grant_table in the table object.
|
|
|
|
This pointer can later be used to verify other access requirements
|
|
|
|
without having to look up the grant table in the hash.
|
|
|
|
*/
|
|
|
|
table->grant.grant_table= grant_table;
|
|
|
|
table->grant.version= grant_version;
|
|
|
|
table->grant.privilege|= grant_table->privs;
|
|
|
|
/*
|
|
|
|
Save all privileges which might be subject to column privileges
|
|
|
|
but not which aren't yet granted by table level ACLs.
|
|
|
|
This is can later be used for column privilege checks.
|
|
|
|
*/
|
|
|
|
table->grant.want_privilege= ((required_access & COL_ACLS)
|
|
|
|
& ~table->grant.privilege);
|
|
|
|
|
|
|
|
/*
|
|
|
|
If the requested privileges share any intersection with the current
|
|
|
|
table privileges we have found at least one common privilege on the
|
|
|
|
table level.
|
|
|
|
*/
|
|
|
|
if (grant_table->privs & required_access)
|
|
|
|
continue; /* Check next table */
|
|
|
|
|
|
|
|
/*
|
|
|
|
There are no table level privileges which satisfies any of the
|
|
|
|
requested privileges. There might still be column privileges which
|
|
|
|
does though.
|
|
|
|
*/
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
All tables in TABLE_LIST satisfy the requirement of having any
|
|
|
|
privilege on the table level.
|
|
|
|
*/
|
|
|
|
|
|
|
|
return TRUE;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-11-30 20:27:11 +01:00
|
|
|
/*
|
|
|
|
Check column rights in given security context
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
check_grant_column()
|
|
|
|
thd thread handler
|
|
|
|
grant grant information structure
|
|
|
|
db_name db name
|
|
|
|
table_name table name
|
|
|
|
name column name
|
|
|
|
length column name length
|
|
|
|
sctx security context
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
FALSE OK
|
|
|
|
TRUE access denied
|
|
|
|
*/
|
|
|
|
|
2004-07-16 00:15:55 +02:00
|
|
|
bool check_grant_column(THD *thd, GRANT_INFO *grant,
|
2005-01-06 12:00:13 +01:00
|
|
|
const char *db_name, const char *table_name,
|
2005-11-30 20:27:11 +01:00
|
|
|
const char *name, uint length, Security_context *sctx)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
GRANT_TABLE *grant_table;
|
|
|
|
GRANT_COLUMN *grant_column;
|
2004-07-16 00:15:55 +02:00
|
|
|
ulong want_access= grant->want_privilege & ~grant->privilege;
|
2004-12-30 23:44:00 +01:00
|
|
|
DBUG_ENTER("check_grant_column");
|
2006-11-20 21:42:06 +01:00
|
|
|
DBUG_PRINT("enter", ("table: %s want_access: %lu", table_name, want_access));
|
2004-12-30 23:44:00 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
if (!want_access)
|
2004-12-30 23:44:00 +01:00
|
|
|
DBUG_RETURN(0); // Already checked
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2002-10-02 12:33:08 +02:00
|
|
|
rw_rdlock(&LOCK_grant);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2003-06-23 19:03:59 +02:00
|
|
|
/* reload table if someone has modified any grants */
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2004-07-16 00:15:55 +02:00
|
|
|
if (grant->version != grant_version)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-07-16 00:15:55 +02:00
|
|
|
grant->grant_table=
|
2005-09-15 21:29:07 +02:00
|
|
|
table_hash_search(sctx->host, sctx->ip, db_name,
|
|
|
|
sctx->priv_user,
|
2004-12-30 23:44:00 +01:00
|
|
|
table_name, 0); /* purecov: inspected */
|
2004-07-16 00:15:55 +02:00
|
|
|
grant->version= grant_version; /* purecov: inspected */
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2004-07-16 00:15:55 +02:00
|
|
|
if (!(grant_table= grant->grant_table))
|
2000-07-31 21:29:14 +02:00
|
|
|
goto err; /* purecov: deadcode */
|
|
|
|
|
|
|
|
grant_column=column_hash_search(grant_table, name, length);
|
|
|
|
if (grant_column && !(~grant_column->rights & want_access))
|
|
|
|
{
|
2002-10-02 12:33:08 +02:00
|
|
|
rw_unlock(&LOCK_grant);
|
2004-12-30 23:44:00 +01:00
|
|
|
DBUG_RETURN(0);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2003-05-07 22:59:24 +02:00
|
|
|
err:
|
2002-10-02 12:33:08 +02:00
|
|
|
rw_unlock(&LOCK_grant);
|
2005-11-30 20:27:11 +01:00
|
|
|
char command[128];
|
|
|
|
get_privilege_desc(command, sizeof(command), want_access);
|
|
|
|
my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0),
|
|
|
|
command,
|
|
|
|
sctx->priv_user,
|
|
|
|
sctx->host_or_ip,
|
|
|
|
name,
|
|
|
|
table_name);
|
|
|
|
DBUG_RETURN(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Check the access right to a column depending on the type of table.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
check_column_grant_in_table_ref()
|
|
|
|
thd thread handler
|
|
|
|
table_ref table reference where to check the field
|
|
|
|
name name of field to check
|
|
|
|
length length of name
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
Check the access rights to a column depending on the type of table
|
|
|
|
reference where the column is checked. The function provides a
|
|
|
|
generic interface to check column access rights that hides the
|
|
|
|
heterogeneity of the column representation - whether it is a view
|
|
|
|
or a stored table colum.
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
FALSE OK
|
|
|
|
TRUE access denied
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool check_column_grant_in_table_ref(THD *thd, TABLE_LIST * table_ref,
|
|
|
|
const char *name, uint length)
|
|
|
|
{
|
|
|
|
GRANT_INFO *grant;
|
|
|
|
const char *db_name;
|
|
|
|
const char *table_name;
|
|
|
|
Security_context *sctx= test(table_ref->security_ctx) ?
|
|
|
|
table_ref->security_ctx : thd->security_ctx;
|
|
|
|
|
|
|
|
if (table_ref->view || table_ref->field_translation)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2005-11-30 20:27:11 +01:00
|
|
|
/* View or derived information schema table. */
|
2006-07-25 14:23:25 +02:00
|
|
|
ulong view_privs;
|
2005-11-30 20:27:11 +01:00
|
|
|
grant= &(table_ref->grant);
|
|
|
|
db_name= table_ref->view_db.str;
|
|
|
|
table_name= table_ref->view_name.str;
|
2006-07-25 14:23:25 +02:00
|
|
|
if (table_ref->belong_to_view &&
|
2009-09-28 13:25:47 +02:00
|
|
|
thd->lex->sql_command == SQLCOM_SHOW_FIELDS)
|
2006-07-25 14:23:25 +02:00
|
|
|
{
|
|
|
|
view_privs= get_column_grant(thd, grant, db_name, table_name, name);
|
|
|
|
if (view_privs & VIEW_ANY_ACL)
|
|
|
|
{
|
|
|
|
table_ref->belong_to_view->allowed_show= TRUE;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
table_ref->belong_to_view->allowed_show= FALSE;
|
|
|
|
my_message(ER_VIEW_NO_EXPLAIN, ER(ER_VIEW_NO_EXPLAIN), MYF(0));
|
|
|
|
return TRUE;
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2005-11-30 20:27:11 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Normal or temporary table. */
|
|
|
|
TABLE *table= table_ref->table;
|
|
|
|
grant= &(table->grant);
|
2005-12-07 12:58:33 +01:00
|
|
|
db_name= table->s->db.str;
|
|
|
|
table_name= table->s->table_name.str;
|
2005-11-30 20:27:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (grant->want_privilege)
|
|
|
|
return check_grant_column(thd, grant, db_name, table_name, name,
|
|
|
|
length, sctx);
|
|
|
|
else
|
|
|
|
return FALSE;
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-09-27 11:15:19 +02:00
|
|
|
/**
|
|
|
|
@brief check if a query can access a set of columns
|
|
|
|
|
|
|
|
@param thd the current thread
|
|
|
|
@param want_access_arg the privileges requested
|
|
|
|
@param fields an iterator over the fields of a table reference.
|
|
|
|
@return Operation status
|
|
|
|
@retval 0 Success
|
|
|
|
@retval 1 Falure
|
|
|
|
@details This function walks over the columns of a table reference
|
|
|
|
The columns may originate from different tables, depending on the kind of
|
2008-09-03 16:45:40 +02:00
|
|
|
table reference, e.g. join, view.
|
2007-09-27 11:15:19 +02:00
|
|
|
For each table it will retrieve the grant information and will use it
|
|
|
|
to check the required access privileges for the fields requested from it.
|
|
|
|
*/
|
|
|
|
bool check_grant_all_columns(THD *thd, ulong want_access_arg,
|
|
|
|
Field_iterator_table_ref *fields)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2005-09-20 20:20:38 +02:00
|
|
|
Security_context *sctx= thd->security_ctx;
|
2007-09-27 11:15:19 +02:00
|
|
|
ulong want_access= want_access_arg;
|
|
|
|
const char *table_name= NULL;
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2007-09-27 11:32:59 +02:00
|
|
|
const char* db_name;
|
|
|
|
GRANT_INFO *grant;
|
2007-09-27 17:02:21 +02:00
|
|
|
/* Initialized only to make gcc happy */
|
|
|
|
GRANT_TABLE *grant_table= NULL;
|
2008-09-03 16:45:40 +02:00
|
|
|
/*
|
|
|
|
Flag that gets set if privilege checking has to be performed on column
|
|
|
|
level.
|
|
|
|
*/
|
|
|
|
bool using_column_privileges= FALSE;
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2002-10-02 12:33:08 +02:00
|
|
|
rw_rdlock(&LOCK_grant);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2004-09-03 20:43:04 +02:00
|
|
|
for (; !fields->end_of_fields(); fields->next())
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-07-16 00:15:55 +02:00
|
|
|
const char *field_name= fields->name();
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2008-09-03 16:45:40 +02:00
|
|
|
if (table_name != fields->get_table_name())
|
2007-09-27 11:32:59 +02:00
|
|
|
{
|
2008-09-03 16:45:40 +02:00
|
|
|
table_name= fields->get_table_name();
|
|
|
|
db_name= fields->get_db_name();
|
2007-09-27 11:32:59 +02:00
|
|
|
grant= fields->grant();
|
|
|
|
/* get a fresh one for each table */
|
|
|
|
want_access= want_access_arg & ~grant->privilege;
|
|
|
|
if (want_access)
|
2007-09-27 11:15:19 +02:00
|
|
|
{
|
2007-09-27 11:32:59 +02:00
|
|
|
/* reload table if someone has modified any grants */
|
|
|
|
if (grant->version != grant_version)
|
2007-09-27 11:15:19 +02:00
|
|
|
{
|
2007-09-27 11:32:59 +02:00
|
|
|
grant->grant_table=
|
|
|
|
table_hash_search(sctx->host, sctx->ip, db_name,
|
|
|
|
sctx->priv_user,
|
|
|
|
table_name, 0); /* purecov: inspected */
|
|
|
|
grant->version= grant_version; /* purecov: inspected */
|
2007-09-27 11:15:19 +02:00
|
|
|
}
|
|
|
|
|
2007-09-27 13:33:55 +02:00
|
|
|
grant_table= grant->grant_table;
|
|
|
|
DBUG_ASSERT (grant_table);
|
2007-09-27 11:15:19 +02:00
|
|
|
}
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2007-09-27 11:32:59 +02:00
|
|
|
if (want_access)
|
|
|
|
{
|
|
|
|
GRANT_COLUMN *grant_column=
|
|
|
|
column_hash_search(grant_table, field_name,
|
|
|
|
(uint) strlen(field_name));
|
2008-09-03 16:45:40 +02:00
|
|
|
if (grant_column)
|
|
|
|
using_column_privileges= TRUE;
|
2007-09-27 11:32:59 +02:00
|
|
|
if (!grant_column || (~grant_column->rights & want_access))
|
|
|
|
goto err;
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2002-10-02 12:33:08 +02:00
|
|
|
rw_unlock(&LOCK_grant);
|
2000-07-31 21:29:14 +02:00
|
|
|
return 0;
|
|
|
|
|
2003-05-19 15:35:49 +02:00
|
|
|
err:
|
2002-10-02 12:33:08 +02:00
|
|
|
rw_unlock(&LOCK_grant);
|
2007-09-27 11:15:19 +02:00
|
|
|
|
2004-12-30 21:01:11 +01:00
|
|
|
char command[128];
|
|
|
|
get_privilege_desc(command, sizeof(command), want_access);
|
2008-09-03 16:45:40 +02:00
|
|
|
/*
|
|
|
|
Do not give an error message listing a column name unless the user has
|
|
|
|
privilege to see all columns.
|
|
|
|
*/
|
|
|
|
if (using_column_privileges)
|
|
|
|
my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0),
|
|
|
|
command, sctx->priv_user,
|
|
|
|
sctx->host_or_ip, table_name);
|
|
|
|
else
|
|
|
|
my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0),
|
|
|
|
command,
|
|
|
|
sctx->priv_user,
|
|
|
|
sctx->host_or_ip,
|
|
|
|
fields->name(),
|
|
|
|
table_name);
|
2000-07-31 21:29:14 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-03-23 12:12:11 +01:00
|
|
|
static bool check_grant_db_routine(THD *thd, const char *db, HASH *hash)
|
|
|
|
{
|
|
|
|
Security_context *sctx= thd->security_ctx;
|
|
|
|
|
|
|
|
for (uint idx= 0; idx < hash->records; ++idx)
|
|
|
|
{
|
2009-10-14 18:37:38 +02:00
|
|
|
GRANT_NAME *item= (GRANT_NAME*) my_hash_element(hash, idx);
|
2007-03-23 12:12:11 +01:00
|
|
|
|
|
|
|
if (strcmp(item->user, sctx->priv_user) == 0 &&
|
|
|
|
strcmp(item->db, db) == 0 &&
|
|
|
|
compare_hostname(&item->host, sctx->host, sctx->ip))
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-06-23 19:03:59 +02:00
|
|
|
/*
|
2002-06-12 14:04:18 +02:00
|
|
|
Check if a user has the right to access a database
|
2004-12-23 11:46:24 +01:00
|
|
|
Access is accepted if he has a grant for any table/routine in the database
|
2002-06-12 14:04:18 +02:00
|
|
|
Return 1 if access is denied
|
2003-06-23 19:03:59 +02:00
|
|
|
*/
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
bool check_grant_db(THD *thd,const char *db)
|
|
|
|
{
|
2005-09-20 20:20:38 +02:00
|
|
|
Security_context *sctx= thd->security_ctx;
|
2006-09-27 16:21:29 +02:00
|
|
|
char helping [NAME_LEN+USERNAME_LENGTH+2];
|
2000-07-31 21:29:14 +02:00
|
|
|
uint len;
|
2007-03-23 12:12:11 +01:00
|
|
|
bool error= TRUE;
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2005-09-15 21:29:07 +02:00
|
|
|
len= (uint) (strmov(strmov(helping, sctx->priv_user) + 1, db) - helping) + 1;
|
2007-03-23 12:12:11 +01:00
|
|
|
|
2002-10-02 12:33:08 +02:00
|
|
|
rw_rdlock(&LOCK_grant);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2003-01-18 15:39:21 +01:00
|
|
|
for (uint idx=0 ; idx < column_priv_hash.records ; idx++)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2009-10-14 18:37:38 +02:00
|
|
|
GRANT_TABLE *grant_table= (GRANT_TABLE*)
|
|
|
|
my_hash_element(&column_priv_hash,
|
|
|
|
idx);
|
2000-07-31 21:29:14 +02:00
|
|
|
if (len < grant_table->key_length &&
|
|
|
|
!memcmp(grant_table->hash_key,helping,len) &&
|
2005-09-15 21:29:07 +02:00
|
|
|
compare_hostname(&grant_table->host, sctx->host, sctx->ip))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2007-03-23 12:12:11 +01:00
|
|
|
error= FALSE; /* Found match. */
|
2000-07-31 21:29:14 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2007-03-23 12:12:11 +01:00
|
|
|
|
|
|
|
if (error)
|
|
|
|
error= check_grant_db_routine(thd, db, &proc_priv_hash) &&
|
|
|
|
check_grant_db_routine(thd, db, &func_priv_hash);
|
|
|
|
|
2002-10-02 12:33:08 +02:00
|
|
|
rw_unlock(&LOCK_grant);
|
2007-03-23 12:12:11 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2004-12-23 11:46:24 +01:00
|
|
|
|
|
|
|
/****************************************************************************
|
2005-05-17 20:54:20 +02:00
|
|
|
Check routine level grants
|
2004-12-23 11:46:24 +01:00
|
|
|
|
|
|
|
SYNPOSIS
|
2005-05-17 20:54:20 +02:00
|
|
|
bool check_grant_routine()
|
2004-12-23 11:46:24 +01:00
|
|
|
thd Thread handler
|
|
|
|
want_access Bits of privileges user needs to have
|
2005-05-17 20:54:20 +02:00
|
|
|
procs List of routines to check. The user should have 'want_access'
|
|
|
|
is_proc True if the list is all procedures, else functions
|
2004-12-23 11:46:24 +01:00
|
|
|
no_errors If 0 then we write an error. The error is sent directly to
|
|
|
|
the client
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
0 ok
|
|
|
|
1 Error: User did not have the requested privielges
|
|
|
|
****************************************************************************/
|
|
|
|
|
2005-09-15 21:29:07 +02:00
|
|
|
bool check_grant_routine(THD *thd, ulong want_access,
|
2005-05-17 20:54:20 +02:00
|
|
|
TABLE_LIST *procs, bool is_proc, bool no_errors)
|
2004-12-23 11:46:24 +01:00
|
|
|
{
|
|
|
|
TABLE_LIST *table;
|
2005-09-20 20:20:38 +02:00
|
|
|
Security_context *sctx= thd->security_ctx;
|
2005-09-15 21:29:07 +02:00
|
|
|
char *user= sctx->priv_user;
|
|
|
|
char *host= sctx->priv_host;
|
2005-05-17 20:54:20 +02:00
|
|
|
DBUG_ENTER("check_grant_routine");
|
2004-12-23 11:46:24 +01:00
|
|
|
|
2005-09-15 21:29:07 +02:00
|
|
|
want_access&= ~sctx->master_access;
|
2004-12-23 11:46:24 +01:00
|
|
|
if (!want_access)
|
|
|
|
DBUG_RETURN(0); // ok
|
|
|
|
|
|
|
|
rw_rdlock(&LOCK_grant);
|
|
|
|
for (table= procs; table; table= table->next_global)
|
|
|
|
{
|
|
|
|
GRANT_NAME *grant_proc;
|
2005-09-15 21:29:07 +02:00
|
|
|
if ((grant_proc= routine_hash_search(host, sctx->ip, table->db, user,
|
2005-05-17 20:54:20 +02:00
|
|
|
table->table_name, is_proc, 0)))
|
2004-12-23 11:46:24 +01:00
|
|
|
table->grant.privilege|= grant_proc->privs;
|
|
|
|
|
|
|
|
if (want_access & ~table->grant.privilege)
|
|
|
|
{
|
|
|
|
want_access &= ~table->grant.privilege;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
rw_unlock(&LOCK_grant);
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
err:
|
|
|
|
rw_unlock(&LOCK_grant);
|
|
|
|
if (!no_errors)
|
|
|
|
{
|
|
|
|
char buff[1024];
|
|
|
|
const char *command="";
|
|
|
|
if (table)
|
2005-01-06 12:00:13 +01:00
|
|
|
strxmov(buff, table->db, ".", table->table_name, NullS);
|
2004-12-23 11:46:24 +01:00
|
|
|
if (want_access & EXECUTE_ACL)
|
|
|
|
command= "execute";
|
|
|
|
else if (want_access & ALTER_PROC_ACL)
|
2005-05-17 20:54:20 +02:00
|
|
|
command= "alter routine";
|
2004-12-23 11:46:24 +01:00
|
|
|
else if (want_access & GRANT_ACL)
|
|
|
|
command= "grant";
|
|
|
|
my_error(ER_PROCACCESS_DENIED_ERROR, MYF(0),
|
|
|
|
command, user, host, table ? buff : "unknown");
|
|
|
|
}
|
|
|
|
DBUG_RETURN(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-03-05 12:35:32 +01:00
|
|
|
/*
|
|
|
|
Check if routine has any of the
|
2005-05-17 20:54:20 +02:00
|
|
|
routine level grants
|
2005-03-05 12:35:32 +01:00
|
|
|
|
|
|
|
SYNPOSIS
|
|
|
|
bool check_routine_level_acl()
|
|
|
|
thd Thread handler
|
|
|
|
db Database name
|
|
|
|
name Routine name
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
0 Ok
|
2005-03-15 15:07:28 +01:00
|
|
|
1 error
|
2005-03-05 12:35:32 +01:00
|
|
|
*/
|
|
|
|
|
2005-05-18 00:49:01 +02:00
|
|
|
bool check_routine_level_acl(THD *thd, const char *db, const char *name,
|
|
|
|
bool is_proc)
|
2005-03-05 12:35:32 +01:00
|
|
|
{
|
|
|
|
bool no_routine_acl= 1;
|
2007-05-28 14:08:04 +02:00
|
|
|
GRANT_NAME *grant_proc;
|
|
|
|
Security_context *sctx= thd->security_ctx;
|
|
|
|
rw_rdlock(&LOCK_grant);
|
|
|
|
if ((grant_proc= routine_hash_search(sctx->priv_host,
|
|
|
|
sctx->ip, db,
|
|
|
|
sctx->priv_user,
|
|
|
|
name, is_proc, 0)))
|
|
|
|
no_routine_acl= !(grant_proc->privs & SHOW_PROC_ACLS);
|
|
|
|
rw_unlock(&LOCK_grant);
|
2005-03-05 12:35:32 +01:00
|
|
|
return no_routine_acl;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
/*****************************************************************************
|
2002-06-12 14:04:18 +02:00
|
|
|
Functions to retrieve the grant for a table/column (for SHOW functions)
|
2000-07-31 21:29:14 +02:00
|
|
|
*****************************************************************************/
|
|
|
|
|
2002-06-12 14:04:18 +02:00
|
|
|
ulong get_table_grant(THD *thd, TABLE_LIST *table)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2002-10-02 16:55:12 +02:00
|
|
|
ulong privilege;
|
2005-09-20 20:20:38 +02:00
|
|
|
Security_context *sctx= thd->security_ctx;
|
2000-07-31 21:29:14 +02:00
|
|
|
const char *db = table->db ? table->db : thd->db;
|
|
|
|
GRANT_TABLE *grant_table;
|
|
|
|
|
2002-10-02 12:33:08 +02:00
|
|
|
rw_rdlock(&LOCK_grant);
|
2002-06-17 13:24:51 +02:00
|
|
|
#ifdef EMBEDDED_LIBRARY
|
|
|
|
grant_table= NULL;
|
|
|
|
#else
|
2005-09-15 21:29:07 +02:00
|
|
|
grant_table= table_hash_search(sctx->host, sctx->ip, db, sctx->priv_user,
|
2005-01-06 12:00:13 +01:00
|
|
|
table->table_name, 0);
|
2002-06-17 13:24:51 +02:00
|
|
|
#endif
|
2000-07-31 21:29:14 +02:00
|
|
|
table->grant.grant_table=grant_table; // Remember for column test
|
|
|
|
table->grant.version=grant_version;
|
|
|
|
if (grant_table)
|
|
|
|
table->grant.privilege|= grant_table->privs;
|
2002-09-21 20:36:23 +02:00
|
|
|
privilege= table->grant.privilege;
|
2002-10-02 12:33:08 +02:00
|
|
|
rw_unlock(&LOCK_grant);
|
2002-09-21 20:36:23 +02:00
|
|
|
return privilege;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-08-12 16:57:19 +02:00
|
|
|
/*
|
|
|
|
Determine the access priviliges for a field.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
get_column_grant()
|
|
|
|
thd thread handler
|
|
|
|
grant grants table descriptor
|
|
|
|
db_name name of database that the field belongs to
|
|
|
|
table_name name of table that the field belongs to
|
|
|
|
field_name name of field
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
The procedure may also modify: grant->grant_table and grant->version.
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
The access priviliges for the field db_name.table_name.field_name
|
|
|
|
*/
|
|
|
|
|
2004-07-16 00:15:55 +02:00
|
|
|
ulong get_column_grant(THD *thd, GRANT_INFO *grant,
|
|
|
|
const char *db_name, const char *table_name,
|
|
|
|
const char *field_name)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
GRANT_TABLE *grant_table;
|
|
|
|
GRANT_COLUMN *grant_column;
|
2002-06-12 14:04:18 +02:00
|
|
|
ulong priv;
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2002-10-02 12:33:08 +02:00
|
|
|
rw_rdlock(&LOCK_grant);
|
2003-06-23 19:03:59 +02:00
|
|
|
/* reload table if someone has modified any grants */
|
2004-07-16 00:15:55 +02:00
|
|
|
if (grant->version != grant_version)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2005-09-20 20:20:38 +02:00
|
|
|
Security_context *sctx= thd->security_ctx;
|
2004-07-16 00:15:55 +02:00
|
|
|
grant->grant_table=
|
2005-09-20 20:20:38 +02:00
|
|
|
table_hash_search(sctx->host, sctx->ip,
|
|
|
|
db_name, sctx->priv_user,
|
2004-07-16 00:15:55 +02:00
|
|
|
table_name, 0); /* purecov: inspected */
|
|
|
|
grant->version= grant_version; /* purecov: inspected */
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2004-07-16 00:15:55 +02:00
|
|
|
if (!(grant_table= grant->grant_table))
|
|
|
|
priv= grant->privilege;
|
2000-07-31 21:29:14 +02:00
|
|
|
else
|
|
|
|
{
|
2004-07-16 00:15:55 +02:00
|
|
|
grant_column= column_hash_search(grant_table, field_name,
|
|
|
|
(uint) strlen(field_name));
|
2000-07-31 21:29:14 +02:00
|
|
|
if (!grant_column)
|
2005-05-07 15:55:46 +02:00
|
|
|
priv= (grant->privilege | grant_table->privs);
|
2000-07-31 21:29:14 +02:00
|
|
|
else
|
2005-05-07 15:55:46 +02:00
|
|
|
priv= (grant->privilege | grant_table->privs | grant_column->rights);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2002-10-02 12:33:08 +02:00
|
|
|
rw_unlock(&LOCK_grant);
|
2000-07-31 21:29:14 +02:00
|
|
|
return priv;
|
|
|
|
}
|
|
|
|
|
2004-07-16 00:15:55 +02:00
|
|
|
|
2003-06-23 19:03:59 +02:00
|
|
|
/* Help function for mysql_show_grants */
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2003-06-23 19:03:59 +02:00
|
|
|
static void add_user_option(String *grant, ulong value, const char *name)
|
|
|
|
{
|
|
|
|
if (value)
|
|
|
|
{
|
|
|
|
char buff[22], *p; // just as in int2str
|
|
|
|
grant->append(' ');
|
|
|
|
grant->append(name, strlen(name));
|
|
|
|
grant->append(' ');
|
|
|
|
p=int10_to_str(value, buff, 10);
|
|
|
|
grant->append(buff,p-buff);
|
|
|
|
}
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
static const char *command_array[]=
|
2002-06-12 14:04:18 +02:00
|
|
|
{
|
2004-07-16 00:15:55 +02:00
|
|
|
"SELECT", "INSERT", "UPDATE", "DELETE", "CREATE", "DROP", "RELOAD",
|
|
|
|
"SHUTDOWN", "PROCESS","FILE", "GRANT", "REFERENCES", "INDEX",
|
|
|
|
"ALTER", "SHOW DATABASES", "SUPER", "CREATE TEMPORARY TABLES",
|
|
|
|
"LOCK TABLES", "EXECUTE", "REPLICATION SLAVE", "REPLICATION CLIENT",
|
2004-12-23 11:46:24 +01:00
|
|
|
"CREATE VIEW", "SHOW VIEW", "CREATE ROUTINE", "ALTER ROUTINE",
|
2009-10-09 22:01:10 +02:00
|
|
|
"CREATE USER", "EVENT", "TRIGGER", "CREATE TABLESPACE"
|
2002-06-12 14:04:18 +02:00
|
|
|
};
|
2003-06-23 19:03:59 +02:00
|
|
|
|
2002-06-12 14:04:18 +02:00
|
|
|
static uint command_lengths[]=
|
|
|
|
{
|
2005-03-22 15:54:18 +01:00
|
|
|
6, 6, 6, 6, 6, 4, 6, 8, 7, 4, 5, 10, 5, 5, 14, 5, 23, 11, 7, 17, 18, 11, 9,
|
2009-10-09 22:01:10 +02:00
|
|
|
14, 13, 11, 5, 7, 17
|
2002-06-12 14:04:18 +02:00
|
|
|
};
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2005-05-17 20:54:20 +02:00
|
|
|
static int show_routine_grants(THD *thd, LEX_USER *lex_user, HASH *hash,
|
|
|
|
const char *type, int typelen,
|
|
|
|
char *buff, int buffsize);
|
|
|
|
|
|
|
|
|
2003-06-23 19:03:59 +02:00
|
|
|
/*
|
|
|
|
SHOW GRANTS; Send grants for a user to the client
|
|
|
|
|
|
|
|
IMPLEMENTATION
|
|
|
|
Send to client grant-like strings depicting user@host privileges
|
|
|
|
*/
|
|
|
|
|
2004-10-20 03:04:37 +02:00
|
|
|
bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2002-06-12 14:04:18 +02:00
|
|
|
ulong want_access;
|
|
|
|
uint counter,index;
|
2000-07-31 21:29:14 +02:00
|
|
|
int error = 0;
|
2003-08-18 23:08:08 +02:00
|
|
|
ACL_USER *acl_user;
|
|
|
|
ACL_DB *acl_db;
|
2000-07-31 21:29:14 +02:00
|
|
|
char buff[1024];
|
2002-12-11 08:17:51 +01:00
|
|
|
Protocol *protocol= thd->protocol;
|
2001-08-29 22:28:55 +02:00
|
|
|
DBUG_ENTER("mysql_show_grants");
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
LINT_INIT(acl_user);
|
|
|
|
if (!initialized)
|
|
|
|
{
|
2004-02-21 15:15:26 +01:00
|
|
|
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables");
|
2004-10-20 03:04:37 +02:00
|
|
|
DBUG_RETURN(TRUE);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2004-05-05 20:24:21 +02:00
|
|
|
|
2006-05-06 09:25:59 +02:00
|
|
|
rw_rdlock(&LOCK_grant);
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_lock(&acl_cache->lock);
|
2006-05-06 09:25:59 +02:00
|
|
|
|
|
|
|
acl_user= find_acl_user(lex_user->host.str, lex_user->user.str, TRUE);
|
|
|
|
if (!acl_user)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_unlock(&acl_cache->lock);
|
2006-05-06 09:25:59 +02:00
|
|
|
rw_unlock(&LOCK_grant);
|
|
|
|
|
2004-02-21 15:15:26 +01:00
|
|
|
my_error(ER_NONEXISTING_GRANT, MYF(0),
|
|
|
|
lex_user->user.str, lex_user->host.str);
|
2004-10-20 03:04:37 +02:00
|
|
|
DBUG_RETURN(TRUE);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2003-01-29 14:31:20 +01:00
|
|
|
Item_string *field=new Item_string("",0,&my_charset_latin1);
|
2000-07-31 21:29:14 +02:00
|
|
|
List<Item> field_list;
|
|
|
|
field->name=buff;
|
|
|
|
field->max_length=1024;
|
|
|
|
strxmov(buff,"Grants for ",lex_user->user.str,"@",
|
|
|
|
lex_user->host.str,NullS);
|
|
|
|
field_list.push_back(field);
|
Backport of revno 2630.28.10, 2630.28.31, 2630.28.26, 2630.33.1,
2630.39.1, 2630.28.29, 2630.34.3, 2630.34.2, 2630.34.1, 2630.29.29,
2630.29.28, 2630.31.1, 2630.28.13, 2630.28.10, 2617.23.14 and
some other minor revisions.
This patch implements:
WL#4264 "Backup: Stabilize Service Interface" -- all the
server prerequisites except si_objects.{h,cc} themselves (they can
be just copied over, when needed).
WL#4435: Support OUT-parameters in prepared statements.
(and all issues in the initial patches for these two
tasks, that were discovered in pushbuild and during testing).
Bug#39519: mysql_stmt_close() should flush all data
associated with the statement.
After execution of a prepared statement, send OUT parameters of the invoked
stored procedure, if any, to the client.
When using the binary protocol, send the parameters in an additional result
set over the wire. When using the text protocol, assign out parameters to
the user variables from the CALL(@var1, @var2, ...) specification.
The following refactoring has been made:
- Protocol::send_fields() was renamed to Protocol::send_result_set_metadata();
- A new Protocol::send_result_set_row() was introduced to incapsulate
common functionality for sending row data.
- Signature of Protocol::prepare_for_send() was changed: this operation
does not need a list of items, the number of items is fully sufficient.
The following backward incompatible changes have been made:
- CLIENT_MULTI_RESULTS is now enabled by default in the client;
- CLIENT_PS_MULTI_RESUTLS is now enabled by default in the client.
2009-10-21 22:02:06 +02:00
|
|
|
if (protocol->send_result_set_metadata(&field_list,
|
2004-08-03 12:32:21 +02:00
|
|
|
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
|
2006-05-06 09:25:59 +02:00
|
|
|
{
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_unlock(&acl_cache->lock);
|
2006-05-06 09:25:59 +02:00
|
|
|
rw_unlock(&LOCK_grant);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2006-05-06 09:25:59 +02:00
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
/* Add first global access grants */
|
|
|
|
{
|
2004-05-14 09:16:27 +02:00
|
|
|
String global(buff,sizeof(buff),system_charset_info);
|
2000-07-31 21:29:14 +02:00
|
|
|
global.length(0);
|
2005-11-20 19:47:07 +01:00
|
|
|
global.append(STRING_WITH_LEN("GRANT "));
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2003-08-18 23:08:08 +02:00
|
|
|
want_access= acl_user->access;
|
2000-07-31 21:29:14 +02:00
|
|
|
if (test_all_bits(want_access, (GLOBAL_ACLS & ~ GRANT_ACL)))
|
2005-11-20 19:47:07 +01:00
|
|
|
global.append(STRING_WITH_LEN("ALL PRIVILEGES"));
|
2000-07-31 21:29:14 +02:00
|
|
|
else if (!(want_access & ~GRANT_ACL))
|
2005-11-20 19:47:07 +01:00
|
|
|
global.append(STRING_WITH_LEN("USAGE"));
|
2002-11-30 18:58:53 +01:00
|
|
|
else
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
bool found=0;
|
2002-06-12 14:04:18 +02:00
|
|
|
ulong j,test_access= want_access & ~GRANT_ACL;
|
2000-07-31 21:29:14 +02:00
|
|
|
for (counter=0, j = SELECT_ACL;j <= GLOBAL_ACLS;counter++,j <<= 1)
|
|
|
|
{
|
2002-11-30 18:58:53 +01:00
|
|
|
if (test_access & j)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
if (found)
|
2005-11-20 19:47:07 +01:00
|
|
|
global.append(STRING_WITH_LEN(", "));
|
2000-07-31 21:29:14 +02:00
|
|
|
found=1;
|
|
|
|
global.append(command_array[counter],command_lengths[counter]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-11-20 19:47:07 +01:00
|
|
|
global.append (STRING_WITH_LEN(" ON *.* TO '"));
|
2004-05-14 09:16:27 +02:00
|
|
|
global.append(lex_user->user.str, lex_user->user.length,
|
|
|
|
system_charset_info);
|
2005-11-20 19:47:07 +01:00
|
|
|
global.append (STRING_WITH_LEN("'@'"));
|
2004-11-25 21:55:49 +01:00
|
|
|
global.append(lex_user->host.str,lex_user->host.length,
|
|
|
|
system_charset_info);
|
2000-07-31 21:29:14 +02:00
|
|
|
global.append ('\'');
|
2003-07-01 21:40:59 +02:00
|
|
|
if (acl_user->salt_len)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2003-07-01 21:40:59 +02:00
|
|
|
char passwd_buff[SCRAMBLED_PASSWORD_CHAR_LENGTH+1];
|
|
|
|
if (acl_user->salt_len == SCRAMBLE_LENGTH)
|
|
|
|
make_password_from_salt(passwd_buff, acl_user->salt);
|
|
|
|
else
|
|
|
|
make_password_from_salt_323(passwd_buff, (ulong *) acl_user->salt);
|
2005-11-20 19:47:07 +01:00
|
|
|
global.append(STRING_WITH_LEN(" IDENTIFIED BY PASSWORD '"));
|
2003-07-01 21:40:59 +02:00
|
|
|
global.append(passwd_buff);
|
2000-07-31 21:29:14 +02:00
|
|
|
global.append('\'');
|
|
|
|
}
|
2001-09-30 04:47:34 +02:00
|
|
|
/* "show grants" SSL related stuff */
|
|
|
|
if (acl_user->ssl_type == SSL_TYPE_ANY)
|
2005-11-20 19:47:07 +01:00
|
|
|
global.append(STRING_WITH_LEN(" REQUIRE SSL"));
|
2002-06-11 10:20:31 +02:00
|
|
|
else if (acl_user->ssl_type == SSL_TYPE_X509)
|
2005-11-20 19:47:07 +01:00
|
|
|
global.append(STRING_WITH_LEN(" REQUIRE X509"));
|
2002-06-11 10:20:31 +02:00
|
|
|
else if (acl_user->ssl_type == SSL_TYPE_SPECIFIED)
|
2001-09-30 04:46:20 +02:00
|
|
|
{
|
2002-06-11 10:20:31 +02:00
|
|
|
int ssl_options = 0;
|
2005-11-20 19:47:07 +01:00
|
|
|
global.append(STRING_WITH_LEN(" REQUIRE "));
|
2001-09-30 04:47:34 +02:00
|
|
|
if (acl_user->x509_issuer)
|
|
|
|
{
|
2003-06-23 19:03:59 +02:00
|
|
|
ssl_options++;
|
2005-11-20 19:47:07 +01:00
|
|
|
global.append(STRING_WITH_LEN("ISSUER \'"));
|
2003-06-23 19:03:59 +02:00
|
|
|
global.append(acl_user->x509_issuer,strlen(acl_user->x509_issuer));
|
2002-06-11 10:20:31 +02:00
|
|
|
global.append('\'');
|
2001-09-30 04:46:20 +02:00
|
|
|
}
|
2001-09-30 04:47:34 +02:00
|
|
|
if (acl_user->x509_subject)
|
|
|
|
{
|
2003-06-23 19:03:59 +02:00
|
|
|
if (ssl_options++)
|
|
|
|
global.append(' ');
|
2005-11-20 19:47:07 +01:00
|
|
|
global.append(STRING_WITH_LEN("SUBJECT \'"));
|
2004-11-25 21:55:49 +01:00
|
|
|
global.append(acl_user->x509_subject,strlen(acl_user->x509_subject),
|
|
|
|
system_charset_info);
|
2002-06-11 10:20:31 +02:00
|
|
|
global.append('\'');
|
2001-08-29 22:28:55 +02:00
|
|
|
}
|
2001-09-30 04:47:34 +02:00
|
|
|
if (acl_user->ssl_cipher)
|
|
|
|
{
|
2003-06-23 19:03:59 +02:00
|
|
|
if (ssl_options++)
|
|
|
|
global.append(' ');
|
2005-11-20 19:47:07 +01:00
|
|
|
global.append(STRING_WITH_LEN("CIPHER '"));
|
2004-11-25 21:55:49 +01:00
|
|
|
global.append(acl_user->ssl_cipher,strlen(acl_user->ssl_cipher),
|
|
|
|
system_charset_info);
|
2002-06-11 10:20:31 +02:00
|
|
|
global.append('\'');
|
2001-09-30 04:46:20 +02:00
|
|
|
}
|
|
|
|
}
|
2002-06-12 14:04:18 +02:00
|
|
|
if ((want_access & GRANT_ACL) ||
|
2004-12-29 18:30:37 +01:00
|
|
|
(acl_user->user_resource.questions ||
|
|
|
|
acl_user->user_resource.updates ||
|
|
|
|
acl_user->user_resource.conn_per_hour ||
|
|
|
|
acl_user->user_resource.user_conn))
|
2002-05-15 12:50:38 +02:00
|
|
|
{
|
2005-11-20 19:47:07 +01:00
|
|
|
global.append(STRING_WITH_LEN(" WITH"));
|
2002-06-12 14:04:18 +02:00
|
|
|
if (want_access & GRANT_ACL)
|
2005-11-20 19:47:07 +01:00
|
|
|
global.append(STRING_WITH_LEN(" GRANT OPTION"));
|
2003-06-23 19:03:59 +02:00
|
|
|
add_user_option(&global, acl_user->user_resource.questions,
|
|
|
|
"MAX_QUERIES_PER_HOUR");
|
|
|
|
add_user_option(&global, acl_user->user_resource.updates,
|
|
|
|
"MAX_UPDATES_PER_HOUR");
|
2004-12-29 18:30:37 +01:00
|
|
|
add_user_option(&global, acl_user->user_resource.conn_per_hour,
|
2003-06-23 19:03:59 +02:00
|
|
|
"MAX_CONNECTIONS_PER_HOUR");
|
2004-12-29 18:30:37 +01:00
|
|
|
add_user_option(&global, acl_user->user_resource.user_conn,
|
|
|
|
"MAX_USER_CONNECTIONS");
|
2002-02-23 13:00:07 +01:00
|
|
|
}
|
2002-12-11 08:17:51 +01:00
|
|
|
protocol->prepare_for_resend();
|
2003-03-17 10:14:04 +01:00
|
|
|
protocol->store(global.ptr(),global.length(),global.charset());
|
2002-12-11 08:17:51 +01:00
|
|
|
if (protocol->write())
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2003-09-11 18:06:23 +02:00
|
|
|
error= -1;
|
2002-12-11 08:17:51 +01:00
|
|
|
goto end;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add database access */
|
|
|
|
for (counter=0 ; counter < acl_dbs.elements ; counter++)
|
|
|
|
{
|
2004-05-06 10:42:23 +02:00
|
|
|
const char *user, *host;
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
acl_db=dynamic_element(&acl_dbs,counter,ACL_DB*);
|
|
|
|
if (!(user=acl_db->user))
|
2004-05-05 16:05:24 +02:00
|
|
|
user= "";
|
2000-07-31 21:29:14 +02:00
|
|
|
if (!(host=acl_db->host.hostname))
|
2004-05-05 16:05:24 +02:00
|
|
|
host= "";
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2007-09-20 18:10:35 +02:00
|
|
|
/*
|
|
|
|
We do not make SHOW GRANTS case-sensitive here (like REVOKE),
|
|
|
|
but make it case-insensitive because that's the way they are
|
|
|
|
actually applied, and showing fewer privileges than are applied
|
|
|
|
would be wrong from a security point of view.
|
|
|
|
*/
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
if (!strcmp(lex_user->user.str,user) &&
|
2004-11-25 21:55:49 +01:00
|
|
|
!my_strcasecmp(system_charset_info, lex_user->host.str, host))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
want_access=acl_db->access;
|
2002-11-30 18:58:53 +01:00
|
|
|
if (want_access)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-05-14 09:16:27 +02:00
|
|
|
String db(buff,sizeof(buff),system_charset_info);
|
2000-07-31 21:29:14 +02:00
|
|
|
db.length(0);
|
2005-11-20 19:47:07 +01:00
|
|
|
db.append(STRING_WITH_LEN("GRANT "));
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
if (test_all_bits(want_access,(DB_ACLS & ~GRANT_ACL)))
|
2005-11-20 19:47:07 +01:00
|
|
|
db.append(STRING_WITH_LEN("ALL PRIVILEGES"));
|
2003-01-11 17:02:10 +01:00
|
|
|
else if (!(want_access & ~GRANT_ACL))
|
2005-11-20 19:47:07 +01:00
|
|
|
db.append(STRING_WITH_LEN("USAGE"));
|
2000-07-31 21:29:14 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
int found=0, cnt;
|
2002-06-12 14:04:18 +02:00
|
|
|
ulong j,test_access= want_access & ~GRANT_ACL;
|
2000-07-31 21:29:14 +02:00
|
|
|
for (cnt=0, j = SELECT_ACL; j <= DB_ACLS; cnt++,j <<= 1)
|
|
|
|
{
|
|
|
|
if (test_access & j)
|
|
|
|
{
|
|
|
|
if (found)
|
2005-11-20 19:47:07 +01:00
|
|
|
db.append(STRING_WITH_LEN(", "));
|
2000-07-31 21:29:14 +02:00
|
|
|
found = 1;
|
|
|
|
db.append(command_array[cnt],command_lengths[cnt]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-11-20 19:47:07 +01:00
|
|
|
db.append (STRING_WITH_LEN(" ON "));
|
2004-03-17 13:19:09 +01:00
|
|
|
append_identifier(thd, &db, acl_db->db, strlen(acl_db->db));
|
2005-11-20 19:47:07 +01:00
|
|
|
db.append (STRING_WITH_LEN(".* TO '"));
|
2004-05-14 09:16:27 +02:00
|
|
|
db.append(lex_user->user.str, lex_user->user.length,
|
|
|
|
system_charset_info);
|
2005-11-20 19:47:07 +01:00
|
|
|
db.append (STRING_WITH_LEN("'@'"));
|
2007-09-20 18:10:35 +02:00
|
|
|
// host and lex_user->host are equal except for case
|
|
|
|
db.append(host, strlen(host), system_charset_info);
|
2002-11-30 18:58:53 +01:00
|
|
|
db.append ('\'');
|
2000-07-31 21:29:14 +02:00
|
|
|
if (want_access & GRANT_ACL)
|
2005-11-20 19:47:07 +01:00
|
|
|
db.append(STRING_WITH_LEN(" WITH GRANT OPTION"));
|
2002-12-11 08:17:51 +01:00
|
|
|
protocol->prepare_for_resend();
|
2003-03-17 10:14:04 +01:00
|
|
|
protocol->store(db.ptr(),db.length(),db.charset());
|
2002-12-11 08:17:51 +01:00
|
|
|
if (protocol->write())
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2003-09-11 18:06:23 +02:00
|
|
|
error= -1;
|
2000-07-31 21:29:14 +02:00
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-04-28 16:45:08 +02:00
|
|
|
/* Add table & column access */
|
2003-01-18 15:39:21 +01:00
|
|
|
for (index=0 ; index < column_priv_hash.records ; index++)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2006-06-06 13:21:07 +02:00
|
|
|
const char *user, *host;
|
2009-10-14 18:37:38 +02:00
|
|
|
GRANT_TABLE *grant_table= (GRANT_TABLE*)
|
|
|
|
my_hash_element(&column_priv_hash, index);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
if (!(user=grant_table->user))
|
2004-04-28 16:45:08 +02:00
|
|
|
user= "";
|
2006-06-06 13:21:07 +02:00
|
|
|
if (!(host= grant_table->host.hostname))
|
|
|
|
host= "";
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2007-09-20 18:10:35 +02:00
|
|
|
/*
|
|
|
|
We do not make SHOW GRANTS case-sensitive here (like REVOKE),
|
|
|
|
but make it case-insensitive because that's the way they are
|
|
|
|
actually applied, and showing fewer privileges than are applied
|
|
|
|
would be wrong from a security point of view.
|
|
|
|
*/
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
if (!strcmp(lex_user->user.str,user) &&
|
2006-06-06 13:21:07 +02:00
|
|
|
!my_strcasecmp(system_charset_info, lex_user->host.str, host))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2003-06-23 19:03:59 +02:00
|
|
|
ulong table_access= grant_table->privs;
|
|
|
|
if ((table_access | grant_table->cols) != 0)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-05-14 09:16:27 +02:00
|
|
|
String global(buff, sizeof(buff), system_charset_info);
|
2003-09-09 19:06:50 +02:00
|
|
|
ulong test_access= (table_access | grant_table->cols) & ~GRANT_ACL;
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
global.length(0);
|
2005-11-20 19:47:07 +01:00
|
|
|
global.append(STRING_WITH_LEN("GRANT "));
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2003-06-23 19:03:59 +02:00
|
|
|
if (test_all_bits(table_access, (TABLE_ACLS & ~GRANT_ACL)))
|
2005-11-20 19:47:07 +01:00
|
|
|
global.append(STRING_WITH_LEN("ALL PRIVILEGES"));
|
2003-09-11 19:24:14 +02:00
|
|
|
else if (!test_access)
|
2005-11-20 19:47:07 +01:00
|
|
|
global.append(STRING_WITH_LEN("USAGE"));
|
2002-11-30 18:58:53 +01:00
|
|
|
else
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-04-28 16:45:08 +02:00
|
|
|
/* Add specific column access */
|
2003-06-23 19:03:59 +02:00
|
|
|
int found= 0;
|
2003-09-09 19:06:50 +02:00
|
|
|
ulong j;
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2003-06-23 19:03:59 +02:00
|
|
|
for (counter= 0, j= SELECT_ACL; j <= TABLE_ACLS; counter++, j<<= 1)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2002-11-30 18:58:53 +01:00
|
|
|
if (test_access & j)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
if (found)
|
2005-11-20 19:47:07 +01:00
|
|
|
global.append(STRING_WITH_LEN(", "));
|
2003-06-23 19:03:59 +02:00
|
|
|
found= 1;
|
2000-07-31 21:29:14 +02:00
|
|
|
global.append(command_array[counter],command_lengths[counter]);
|
|
|
|
|
2002-11-30 18:58:53 +01:00
|
|
|
if (grant_table->cols)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2003-06-23 19:03:59 +02:00
|
|
|
uint found_col= 0;
|
2000-07-31 21:29:14 +02:00
|
|
|
for (uint col_index=0 ;
|
|
|
|
col_index < grant_table->hash_columns.records ;
|
|
|
|
col_index++)
|
|
|
|
{
|
|
|
|
GRANT_COLUMN *grant_column = (GRANT_COLUMN*)
|
2009-10-14 18:37:38 +02:00
|
|
|
my_hash_element(&grant_table->hash_columns,col_index);
|
2002-11-30 18:58:53 +01:00
|
|
|
if (grant_column->rights & j)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2002-11-30 18:58:53 +01:00
|
|
|
if (!found_col)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2003-06-23 19:03:59 +02:00
|
|
|
found_col= 1;
|
|
|
|
/*
|
|
|
|
If we have a duplicated table level privilege, we
|
|
|
|
must write the access privilege name again.
|
|
|
|
*/
|
|
|
|
if (table_access & j)
|
|
|
|
{
|
2005-11-20 19:47:07 +01:00
|
|
|
global.append(STRING_WITH_LEN(", "));
|
2003-06-23 19:03:59 +02:00
|
|
|
global.append(command_array[counter],
|
|
|
|
command_lengths[counter]);
|
|
|
|
}
|
2005-11-20 19:47:07 +01:00
|
|
|
global.append(STRING_WITH_LEN(" ("));
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
else
|
2005-11-20 19:47:07 +01:00
|
|
|
global.append(STRING_WITH_LEN(", "));
|
2000-07-31 21:29:14 +02:00
|
|
|
global.append(grant_column->column,
|
2004-05-14 09:16:27 +02:00
|
|
|
grant_column->key_length,
|
|
|
|
system_charset_info);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (found_col)
|
|
|
|
global.append(')');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-11-20 19:47:07 +01:00
|
|
|
global.append(STRING_WITH_LEN(" ON "));
|
2004-03-17 13:19:09 +01:00
|
|
|
append_identifier(thd, &global, grant_table->db,
|
|
|
|
strlen(grant_table->db));
|
|
|
|
global.append('.');
|
|
|
|
append_identifier(thd, &global, grant_table->tname,
|
|
|
|
strlen(grant_table->tname));
|
2005-11-20 19:47:07 +01:00
|
|
|
global.append(STRING_WITH_LEN(" TO '"));
|
2004-05-14 09:16:27 +02:00
|
|
|
global.append(lex_user->user.str, lex_user->user.length,
|
|
|
|
system_charset_info);
|
2005-11-20 19:47:07 +01:00
|
|
|
global.append(STRING_WITH_LEN("'@'"));
|
2007-09-20 18:10:35 +02:00
|
|
|
// host and lex_user->host are equal except for case
|
|
|
|
global.append(host, strlen(host), system_charset_info);
|
2000-07-31 21:29:14 +02:00
|
|
|
global.append('\'');
|
2003-06-23 19:03:59 +02:00
|
|
|
if (table_access & GRANT_ACL)
|
2005-11-20 19:47:07 +01:00
|
|
|
global.append(STRING_WITH_LEN(" WITH GRANT OPTION"));
|
2002-12-11 08:17:51 +01:00
|
|
|
protocol->prepare_for_resend();
|
2003-03-17 10:14:04 +01:00
|
|
|
protocol->store(global.ptr(),global.length(),global.charset());
|
2002-12-11 08:17:51 +01:00
|
|
|
if (protocol->write())
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2002-10-02 16:55:12 +02:00
|
|
|
error= -1;
|
2002-09-21 20:36:23 +02:00
|
|
|
break;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2004-12-23 11:46:24 +01:00
|
|
|
|
2005-05-17 20:54:20 +02:00
|
|
|
if (show_routine_grants(thd, lex_user, &proc_priv_hash,
|
2005-11-20 19:47:07 +01:00
|
|
|
STRING_WITH_LEN("PROCEDURE"), buff, sizeof(buff)))
|
2005-05-17 20:54:20 +02:00
|
|
|
{
|
|
|
|
error= -1;
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (show_routine_grants(thd, lex_user, &func_priv_hash,
|
2005-11-20 19:47:07 +01:00
|
|
|
STRING_WITH_LEN("FUNCTION"), buff, sizeof(buff)))
|
2005-05-17 20:54:20 +02:00
|
|
|
{
|
|
|
|
error= -1;
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
end:
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_unlock(&acl_cache->lock);
|
2005-05-17 20:54:20 +02:00
|
|
|
rw_unlock(&LOCK_grant);
|
|
|
|
|
2008-02-19 13:58:08 +01:00
|
|
|
my_eof(thd);
|
2005-05-17 20:54:20 +02:00
|
|
|
DBUG_RETURN(error);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int show_routine_grants(THD* thd, LEX_USER *lex_user, HASH *hash,
|
|
|
|
const char *type, int typelen,
|
|
|
|
char *buff, int buffsize)
|
|
|
|
{
|
|
|
|
uint counter, index;
|
|
|
|
int error= 0;
|
|
|
|
Protocol *protocol= thd->protocol;
|
|
|
|
/* Add routine access */
|
|
|
|
for (index=0 ; index < hash->records ; index++)
|
2004-12-23 11:46:24 +01:00
|
|
|
{
|
2006-06-06 13:21:07 +02:00
|
|
|
const char *user, *host;
|
2009-10-14 18:37:38 +02:00
|
|
|
GRANT_NAME *grant_proc= (GRANT_NAME*) my_hash_element(hash, index);
|
2004-12-23 11:46:24 +01:00
|
|
|
|
|
|
|
if (!(user=grant_proc->user))
|
|
|
|
user= "";
|
2006-06-06 13:21:07 +02:00
|
|
|
if (!(host= grant_proc->host.hostname))
|
|
|
|
host= "";
|
2004-12-23 11:46:24 +01:00
|
|
|
|
2007-09-20 18:10:35 +02:00
|
|
|
/*
|
|
|
|
We do not make SHOW GRANTS case-sensitive here (like REVOKE),
|
|
|
|
but make it case-insensitive because that's the way they are
|
|
|
|
actually applied, and showing fewer privileges than are applied
|
|
|
|
would be wrong from a security point of view.
|
|
|
|
*/
|
|
|
|
|
2004-12-23 11:46:24 +01:00
|
|
|
if (!strcmp(lex_user->user.str,user) &&
|
2006-06-06 13:21:07 +02:00
|
|
|
!my_strcasecmp(system_charset_info, lex_user->host.str, host))
|
2004-12-23 11:46:24 +01:00
|
|
|
{
|
|
|
|
ulong proc_access= grant_proc->privs;
|
|
|
|
if (proc_access != 0)
|
|
|
|
{
|
2005-05-17 20:54:20 +02:00
|
|
|
String global(buff, buffsize, system_charset_info);
|
2004-12-23 11:46:24 +01:00
|
|
|
ulong test_access= proc_access & ~GRANT_ACL;
|
|
|
|
|
|
|
|
global.length(0);
|
2005-11-20 19:47:07 +01:00
|
|
|
global.append(STRING_WITH_LEN("GRANT "));
|
2004-12-23 11:46:24 +01:00
|
|
|
|
|
|
|
if (!test_access)
|
2005-11-20 19:47:07 +01:00
|
|
|
global.append(STRING_WITH_LEN("USAGE"));
|
2004-12-23 11:46:24 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Add specific procedure access */
|
|
|
|
int found= 0;
|
|
|
|
ulong j;
|
|
|
|
|
|
|
|
for (counter= 0, j= SELECT_ACL; j <= PROC_ACLS; counter++, j<<= 1)
|
|
|
|
{
|
|
|
|
if (test_access & j)
|
|
|
|
{
|
|
|
|
if (found)
|
2005-11-20 19:47:07 +01:00
|
|
|
global.append(STRING_WITH_LEN(", "));
|
2004-12-23 11:46:24 +01:00
|
|
|
found= 1;
|
|
|
|
global.append(command_array[counter],command_lengths[counter]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-11-20 19:47:07 +01:00
|
|
|
global.append(STRING_WITH_LEN(" ON "));
|
2005-05-17 20:54:20 +02:00
|
|
|
global.append(type,typelen);
|
|
|
|
global.append(' ');
|
2004-12-23 11:46:24 +01:00
|
|
|
append_identifier(thd, &global, grant_proc->db,
|
|
|
|
strlen(grant_proc->db));
|
|
|
|
global.append('.');
|
|
|
|
append_identifier(thd, &global, grant_proc->tname,
|
|
|
|
strlen(grant_proc->tname));
|
2005-11-20 19:47:07 +01:00
|
|
|
global.append(STRING_WITH_LEN(" TO '"));
|
2004-12-23 11:46:24 +01:00
|
|
|
global.append(lex_user->user.str, lex_user->user.length,
|
|
|
|
system_charset_info);
|
2005-11-20 19:47:07 +01:00
|
|
|
global.append(STRING_WITH_LEN("'@'"));
|
2007-09-20 18:10:35 +02:00
|
|
|
// host and lex_user->host are equal except for case
|
|
|
|
global.append(host, strlen(host), system_charset_info);
|
2004-12-23 11:46:24 +01:00
|
|
|
global.append('\'');
|
|
|
|
if (proc_access & GRANT_ACL)
|
2005-11-20 19:47:07 +01:00
|
|
|
global.append(STRING_WITH_LEN(" WITH GRANT OPTION"));
|
2004-12-23 11:46:24 +01:00
|
|
|
protocol->prepare_for_resend();
|
|
|
|
protocol->store(global.ptr(),global.length(),global.charset());
|
|
|
|
if (protocol->write())
|
|
|
|
{
|
|
|
|
error= -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-05-17 20:54:20 +02:00
|
|
|
return error;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2002-06-12 14:04:18 +02:00
|
|
|
/*
|
|
|
|
Make a clear-text version of the requested privilege.
|
|
|
|
*/
|
|
|
|
|
|
|
|
void get_privilege_desc(char *to, uint max_length, ulong access)
|
|
|
|
{
|
|
|
|
uint pos;
|
|
|
|
char *start=to;
|
|
|
|
DBUG_ASSERT(max_length >= 30); // For end ',' removal
|
|
|
|
|
|
|
|
if (access)
|
|
|
|
{
|
|
|
|
max_length--; // Reserve place for end-zero
|
|
|
|
for (pos=0 ; access ; pos++, access>>=1)
|
|
|
|
{
|
|
|
|
if ((access & 1) &&
|
|
|
|
command_lengths[pos] + (uint) (to-start) < max_length)
|
|
|
|
{
|
|
|
|
to= strmov(to, command_array[pos]);
|
|
|
|
*to++=',';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
to--; // Remove end ','
|
|
|
|
}
|
|
|
|
*to=0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-05-15 12:50:38 +02:00
|
|
|
void get_mqh(const char *user, const char *host, USER_CONN *uc)
|
2002-02-01 20:45:23 +01:00
|
|
|
{
|
|
|
|
ACL_USER *acl_user;
|
2006-05-06 09:25:59 +02:00
|
|
|
|
|
|
|
pthread_mutex_lock(&acl_cache->lock);
|
|
|
|
|
2005-08-23 00:48:50 +02:00
|
|
|
if (initialized && (acl_user= find_acl_user(host,user, FALSE)))
|
2002-05-15 12:50:38 +02:00
|
|
|
uc->user_resources= acl_user->user_resource;
|
|
|
|
else
|
|
|
|
bzero((char*) &uc->user_resources, sizeof(uc->user_resources));
|
2006-05-06 09:25:59 +02:00
|
|
|
|
|
|
|
pthread_mutex_unlock(&acl_cache->lock);
|
2002-02-01 20:45:23 +01:00
|
|
|
}
|
|
|
|
|
2004-11-25 21:55:49 +01:00
|
|
|
/*
|
|
|
|
Open the grant tables.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
open_grant_tables()
|
|
|
|
thd The current thread.
|
|
|
|
tables (out) The 4 elements array for the opened tables.
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
Tables are numbered as follows:
|
|
|
|
0 user
|
|
|
|
1 db
|
|
|
|
2 tables_priv
|
|
|
|
3 columns_priv
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
1 Skip GRANT handling during replication.
|
|
|
|
0 OK.
|
|
|
|
< 0 Error.
|
|
|
|
*/
|
|
|
|
|
2004-12-23 11:46:24 +01:00
|
|
|
#define GRANT_TABLES 5
|
2003-06-06 14:43:23 +02:00
|
|
|
int open_grant_tables(THD *thd, TABLE_LIST *tables)
|
|
|
|
{
|
|
|
|
DBUG_ENTER("open_grant_tables");
|
|
|
|
|
|
|
|
if (!initialized)
|
|
|
|
{
|
2004-10-20 03:04:37 +02:00
|
|
|
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables");
|
2003-06-06 14:43:23 +02:00
|
|
|
DBUG_RETURN(-1);
|
|
|
|
}
|
|
|
|
|
2004-12-23 11:46:24 +01:00
|
|
|
bzero((char*) tables, GRANT_TABLES*sizeof(*tables));
|
2005-01-06 12:00:13 +01:00
|
|
|
tables->alias= tables->table_name= (char*) "user";
|
|
|
|
(tables+1)->alias= (tables+1)->table_name= (char*) "db";
|
|
|
|
(tables+2)->alias= (tables+2)->table_name= (char*) "tables_priv";
|
|
|
|
(tables+3)->alias= (tables+3)->table_name= (char*) "columns_priv";
|
|
|
|
(tables+4)->alias= (tables+4)->table_name= (char*) "procs_priv";
|
2004-07-16 00:15:55 +02:00
|
|
|
tables->next_local= tables->next_global= tables+1;
|
|
|
|
(tables+1)->next_local= (tables+1)->next_global= tables+2;
|
|
|
|
(tables+2)->next_local= (tables+2)->next_global= tables+3;
|
2004-12-23 11:46:24 +01:00
|
|
|
(tables+3)->next_local= (tables+3)->next_global= tables+4;
|
2003-06-06 14:43:23 +02:00
|
|
|
tables->lock_type= (tables+1)->lock_type=
|
2004-12-23 11:46:24 +01:00
|
|
|
(tables+2)->lock_type= (tables+3)->lock_type=
|
|
|
|
(tables+4)->lock_type= TL_WRITE;
|
|
|
|
tables->db= (tables+1)->db= (tables+2)->db=
|
|
|
|
(tables+3)->db= (tables+4)->db= (char*) "mysql";
|
2003-06-06 14:43:23 +02:00
|
|
|
|
|
|
|
#ifdef HAVE_REPLICATION
|
|
|
|
/*
|
|
|
|
GRANT and REVOKE are applied the slave in/exclusion rules as they are
|
|
|
|
some kind of updates to the mysql.% tables.
|
|
|
|
*/
|
2005-03-08 21:12:35 +01:00
|
|
|
if (thd->slave_thread && rpl_filter->is_on())
|
2003-08-02 17:23:39 +02:00
|
|
|
{
|
2003-08-11 21:44:43 +02:00
|
|
|
/*
|
|
|
|
The tables must be marked "updating" so that tables_ok() takes them into
|
|
|
|
account in tests.
|
2003-08-02 17:23:39 +02:00
|
|
|
*/
|
2004-12-23 11:46:24 +01:00
|
|
|
tables[0].updating=tables[1].updating=tables[2].updating=
|
|
|
|
tables[3].updating=tables[4].updating=1;
|
2005-05-09 11:43:09 +02:00
|
|
|
if (!(thd->spcont || rpl_filter->tables_ok(0, tables)))
|
2003-08-02 17:23:39 +02:00
|
|
|
DBUG_RETURN(1);
|
2004-12-23 11:46:24 +01:00
|
|
|
tables[0].updating=tables[1].updating=tables[2].updating=
|
|
|
|
tables[3].updating=tables[4].updating=0;;
|
2003-08-02 17:23:39 +02:00
|
|
|
}
|
2003-06-06 14:43:23 +02:00
|
|
|
#endif
|
|
|
|
|
2004-02-01 14:30:32 +01:00
|
|
|
if (simple_open_n_lock_tables(thd, tables))
|
2003-06-06 14:43:23 +02:00
|
|
|
{ // This should never happen
|
|
|
|
close_thread_tables(thd);
|
|
|
|
DBUG_RETURN(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
ACL_USER *check_acl_user(LEX_USER *user_name,
|
2003-09-03 18:53:08 +02:00
|
|
|
uint *acl_acl_userdx)
|
2003-06-06 14:43:23 +02:00
|
|
|
{
|
|
|
|
ACL_USER *acl_user= 0;
|
|
|
|
uint counter;
|
|
|
|
|
2006-04-27 12:54:36 +02:00
|
|
|
safe_mutex_assert_owner(&acl_cache->lock);
|
|
|
|
|
2003-06-06 14:43:23 +02:00
|
|
|
for (counter= 0 ; counter < acl_users.elements ; counter++)
|
|
|
|
{
|
|
|
|
const char *user,*host;
|
|
|
|
acl_user= dynamic_element(&acl_users, counter, ACL_USER*);
|
|
|
|
if (!(user=acl_user->user))
|
2004-05-05 16:05:24 +02:00
|
|
|
user= "";
|
2003-06-06 14:43:23 +02:00
|
|
|
if (!(host=acl_user->host.hostname))
|
2006-01-09 10:31:07 +01:00
|
|
|
host= "";
|
2003-06-06 14:43:23 +02:00
|
|
|
if (!strcmp(user_name->user.str,user) &&
|
|
|
|
!my_strcasecmp(system_charset_info, user_name->host.str, host))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (counter == acl_users.elements)
|
|
|
|
return 0;
|
|
|
|
|
2003-09-03 18:53:08 +02:00
|
|
|
*acl_acl_userdx= counter;
|
2003-08-11 21:44:43 +02:00
|
|
|
return acl_user;
|
2003-06-06 14:43:23 +02:00
|
|
|
}
|
2003-08-11 21:44:43 +02:00
|
|
|
|
2004-11-25 21:55:49 +01:00
|
|
|
/*
|
|
|
|
Modify a privilege table.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
modify_grant_table()
|
|
|
|
table The table to modify.
|
|
|
|
host_field The host name field.
|
|
|
|
user_field The user name field.
|
|
|
|
user_to The new name for the user if to be renamed,
|
|
|
|
NULL otherwise.
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
Update user/host in the current record if user_to is not NULL.
|
|
|
|
Delete the current record if user_to is NULL.
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
0 OK.
|
|
|
|
!= 0 Error.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int modify_grant_table(TABLE *table, Field *host_field,
|
|
|
|
Field *user_field, LEX_USER *user_to)
|
2003-06-06 14:43:23 +02:00
|
|
|
{
|
2004-11-25 21:55:49 +01:00
|
|
|
int error;
|
|
|
|
DBUG_ENTER("modify_grant_table");
|
2003-06-06 14:43:23 +02:00
|
|
|
|
2004-11-25 21:55:49 +01:00
|
|
|
if (user_to)
|
|
|
|
{
|
|
|
|
/* rename */
|
|
|
|
store_record(table, record[1]);
|
|
|
|
host_field->store(user_to->host.str, user_to->host.length,
|
|
|
|
system_charset_info);
|
|
|
|
user_field->store(user_to->user.str, user_to->user.length,
|
|
|
|
system_charset_info);
|
2007-06-28 15:07:55 +02:00
|
|
|
if ((error= table->file->ha_update_row(table->record[1],
|
|
|
|
table->record[0])) &&
|
|
|
|
error != HA_ERR_RECORD_IS_THE_SAME)
|
2004-11-25 21:55:49 +01:00
|
|
|
table->file->print_error(error, MYF(0));
|
2007-06-28 15:07:55 +02:00
|
|
|
else
|
|
|
|
error= 0;
|
2004-11-25 21:55:49 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* delete */
|
2005-12-22 06:39:02 +01:00
|
|
|
if ((error=table->file->ha_delete_row(table->record[0])))
|
2004-11-25 21:55:49 +01:00
|
|
|
table->file->print_error(error, MYF(0));
|
|
|
|
}
|
2003-06-06 14:43:23 +02:00
|
|
|
|
2004-11-25 21:55:49 +01:00
|
|
|
DBUG_RETURN(error);
|
|
|
|
}
|
2003-06-06 14:43:23 +02:00
|
|
|
|
2004-11-25 21:55:49 +01:00
|
|
|
/*
|
|
|
|
Handle a privilege table.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
handle_grant_table()
|
|
|
|
tables The array with the four open tables.
|
2004-12-23 11:46:24 +01:00
|
|
|
table_no The number of the table to handle (0..4).
|
2004-11-25 21:55:49 +01:00
|
|
|
drop If user_from is to be dropped.
|
|
|
|
user_from The the user to be searched/dropped/renamed.
|
|
|
|
user_to The new name for the user if to be renamed,
|
|
|
|
NULL otherwise.
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
Scan through all records in a grant table and apply the requested
|
|
|
|
operation. For the "user" table, a single index access is sufficient,
|
|
|
|
since there is an unique index on (host, user).
|
|
|
|
Delete from grant table if drop is true.
|
|
|
|
Update in grant table if drop is false and user_to is not NULL.
|
|
|
|
Search in grant table if drop is false and user_to is NULL.
|
|
|
|
Tables are numbered as follows:
|
|
|
|
0 user
|
|
|
|
1 db
|
|
|
|
2 tables_priv
|
|
|
|
3 columns_priv
|
2004-12-23 11:46:24 +01:00
|
|
|
4 procs_priv
|
2004-11-25 21:55:49 +01:00
|
|
|
|
|
|
|
RETURN
|
|
|
|
> 0 At least one record matched.
|
|
|
|
0 OK, but no record matched.
|
|
|
|
< 0 Error.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int handle_grant_table(TABLE_LIST *tables, uint table_no, bool drop,
|
|
|
|
LEX_USER *user_from, LEX_USER *user_to)
|
|
|
|
{
|
|
|
|
int result= 0;
|
|
|
|
int error;
|
|
|
|
TABLE *table= tables[table_no].table;
|
|
|
|
Field *host_field= table->field[0];
|
|
|
|
Field *user_field= table->field[table_no ? 2 : 1];
|
|
|
|
char *host_str= user_from->host.str;
|
|
|
|
char *user_str= user_from->user.str;
|
|
|
|
const char *host;
|
|
|
|
const char *user;
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
uchar user_key[MAX_KEY_LENGTH];
|
2004-12-06 18:18:35 +01:00
|
|
|
uint key_prefix_length;
|
2004-11-25 21:55:49 +01:00
|
|
|
DBUG_ENTER("handle_grant_table");
|
2007-10-31 12:25:18 +01:00
|
|
|
THD *thd= current_thd;
|
2004-11-25 21:55:49 +01:00
|
|
|
|
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes
Changes that requires code changes in other code of other storage engines.
(Note that all changes are very straightforward and one should find all issues
by compiling a --debug build and fixing all compiler errors and all
asserts in field.cc while running the test suite),
- New optional handler function introduced: reset()
This is called after every DML statement to make it easy for a handler to
statement specific cleanups.
(The only case it's not called is if force the file to be closed)
- handler::extra(HA_EXTRA_RESET) is removed. Code that was there before
should be moved to handler::reset()
- table->read_set contains a bitmap over all columns that are needed
in the query. read_row() and similar functions only needs to read these
columns
- table->write_set contains a bitmap over all columns that will be updated
in the query. write_row() and update_row() only needs to update these
columns.
The above bitmaps should now be up to date in all context
(including ALTER TABLE, filesort()).
The handler is informed of any changes to the bitmap after
fix_fields() by calling the virtual function
handler::column_bitmaps_signal(). If the handler does caching of
these bitmaps (instead of using table->read_set, table->write_set),
it should redo the caching in this code. as the signal() may be sent
several times, it's probably best to set a variable in the signal
and redo the caching on read_row() / write_row() if the variable was
set.
- Removed the read_set and write_set bitmap objects from the handler class
- Removed all column bit handling functions from the handler class.
(Now one instead uses the normal bitmap functions in my_bitmap.c instead
of handler dedicated bitmap functions)
- field->query_id is removed. One should instead instead check
table->read_set and table->write_set if a field is used in the query.
- handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and
handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now
instead use table->read_set to check for which columns to retrieve.
- If a handler needs to call Field->val() or Field->store() on columns
that are not used in the query, one should install a temporary
all-columns-used map while doing so. For this, we provide the following
functions:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
field->val();
dbug_tmp_restore_column_map(table->read_set, old_map);
and similar for the write map:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
field->val();
dbug_tmp_restore_column_map(table->write_set, old_map);
If this is not done, you will sooner or later hit a DBUG_ASSERT
in the field store() / val() functions.
(For not DBUG binaries, the dbug_tmp_restore_column_map() and
dbug_tmp_restore_column_map() are inline dummy functions and should
be optimized away be the compiler).
- If one needs to temporary set the column map for all binaries (and not
just to avoid the DBUG_ASSERT() in the Field::store() / Field::val()
methods) one should use the functions tmp_use_all_columns() and
tmp_restore_column_map() instead of the above dbug_ variants.
- All 'status' fields in the handler base class (like records,
data_file_length etc) are now stored in a 'stats' struct. This makes
it easier to know what status variables are provided by the base
handler. This requires some trivial variable names in the extra()
function.
- New virtual function handler::records(). This is called to optimize
COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true.
(stats.records is not supposed to be an exact value. It's only has to
be 'reasonable enough' for the optimizer to be able to choose a good
optimization path).
- Non virtual handler::init() function added for caching of virtual
constants from engine.
- Removed has_transactions() virtual method. Now one should instead return
HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support
transactions.
- The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument
that is to be used with 'new handler_name()' to allocate the handler
in the right area. The xxxx_create_handler() function is also
responsible for any initialization of the object before returning.
For example, one should change:
static handler *myisam_create_handler(TABLE_SHARE *table)
{
return new ha_myisam(table);
}
->
static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisam(table);
}
- New optional virtual function: use_hidden_primary_key().
This is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key. This allows the handler to take precisions
in remembering any hidden primary key to able to update/delete any
found row. The default handler marks all columns to be read.
- handler::table_flags() now returns a ulonglong (to allow for more flags).
- New/changed table_flags()
- HA_HAS_RECORDS Set if ::records() is supported
- HA_NO_TRANSACTIONS Set if engine doesn't support transactions
- HA_PRIMARY_KEY_REQUIRED_FOR_DELETE
Set if we should mark all primary key columns for
read when reading rows as part of a DELETE
statement. If there is no primary key,
all columns are marked for read.
- HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some
cases (based on table->read_set)
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
- HA_DUPP_POS Renamed to HA_DUPLICATE_POS
- HA_REQUIRES_KEY_COLUMNS_FOR_DELETE
Set this if we should mark ALL key columns for
read when when reading rows as part of a DELETE
statement. In case of an update we will mark
all keys for read for which key part changed
value.
- HA_STATS_RECORDS_IS_EXACT
Set this if stats.records is exact.
(This saves us some extra records() calls
when optimizing COUNT(*))
- Removed table_flags()
- HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if
handler::records() gives an exact count() and
HA_STATS_RECORDS_IS_EXACT if stats.records is exact.
- HA_READ_RND_SAME Removed (no one supported this one)
- Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk()
- Renamed handler::dupp_pos to handler::dup_pos
- Removed not used variable handler::sortkey
Upper level handler changes:
- ha_reset() now does some overall checks and calls ::reset()
- ha_table_flags() added. This is a cached version of table_flags(). The
cache is updated on engine creation time and updated on open.
MySQL level changes (not obvious from the above):
- DBUG_ASSERT() added to check that column usage matches what is set
in the column usage bit maps. (This found a LOT of bugs in current
column marking code).
- In 5.1 before, all used columns was marked in read_set and only updated
columns was marked in write_set. Now we only mark columns for which we
need a value in read_set.
- Column bitmaps are created in open_binary_frm() and open_table_from_share().
(Before this was in table.cc)
- handler::table_flags() calls are replaced with handler::ha_table_flags()
- For calling field->val() you must have the corresponding bit set in
table->read_set. For calling field->store() you must have the
corresponding bit set in table->write_set. (There are asserts in
all store()/val() functions to catch wrong usage)
- thd->set_query_id is renamed to thd->mark_used_columns and instead
of setting this to an integer value, this has now the values:
MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE
Changed also all variables named 'set_query_id' to mark_used_columns.
- In filesort() we now inform the handler of exactly which columns are needed
doing the sort and choosing the rows.
- The TABLE_SHARE object has a 'all_set' column bitmap one can use
when one needs a column bitmap with all columns set.
(This is used for table->use_all_columns() and other places)
- The TABLE object has 3 column bitmaps:
- def_read_set Default bitmap for columns to be read
- def_write_set Default bitmap for columns to be written
- tmp_set Can be used as a temporary bitmap when needed.
The table object has also two pointer to bitmaps read_set and write_set
that the handler should use to find out which columns are used in which way.
- count() optimization now calls handler::records() instead of using
handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true).
- Added extra argument to Item::walk() to indicate if we should also
traverse sub queries.
- Added TABLE parameter to cp_buffer_from_ref()
- Don't close tables created with CREATE ... SELECT but keep them in
the table cache. (Faster usage of newly created tables).
New interfaces:
- table->clear_column_bitmaps() to initialize the bitmaps for tables
at start of new statements.
- table->column_bitmaps_set() to set up new column bitmaps and signal
the handler about this.
- table->column_bitmaps_set_no_signal() for some few cases where we need
to setup new column bitmaps but don't signal the handler (as the handler
has already been signaled about these before). Used for the momement
only in opt_range.cc when doing ROR scans.
- table->use_all_columns() to install a bitmap where all columns are marked
as use in the read and the write set.
- table->default_column_bitmaps() to install the normal read and write
column bitmaps, but not signaling the handler about this.
This is mainly used when creating TABLE instances.
- table->mark_columns_needed_for_delete(),
table->mark_columns_needed_for_delete() and
table->mark_columns_needed_for_insert() to allow us to put additional
columns in column usage maps if handler so requires.
(The handler indicates what it neads in handler->table_flags())
- table->prepare_for_position() to allow us to tell handler that it
needs to read primary key parts to be able to store them in
future table->position() calls.
(This replaces the table->file->ha_retrieve_all_pk function)
- table->mark_auto_increment_column() to tell handler are going to update
columns part of any auto_increment key.
- table->mark_columns_used_by_index() to mark all columns that is part of
an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow
it to quickly know that it only needs to read colums that are part
of the key. (The handler can also use the column map for detecting this,
but simpler/faster handler can just monitor the extra() call).
- table->mark_columns_used_by_index_no_reset() to in addition to other columns,
also mark all columns that is used by the given key.
- table->restore_column_maps_after_mark_index() to restore to default
column maps after a call to table->mark_columns_used_by_index().
- New item function register_field_in_read_map(), for marking used columns
in table->read_map. Used by filesort() to mark all used columns
- Maintain in TABLE->merge_keys set of all keys that are used in query.
(Simplices some optimization loops)
- Maintain Field->part_of_key_not_clustered which is like Field->part_of_key
but the field in the clustered key is not assumed to be part of all index.
(used in opt_range.cc for faster loops)
- dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map()
tmp_use_all_columns() and tmp_restore_column_map() functions to temporally
mark all columns as usable. The 'dbug_' version is primarily intended
inside a handler when it wants to just call Field:store() & Field::val()
functions, but don't need the column maps set for any other usage.
(ie:: bitmap_is_set() is never called)
- We can't use compare_records() to skip updates for handlers that returns
a partial column set and the read_set doesn't cover all columns in the
write set. The reason for this is that if we have a column marked only for
write we can't in the MySQL level know if the value changed or not.
The reason this worked before was that MySQL marked all to be written
columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden
bug'.
- open_table_from_share() does not anymore setup temporary MEM_ROOT
object as a thread specific variable for the handler. Instead we
send the to-be-used MEMROOT to get_new_handler().
(Simpler, faster code)
Bugs fixed:
- Column marking was not done correctly in a lot of cases.
(ALTER TABLE, when using triggers, auto_increment fields etc)
(Could potentially result in wrong values inserted in table handlers
relying on that the old column maps or field->set_query_id was correct)
Especially when it comes to triggers, there may be cases where the
old code would cause lost/wrong values for NDB and/or InnoDB tables.
- Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags:
OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG.
This allowed me to remove some wrong warnings about:
"Some non-transactional changed tables couldn't be rolled back"
- Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset
(thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose
some warnings about
"Some non-transactional changed tables couldn't be rolled back")
- Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table()
which could cause delete_table to report random failures.
- Fixed core dumps for some tests when running with --debug
- Added missing FN_LIBCHAR in mysql_rm_tmp_tables()
(This has probably caused us to not properly remove temporary files after
crash)
- slow_logs was not properly initialized, which could maybe cause
extra/lost entries in slow log.
- If we get an duplicate row on insert, change column map to read and
write all columns while retrying the operation. This is required by
the definition of REPLACE and also ensures that fields that are only
part of UPDATE are properly handled. This fixed a bug in NDB and
REPLACE where REPLACE wrongly copied some column values from the replaced
row.
- For table handler that doesn't support NULL in keys, we would give an error
when creating a primary key with NULL fields, even after the fields has been
automaticly converted to NOT NULL.
- Creating a primary key on a SPATIAL key, would fail if field was not
declared as NOT NULL.
Cleanups:
- Removed not used condition argument to setup_tables
- Removed not needed item function reset_query_id_processor().
- Field->add_index is removed. Now this is instead maintained in
(field->flags & FIELD_IN_ADD_INDEX)
- Field->fieldnr is removed (use field->field_index instead)
- New argument to filesort() to indicate that it should return a set of
row pointers (not used columns). This allowed me to remove some references
to sql_command in filesort and should also enable us to return column
results in some cases where we couldn't before.
- Changed column bitmap handling in opt_range.cc to be aligned with TABLE
bitmap, which allowed me to use bitmap functions instead of looping over
all fields to create some needed bitmaps. (Faster and smaller code)
- Broke up found too long lines
- Moved some variable declaration at start of function for better code
readability.
- Removed some not used arguments from functions.
(setup_fields(), mysql_prepare_insert_check_table())
- setup_fields() now takes an enum instead of an int for marking columns
usage.
- For internal temporary tables, use handler::write_row(),
handler::delete_row() and handler::update_row() instead of
handler::ha_xxxx() for faster execution.
- Changed some constants to enum's and define's.
- Using separate column read and write sets allows for easier checking
of timestamp field was set by statement.
- Remove calls to free_io_cache() as this is now done automaticly in ha_reset()
- Don't build table->normalized_path as this is now identical to table->path
(after bar's fixes to convert filenames)
- Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to
do comparision with the 'convert-dbug-for-diff' tool.
Things left to do in 5.1:
- We wrongly log failed CREATE TABLE ... SELECT in some cases when using
row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result)
Mats has promised to look into this.
- Test that my fix for CREATE TABLE ... SELECT is indeed correct.
(I added several test cases for this, but in this case it's better that
someone else also tests this throughly).
Lars has promosed to do this.
2006-06-04 17:52:22 +02:00
|
|
|
table->use_all_columns();
|
2004-11-27 23:07:30 +01:00
|
|
|
if (! table_no) // mysql.user table
|
2003-06-06 14:43:23 +02:00
|
|
|
{
|
2004-11-25 21:55:49 +01:00
|
|
|
/*
|
|
|
|
The 'user' table has an unique index on (host, user).
|
|
|
|
Thus, we can handle everything with a single index access.
|
|
|
|
The host- and user fields are consecutive in the user table records.
|
|
|
|
So we set host- and user fields of table->record[0] and use the
|
|
|
|
pointer to the host field as key.
|
|
|
|
index_read_idx() will replace table->record[0] (its first argument)
|
|
|
|
by the searched record, if it exists.
|
|
|
|
*/
|
|
|
|
DBUG_PRINT("info",("read table: '%s' search: '%s'@'%s'",
|
2005-11-23 21:45:02 +01:00
|
|
|
table->s->table_name.str, user_str, host_str));
|
2004-11-25 21:55:49 +01:00
|
|
|
host_field->store(host_str, user_from->host.length, system_charset_info);
|
|
|
|
user_field->store(user_str, user_from->user.length, system_charset_info);
|
2004-12-06 18:18:35 +01:00
|
|
|
|
|
|
|
key_prefix_length= (table->key_info->key_part[0].store_length +
|
|
|
|
table->key_info->key_part[1].store_length);
|
|
|
|
key_copy(user_key, table->record[0], table->key_info, key_prefix_length);
|
|
|
|
|
2007-08-13 15:11:25 +02:00
|
|
|
if ((error= table->file->index_read_idx_map(table->record[0], 0,
|
|
|
|
user_key, (key_part_map)3,
|
|
|
|
HA_READ_KEY_EXACT)))
|
2003-06-06 14:43:23 +02:00
|
|
|
{
|
2005-07-18 13:31:02 +02:00
|
|
|
if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
|
2004-11-25 21:55:49 +01:00
|
|
|
{
|
|
|
|
table->file->print_error(error, MYF(0));
|
|
|
|
result= -1;
|
|
|
|
}
|
2003-06-06 14:43:23 +02:00
|
|
|
}
|
2004-11-25 21:55:49 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/* If requested, delete or update the record. */
|
|
|
|
result= ((drop || user_to) &&
|
|
|
|
modify_grant_table(table, host_field, user_field, user_to)) ?
|
|
|
|
-1 : 1; /* Error or found. */
|
|
|
|
}
|
|
|
|
DBUG_PRINT("info",("read result: %d", result));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
The non-'user' table do not have indexes on (host, user).
|
|
|
|
And their host- and user fields are not consecutive.
|
|
|
|
Thus, we need to do a table scan to find all matching records.
|
|
|
|
*/
|
|
|
|
if ((error= table->file->ha_rnd_init(1)))
|
2003-06-06 14:43:23 +02:00
|
|
|
{
|
2004-11-25 21:55:49 +01:00
|
|
|
table->file->print_error(error, MYF(0));
|
2003-06-06 14:43:23 +02:00
|
|
|
result= -1;
|
2004-11-25 21:55:49 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
#ifdef EXTRA_DEBUG
|
|
|
|
DBUG_PRINT("info",("scan table: '%s' search: '%s'@'%s'",
|
2005-11-23 21:45:02 +01:00
|
|
|
table->s->table_name.str, user_str, host_str));
|
2004-11-25 21:55:49 +01:00
|
|
|
#endif
|
|
|
|
while ((error= table->file->rnd_next(table->record[0])) !=
|
|
|
|
HA_ERR_END_OF_FILE)
|
|
|
|
{
|
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
/* Most probable 'deleted record'. */
|
|
|
|
DBUG_PRINT("info",("scan error: %d", error));
|
|
|
|
continue;
|
|
|
|
}
|
2007-10-31 12:25:18 +01:00
|
|
|
if (! (host= get_field(thd->mem_root, host_field)))
|
2004-11-25 21:55:49 +01:00
|
|
|
host= "";
|
2007-10-31 12:25:18 +01:00
|
|
|
if (! (user= get_field(thd->mem_root, user_field)))
|
2004-11-25 21:55:49 +01:00
|
|
|
user= "";
|
|
|
|
|
|
|
|
#ifdef EXTRA_DEBUG
|
|
|
|
DBUG_PRINT("loop",("scan fields: '%s'@'%s' '%s' '%s' '%s'",
|
|
|
|
user, host,
|
2007-10-31 12:25:18 +01:00
|
|
|
get_field(thd->mem_root, table->field[1]) /*db*/,
|
|
|
|
get_field(thd->mem_root, table->field[3]) /*table*/,
|
|
|
|
get_field(thd->mem_root,
|
|
|
|
table->field[4]) /*column*/));
|
2004-11-25 21:55:49 +01:00
|
|
|
#endif
|
|
|
|
if (strcmp(user_str, user) ||
|
|
|
|
my_strcasecmp(system_charset_info, host_str, host))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* If requested, delete or update the record. */
|
|
|
|
result= ((drop || user_to) &&
|
|
|
|
modify_grant_table(table, host_field, user_field, user_to)) ?
|
|
|
|
-1 : result ? result : 1; /* Error or keep result or found. */
|
|
|
|
/* If search is requested, we do not need to search further. */
|
|
|
|
if (! drop && ! user_to)
|
|
|
|
break ;
|
|
|
|
}
|
|
|
|
(void) table->file->ha_rnd_end();
|
|
|
|
DBUG_PRINT("info",("scan result: %d", result));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DBUG_RETURN(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Handle an in-memory privilege structure.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
handle_grant_struct()
|
2005-01-06 12:00:13 +01:00
|
|
|
struct_no The number of the structure to handle (0..3).
|
2004-11-25 21:55:49 +01:00
|
|
|
drop If user_from is to be dropped.
|
|
|
|
user_from The the user to be searched/dropped/renamed.
|
|
|
|
user_to The new name for the user if to be renamed,
|
|
|
|
NULL otherwise.
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
Scan through all elements in an in-memory grant structure and apply
|
|
|
|
the requested operation.
|
|
|
|
Delete from grant structure if drop is true.
|
|
|
|
Update in grant structure if drop is false and user_to is not NULL.
|
|
|
|
Search in grant structure if drop is false and user_to is NULL.
|
|
|
|
Structures are numbered as follows:
|
|
|
|
0 acl_users
|
|
|
|
1 acl_dbs
|
|
|
|
2 column_priv_hash
|
2004-12-23 11:46:24 +01:00
|
|
|
3 procs_priv_hash
|
2004-11-25 21:55:49 +01:00
|
|
|
|
|
|
|
RETURN
|
|
|
|
> 0 At least one element matched.
|
|
|
|
0 OK, but no element matched.
|
2005-01-06 12:00:13 +01:00
|
|
|
-1 Wrong arguments to function
|
2004-11-25 21:55:49 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
static int handle_grant_struct(uint struct_no, bool drop,
|
|
|
|
LEX_USER *user_from, LEX_USER *user_to)
|
|
|
|
{
|
|
|
|
int result= 0;
|
|
|
|
uint idx;
|
|
|
|
uint elements;
|
|
|
|
const char *user;
|
|
|
|
const char *host;
|
2009-06-17 16:56:44 +02:00
|
|
|
ACL_USER *acl_user= NULL;
|
|
|
|
ACL_DB *acl_db= NULL;
|
|
|
|
GRANT_NAME *grant_name= NULL;
|
2004-11-25 21:55:49 +01:00
|
|
|
DBUG_ENTER("handle_grant_struct");
|
2005-08-25 08:38:06 +02:00
|
|
|
DBUG_PRINT("info",("scan struct: %u search: '%s'@'%s'",
|
|
|
|
struct_no, user_from->user.str, user_from->host.str));
|
|
|
|
|
2006-03-29 13:27:36 +02:00
|
|
|
LINT_INIT(user);
|
|
|
|
LINT_INIT(host);
|
2004-11-25 21:55:49 +01:00
|
|
|
|
2006-05-06 09:25:59 +02:00
|
|
|
safe_mutex_assert_owner(&acl_cache->lock);
|
|
|
|
|
2004-11-25 21:55:49 +01:00
|
|
|
/* Get the number of elements in the in-memory structure. */
|
2005-01-06 12:00:13 +01:00
|
|
|
switch (struct_no) {
|
2004-11-25 21:55:49 +01:00
|
|
|
case 0:
|
|
|
|
elements= acl_users.elements;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
elements= acl_dbs.elements;
|
|
|
|
break;
|
2004-12-23 11:46:24 +01:00
|
|
|
case 2:
|
2004-11-25 21:55:49 +01:00
|
|
|
elements= column_priv_hash.records;
|
2004-12-23 11:46:24 +01:00
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
elements= proc_priv_hash.records;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -1;
|
2004-11-25 21:55:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef EXTRA_DEBUG
|
|
|
|
DBUG_PRINT("loop",("scan struct: %u search user: '%s' host: '%s'",
|
|
|
|
struct_no, user_from->user.str, user_from->host.str));
|
|
|
|
#endif
|
|
|
|
/* Loop over all elements. */
|
|
|
|
for (idx= 0; idx < elements; idx++)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
Get a pointer to the element.
|
|
|
|
*/
|
2005-01-06 12:00:13 +01:00
|
|
|
switch (struct_no) {
|
2004-11-25 21:55:49 +01:00
|
|
|
case 0:
|
|
|
|
acl_user= dynamic_element(&acl_users, idx, ACL_USER*);
|
|
|
|
user= acl_user->user;
|
2006-06-06 13:21:07 +02:00
|
|
|
host= acl_user->host.hostname;
|
|
|
|
break;
|
2004-11-25 21:55:49 +01:00
|
|
|
|
|
|
|
case 1:
|
|
|
|
acl_db= dynamic_element(&acl_dbs, idx, ACL_DB*);
|
|
|
|
user= acl_db->user;
|
2006-06-06 13:21:07 +02:00
|
|
|
host= acl_db->host.hostname;
|
2004-11-25 21:55:49 +01:00
|
|
|
break;
|
|
|
|
|
2004-12-23 11:46:24 +01:00
|
|
|
case 2:
|
2009-10-14 18:37:38 +02:00
|
|
|
grant_name= (GRANT_NAME*) my_hash_element(&column_priv_hash, idx);
|
2004-12-23 11:46:24 +01:00
|
|
|
user= grant_name->user;
|
2006-06-06 13:21:07 +02:00
|
|
|
host= grant_name->host.hostname;
|
2004-12-23 11:46:24 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 3:
|
2009-10-14 18:37:38 +02:00
|
|
|
grant_name= (GRANT_NAME*) my_hash_element(&proc_priv_hash, idx);
|
2004-12-23 11:46:24 +01:00
|
|
|
user= grant_name->user;
|
2006-06-06 13:21:07 +02:00
|
|
|
host= grant_name->host.hostname;
|
2004-12-23 11:46:24 +01:00
|
|
|
break;
|
2007-02-23 12:13:55 +01:00
|
|
|
default:
|
|
|
|
assert(0);
|
2004-11-25 21:55:49 +01:00
|
|
|
}
|
|
|
|
if (! user)
|
2005-01-06 12:00:13 +01:00
|
|
|
user= "";
|
2006-06-06 13:21:07 +02:00
|
|
|
if (! host)
|
|
|
|
host= "";
|
|
|
|
|
2004-11-25 21:55:49 +01:00
|
|
|
#ifdef EXTRA_DEBUG
|
|
|
|
DBUG_PRINT("loop",("scan struct: %u index: %u user: '%s' host: '%s'",
|
|
|
|
struct_no, idx, user, host));
|
|
|
|
#endif
|
|
|
|
if (strcmp(user_from->user.str, user) ||
|
|
|
|
my_strcasecmp(system_charset_info, user_from->host.str, host))
|
2003-06-06 14:43:23 +02:00
|
|
|
continue;
|
2004-11-25 21:55:49 +01:00
|
|
|
|
|
|
|
result= 1; /* At least one element found. */
|
|
|
|
if ( drop )
|
|
|
|
{
|
2006-03-29 13:27:36 +02:00
|
|
|
switch ( struct_no ) {
|
2004-11-25 21:55:49 +01:00
|
|
|
case 0:
|
|
|
|
delete_dynamic_element(&acl_users, idx);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1:
|
|
|
|
delete_dynamic_element(&acl_dbs, idx);
|
|
|
|
break;
|
|
|
|
|
2004-12-23 11:46:24 +01:00
|
|
|
case 2:
|
2009-10-14 18:37:38 +02:00
|
|
|
my_hash_delete(&column_priv_hash, (uchar*) grant_name);
|
2004-12-23 11:46:24 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 3:
|
2009-10-14 18:37:38 +02:00
|
|
|
my_hash_delete(&proc_priv_hash, (uchar*) grant_name);
|
2004-12-23 11:46:24 +01:00
|
|
|
break;
|
2004-11-25 21:55:49 +01:00
|
|
|
}
|
|
|
|
elements--;
|
|
|
|
idx--;
|
2003-06-06 14:43:23 +02:00
|
|
|
}
|
2004-11-25 21:55:49 +01:00
|
|
|
else if ( user_to )
|
|
|
|
{
|
2005-01-06 12:00:13 +01:00
|
|
|
switch ( struct_no ) {
|
2004-11-25 21:55:49 +01:00
|
|
|
case 0:
|
|
|
|
acl_user->user= strdup_root(&mem, user_to->user.str);
|
|
|
|
acl_user->host.hostname= strdup_root(&mem, user_to->host.str);
|
|
|
|
break;
|
2003-06-06 14:43:23 +02:00
|
|
|
|
2004-11-25 21:55:49 +01:00
|
|
|
case 1:
|
|
|
|
acl_db->user= strdup_root(&mem, user_to->user.str);
|
|
|
|
acl_db->host.hostname= strdup_root(&mem, user_to->host.str);
|
|
|
|
break;
|
|
|
|
|
2004-12-23 11:46:24 +01:00
|
|
|
case 2:
|
|
|
|
case 3:
|
2009-10-20 08:17:57 +02:00
|
|
|
/*
|
|
|
|
Update the grant structure with the new user name and
|
|
|
|
host name
|
|
|
|
*/
|
|
|
|
grant_name->set_user_details(user_to->host.str, grant_name->db,
|
2009-10-27 09:09:19 +01:00
|
|
|
user_to->user.str, grant_name->tname,
|
|
|
|
TRUE);
|
2009-10-20 08:17:57 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
Since username is part of the hash key, when the user name
|
|
|
|
is renamed, the hash key is changed. Update the hash to
|
|
|
|
ensure that the position matches the new hash key value
|
|
|
|
*/
|
2009-11-06 15:20:27 +01:00
|
|
|
my_hash_update(&column_priv_hash, (uchar*) grant_name,
|
|
|
|
(uchar*) grant_name->hash_key, grant_name->key_length);
|
2004-12-23 11:46:24 +01:00
|
|
|
break;
|
2004-11-25 21:55:49 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2003-06-06 14:43:23 +02:00
|
|
|
{
|
2004-11-25 21:55:49 +01:00
|
|
|
/* If search is requested, we do not need to search further. */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef EXTRA_DEBUG
|
|
|
|
DBUG_PRINT("loop",("scan struct: %u result %d", struct_no, result));
|
|
|
|
#endif
|
2003-06-06 14:43:23 +02:00
|
|
|
|
2004-11-25 21:55:49 +01:00
|
|
|
DBUG_RETURN(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Handle all privilege tables and in-memory privilege structures.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
handle_grant_data()
|
|
|
|
tables The array with the four open tables.
|
|
|
|
drop If user_from is to be dropped.
|
|
|
|
user_from The the user to be searched/dropped/renamed.
|
|
|
|
user_to The new name for the user if to be renamed,
|
|
|
|
NULL otherwise.
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
Go through all grant tables and in-memory grant structures and apply
|
|
|
|
the requested operation.
|
|
|
|
Delete from grant data if drop is true.
|
|
|
|
Update in grant data if drop is false and user_to is not NULL.
|
|
|
|
Search in grant data if drop is false and user_to is NULL.
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
> 0 At least one element matched.
|
|
|
|
0 OK, but no element matched.
|
|
|
|
< 0 Error.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int handle_grant_data(TABLE_LIST *tables, bool drop,
|
|
|
|
LEX_USER *user_from, LEX_USER *user_to)
|
|
|
|
{
|
|
|
|
int result= 0;
|
|
|
|
int found;
|
|
|
|
DBUG_ENTER("handle_grant_data");
|
|
|
|
|
|
|
|
/* Handle user table. */
|
|
|
|
if ((found= handle_grant_table(tables, 0, drop, user_from, user_to)) < 0)
|
|
|
|
{
|
|
|
|
/* Handle of table failed, don't touch the in-memory array. */
|
|
|
|
result= -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Handle user array. */
|
2004-12-06 18:18:35 +01:00
|
|
|
if ((handle_grant_struct(0, drop, user_from, user_to) && ! result) ||
|
|
|
|
found)
|
2004-11-25 21:55:49 +01:00
|
|
|
{
|
|
|
|
result= 1; /* At least one record/element found. */
|
|
|
|
/* If search is requested, we do not need to search further. */
|
|
|
|
if (! drop && ! user_to)
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Handle db table. */
|
|
|
|
if ((found= handle_grant_table(tables, 1, drop, user_from, user_to)) < 0)
|
|
|
|
{
|
|
|
|
/* Handle of table failed, don't touch the in-memory array. */
|
|
|
|
result= -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Handle db array. */
|
|
|
|
if (((handle_grant_struct(1, drop, user_from, user_to) && ! result) ||
|
|
|
|
found) && ! result)
|
|
|
|
{
|
|
|
|
result= 1; /* At least one record/element found. */
|
|
|
|
/* If search is requested, we do not need to search further. */
|
|
|
|
if (! drop && ! user_to)
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-12-23 11:46:24 +01:00
|
|
|
/* Handle procedures table. */
|
|
|
|
if ((found= handle_grant_table(tables, 4, drop, user_from, user_to)) < 0)
|
|
|
|
{
|
|
|
|
/* Handle of table failed, don't touch in-memory array. */
|
|
|
|
result= -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Handle procs array. */
|
|
|
|
if (((handle_grant_struct(3, drop, user_from, user_to) && ! result) ||
|
|
|
|
found) && ! result)
|
|
|
|
{
|
|
|
|
result= 1; /* At least one record/element found. */
|
|
|
|
/* If search is requested, we do not need to search further. */
|
|
|
|
if (! drop && ! user_to)
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-11-25 21:55:49 +01:00
|
|
|
/* Handle tables table. */
|
|
|
|
if ((found= handle_grant_table(tables, 2, drop, user_from, user_to)) < 0)
|
|
|
|
{
|
|
|
|
/* Handle of table failed, don't touch columns and in-memory array. */
|
|
|
|
result= -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (found && ! result)
|
|
|
|
{
|
|
|
|
result= 1; /* At least one record found. */
|
|
|
|
/* If search is requested, we do not need to search further. */
|
|
|
|
if (! drop && ! user_to)
|
|
|
|
goto end;
|
2003-06-06 14:43:23 +02:00
|
|
|
}
|
2004-11-25 21:55:49 +01:00
|
|
|
|
|
|
|
/* Handle columns table. */
|
|
|
|
if ((found= handle_grant_table(tables, 3, drop, user_from, user_to)) < 0)
|
2003-06-06 14:43:23 +02:00
|
|
|
{
|
2004-11-25 21:55:49 +01:00
|
|
|
/* Handle of table failed, don't touch the in-memory array. */
|
2003-06-06 14:43:23 +02:00
|
|
|
result= -1;
|
|
|
|
}
|
2004-11-25 21:55:49 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Handle columns hash. */
|
|
|
|
if (((handle_grant_struct(2, drop, user_from, user_to) && ! result) ||
|
|
|
|
found) && ! result)
|
|
|
|
result= 1; /* At least one record/element found. */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
end:
|
|
|
|
DBUG_RETURN(result);
|
|
|
|
}
|
|
|
|
|
2004-12-06 18:18:35 +01:00
|
|
|
|
2004-11-27 23:07:30 +01:00
|
|
|
static void append_user(String *str, LEX_USER *user)
|
|
|
|
{
|
|
|
|
if (str->length())
|
|
|
|
str->append(',');
|
|
|
|
str->append('\'');
|
|
|
|
str->append(user->user.str);
|
2005-11-20 19:47:07 +01:00
|
|
|
str->append(STRING_WITH_LEN("'@'"));
|
2004-11-27 23:07:30 +01:00
|
|
|
str->append(user->host.str);
|
|
|
|
str->append('\'');
|
|
|
|
}
|
2004-11-25 21:55:49 +01:00
|
|
|
|
2004-12-06 18:18:35 +01:00
|
|
|
|
2004-11-25 21:55:49 +01:00
|
|
|
/*
|
|
|
|
Create a list of users.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
mysql_create_user()
|
|
|
|
thd The current thread.
|
|
|
|
list The users to create.
|
2003-06-06 14:43:23 +02:00
|
|
|
|
2004-11-25 21:55:49 +01:00
|
|
|
RETURN
|
|
|
|
FALSE OK.
|
|
|
|
TRUE Error.
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool mysql_create_user(THD *thd, List <LEX_USER> &list)
|
|
|
|
{
|
|
|
|
int result;
|
2004-11-27 23:07:30 +01:00
|
|
|
String wrong_users;
|
2004-11-25 21:55:49 +01:00
|
|
|
ulong sql_mode;
|
2006-06-29 12:50:44 +02:00
|
|
|
LEX_USER *user_name, *tmp_user_name;
|
2004-11-25 21:55:49 +01:00
|
|
|
List_iterator <LEX_USER> user_list(list);
|
2004-12-23 11:46:24 +01:00
|
|
|
TABLE_LIST tables[GRANT_TABLES];
|
2008-01-25 08:02:26 +01:00
|
|
|
bool some_users_created= FALSE;
|
2004-11-25 21:55:49 +01:00
|
|
|
DBUG_ENTER("mysql_create_user");
|
|
|
|
|
BUG#25091 (A DELETE statement to mysql database is not logged in ROW format):
With this patch, statements that change metadata (in the mysql database)
is logged as statements, while normal changes (e.g., using INSERT, DELETE,
and/or UPDATE) is logged according to the format in effect.
The log tables (i.e., general_log and slow_log) are not replicated at all.
With this patch, the following statements are replicated as statements:
GRANT, REVOKE (ALL), CREATE USER, DROP USER, and RENAME USER.
2007-02-26 10:19:08 +01:00
|
|
|
/*
|
|
|
|
This statement will be replicated as a statement, even when using
|
|
|
|
row-based replication. The flag will be reset at the end of the
|
|
|
|
statement.
|
|
|
|
*/
|
|
|
|
thd->clear_current_stmt_binlog_row_based();
|
|
|
|
|
2004-11-25 21:55:49 +01:00
|
|
|
/* CREATE USER may be skipped on replication client. */
|
|
|
|
if ((result= open_grant_tables(thd, tables)))
|
|
|
|
DBUG_RETURN(result != 1);
|
|
|
|
|
|
|
|
rw_wrlock(&LOCK_grant);
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_lock(&acl_cache->lock);
|
2004-11-25 21:55:49 +01:00
|
|
|
|
2006-06-29 12:50:44 +02:00
|
|
|
while ((tmp_user_name= user_list++))
|
2004-11-25 21:55:49 +01:00
|
|
|
{
|
2006-06-29 12:50:44 +02:00
|
|
|
if (!(user_name= get_current_user(thd, tmp_user_name)))
|
|
|
|
{
|
|
|
|
result= TRUE;
|
|
|
|
continue;
|
2006-07-25 01:45:26 +02:00
|
|
|
}
|
|
|
|
|
2004-11-25 21:55:49 +01:00
|
|
|
/*
|
|
|
|
Search all in-memory structures and grant tables
|
|
|
|
for a mention of the new user name.
|
|
|
|
*/
|
2005-02-25 15:53:22 +01:00
|
|
|
if (handle_grant_data(tables, 0, user_name, NULL))
|
2003-06-06 14:43:23 +02:00
|
|
|
{
|
2004-11-27 23:07:30 +01:00
|
|
|
append_user(&wrong_users, user_name);
|
2004-11-25 21:55:49 +01:00
|
|
|
result= TRUE;
|
2004-11-27 23:07:30 +01:00
|
|
|
continue;
|
2004-11-25 21:55:49 +01:00
|
|
|
}
|
2003-06-06 14:43:23 +02:00
|
|
|
|
2008-01-25 08:02:26 +01:00
|
|
|
some_users_created= TRUE;
|
2004-11-25 21:55:49 +01:00
|
|
|
sql_mode= thd->variables.sql_mode;
|
2005-03-23 19:18:25 +01:00
|
|
|
if (replace_user_table(thd, tables[0].table, *user_name, 0, 0, 1, 0))
|
2004-11-25 21:55:49 +01:00
|
|
|
{
|
2004-11-27 23:07:30 +01:00
|
|
|
append_user(&wrong_users, user_name);
|
2004-11-25 21:55:49 +01:00
|
|
|
result= TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_unlock(&acl_cache->lock);
|
2006-10-03 19:38:25 +02:00
|
|
|
|
2008-01-25 08:02:26 +01:00
|
|
|
if (result)
|
|
|
|
my_error(ER_CANNOT_USER, MYF(0), "CREATE USER", wrong_users.c_ptr_safe());
|
|
|
|
|
2008-01-30 12:14:14 +01:00
|
|
|
if (some_users_created)
|
2009-11-21 05:28:01 +01:00
|
|
|
result |= write_bin_log(thd, FALSE, thd->query(), thd->query_length());
|
2006-10-03 19:38:25 +02:00
|
|
|
|
2004-11-25 21:55:49 +01:00
|
|
|
rw_unlock(&LOCK_grant);
|
|
|
|
close_thread_tables(thd);
|
|
|
|
DBUG_RETURN(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Drop a list of users and all their privileges.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
mysql_drop_user()
|
|
|
|
thd The current thread.
|
|
|
|
list The users to drop.
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
FALSE OK.
|
|
|
|
TRUE Error.
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool mysql_drop_user(THD *thd, List <LEX_USER> &list)
|
|
|
|
{
|
|
|
|
int result;
|
2004-11-27 23:07:30 +01:00
|
|
|
String wrong_users;
|
2006-06-29 12:50:44 +02:00
|
|
|
LEX_USER *user_name, *tmp_user_name;
|
2004-11-25 21:55:49 +01:00
|
|
|
List_iterator <LEX_USER> user_list(list);
|
2004-12-23 11:46:24 +01:00
|
|
|
TABLE_LIST tables[GRANT_TABLES];
|
2008-01-25 08:02:26 +01:00
|
|
|
bool some_users_deleted= FALSE;
|
2009-06-12 23:11:19 +02:00
|
|
|
ulong old_sql_mode= thd->variables.sql_mode;
|
2004-11-25 21:55:49 +01:00
|
|
|
DBUG_ENTER("mysql_drop_user");
|
|
|
|
|
BUG#25091 (A DELETE statement to mysql database is not logged in ROW format):
With this patch, statements that change metadata (in the mysql database)
is logged as statements, while normal changes (e.g., using INSERT, DELETE,
and/or UPDATE) is logged according to the format in effect.
The log tables (i.e., general_log and slow_log) are not replicated at all.
With this patch, the following statements are replicated as statements:
GRANT, REVOKE (ALL), CREATE USER, DROP USER, and RENAME USER.
2007-02-26 10:19:08 +01:00
|
|
|
/*
|
|
|
|
This statement will be replicated as a statement, even when using
|
|
|
|
row-based replication. The flag will be reset at the end of the
|
|
|
|
statement.
|
|
|
|
*/
|
|
|
|
thd->clear_current_stmt_binlog_row_based();
|
|
|
|
|
2004-11-27 23:07:30 +01:00
|
|
|
/* DROP USER may be skipped on replication client. */
|
2004-11-25 21:55:49 +01:00
|
|
|
if ((result= open_grant_tables(thd, tables)))
|
|
|
|
DBUG_RETURN(result != 1);
|
|
|
|
|
2009-06-12 23:11:19 +02:00
|
|
|
thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH;
|
|
|
|
|
2004-11-25 21:55:49 +01:00
|
|
|
rw_wrlock(&LOCK_grant);
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_lock(&acl_cache->lock);
|
2004-11-25 21:55:49 +01:00
|
|
|
|
2006-06-29 12:50:44 +02:00
|
|
|
while ((tmp_user_name= user_list++))
|
2004-11-25 21:55:49 +01:00
|
|
|
{
|
2006-06-29 12:50:44 +02:00
|
|
|
if (!(user_name= get_current_user(thd, tmp_user_name)))
|
|
|
|
{
|
|
|
|
result= TRUE;
|
|
|
|
continue;
|
|
|
|
}
|
2005-02-25 15:53:22 +01:00
|
|
|
if (handle_grant_data(tables, 1, user_name, NULL) <= 0)
|
2003-06-06 14:43:23 +02:00
|
|
|
{
|
2004-11-27 23:07:30 +01:00
|
|
|
append_user(&wrong_users, user_name);
|
2004-11-25 21:55:49 +01:00
|
|
|
result= TRUE;
|
2008-01-25 08:02:26 +01:00
|
|
|
continue;
|
2003-06-06 14:43:23 +02:00
|
|
|
}
|
2008-01-25 08:02:26 +01:00
|
|
|
some_users_deleted= TRUE;
|
2004-11-25 21:55:49 +01:00
|
|
|
}
|
2003-06-06 14:43:23 +02:00
|
|
|
|
2005-12-28 14:43:50 +01:00
|
|
|
/* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */
|
|
|
|
rebuild_check_host();
|
|
|
|
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_unlock(&acl_cache->lock);
|
2006-10-03 19:38:25 +02:00
|
|
|
|
2007-06-20 14:24:31 +02:00
|
|
|
if (result)
|
|
|
|
my_error(ER_CANNOT_USER, MYF(0), "DROP USER", wrong_users.c_ptr_safe());
|
|
|
|
|
2008-01-30 12:14:14 +01:00
|
|
|
if (some_users_deleted)
|
2009-11-21 05:28:01 +01:00
|
|
|
result |= write_bin_log(thd, FALSE, thd->query(), thd->query_length());
|
2006-10-03 19:38:25 +02:00
|
|
|
|
2004-11-25 21:55:49 +01:00
|
|
|
rw_unlock(&LOCK_grant);
|
|
|
|
close_thread_tables(thd);
|
2009-06-12 23:11:19 +02:00
|
|
|
thd->variables.sql_mode= old_sql_mode;
|
2004-11-25 21:55:49 +01:00
|
|
|
DBUG_RETURN(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Rename a user.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
mysql_rename_user()
|
|
|
|
thd The current thread.
|
|
|
|
list The user name pairs: (from, to).
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
FALSE OK.
|
|
|
|
TRUE Error.
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool mysql_rename_user(THD *thd, List <LEX_USER> &list)
|
|
|
|
{
|
2005-12-28 14:43:50 +01:00
|
|
|
int result;
|
2004-11-27 23:07:30 +01:00
|
|
|
String wrong_users;
|
2006-06-29 12:50:44 +02:00
|
|
|
LEX_USER *user_from, *tmp_user_from;
|
|
|
|
LEX_USER *user_to, *tmp_user_to;
|
2004-11-25 21:55:49 +01:00
|
|
|
List_iterator <LEX_USER> user_list(list);
|
2004-12-23 11:46:24 +01:00
|
|
|
TABLE_LIST tables[GRANT_TABLES];
|
2008-01-25 08:02:26 +01:00
|
|
|
bool some_users_renamed= FALSE;
|
2004-11-25 21:55:49 +01:00
|
|
|
DBUG_ENTER("mysql_rename_user");
|
|
|
|
|
BUG#25091 (A DELETE statement to mysql database is not logged in ROW format):
With this patch, statements that change metadata (in the mysql database)
is logged as statements, while normal changes (e.g., using INSERT, DELETE,
and/or UPDATE) is logged according to the format in effect.
The log tables (i.e., general_log and slow_log) are not replicated at all.
With this patch, the following statements are replicated as statements:
GRANT, REVOKE (ALL), CREATE USER, DROP USER, and RENAME USER.
2007-02-26 10:19:08 +01:00
|
|
|
/*
|
|
|
|
This statement will be replicated as a statement, even when using
|
|
|
|
row-based replication. The flag will be reset at the end of the
|
|
|
|
statement.
|
|
|
|
*/
|
|
|
|
thd->clear_current_stmt_binlog_row_based();
|
|
|
|
|
2004-11-27 23:07:30 +01:00
|
|
|
/* RENAME USER may be skipped on replication client. */
|
2004-11-25 21:55:49 +01:00
|
|
|
if ((result= open_grant_tables(thd, tables)))
|
|
|
|
DBUG_RETURN(result != 1);
|
|
|
|
|
|
|
|
rw_wrlock(&LOCK_grant);
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_lock(&acl_cache->lock);
|
2004-11-25 21:55:49 +01:00
|
|
|
|
2006-06-29 12:50:44 +02:00
|
|
|
while ((tmp_user_from= user_list++))
|
2004-11-25 21:55:49 +01:00
|
|
|
{
|
2006-06-29 12:50:44 +02:00
|
|
|
if (!(user_from= get_current_user(thd, tmp_user_from)))
|
|
|
|
{
|
|
|
|
result= TRUE;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
tmp_user_to= user_list++;
|
|
|
|
if (!(user_to= get_current_user(thd, tmp_user_to)))
|
|
|
|
{
|
|
|
|
result= TRUE;
|
|
|
|
continue;
|
|
|
|
}
|
2005-02-25 15:53:22 +01:00
|
|
|
DBUG_ASSERT(user_to != 0); /* Syntax enforces pairs of users. */
|
2004-11-25 21:55:49 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
Search all in-memory structures and grant tables
|
|
|
|
for a mention of the new user name.
|
|
|
|
*/
|
2004-11-27 23:07:30 +01:00
|
|
|
if (handle_grant_data(tables, 0, user_to, NULL) ||
|
|
|
|
handle_grant_data(tables, 0, user_from, user_to) <= 0)
|
2004-11-25 21:55:49 +01:00
|
|
|
{
|
2004-11-27 23:07:30 +01:00
|
|
|
append_user(&wrong_users, user_from);
|
2004-11-25 21:55:49 +01:00
|
|
|
result= TRUE;
|
2008-01-25 08:02:26 +01:00
|
|
|
continue;
|
2004-11-25 21:55:49 +01:00
|
|
|
}
|
2008-01-25 08:02:26 +01:00
|
|
|
some_users_renamed= TRUE;
|
2003-06-06 14:43:23 +02:00
|
|
|
}
|
2006-08-17 01:19:49 +02:00
|
|
|
|
2005-12-28 14:43:50 +01:00
|
|
|
/* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */
|
|
|
|
rebuild_check_host();
|
|
|
|
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_unlock(&acl_cache->lock);
|
2006-10-03 19:38:25 +02:00
|
|
|
|
2008-01-25 08:02:26 +01:00
|
|
|
if (result)
|
|
|
|
my_error(ER_CANNOT_USER, MYF(0), "RENAME USER", wrong_users.c_ptr_safe());
|
|
|
|
|
|
|
|
if (some_users_renamed && mysql_bin_log.is_open())
|
2009-11-21 05:28:01 +01:00
|
|
|
result |= write_bin_log(thd, FALSE, thd->query(), thd->query_length());
|
2006-10-03 19:38:25 +02:00
|
|
|
|
2003-06-06 14:43:23 +02:00
|
|
|
rw_unlock(&LOCK_grant);
|
|
|
|
close_thread_tables(thd);
|
|
|
|
DBUG_RETURN(result);
|
|
|
|
}
|
|
|
|
|
2004-12-06 01:00:37 +01:00
|
|
|
|
2004-11-25 21:55:49 +01:00
|
|
|
/*
|
|
|
|
Revoke all privileges from a list of users.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
mysql_revoke_all()
|
|
|
|
thd The current thread.
|
|
|
|
list The users to revoke all privileges from.
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
> 0 Error. Error message already sent.
|
|
|
|
0 OK.
|
|
|
|
< 0 Error. Error message not yet sent.
|
|
|
|
*/
|
|
|
|
|
2004-10-20 03:04:37 +02:00
|
|
|
bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
|
2003-06-06 14:43:23 +02:00
|
|
|
{
|
2005-05-17 20:54:20 +02:00
|
|
|
uint counter, revoked, is_proc;
|
2003-06-06 14:43:23 +02:00
|
|
|
int result;
|
2003-11-20 21:06:25 +01:00
|
|
|
ACL_DB *acl_db;
|
2004-12-23 11:46:24 +01:00
|
|
|
TABLE_LIST tables[GRANT_TABLES];
|
2003-06-06 14:43:23 +02:00
|
|
|
DBUG_ENTER("mysql_revoke_all");
|
|
|
|
|
BUG#25091 (A DELETE statement to mysql database is not logged in ROW format):
With this patch, statements that change metadata (in the mysql database)
is logged as statements, while normal changes (e.g., using INSERT, DELETE,
and/or UPDATE) is logged according to the format in effect.
The log tables (i.e., general_log and slow_log) are not replicated at all.
With this patch, the following statements are replicated as statements:
GRANT, REVOKE (ALL), CREATE USER, DROP USER, and RENAME USER.
2007-02-26 10:19:08 +01:00
|
|
|
/*
|
|
|
|
This statement will be replicated as a statement, even when using
|
|
|
|
row-based replication. The flag will be reset at the end of the
|
|
|
|
statement.
|
|
|
|
*/
|
|
|
|
thd->clear_current_stmt_binlog_row_based();
|
|
|
|
|
2003-06-06 14:43:23 +02:00
|
|
|
if ((result= open_grant_tables(thd, tables)))
|
2004-10-20 03:04:37 +02:00
|
|
|
DBUG_RETURN(result != 1);
|
2003-06-06 14:43:23 +02:00
|
|
|
|
|
|
|
rw_wrlock(&LOCK_grant);
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_lock(&acl_cache->lock);
|
2003-06-06 14:43:23 +02:00
|
|
|
|
2006-06-29 12:50:44 +02:00
|
|
|
LEX_USER *lex_user, *tmp_lex_user;
|
2003-06-06 14:43:23 +02:00
|
|
|
List_iterator <LEX_USER> user_list(list);
|
2006-06-29 12:50:44 +02:00
|
|
|
while ((tmp_lex_user= user_list++))
|
2003-06-06 14:43:23 +02:00
|
|
|
{
|
2006-06-29 12:50:44 +02:00
|
|
|
if (!(lex_user= get_current_user(thd, tmp_lex_user)))
|
|
|
|
{
|
|
|
|
result= -1;
|
|
|
|
continue;
|
|
|
|
}
|
2006-05-06 09:25:59 +02:00
|
|
|
if (!find_acl_user(lex_user->host.str, lex_user->user.str, TRUE))
|
2003-06-06 14:43:23 +02:00
|
|
|
{
|
|
|
|
result= -1;
|
|
|
|
continue;
|
|
|
|
}
|
2003-08-11 21:44:43 +02:00
|
|
|
|
2003-06-06 14:43:23 +02:00
|
|
|
if (replace_user_table(thd, tables[0].table,
|
2005-06-02 06:56:30 +02:00
|
|
|
*lex_user, ~(ulong)0, 1, 0, 0))
|
2003-06-06 14:43:23 +02:00
|
|
|
{
|
|
|
|
result= -1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Remove db access privileges */
|
2004-10-19 03:25:47 +02:00
|
|
|
/*
|
|
|
|
Because acl_dbs and column_priv_hash shrink and may re-order
|
|
|
|
as privileges are removed, removal occurs in a repeated loop
|
|
|
|
until no more privileges are revoked.
|
|
|
|
*/
|
2004-10-22 20:41:40 +02:00
|
|
|
do
|
2003-06-06 14:43:23 +02:00
|
|
|
{
|
2004-10-22 20:41:40 +02:00
|
|
|
for (counter= 0, revoked= 0 ; counter < acl_dbs.elements ; )
|
2003-06-06 14:43:23 +02:00
|
|
|
{
|
2004-10-19 03:25:47 +02:00
|
|
|
const char *user,*host;
|
2004-11-27 23:07:30 +01:00
|
|
|
|
2004-10-19 03:25:47 +02:00
|
|
|
acl_db=dynamic_element(&acl_dbs,counter,ACL_DB*);
|
|
|
|
if (!(user=acl_db->user))
|
|
|
|
user= "";
|
|
|
|
if (!(host=acl_db->host.hostname))
|
|
|
|
host= "";
|
2004-11-27 23:07:30 +01:00
|
|
|
|
2004-10-19 03:25:47 +02:00
|
|
|
if (!strcmp(lex_user->user.str,user) &&
|
2007-09-20 18:10:35 +02:00
|
|
|
!strcmp(lex_user->host.str, host))
|
2004-10-19 03:25:47 +02:00
|
|
|
{
|
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes
Changes that requires code changes in other code of other storage engines.
(Note that all changes are very straightforward and one should find all issues
by compiling a --debug build and fixing all compiler errors and all
asserts in field.cc while running the test suite),
- New optional handler function introduced: reset()
This is called after every DML statement to make it easy for a handler to
statement specific cleanups.
(The only case it's not called is if force the file to be closed)
- handler::extra(HA_EXTRA_RESET) is removed. Code that was there before
should be moved to handler::reset()
- table->read_set contains a bitmap over all columns that are needed
in the query. read_row() and similar functions only needs to read these
columns
- table->write_set contains a bitmap over all columns that will be updated
in the query. write_row() and update_row() only needs to update these
columns.
The above bitmaps should now be up to date in all context
(including ALTER TABLE, filesort()).
The handler is informed of any changes to the bitmap after
fix_fields() by calling the virtual function
handler::column_bitmaps_signal(). If the handler does caching of
these bitmaps (instead of using table->read_set, table->write_set),
it should redo the caching in this code. as the signal() may be sent
several times, it's probably best to set a variable in the signal
and redo the caching on read_row() / write_row() if the variable was
set.
- Removed the read_set and write_set bitmap objects from the handler class
- Removed all column bit handling functions from the handler class.
(Now one instead uses the normal bitmap functions in my_bitmap.c instead
of handler dedicated bitmap functions)
- field->query_id is removed. One should instead instead check
table->read_set and table->write_set if a field is used in the query.
- handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and
handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now
instead use table->read_set to check for which columns to retrieve.
- If a handler needs to call Field->val() or Field->store() on columns
that are not used in the query, one should install a temporary
all-columns-used map while doing so. For this, we provide the following
functions:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
field->val();
dbug_tmp_restore_column_map(table->read_set, old_map);
and similar for the write map:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
field->val();
dbug_tmp_restore_column_map(table->write_set, old_map);
If this is not done, you will sooner or later hit a DBUG_ASSERT
in the field store() / val() functions.
(For not DBUG binaries, the dbug_tmp_restore_column_map() and
dbug_tmp_restore_column_map() are inline dummy functions and should
be optimized away be the compiler).
- If one needs to temporary set the column map for all binaries (and not
just to avoid the DBUG_ASSERT() in the Field::store() / Field::val()
methods) one should use the functions tmp_use_all_columns() and
tmp_restore_column_map() instead of the above dbug_ variants.
- All 'status' fields in the handler base class (like records,
data_file_length etc) are now stored in a 'stats' struct. This makes
it easier to know what status variables are provided by the base
handler. This requires some trivial variable names in the extra()
function.
- New virtual function handler::records(). This is called to optimize
COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true.
(stats.records is not supposed to be an exact value. It's only has to
be 'reasonable enough' for the optimizer to be able to choose a good
optimization path).
- Non virtual handler::init() function added for caching of virtual
constants from engine.
- Removed has_transactions() virtual method. Now one should instead return
HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support
transactions.
- The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument
that is to be used with 'new handler_name()' to allocate the handler
in the right area. The xxxx_create_handler() function is also
responsible for any initialization of the object before returning.
For example, one should change:
static handler *myisam_create_handler(TABLE_SHARE *table)
{
return new ha_myisam(table);
}
->
static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisam(table);
}
- New optional virtual function: use_hidden_primary_key().
This is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key. This allows the handler to take precisions
in remembering any hidden primary key to able to update/delete any
found row. The default handler marks all columns to be read.
- handler::table_flags() now returns a ulonglong (to allow for more flags).
- New/changed table_flags()
- HA_HAS_RECORDS Set if ::records() is supported
- HA_NO_TRANSACTIONS Set if engine doesn't support transactions
- HA_PRIMARY_KEY_REQUIRED_FOR_DELETE
Set if we should mark all primary key columns for
read when reading rows as part of a DELETE
statement. If there is no primary key,
all columns are marked for read.
- HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some
cases (based on table->read_set)
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
- HA_DUPP_POS Renamed to HA_DUPLICATE_POS
- HA_REQUIRES_KEY_COLUMNS_FOR_DELETE
Set this if we should mark ALL key columns for
read when when reading rows as part of a DELETE
statement. In case of an update we will mark
all keys for read for which key part changed
value.
- HA_STATS_RECORDS_IS_EXACT
Set this if stats.records is exact.
(This saves us some extra records() calls
when optimizing COUNT(*))
- Removed table_flags()
- HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if
handler::records() gives an exact count() and
HA_STATS_RECORDS_IS_EXACT if stats.records is exact.
- HA_READ_RND_SAME Removed (no one supported this one)
- Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk()
- Renamed handler::dupp_pos to handler::dup_pos
- Removed not used variable handler::sortkey
Upper level handler changes:
- ha_reset() now does some overall checks and calls ::reset()
- ha_table_flags() added. This is a cached version of table_flags(). The
cache is updated on engine creation time and updated on open.
MySQL level changes (not obvious from the above):
- DBUG_ASSERT() added to check that column usage matches what is set
in the column usage bit maps. (This found a LOT of bugs in current
column marking code).
- In 5.1 before, all used columns was marked in read_set and only updated
columns was marked in write_set. Now we only mark columns for which we
need a value in read_set.
- Column bitmaps are created in open_binary_frm() and open_table_from_share().
(Before this was in table.cc)
- handler::table_flags() calls are replaced with handler::ha_table_flags()
- For calling field->val() you must have the corresponding bit set in
table->read_set. For calling field->store() you must have the
corresponding bit set in table->write_set. (There are asserts in
all store()/val() functions to catch wrong usage)
- thd->set_query_id is renamed to thd->mark_used_columns and instead
of setting this to an integer value, this has now the values:
MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE
Changed also all variables named 'set_query_id' to mark_used_columns.
- In filesort() we now inform the handler of exactly which columns are needed
doing the sort and choosing the rows.
- The TABLE_SHARE object has a 'all_set' column bitmap one can use
when one needs a column bitmap with all columns set.
(This is used for table->use_all_columns() and other places)
- The TABLE object has 3 column bitmaps:
- def_read_set Default bitmap for columns to be read
- def_write_set Default bitmap for columns to be written
- tmp_set Can be used as a temporary bitmap when needed.
The table object has also two pointer to bitmaps read_set and write_set
that the handler should use to find out which columns are used in which way.
- count() optimization now calls handler::records() instead of using
handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true).
- Added extra argument to Item::walk() to indicate if we should also
traverse sub queries.
- Added TABLE parameter to cp_buffer_from_ref()
- Don't close tables created with CREATE ... SELECT but keep them in
the table cache. (Faster usage of newly created tables).
New interfaces:
- table->clear_column_bitmaps() to initialize the bitmaps for tables
at start of new statements.
- table->column_bitmaps_set() to set up new column bitmaps and signal
the handler about this.
- table->column_bitmaps_set_no_signal() for some few cases where we need
to setup new column bitmaps but don't signal the handler (as the handler
has already been signaled about these before). Used for the momement
only in opt_range.cc when doing ROR scans.
- table->use_all_columns() to install a bitmap where all columns are marked
as use in the read and the write set.
- table->default_column_bitmaps() to install the normal read and write
column bitmaps, but not signaling the handler about this.
This is mainly used when creating TABLE instances.
- table->mark_columns_needed_for_delete(),
table->mark_columns_needed_for_delete() and
table->mark_columns_needed_for_insert() to allow us to put additional
columns in column usage maps if handler so requires.
(The handler indicates what it neads in handler->table_flags())
- table->prepare_for_position() to allow us to tell handler that it
needs to read primary key parts to be able to store them in
future table->position() calls.
(This replaces the table->file->ha_retrieve_all_pk function)
- table->mark_auto_increment_column() to tell handler are going to update
columns part of any auto_increment key.
- table->mark_columns_used_by_index() to mark all columns that is part of
an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow
it to quickly know that it only needs to read colums that are part
of the key. (The handler can also use the column map for detecting this,
but simpler/faster handler can just monitor the extra() call).
- table->mark_columns_used_by_index_no_reset() to in addition to other columns,
also mark all columns that is used by the given key.
- table->restore_column_maps_after_mark_index() to restore to default
column maps after a call to table->mark_columns_used_by_index().
- New item function register_field_in_read_map(), for marking used columns
in table->read_map. Used by filesort() to mark all used columns
- Maintain in TABLE->merge_keys set of all keys that are used in query.
(Simplices some optimization loops)
- Maintain Field->part_of_key_not_clustered which is like Field->part_of_key
but the field in the clustered key is not assumed to be part of all index.
(used in opt_range.cc for faster loops)
- dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map()
tmp_use_all_columns() and tmp_restore_column_map() functions to temporally
mark all columns as usable. The 'dbug_' version is primarily intended
inside a handler when it wants to just call Field:store() & Field::val()
functions, but don't need the column maps set for any other usage.
(ie:: bitmap_is_set() is never called)
- We can't use compare_records() to skip updates for handlers that returns
a partial column set and the read_set doesn't cover all columns in the
write set. The reason for this is that if we have a column marked only for
write we can't in the MySQL level know if the value changed or not.
The reason this worked before was that MySQL marked all to be written
columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden
bug'.
- open_table_from_share() does not anymore setup temporary MEM_ROOT
object as a thread specific variable for the handler. Instead we
send the to-be-used MEMROOT to get_new_handler().
(Simpler, faster code)
Bugs fixed:
- Column marking was not done correctly in a lot of cases.
(ALTER TABLE, when using triggers, auto_increment fields etc)
(Could potentially result in wrong values inserted in table handlers
relying on that the old column maps or field->set_query_id was correct)
Especially when it comes to triggers, there may be cases where the
old code would cause lost/wrong values for NDB and/or InnoDB tables.
- Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags:
OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG.
This allowed me to remove some wrong warnings about:
"Some non-transactional changed tables couldn't be rolled back"
- Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset
(thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose
some warnings about
"Some non-transactional changed tables couldn't be rolled back")
- Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table()
which could cause delete_table to report random failures.
- Fixed core dumps for some tests when running with --debug
- Added missing FN_LIBCHAR in mysql_rm_tmp_tables()
(This has probably caused us to not properly remove temporary files after
crash)
- slow_logs was not properly initialized, which could maybe cause
extra/lost entries in slow log.
- If we get an duplicate row on insert, change column map to read and
write all columns while retrying the operation. This is required by
the definition of REPLACE and also ensures that fields that are only
part of UPDATE are properly handled. This fixed a bug in NDB and
REPLACE where REPLACE wrongly copied some column values from the replaced
row.
- For table handler that doesn't support NULL in keys, we would give an error
when creating a primary key with NULL fields, even after the fields has been
automaticly converted to NOT NULL.
- Creating a primary key on a SPATIAL key, would fail if field was not
declared as NOT NULL.
Cleanups:
- Removed not used condition argument to setup_tables
- Removed not needed item function reset_query_id_processor().
- Field->add_index is removed. Now this is instead maintained in
(field->flags & FIELD_IN_ADD_INDEX)
- Field->fieldnr is removed (use field->field_index instead)
- New argument to filesort() to indicate that it should return a set of
row pointers (not used columns). This allowed me to remove some references
to sql_command in filesort and should also enable us to return column
results in some cases where we couldn't before.
- Changed column bitmap handling in opt_range.cc to be aligned with TABLE
bitmap, which allowed me to use bitmap functions instead of looping over
all fields to create some needed bitmaps. (Faster and smaller code)
- Broke up found too long lines
- Moved some variable declaration at start of function for better code
readability.
- Removed some not used arguments from functions.
(setup_fields(), mysql_prepare_insert_check_table())
- setup_fields() now takes an enum instead of an int for marking columns
usage.
- For internal temporary tables, use handler::write_row(),
handler::delete_row() and handler::update_row() instead of
handler::ha_xxxx() for faster execution.
- Changed some constants to enum's and define's.
- Using separate column read and write sets allows for easier checking
of timestamp field was set by statement.
- Remove calls to free_io_cache() as this is now done automaticly in ha_reset()
- Don't build table->normalized_path as this is now identical to table->path
(after bar's fixes to convert filenames)
- Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to
do comparision with the 'convert-dbug-for-diff' tool.
Things left to do in 5.1:
- We wrongly log failed CREATE TABLE ... SELECT in some cases when using
row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result)
Mats has promised to look into this.
- Test that my fix for CREATE TABLE ... SELECT is indeed correct.
(I added several test cases for this, but in this case it's better that
someone else also tests this throughly).
Lars has promosed to do this.
2006-06-04 17:52:22 +02:00
|
|
|
if (!replace_db_table(tables[1].table, acl_db->db, *lex_user,
|
|
|
|
~(ulong)0, 1))
|
2004-10-19 03:25:47 +02:00
|
|
|
{
|
2004-10-22 20:41:40 +02:00
|
|
|
/*
|
|
|
|
Don't increment counter as replace_db_table deleted the
|
|
|
|
current element in acl_dbs.
|
|
|
|
*/
|
|
|
|
revoked= 1;
|
2004-10-19 03:25:47 +02:00
|
|
|
continue;
|
|
|
|
}
|
2004-10-22 20:41:40 +02:00
|
|
|
result= -1; // Something went wrong
|
2004-10-19 03:25:47 +02:00
|
|
|
}
|
2004-10-22 20:41:40 +02:00
|
|
|
counter++;
|
2003-06-06 14:43:23 +02:00
|
|
|
}
|
2004-10-22 20:41:40 +02:00
|
|
|
} while (revoked);
|
2003-06-06 14:43:23 +02:00
|
|
|
|
|
|
|
/* Remove column access */
|
2004-10-22 20:41:40 +02:00
|
|
|
do
|
2003-06-06 14:43:23 +02:00
|
|
|
{
|
2004-10-22 20:41:40 +02:00
|
|
|
for (counter= 0, revoked= 0 ; counter < column_priv_hash.records ; )
|
2003-06-06 14:43:23 +02:00
|
|
|
{
|
2004-10-19 03:25:47 +02:00
|
|
|
const char *user,*host;
|
2009-10-14 18:37:38 +02:00
|
|
|
GRANT_TABLE *grant_table=
|
|
|
|
(GRANT_TABLE*) my_hash_element(&column_priv_hash, counter);
|
2004-10-19 03:25:47 +02:00
|
|
|
if (!(user=grant_table->user))
|
|
|
|
user= "";
|
2005-03-03 01:30:24 +01:00
|
|
|
if (!(host=grant_table->host.hostname))
|
2004-10-19 03:25:47 +02:00
|
|
|
host= "";
|
2004-11-27 23:07:30 +01:00
|
|
|
|
2004-10-19 03:25:47 +02:00
|
|
|
if (!strcmp(lex_user->user.str,user) &&
|
2007-09-20 18:10:35 +02:00
|
|
|
!strcmp(lex_user->host.str, host))
|
2003-06-06 14:43:23 +02:00
|
|
|
{
|
2004-10-19 03:25:47 +02:00
|
|
|
if (replace_table_table(thd,grant_table,tables[2].table,*lex_user,
|
|
|
|
grant_table->db,
|
|
|
|
grant_table->tname,
|
2005-06-02 02:34:10 +02:00
|
|
|
~(ulong)0, 0, 1))
|
2004-10-22 20:41:40 +02:00
|
|
|
{
|
2004-10-19 03:25:47 +02:00
|
|
|
result= -1;
|
2004-10-22 20:41:40 +02:00
|
|
|
}
|
2004-10-19 03:25:47 +02:00
|
|
|
else
|
2004-10-22 21:32:23 +02:00
|
|
|
{
|
2004-10-22 20:41:40 +02:00
|
|
|
if (!grant_table->cols)
|
2004-10-19 03:25:47 +02:00
|
|
|
{
|
2004-10-22 20:41:40 +02:00
|
|
|
revoked= 1;
|
|
|
|
continue;
|
2004-10-19 03:25:47 +02:00
|
|
|
}
|
2004-10-22 20:41:40 +02:00
|
|
|
List<LEX_COLUMN> columns;
|
|
|
|
if (!replace_column_table(grant_table,tables[3].table, *lex_user,
|
2004-10-22 21:32:23 +02:00
|
|
|
columns,
|
|
|
|
grant_table->db,
|
|
|
|
grant_table->tname,
|
2005-06-02 02:34:10 +02:00
|
|
|
~(ulong)0, 1))
|
2004-10-19 03:25:47 +02:00
|
|
|
{
|
2004-10-22 20:41:40 +02:00
|
|
|
revoked= 1;
|
2004-10-01 21:48:48 +02:00
|
|
|
continue;
|
2004-10-19 03:25:47 +02:00
|
|
|
}
|
2003-06-06 14:43:23 +02:00
|
|
|
result= -1;
|
2004-10-01 14:50:26 +02:00
|
|
|
}
|
2003-06-06 14:43:23 +02:00
|
|
|
}
|
2004-10-22 20:41:40 +02:00
|
|
|
counter++;
|
2003-06-06 14:43:23 +02:00
|
|
|
}
|
2004-10-22 20:41:40 +02:00
|
|
|
} while (revoked);
|
2004-12-23 11:46:24 +01:00
|
|
|
|
|
|
|
/* Remove procedure access */
|
2005-05-17 20:54:20 +02:00
|
|
|
for (is_proc=0; is_proc<2; is_proc++) do {
|
|
|
|
HASH *hash= is_proc ? &proc_priv_hash : &func_priv_hash;
|
|
|
|
for (counter= 0, revoked= 0 ; counter < hash->records ; )
|
2004-12-23 11:46:24 +01:00
|
|
|
{
|
|
|
|
const char *user,*host;
|
2009-10-14 18:37:38 +02:00
|
|
|
GRANT_NAME *grant_proc= (GRANT_NAME*) my_hash_element(hash, counter);
|
2004-12-23 11:46:24 +01:00
|
|
|
if (!(user=grant_proc->user))
|
|
|
|
user= "";
|
2005-03-04 02:44:28 +01:00
|
|
|
if (!(host=grant_proc->host.hostname))
|
2004-12-23 11:46:24 +01:00
|
|
|
host= "";
|
|
|
|
|
|
|
|
if (!strcmp(lex_user->user.str,user) &&
|
2007-09-20 18:10:35 +02:00
|
|
|
!strcmp(lex_user->host.str, host))
|
2004-12-23 11:46:24 +01:00
|
|
|
{
|
2008-03-05 15:33:32 +01:00
|
|
|
if (replace_routine_table(thd,grant_proc,tables[4].table,*lex_user,
|
2004-12-23 11:46:24 +01:00
|
|
|
grant_proc->db,
|
|
|
|
grant_proc->tname,
|
2005-05-17 20:54:20 +02:00
|
|
|
is_proc,
|
2008-03-05 15:33:32 +01:00
|
|
|
~(ulong)0, 1) == 0)
|
2004-12-23 11:46:24 +01:00
|
|
|
{
|
|
|
|
revoked= 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
result= -1; // Something went wrong
|
|
|
|
}
|
|
|
|
counter++;
|
|
|
|
}
|
|
|
|
} while (revoked);
|
2003-06-06 14:43:23 +02:00
|
|
|
}
|
2004-11-27 23:07:30 +01:00
|
|
|
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_unlock(&acl_cache->lock);
|
2006-10-03 19:38:25 +02:00
|
|
|
|
2009-11-21 05:28:01 +01:00
|
|
|
int binlog_error=
|
|
|
|
write_bin_log(thd, FALSE, thd->query(), thd->query_length());
|
2006-10-03 19:38:25 +02:00
|
|
|
|
2003-06-06 14:43:23 +02:00
|
|
|
rw_unlock(&LOCK_grant);
|
|
|
|
close_thread_tables(thd);
|
2004-11-27 23:07:30 +01:00
|
|
|
|
2009-11-21 05:28:01 +01:00
|
|
|
/* error for writing binary log has already been reported */
|
|
|
|
if (result && !binlog_error)
|
2004-11-12 13:34:00 +01:00
|
|
|
my_message(ER_REVOKE_GRANTS, ER(ER_REVOKE_GRANTS), MYF(0));
|
2004-11-27 23:07:30 +01:00
|
|
|
|
2009-11-21 05:28:01 +01:00
|
|
|
DBUG_RETURN(result || binlog_error);
|
2003-06-06 14:43:23 +02:00
|
|
|
}
|
2002-02-01 20:45:23 +01:00
|
|
|
|
2002-05-15 12:50:38 +02:00
|
|
|
|
2004-12-23 11:46:24 +01:00
|
|
|
|
2008-03-05 15:33:32 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
If the defining user for a routine does not exist, then the ACL lookup
|
|
|
|
code should raise two errors which we should intercept. We convert the more
|
|
|
|
descriptive error into a warning, and consume the other.
|
|
|
|
|
|
|
|
If any other errors are raised, then we set a flag that should indicate
|
|
|
|
that there was some failure we should complain at a higher level.
|
|
|
|
*/
|
|
|
|
class Silence_routine_definer_errors : public Internal_error_handler
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
Silence_routine_definer_errors()
|
|
|
|
: is_grave(FALSE)
|
|
|
|
{}
|
|
|
|
|
|
|
|
virtual ~Silence_routine_definer_errors()
|
|
|
|
{}
|
|
|
|
|
2009-09-10 11:18:29 +02:00
|
|
|
virtual bool handle_condition(THD *thd,
|
|
|
|
uint sql_errno,
|
|
|
|
const char* sqlstate,
|
|
|
|
MYSQL_ERROR::enum_warning_level level,
|
|
|
|
const char* msg,
|
|
|
|
MYSQL_ERROR ** cond_hdl);
|
2008-03-05 15:33:32 +01:00
|
|
|
|
|
|
|
bool has_errors() { return is_grave; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
bool is_grave;
|
|
|
|
};
|
|
|
|
|
|
|
|
bool
|
2009-09-10 11:18:29 +02:00
|
|
|
Silence_routine_definer_errors::handle_condition(
|
|
|
|
THD *thd,
|
|
|
|
uint sql_errno,
|
|
|
|
const char*,
|
|
|
|
MYSQL_ERROR::enum_warning_level level,
|
|
|
|
const char* msg,
|
|
|
|
MYSQL_ERROR ** cond_hdl)
|
2008-03-05 15:33:32 +01:00
|
|
|
{
|
2009-09-10 11:18:29 +02:00
|
|
|
*cond_hdl= NULL;
|
2008-03-05 15:33:32 +01:00
|
|
|
if (level == MYSQL_ERROR::WARN_LEVEL_ERROR)
|
|
|
|
{
|
|
|
|
switch (sql_errno)
|
|
|
|
{
|
|
|
|
case ER_NONEXISTING_PROC_GRANT:
|
|
|
|
/* Convert the error into a warning. */
|
2009-09-10 11:18:29 +02:00
|
|
|
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
|
|
|
sql_errno, msg);
|
2008-03-05 15:33:32 +01:00
|
|
|
return TRUE;
|
|
|
|
default:
|
|
|
|
is_grave= TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
Revoke privileges for all users on a stored procedure. Use an error handler
|
|
|
|
that converts errors about missing grants into warnings.
|
|
|
|
|
|
|
|
@param
|
2004-12-23 11:46:24 +01:00
|
|
|
thd The current thread.
|
2008-03-05 15:33:32 +01:00
|
|
|
@param
|
2004-12-23 11:46:24 +01:00
|
|
|
db DB of the stored procedure
|
2008-03-05 15:33:32 +01:00
|
|
|
@param
|
2004-12-23 11:46:24 +01:00
|
|
|
name Name of the stored procedure
|
|
|
|
|
2008-03-05 15:33:32 +01:00
|
|
|
@retval
|
2004-12-23 11:46:24 +01:00
|
|
|
0 OK.
|
2008-03-05 15:33:32 +01:00
|
|
|
@retval
|
2004-12-23 11:46:24 +01:00
|
|
|
< 0 Error. Error message not yet sent.
|
|
|
|
*/
|
|
|
|
|
2005-05-17 20:54:20 +02:00
|
|
|
bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
|
|
|
|
bool is_proc)
|
2004-12-23 11:46:24 +01:00
|
|
|
{
|
|
|
|
uint counter, revoked;
|
|
|
|
int result;
|
|
|
|
TABLE_LIST tables[GRANT_TABLES];
|
2005-05-17 20:54:20 +02:00
|
|
|
HASH *hash= is_proc ? &proc_priv_hash : &func_priv_hash;
|
2008-03-05 15:33:32 +01:00
|
|
|
Silence_routine_definer_errors error_handler;
|
2004-12-23 11:46:24 +01:00
|
|
|
DBUG_ENTER("sp_revoke_privileges");
|
|
|
|
|
|
|
|
if ((result= open_grant_tables(thd, tables)))
|
|
|
|
DBUG_RETURN(result != 1);
|
|
|
|
|
2008-03-05 15:33:32 +01:00
|
|
|
/* Be sure to pop this before exiting this scope! */
|
|
|
|
thd->push_internal_handler(&error_handler);
|
|
|
|
|
2004-12-23 11:46:24 +01:00
|
|
|
rw_wrlock(&LOCK_grant);
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_lock(&acl_cache->lock);
|
2004-12-23 11:46:24 +01:00
|
|
|
|
BUG#25091 (A DELETE statement to mysql database is not logged in ROW format):
With this patch, statements that change metadata (in the mysql database)
is logged as statements, while normal changes (e.g., using INSERT, DELETE,
and/or UPDATE) is logged according to the format in effect.
The log tables (i.e., general_log and slow_log) are not replicated at all.
With this patch, the following statements are replicated as statements:
GRANT, REVOKE (ALL), CREATE USER, DROP USER, and RENAME USER.
2007-02-26 10:19:08 +01:00
|
|
|
/*
|
|
|
|
This statement will be replicated as a statement, even when using
|
|
|
|
row-based replication. The flag will be reset at the end of the
|
|
|
|
statement.
|
|
|
|
*/
|
|
|
|
thd->clear_current_stmt_binlog_row_based();
|
|
|
|
|
2004-12-23 11:46:24 +01:00
|
|
|
/* Remove procedure access */
|
2005-02-25 15:53:22 +01:00
|
|
|
do
|
|
|
|
{
|
2005-05-17 20:54:20 +02:00
|
|
|
for (counter= 0, revoked= 0 ; counter < hash->records ; )
|
2004-12-23 11:46:24 +01:00
|
|
|
{
|
2009-10-14 18:37:38 +02:00
|
|
|
GRANT_NAME *grant_proc= (GRANT_NAME*) my_hash_element(hash, counter);
|
2009-10-27 09:09:19 +01:00
|
|
|
if (!my_strcasecmp(&my_charset_utf8_bin, grant_proc->db, sp_db) &&
|
2004-12-23 11:46:24 +01:00
|
|
|
!my_strcasecmp(system_charset_info, grant_proc->tname, sp_name))
|
|
|
|
{
|
|
|
|
LEX_USER lex_user;
|
|
|
|
lex_user.user.str= grant_proc->user;
|
|
|
|
lex_user.user.length= strlen(grant_proc->user);
|
2006-06-06 13:21:07 +02:00
|
|
|
lex_user.host.str= grant_proc->host.hostname ?
|
|
|
|
grant_proc->host.hostname : (char*)"";
|
|
|
|
lex_user.host.length= grant_proc->host.hostname ?
|
|
|
|
strlen(grant_proc->host.hostname) : 0;
|
2008-03-05 15:33:32 +01:00
|
|
|
|
|
|
|
if (replace_routine_table(thd,grant_proc,tables[4].table,lex_user,
|
|
|
|
grant_proc->db, grant_proc->tname,
|
|
|
|
is_proc, ~(ulong)0, 1) == 0)
|
2004-12-23 11:46:24 +01:00
|
|
|
{
|
|
|
|
revoked= 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
counter++;
|
|
|
|
}
|
|
|
|
} while (revoked);
|
|
|
|
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_unlock(&acl_cache->lock);
|
2004-12-23 11:46:24 +01:00
|
|
|
rw_unlock(&LOCK_grant);
|
|
|
|
close_thread_tables(thd);
|
|
|
|
|
2008-03-05 15:33:32 +01:00
|
|
|
thd->pop_internal_handler();
|
2004-12-23 11:46:24 +01:00
|
|
|
|
2008-03-05 15:33:32 +01:00
|
|
|
DBUG_RETURN(error_handler.has_errors());
|
2004-12-23 11:46:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-05-29 15:37:54 +02:00
|
|
|
/**
|
2004-12-23 11:46:24 +01:00
|
|
|
Grant EXECUTE,ALTER privilege for a stored procedure
|
|
|
|
|
2009-05-29 15:37:54 +02:00
|
|
|
@param thd The current thread.
|
|
|
|
@param sp_db
|
|
|
|
@param sp_name
|
|
|
|
@param is_proc
|
2004-12-23 11:46:24 +01:00
|
|
|
|
2009-05-29 15:37:54 +02:00
|
|
|
@return
|
|
|
|
@retval FALSE Success
|
|
|
|
@retval TRUE An error occured. Error message not yet sent.
|
2004-12-23 11:46:24 +01:00
|
|
|
*/
|
|
|
|
|
2009-05-29 15:37:54 +02:00
|
|
|
bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
|
2005-05-17 20:54:20 +02:00
|
|
|
bool is_proc)
|
2004-12-23 11:46:24 +01:00
|
|
|
{
|
2005-09-20 20:20:38 +02:00
|
|
|
Security_context *sctx= thd->security_ctx;
|
2004-12-23 11:46:24 +01:00
|
|
|
LEX_USER *combo;
|
|
|
|
TABLE_LIST tables[1];
|
|
|
|
List<LEX_USER> user_list;
|
|
|
|
bool result;
|
2006-06-28 12:40:17 +02:00
|
|
|
ACL_USER *au;
|
|
|
|
char passwd_buff[SCRAMBLED_PASSWORD_CHAR_LENGTH+1];
|
2009-05-29 15:37:54 +02:00
|
|
|
Dummy_error_handler error_handler;
|
2005-09-15 21:29:07 +02:00
|
|
|
DBUG_ENTER("sp_grant_privileges");
|
2004-12-23 11:46:24 +01:00
|
|
|
|
|
|
|
if (!(combo=(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
|
2005-09-15 21:29:07 +02:00
|
|
|
combo->user.str= sctx->user;
|
2006-06-28 12:40:17 +02:00
|
|
|
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_lock(&acl_cache->lock);
|
2006-06-28 12:40:17 +02:00
|
|
|
|
|
|
|
if ((au= find_acl_user(combo->host.str=(char*)sctx->host_or_ip,combo->user.str,FALSE)))
|
|
|
|
goto found_acl;
|
|
|
|
if ((au= find_acl_user(combo->host.str=(char*)sctx->host, combo->user.str,FALSE)))
|
|
|
|
goto found_acl;
|
|
|
|
if ((au= find_acl_user(combo->host.str=(char*)sctx->ip, combo->user.str,FALSE)))
|
|
|
|
goto found_acl;
|
|
|
|
if((au= find_acl_user(combo->host.str=(char*)"%", combo->user.str, FALSE)))
|
|
|
|
goto found_acl;
|
|
|
|
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_unlock(&acl_cache->lock);
|
2006-06-28 12:40:17 +02:00
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
|
|
|
|
found_acl:
|
2009-11-24 14:54:59 +01:00
|
|
|
pthread_mutex_unlock(&acl_cache->lock);
|
2004-12-23 11:46:24 +01:00
|
|
|
|
|
|
|
bzero((char*)tables, sizeof(TABLE_LIST));
|
|
|
|
user_list.empty();
|
|
|
|
|
|
|
|
tables->db= (char*)sp_db;
|
2005-01-06 12:00:13 +01:00
|
|
|
tables->table_name= tables->alias= (char*)sp_name;
|
2006-06-28 12:40:17 +02:00
|
|
|
|
2004-12-23 11:46:24 +01:00
|
|
|
combo->host.length= strlen(combo->host.str);
|
|
|
|
combo->user.length= strlen(combo->user.str);
|
|
|
|
combo->host.str= thd->strmake(combo->host.str,combo->host.length);
|
|
|
|
combo->user.str= thd->strmake(combo->user.str,combo->user.length);
|
2006-06-28 12:40:17 +02:00
|
|
|
|
|
|
|
|
|
|
|
if(au && au->salt_len)
|
|
|
|
{
|
|
|
|
if (au->salt_len == SCRAMBLE_LENGTH)
|
|
|
|
{
|
|
|
|
make_password_from_salt(passwd_buff, au->salt);
|
|
|
|
combo->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH;
|
|
|
|
}
|
|
|
|
else if (au->salt_len == SCRAMBLE_LENGTH_323)
|
|
|
|
{
|
|
|
|
make_password_from_salt_323(passwd_buff, (ulong *) au->salt);
|
|
|
|
combo->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-05-29 15:37:54 +02:00
|
|
|
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
|
|
|
ER_PASSWD_LENGTH,
|
|
|
|
ER(ER_PASSWD_LENGTH),
|
|
|
|
SCRAMBLED_PASSWORD_CHAR_LENGTH);
|
|
|
|
return TRUE;
|
2006-06-28 12:40:17 +02:00
|
|
|
}
|
|
|
|
combo->password.str= passwd_buff;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
combo->password.str= (char*)"";
|
|
|
|
combo->password.length= 0;
|
|
|
|
}
|
2004-12-23 11:46:24 +01:00
|
|
|
|
|
|
|
if (user_list.push_back(combo))
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
|
|
|
|
thd->lex->ssl_type= SSL_TYPE_NOT_SPECIFIED;
|
2009-06-04 07:28:45 +02:00
|
|
|
thd->lex->ssl_cipher= thd->lex->x509_subject= thd->lex->x509_issuer= 0;
|
2005-01-10 17:24:05 +01:00
|
|
|
bzero((char*) &thd->lex->mqh, sizeof(thd->lex->mqh));
|
2004-12-23 11:46:24 +01:00
|
|
|
|
2009-05-29 15:37:54 +02:00
|
|
|
/*
|
|
|
|
Only care about whether the operation failed or succeeded
|
|
|
|
as all errors will be handled later.
|
|
|
|
*/
|
|
|
|
thd->push_internal_handler(&error_handler);
|
2005-05-17 20:54:20 +02:00
|
|
|
result= mysql_routine_grant(thd, tables, is_proc, user_list,
|
2009-05-29 15:37:54 +02:00
|
|
|
DEFAULT_CREATE_PROC_ACLS, FALSE, FALSE);
|
|
|
|
thd->pop_internal_handler();
|
2004-12-23 11:46:24 +01:00
|
|
|
DBUG_RETURN(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
/*****************************************************************************
|
2002-06-12 14:04:18 +02:00
|
|
|
Instantiate used templates
|
2000-07-31 21:29:14 +02:00
|
|
|
*****************************************************************************/
|
|
|
|
|
2005-06-22 11:08:28 +02:00
|
|
|
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
|
2000-07-31 21:29:14 +02:00
|
|
|
template class List_iterator<LEX_COLUMN>;
|
|
|
|
template class List_iterator<LEX_USER>;
|
|
|
|
template class List<LEX_COLUMN>;
|
|
|
|
template class List<LEX_USER>;
|
|
|
|
#endif
|
2003-09-26 12:33:13 +02:00
|
|
|
|
|
|
|
#endif /*NO_EMBEDDED_ACCESS_CHECKS */
|
|
|
|
|
|
|
|
|
|
|
|
int wild_case_compare(CHARSET_INFO *cs, const char *str,const char *wildstr)
|
|
|
|
{
|
|
|
|
reg3 int flag;
|
|
|
|
DBUG_ENTER("wild_case_compare");
|
|
|
|
DBUG_PRINT("enter",("str: '%s' wildstr: '%s'",str,wildstr));
|
|
|
|
while (*wildstr)
|
|
|
|
{
|
|
|
|
while (*wildstr && *wildstr != wild_many && *wildstr != wild_one)
|
|
|
|
{
|
|
|
|
if (*wildstr == wild_prefix && wildstr[1])
|
|
|
|
wildstr++;
|
|
|
|
if (my_toupper(cs, *wildstr++) !=
|
|
|
|
my_toupper(cs, *str++)) DBUG_RETURN(1);
|
|
|
|
}
|
|
|
|
if (! *wildstr ) DBUG_RETURN (*str != 0);
|
|
|
|
if (*wildstr++ == wild_one)
|
|
|
|
{
|
|
|
|
if (! *str++) DBUG_RETURN (1); /* One char; skip */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ /* Found '*' */
|
|
|
|
if (!*wildstr) DBUG_RETURN(0); /* '*' as last char: OK */
|
|
|
|
flag=(*wildstr != wild_many && *wildstr != wild_one);
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if (flag)
|
|
|
|
{
|
|
|
|
char cmp;
|
|
|
|
if ((cmp= *wildstr) == wild_prefix && wildstr[1])
|
|
|
|
cmp=wildstr[1];
|
|
|
|
cmp=my_toupper(cs, cmp);
|
|
|
|
while (*str && my_toupper(cs, *str) != cmp)
|
|
|
|
str++;
|
|
|
|
if (!*str) DBUG_RETURN (1);
|
|
|
|
}
|
|
|
|
if (wild_case_compare(cs, str,wildstr) == 0) DBUG_RETURN (0);
|
|
|
|
} while (*str++);
|
|
|
|
DBUG_RETURN(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DBUG_RETURN (*str != '\0');
|
|
|
|
}
|
|
|
|
|
2004-11-13 11:56:39 +01:00
|
|
|
|
2008-12-24 15:45:47 +01:00
|
|
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
2008-12-23 15:56:08 +01:00
|
|
|
static bool update_schema_privilege(THD *thd, TABLE *table, char *buff,
|
|
|
|
const char* db, const char* t_name,
|
|
|
|
const char* column, uint col_length,
|
|
|
|
const char *priv, uint priv_length,
|
|
|
|
const char* is_grantable)
|
2004-11-13 11:56:39 +01:00
|
|
|
{
|
|
|
|
int i= 2;
|
|
|
|
CHARSET_INFO *cs= system_charset_info;
|
2005-01-06 12:00:13 +01:00
|
|
|
restore_record(table, s->default_values);
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
table->field[0]->store(buff, (uint) strlen(buff), cs);
|
2009-10-23 13:02:20 +02:00
|
|
|
table->field[1]->store(STRING_WITH_LEN("def"), cs);
|
2004-11-13 11:56:39 +01:00
|
|
|
if (db)
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
table->field[i++]->store(db, (uint) strlen(db), cs);
|
2004-11-13 11:56:39 +01:00
|
|
|
if (t_name)
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
table->field[i++]->store(t_name, (uint) strlen(t_name), cs);
|
2004-11-13 11:56:39 +01:00
|
|
|
if (column)
|
|
|
|
table->field[i++]->store(column, col_length, cs);
|
|
|
|
table->field[i++]->store(priv, priv_length, cs);
|
|
|
|
table->field[i]->store(is_grantable, strlen(is_grantable), cs);
|
2008-12-23 15:56:08 +01:00
|
|
|
return schema_table_store_record(thd, table);
|
2004-11-13 11:56:39 +01:00
|
|
|
}
|
2008-12-24 15:45:47 +01:00
|
|
|
#endif
|
2004-11-13 11:56:39 +01:00
|
|
|
|
|
|
|
|
|
|
|
int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
|
|
|
|
{
|
|
|
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
2008-12-23 15:56:08 +01:00
|
|
|
int error= 0;
|
2004-11-13 11:56:39 +01:00
|
|
|
uint counter;
|
|
|
|
ACL_USER *acl_user;
|
|
|
|
ulong want_access;
|
|
|
|
char buff[100];
|
|
|
|
TABLE *table= tables->table;
|
2005-09-13 13:07:38 +02:00
|
|
|
bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1,0);
|
2005-09-20 20:20:38 +02:00
|
|
|
char *curr_host= thd->security_ctx->priv_host_name();
|
2004-11-13 11:56:39 +01:00
|
|
|
DBUG_ENTER("fill_schema_user_privileges");
|
2005-06-02 12:33:53 +02:00
|
|
|
|
2007-03-16 09:15:51 +01:00
|
|
|
if (!initialized)
|
|
|
|
DBUG_RETURN(0);
|
2006-05-06 09:25:59 +02:00
|
|
|
pthread_mutex_lock(&acl_cache->lock);
|
|
|
|
|
2004-11-13 11:56:39 +01:00
|
|
|
for (counter=0 ; counter < acl_users.elements ; counter++)
|
|
|
|
{
|
|
|
|
const char *user,*host, *is_grantable="YES";
|
|
|
|
acl_user=dynamic_element(&acl_users,counter,ACL_USER*);
|
|
|
|
if (!(user=acl_user->user))
|
|
|
|
user= "";
|
|
|
|
if (!(host=acl_user->host.hostname))
|
|
|
|
host= "";
|
2005-06-02 12:33:53 +02:00
|
|
|
|
|
|
|
if (no_global_access &&
|
2005-09-15 21:29:07 +02:00
|
|
|
(strcmp(thd->security_ctx->priv_user, user) ||
|
2005-06-02 12:33:53 +02:00
|
|
|
my_strcasecmp(system_charset_info, curr_host, host)))
|
|
|
|
continue;
|
|
|
|
|
2004-11-13 11:56:39 +01:00
|
|
|
want_access= acl_user->access;
|
|
|
|
if (!(want_access & GRANT_ACL))
|
|
|
|
is_grantable= "NO";
|
|
|
|
|
|
|
|
strxmov(buff,"'",user,"'@'",host,"'",NullS);
|
|
|
|
if (!(want_access & ~GRANT_ACL))
|
2008-12-23 15:56:08 +01:00
|
|
|
{
|
|
|
|
if (update_schema_privilege(thd, table, buff, 0, 0, 0, 0,
|
|
|
|
STRING_WITH_LEN("USAGE"), is_grantable))
|
|
|
|
{
|
|
|
|
error= 1;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
2004-11-13 11:56:39 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
uint priv_id;
|
|
|
|
ulong j,test_access= want_access & ~GRANT_ACL;
|
|
|
|
for (priv_id=0, j = SELECT_ACL;j <= GLOBAL_ACLS; priv_id++,j <<= 1)
|
|
|
|
{
|
|
|
|
if (test_access & j)
|
2008-12-23 15:56:08 +01:00
|
|
|
{
|
|
|
|
if (update_schema_privilege(thd, table, buff, 0, 0, 0, 0,
|
|
|
|
command_array[priv_id],
|
|
|
|
command_lengths[priv_id], is_grantable))
|
|
|
|
{
|
|
|
|
error= 1;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
2004-11-13 11:56:39 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-12-23 15:56:08 +01:00
|
|
|
err:
|
2006-05-06 09:25:59 +02:00
|
|
|
pthread_mutex_unlock(&acl_cache->lock);
|
|
|
|
|
2008-12-23 15:56:08 +01:00
|
|
|
DBUG_RETURN(error);
|
2004-11-13 23:28:44 +01:00
|
|
|
#else
|
|
|
|
return(0);
|
|
|
|
#endif
|
2004-11-13 11:56:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
|
|
|
|
{
|
|
|
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
2008-12-23 15:56:08 +01:00
|
|
|
int error= 0;
|
2004-11-13 11:56:39 +01:00
|
|
|
uint counter;
|
|
|
|
ACL_DB *acl_db;
|
|
|
|
ulong want_access;
|
|
|
|
char buff[100];
|
|
|
|
TABLE *table= tables->table;
|
2005-09-13 13:07:38 +02:00
|
|
|
bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1,0);
|
2005-09-20 20:20:38 +02:00
|
|
|
char *curr_host= thd->security_ctx->priv_host_name();
|
2004-11-13 11:56:39 +01:00
|
|
|
DBUG_ENTER("fill_schema_schema_privileges");
|
|
|
|
|
2007-03-16 09:15:51 +01:00
|
|
|
if (!initialized)
|
|
|
|
DBUG_RETURN(0);
|
2006-05-06 09:25:59 +02:00
|
|
|
pthread_mutex_lock(&acl_cache->lock);
|
|
|
|
|
2004-11-13 11:56:39 +01:00
|
|
|
for (counter=0 ; counter < acl_dbs.elements ; counter++)
|
|
|
|
{
|
|
|
|
const char *user, *host, *is_grantable="YES";
|
|
|
|
|
|
|
|
acl_db=dynamic_element(&acl_dbs,counter,ACL_DB*);
|
|
|
|
if (!(user=acl_db->user))
|
|
|
|
user= "";
|
|
|
|
if (!(host=acl_db->host.hostname))
|
|
|
|
host= "";
|
|
|
|
|
2005-06-02 12:33:53 +02:00
|
|
|
if (no_global_access &&
|
2005-09-15 21:29:07 +02:00
|
|
|
(strcmp(thd->security_ctx->priv_user, user) ||
|
2005-06-02 12:33:53 +02:00
|
|
|
my_strcasecmp(system_charset_info, curr_host, host)))
|
|
|
|
continue;
|
|
|
|
|
2004-11-13 11:56:39 +01:00
|
|
|
want_access=acl_db->access;
|
|
|
|
if (want_access)
|
|
|
|
{
|
|
|
|
if (!(want_access & GRANT_ACL))
|
|
|
|
{
|
|
|
|
is_grantable= "NO";
|
|
|
|
}
|
|
|
|
strxmov(buff,"'",user,"'@'",host,"'",NullS);
|
|
|
|
if (!(want_access & ~GRANT_ACL))
|
2008-12-23 15:56:08 +01:00
|
|
|
{
|
|
|
|
if (update_schema_privilege(thd, table, buff, acl_db->db, 0, 0,
|
|
|
|
0, STRING_WITH_LEN("USAGE"), is_grantable))
|
|
|
|
{
|
|
|
|
error= 1;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
2004-11-13 11:56:39 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
int cnt;
|
|
|
|
ulong j,test_access= want_access & ~GRANT_ACL;
|
|
|
|
for (cnt=0, j = SELECT_ACL; j <= DB_ACLS; cnt++,j <<= 1)
|
|
|
|
if (test_access & j)
|
2008-12-23 15:56:08 +01:00
|
|
|
{
|
|
|
|
if (update_schema_privilege(thd, table, buff, acl_db->db, 0, 0, 0,
|
|
|
|
command_array[cnt], command_lengths[cnt],
|
|
|
|
is_grantable))
|
|
|
|
{
|
|
|
|
error= 1;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
2004-11-13 11:56:39 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-12-23 15:56:08 +01:00
|
|
|
err:
|
2006-05-06 09:25:59 +02:00
|
|
|
pthread_mutex_unlock(&acl_cache->lock);
|
|
|
|
|
2008-12-23 15:56:08 +01:00
|
|
|
DBUG_RETURN(error);
|
2004-11-13 23:28:44 +01:00
|
|
|
#else
|
|
|
|
return (0);
|
|
|
|
#endif
|
2004-11-13 11:56:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
|
|
|
|
{
|
|
|
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
2008-12-23 15:56:08 +01:00
|
|
|
int error= 0;
|
2004-11-13 11:56:39 +01:00
|
|
|
uint index;
|
|
|
|
char buff[100];
|
|
|
|
TABLE *table= tables->table;
|
2005-09-13 13:07:38 +02:00
|
|
|
bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1,0);
|
2005-09-20 20:20:38 +02:00
|
|
|
char *curr_host= thd->security_ctx->priv_host_name();
|
2004-11-13 11:56:39 +01:00
|
|
|
DBUG_ENTER("fill_schema_table_privileges");
|
|
|
|
|
2006-05-06 09:25:59 +02:00
|
|
|
rw_rdlock(&LOCK_grant);
|
|
|
|
|
2004-11-13 11:56:39 +01:00
|
|
|
for (index=0 ; index < column_priv_hash.records ; index++)
|
|
|
|
{
|
2006-06-06 13:21:07 +02:00
|
|
|
const char *user, *host, *is_grantable= "YES";
|
2009-10-14 18:37:38 +02:00
|
|
|
GRANT_TABLE *grant_table= (GRANT_TABLE*) my_hash_element(&column_priv_hash,
|
2004-11-13 11:56:39 +01:00
|
|
|
index);
|
|
|
|
if (!(user=grant_table->user))
|
|
|
|
user= "";
|
2006-06-06 13:21:07 +02:00
|
|
|
if (!(host= grant_table->host.hostname))
|
|
|
|
host= "";
|
2005-06-02 12:33:53 +02:00
|
|
|
|
|
|
|
if (no_global_access &&
|
2005-09-15 21:29:07 +02:00
|
|
|
(strcmp(thd->security_ctx->priv_user, user) ||
|
2006-06-06 13:21:07 +02:00
|
|
|
my_strcasecmp(system_charset_info, curr_host, host)))
|
2005-06-02 12:33:53 +02:00
|
|
|
continue;
|
|
|
|
|
2004-11-13 11:56:39 +01:00
|
|
|
ulong table_access= grant_table->privs;
|
2004-12-10 10:07:11 +01:00
|
|
|
if (table_access)
|
2004-11-13 11:56:39 +01:00
|
|
|
{
|
|
|
|
ulong test_access= table_access & ~GRANT_ACL;
|
2004-12-10 16:25:12 +01:00
|
|
|
/*
|
|
|
|
We should skip 'usage' privilege on table if
|
|
|
|
we have any privileges on column(s) of this table
|
|
|
|
*/
|
2004-12-10 10:07:11 +01:00
|
|
|
if (!test_access && grant_table->cols)
|
|
|
|
continue;
|
2004-11-13 11:56:39 +01:00
|
|
|
if (!(table_access & GRANT_ACL))
|
|
|
|
is_grantable= "NO";
|
|
|
|
|
2006-06-06 13:21:07 +02:00
|
|
|
strxmov(buff, "'", user, "'@'", host, "'", NullS);
|
2004-11-13 11:56:39 +01:00
|
|
|
if (!test_access)
|
2008-12-23 15:56:08 +01:00
|
|
|
{
|
|
|
|
if (update_schema_privilege(thd, table, buff, grant_table->db,
|
|
|
|
grant_table->tname, 0, 0,
|
|
|
|
STRING_WITH_LEN("USAGE"), is_grantable))
|
|
|
|
{
|
|
|
|
error= 1;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
2004-11-13 11:56:39 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
ulong j;
|
|
|
|
int cnt;
|
|
|
|
for (cnt= 0, j= SELECT_ACL; j <= TABLE_ACLS; cnt++, j<<= 1)
|
|
|
|
{
|
|
|
|
if (test_access & j)
|
2008-12-23 15:56:08 +01:00
|
|
|
{
|
|
|
|
if (update_schema_privilege(thd, table, buff, grant_table->db,
|
|
|
|
grant_table->tname, 0, 0,
|
|
|
|
command_array[cnt],
|
|
|
|
command_lengths[cnt], is_grantable))
|
|
|
|
{
|
|
|
|
error= 1;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
2004-11-13 11:56:39 +01:00
|
|
|
}
|
|
|
|
}
|
2008-12-23 15:56:08 +01:00
|
|
|
}
|
2004-11-13 11:56:39 +01:00
|
|
|
}
|
2008-12-23 15:56:08 +01:00
|
|
|
err:
|
2006-05-06 09:25:59 +02:00
|
|
|
rw_unlock(&LOCK_grant);
|
|
|
|
|
2008-12-23 15:56:08 +01:00
|
|
|
DBUG_RETURN(error);
|
2004-11-13 23:28:44 +01:00
|
|
|
#else
|
|
|
|
return (0);
|
|
|
|
#endif
|
2004-11-13 11:56:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
|
|
|
|
{
|
|
|
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
2008-12-23 15:56:08 +01:00
|
|
|
int error= 0;
|
2004-11-13 11:56:39 +01:00
|
|
|
uint index;
|
|
|
|
char buff[100];
|
|
|
|
TABLE *table= tables->table;
|
2005-09-13 13:07:38 +02:00
|
|
|
bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1,0);
|
2005-09-20 20:20:38 +02:00
|
|
|
char *curr_host= thd->security_ctx->priv_host_name();
|
2004-11-13 11:56:39 +01:00
|
|
|
DBUG_ENTER("fill_schema_table_privileges");
|
|
|
|
|
2006-05-06 09:25:59 +02:00
|
|
|
rw_rdlock(&LOCK_grant);
|
|
|
|
|
2004-11-13 11:56:39 +01:00
|
|
|
for (index=0 ; index < column_priv_hash.records ; index++)
|
|
|
|
{
|
2006-06-06 13:21:07 +02:00
|
|
|
const char *user, *host, *is_grantable= "YES";
|
2009-10-14 18:37:38 +02:00
|
|
|
GRANT_TABLE *grant_table= (GRANT_TABLE*) my_hash_element(&column_priv_hash,
|
2004-11-13 11:56:39 +01:00
|
|
|
index);
|
|
|
|
if (!(user=grant_table->user))
|
|
|
|
user= "";
|
2006-06-06 13:21:07 +02:00
|
|
|
if (!(host= grant_table->host.hostname))
|
|
|
|
host= "";
|
2005-06-02 12:33:53 +02:00
|
|
|
|
|
|
|
if (no_global_access &&
|
2005-09-15 21:29:07 +02:00
|
|
|
(strcmp(thd->security_ctx->priv_user, user) ||
|
2006-06-06 13:21:07 +02:00
|
|
|
my_strcasecmp(system_charset_info, curr_host, host)))
|
2005-06-02 12:33:53 +02:00
|
|
|
continue;
|
|
|
|
|
2004-11-13 11:56:39 +01:00
|
|
|
ulong table_access= grant_table->cols;
|
|
|
|
if (table_access != 0)
|
|
|
|
{
|
2004-11-15 17:20:45 +01:00
|
|
|
if (!(grant_table->privs & GRANT_ACL))
|
2004-11-13 11:56:39 +01:00
|
|
|
is_grantable= "NO";
|
|
|
|
|
2004-11-15 17:20:45 +01:00
|
|
|
ulong test_access= table_access & ~GRANT_ACL;
|
2006-06-06 13:21:07 +02:00
|
|
|
strxmov(buff, "'", user, "'@'", host, "'", NullS);
|
2004-11-13 11:56:39 +01:00
|
|
|
if (!test_access)
|
|
|
|
continue;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ulong j;
|
|
|
|
int cnt;
|
|
|
|
for (cnt= 0, j= SELECT_ACL; j <= TABLE_ACLS; cnt++, j<<= 1)
|
|
|
|
{
|
|
|
|
if (test_access & j)
|
|
|
|
{
|
|
|
|
for (uint col_index=0 ;
|
|
|
|
col_index < grant_table->hash_columns.records ;
|
|
|
|
col_index++)
|
|
|
|
{
|
|
|
|
GRANT_COLUMN *grant_column = (GRANT_COLUMN*)
|
2009-10-14 18:37:38 +02:00
|
|
|
my_hash_element(&grant_table->hash_columns,col_index);
|
2004-11-13 11:56:39 +01:00
|
|
|
if ((grant_column->rights & j) && (table_access & j))
|
2008-12-23 15:56:08 +01:00
|
|
|
{
|
|
|
|
if (update_schema_privilege(thd, table, buff, grant_table->db,
|
|
|
|
grant_table->tname,
|
|
|
|
grant_column->column,
|
|
|
|
grant_column->key_length,
|
|
|
|
command_array[cnt],
|
|
|
|
command_lengths[cnt], is_grantable))
|
|
|
|
{
|
|
|
|
error= 1;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
2004-11-13 11:56:39 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-12-23 15:56:08 +01:00
|
|
|
err:
|
2006-05-06 09:25:59 +02:00
|
|
|
rw_unlock(&LOCK_grant);
|
|
|
|
|
2008-12-23 15:56:08 +01:00
|
|
|
DBUG_RETURN(error);
|
2004-11-13 23:28:44 +01:00
|
|
|
#else
|
|
|
|
return (0);
|
|
|
|
#endif
|
2004-11-13 11:56:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-07-16 00:15:55 +02:00
|
|
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
|
|
|
/*
|
|
|
|
fill effective privileges for table
|
|
|
|
|
|
|
|
SYNOPSIS
|
2004-10-07 00:45:06 +02:00
|
|
|
fill_effective_table_privileges()
|
|
|
|
thd thread handler
|
2004-07-16 00:15:55 +02:00
|
|
|
grant grants table descriptor
|
|
|
|
db db name
|
|
|
|
table table name
|
|
|
|
*/
|
|
|
|
|
|
|
|
void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
|
|
|
|
const char *db, const char *table)
|
|
|
|
{
|
2005-09-20 20:20:38 +02:00
|
|
|
Security_context *sctx= thd->security_ctx;
|
2005-10-27 23:18:23 +02:00
|
|
|
DBUG_ENTER("fill_effective_table_privileges");
|
|
|
|
DBUG_PRINT("enter", ("Host: '%s', Ip: '%s', User: '%s', table: `%s`.`%s`",
|
|
|
|
sctx->priv_host, (sctx->ip ? sctx->ip : "(NULL)"),
|
|
|
|
(sctx->priv_user ? sctx->priv_user : "(NULL)"),
|
|
|
|
db, table));
|
2004-10-25 16:32:28 +02:00
|
|
|
/* --skip-grants */
|
|
|
|
if (!initialized)
|
|
|
|
{
|
2005-10-27 23:18:23 +02:00
|
|
|
DBUG_PRINT("info", ("skip grants"));
|
2004-10-25 16:32:28 +02:00
|
|
|
grant->privilege= ~NO_ACCESS; // everything is allowed
|
2005-10-27 23:18:23 +02:00
|
|
|
DBUG_PRINT("info", ("privilege 0x%lx", grant->privilege));
|
|
|
|
DBUG_VOID_RETURN;
|
2004-10-25 16:32:28 +02:00
|
|
|
}
|
|
|
|
|
2004-07-16 00:15:55 +02:00
|
|
|
/* global privileges */
|
2005-09-15 21:29:07 +02:00
|
|
|
grant->privilege= sctx->master_access;
|
2004-07-20 00:01:02 +02:00
|
|
|
|
2005-09-15 21:29:07 +02:00
|
|
|
if (!sctx->priv_user)
|
2005-10-27 23:18:23 +02:00
|
|
|
{
|
|
|
|
DBUG_PRINT("info", ("privilege 0x%lx", grant->privilege));
|
|
|
|
DBUG_VOID_RETURN; // it is slave
|
|
|
|
}
|
2005-01-17 00:18:08 +01:00
|
|
|
|
2004-10-22 14:43:22 +02:00
|
|
|
/* db privileges */
|
2005-09-15 21:29:07 +02:00
|
|
|
grant->privilege|= acl_get(sctx->host, sctx->ip, sctx->priv_user, db, 0);
|
2004-10-22 14:43:22 +02:00
|
|
|
|
2004-07-16 00:15:55 +02:00
|
|
|
/* table privileges */
|
2006-05-15 09:56:02 +02:00
|
|
|
rw_rdlock(&LOCK_grant);
|
2004-07-16 00:15:55 +02:00
|
|
|
if (grant->version != grant_version)
|
|
|
|
{
|
|
|
|
grant->grant_table=
|
2005-09-15 21:29:07 +02:00
|
|
|
table_hash_search(sctx->host, sctx->ip, db,
|
|
|
|
sctx->priv_user,
|
2004-07-16 00:15:55 +02:00
|
|
|
table, 0); /* purecov: inspected */
|
|
|
|
grant->version= grant_version; /* purecov: inspected */
|
|
|
|
}
|
|
|
|
if (grant->grant_table != 0)
|
|
|
|
{
|
|
|
|
grant->privilege|= grant->grant_table->privs;
|
|
|
|
}
|
2006-05-15 09:56:02 +02:00
|
|
|
rw_unlock(&LOCK_grant);
|
|
|
|
|
2005-10-27 23:18:23 +02:00
|
|
|
DBUG_PRINT("info", ("privilege 0x%lx", grant->privilege));
|
|
|
|
DBUG_VOID_RETURN;
|
2004-07-16 00:15:55 +02:00
|
|
|
}
|
2005-03-15 15:07:28 +01:00
|
|
|
|
|
|
|
#else /* NO_EMBEDDED_ACCESS_CHECKS */
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
Dummy wrappers when we don't have any access checks
|
|
|
|
****************************************************************************/
|
|
|
|
|
2005-05-18 00:49:01 +02:00
|
|
|
bool check_routine_level_acl(THD *thd, const char *db, const char *name,
|
|
|
|
bool is_proc)
|
2005-03-15 15:07:28 +01:00
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2004-07-16 00:15:55 +02:00
|
|
|
#endif
|