Temporary commit of merge of MariaDB 10.0-base and MySQL 5.6

This commit is contained in:
Michael Widenius 2012-08-01 17:27:34 +03:00
parent 5a86a61219
commit 1d0f70c2f8
557 changed files with 124450 additions and 30236 deletions

View file

@ -800,14 +800,32 @@ static void print_line(char* line)
static int run_sql_fix_privilege_tables(void)
{
int found_real_errors= 0;
const char **query_ptr;
DYNAMIC_STRING ds_script;
DYNAMIC_STRING ds_result;
DBUG_ENTER("run_sql_fix_privilege_tables");
if (init_dynamic_string(&ds_script, "", 65536, 1024))
die("Out of memory");
if (init_dynamic_string(&ds_result, "", 512, 512))
die("Out of memory");
verbose("Phase 3/3: Running 'mysql_fix_privilege_tables'...");
run_query(mysql_fix_privilege_tables,
/*
Individual queries can not be executed independently by invoking
a forked mysql client, because the script uses session variables
and prepared statements.
*/
for ( query_ptr= &mysql_fix_privilege_tables[0];
*query_ptr != NULL;
query_ptr++
)
{
dynstr_append(&ds_script, *query_ptr);
}
run_query(ds_script.str,
&ds_result, /* Collect result */
TRUE);
@ -835,6 +853,7 @@ static int run_sql_fix_privilege_tables(void)
}
dynstr_free(&ds_result);
dynstr_free(&ds_script);
DBUG_RETURN(found_real_errors);
}

View file

@ -67,14 +67,7 @@ IF(CMAKE_COMPILER_IS_GNUCXX)
# MySQL "canonical" GCC flags. At least -fno-rtti flag affects
# ABI and cannot be simply removed.
SET(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -fno-implicit-templates -fno-exceptions -fno-rtti")
IF(CMAKE_CXX_FLAGS)
STRING(REGEX MATCH "fno-implicit-templates" NO_IMPLICIT_TEMPLATES
${CMAKE_CXX_FLAGS})
IF (NO_IMPLICIT_TEMPLATES)
SET(HAVE_EXPLICIT_TEMPLATE_INSTANTIATION TRUE)
ENDIF()
ENDIF()
"${CMAKE_CXX_FLAGS} -fno-exceptions -fno-rtti")
IF (CMAKE_EXE_LINKER_FLAGS MATCHES " -static "
OR CMAKE_EXE_LINKER_FLAGS MATCHES " -static$")

View file

@ -18,6 +18,7 @@
#ifndef _global_h
#define _global_h
#define MY_GLOBAL_INCLUDED
/* Client library users on Windows need this macro defined here. */
#if !defined(__WIN__) && defined(_WIN32)
@ -1438,6 +1439,8 @@ static inline char *dlerror(void)
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
#endif
#define MY_MAX(a, b) ((a) > (b) ? (a) : (b))
#define MY_MIN(a, b) ((a) < (b) ? (a) : (b))
#define CMP_NUM(a,b) (((a) < (b)) ? -1 : ((a) == (b)) ? 0 : 1)

View file

@ -22,6 +22,36 @@
* $FreeBSD: src/contrib/cvs/lib/md5.h,v 1.2 1999/12/11 15:10:02 peter Exp $
*/
#if defined(HAVE_YASSL) || defined(HAVE_OPENSSL)
/*
Use MD5 implementation provided by the SSL libraries.
*/
#if defined(HAVE_YASSL)
C_MODE_START
void my_md5_hash(char *digest, const char *buf, int len);
C_MODE_END
#else /* HAVE_YASSL */
#include <openssl/md5.h>
#define MY_MD5_HASH(digest, buf, len) \
do { \
MD5_CTX ctx; \
MD5_Init (&ctx); \
MD5_Update (&ctx, buf, len); \
MD5_Final (digest, &ctx); \
} while (0)
#endif /* HAVE_YASSL */
#else /* HAVE_YASSL || HAVE_OPENSSL */
/* Fallback to the MySQL's implementation. */
/* Unlike previous versions of this code, uint32 need not be exactly
32 bits, merely 32 bits or more. Choosing a data type which is 32
bits instead of 64 is not important; speed is considerably more
@ -35,18 +65,15 @@ typedef struct {
unsigned char in[64];
} my_MD5Context;
#ifdef __cplusplus
extern "C" {
#endif
C_MODE_START
void my_MD5Init (my_MD5Context *context);
void my_MD5Update (my_MD5Context *context,
unsigned char const *buf, unsigned len);
void my_MD5Final (unsigned char digest[16],
my_MD5Context *context);
#ifdef __cplusplus
}
#endif
C_MODE_END
#define MY_MD5_HASH(digest,buf,len) \
do { \
@ -56,4 +83,12 @@ do { \
my_MD5Final (digest, &ctx); \
} while (0)
#endif /* MY_MD__INCLUDED */
#endif /* defined(HAVE_YASSL) || defined(HAVE_OPENSSL) */
C_MODE_START
void compute_md5_hash(char *digest, const char *buf, int len);
C_MODE_END
#endif /* MY_MD5_INCLUDED */

View file

@ -498,13 +498,22 @@ void safe_mutex_free_deadlock_data(safe_mutex_t *mp);
DBUG_ASSERT(! (mp)->count || \
! pthread_equal(pthread_self(), (mp)->thread))
#define safe_mutex_setflags(mp, F) do { (mp)->create_flags|= (F); } while (0)
#define my_cond_timedwait(A,B,C) safe_cond_timedwait((A),(B),(C),__FILE__,__LINE__)
#define my_cond_wait(A,B) safe_cond_wait((A), (B), __FILE__, __LINE__)
#else
#define my_pthread_mutex_init(A,B,C,D) pthread_mutex_init((A),(B))
#define safe_mutex_assert_owner(mp) do {} while(0)
#define safe_mutex_assert_not_owner(mp) do {} while(0)
#define safe_mutex_free_deadlock_data(mp) do {} while(0)
#define safe_mutex_assert_owner(mp) do {} while (0)
#define safe_mutex_assert_not_owner(mp) do {} while (0)
#define safe_mutex_setflags(mp, F) do {} while (0)
#endif /* SAFE_MUTEX */
#if defined(MY_PTHREAD_FASTMUTEX)
#define my_cond_timedwait(A,B,C) pthread_cond_timedwait((A), &(B)->mutex, (C))
#define my_cond_wait(A,B) pthread_cond_wait((A), &(B)->mutex)
#else
#define my_cond_timedwait(A,B,C) pthread_cond_timedwait((A),(B),(C))
#define my_cond_wait(A,B) pthread_cond_wait((A), (B))
#endif /* MY_PTHREAD_FASTMUTEX */
#endif /* !SAFE_MUTEX */
#if defined(MY_PTHREAD_FASTMUTEX) && !defined(SAFE_MUTEX)
typedef struct st_my_pthread_fastmutex_t

View file

@ -252,7 +252,9 @@ extern const char *my_defaults_extra_file;
extern const char *my_defaults_group_suffix;
extern const char *my_defaults_file;
#ifndef timed_mutexes
extern my_bool timed_mutexes;
#endif
enum loglevel {
ERROR_LEVEL,
@ -772,16 +774,17 @@ extern my_bool init_dynamic_array2(DYNAMIC_ARRAY *array, uint element_size,
/* init_dynamic_array() function is deprecated */
extern my_bool init_dynamic_array(DYNAMIC_ARRAY *array, uint element_size,
uint init_alloc, uint alloc_increment);
extern my_bool insert_dynamic(DYNAMIC_ARRAY *array, const uchar * element);
extern uchar *alloc_dynamic(DYNAMIC_ARRAY *array);
extern uchar *pop_dynamic(DYNAMIC_ARRAY*);
extern my_bool set_dynamic(DYNAMIC_ARRAY *array,uchar * element,uint array_index);
extern my_bool insert_dynamic(DYNAMIC_ARRAY *array, const void* element);
extern void *alloc_dynamic(DYNAMIC_ARRAY *array);
extern void *pop_dynamic(DYNAMIC_ARRAY*);
extern my_bool set_dynamic(DYNAMIC_ARRAY *array, const void *element,
uint array_index);
extern my_bool allocate_dynamic(DYNAMIC_ARRAY *array, uint max_elements);
extern void get_dynamic(DYNAMIC_ARRAY *array,uchar * element,uint array_index);
extern void get_dynamic(DYNAMIC_ARRAY *array, void *element, uint array_index);
extern void delete_dynamic(DYNAMIC_ARRAY *array);
extern void delete_dynamic_element(DYNAMIC_ARRAY *array, uint array_index);
extern void freeze_size(DYNAMIC_ARRAY *array);
extern int get_index_dynamic(DYNAMIC_ARRAY *array, uchar * element);
extern int get_index_dynamic(DYNAMIC_ARRAY *array, void *element);
#define dynamic_array_ptr(array,array_index) ((array)->buffer+(array_index)*(array)->size_of_element)
#define dynamic_element(array,array_index,type) ((type)((array)->buffer) +(array_index))
#define push_dynamic(A,B) insert_dynamic((A),(B))

View file

@ -37,9 +37,9 @@
#endif /* HAVE_VALGRIND */
#ifndef DBUG_OFF
#define TRASH_FILL(A,B,C) do { bfill(A, B, C); MEM_UNDEFINED(A, B); } while (0)
#define TRASH_FILL(A,B,C) do { const size_t trash_tmp= (B) ; bfill(A, trash_tmp, C); MEM_UNDEFINED(A, trash_tmp); } while (0)
#else
#define TRASH_FILL(A,B,C) do{ MEM_CHECK_ADDRESSABLE(A,B);MEM_UNDEFINED(A,B);} while (0)
#define TRASH_FILL(A,B,C) do{ const size_t trash_tmp= (B) ; MEM_CHECK_ADDRESSABLE(A,trash_tmp);MEM_UNDEFINED(A,trash_tmp);} while (0)
#endif
#define TRASH_ALLOC(A,B) TRASH_FILL(A,B,0xA5)
#define TRASH_FREE(A,B) TRASH_FILL(A,B,0x8F)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,92 @@
/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
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
the Free Software Foundation; version 2 of the License.
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.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
#ifndef MYSQL_IDLE_H
#define MYSQL_IDLE_H
/**
@file mysql/psi/mysql_idle.h
Instrumentation helpers for idle waits.
*/
#include "mysql/psi/psi.h"
/**
@defgroup Idle_instrumentation Idle Instrumentation
@ingroup Instrumentation_interface
@{
*/
/**
@def MYSQL_START_IDLE_WAIT
Instrumentation helper for table io_waits.
This instrumentation marks the start of a wait event.
@param LOCKER the locker
@param STATE the locker state
@sa MYSQL_END_IDLE_WAIT.
*/
#ifdef HAVE_PSI_IDLE_INTERFACE
#define MYSQL_START_IDLE_WAIT(LOCKER, STATE) \
LOCKER= inline_mysql_start_idle_wait(STATE, __FILE__, __LINE__)
#else
#define MYSQL_START_IDLE_WAIT(LOCKER, STATE) \
do {} while (0)
#endif
/**
@def MYSQL_END_IDLE_WAIT
Instrumentation helper for idle waits.
This instrumentation marks the end of a wait event.
@param LOCKER the locker
@sa MYSQL_START_IDLE_WAIT.
*/
#ifdef HAVE_PSI_IDLE_INTERFACE
#define MYSQL_END_IDLE_WAIT(LOCKER) \
inline_mysql_end_idle_wait(LOCKER)
#else
#define MYSQL_END_IDLE_WAIT(LOCKER) \
do {} while (0)
#endif
#ifdef HAVE_PSI_IDLE_INTERFACE
/**
Instrumentation calls for MYSQL_START_IDLE_WAIT.
@sa MYSQL_END_IDLE_WAIT.
*/
static inline struct PSI_idle_locker *
inline_mysql_start_idle_wait(PSI_idle_locker_state *state,
const char *src_file, int src_line)
{
struct PSI_idle_locker *locker;
locker= PSI_CALL(start_idle_wait)(state, src_file, src_line);
return locker;
}
/**
Instrumentation calls for MYSQL_END_IDLE_WAIT.
@sa MYSQL_START_IDLE_WAIT.
*/
static inline void
inline_mysql_end_idle_wait(struct PSI_idle_locker *locker)
{
if (likely(locker != NULL))
PSI_CALL(end_idle_wait)(locker);
}
#endif
/** @} (end of group Idle_instrumentation) */
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,72 @@
/* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
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
the Free Software Foundation; version 2 of the License.
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.
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#ifndef MYSQL_STAGE_H
#define MYSQL_STAGE_H
/**
@file mysql/psi/mysql_stage.h
Instrumentation helpers for stages.
*/
#include "mysql/psi/psi.h"
/**
@defgroup Stage_instrumentation Stage Instrumentation
@ingroup Instrumentation_interface
@{
*/
/**
@def mysql_stage_register(P1, P2, P3)
Stage registration.
*/
#ifdef HAVE_PSI_STAGE_INTERFACE
#define mysql_stage_register(P1, P2, P3) \
inline_mysql_stage_register(P1, P2, P3)
#else
#define mysql_stage_register(P1, P2, P3) \
do {} while (0)
#endif
#ifdef HAVE_PSI_STAGE_INTERFACE
#define MYSQL_SET_STAGE(K, F, L) \
inline_mysql_set_stage(K, F, L)
#else
#define MYSQL_SET_STAGE(K, F, L) \
do {} while (0)
#endif
#ifdef HAVE_PSI_STAGE_INTERFACE
static inline void inline_mysql_stage_register(
const char *category, PSI_stage_info **info, int count)
{
PSI_CALL(register_stage)(category, info, count);
}
#endif
#ifdef HAVE_PSI_STAGE_INTERFACE
static inline void
inline_mysql_set_stage(PSI_stage_key key,
const char *src_file, int src_line)
{
PSI_CALL(start_stage)(key, src_file, src_line);
}
#endif
/** @} (end of group Stage_instrumentation) */
#endif

View file

@ -0,0 +1,229 @@
/* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
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
the Free Software Foundation; version 2 of the License.
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.
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#ifndef MYSQL_STATEMENT_H
#define MYSQL_STATEMENT_H
/**
@file mysql/psi/mysql_statement.h
Instrumentation helpers for statements.
*/
#include "mysql/psi/psi.h"
/**
@defgroup Statement_instrumentation Statement Instrumentation
@ingroup Instrumentation_interface
@{
*/
/**
@def mysql_statement_register(P1, P2, P3)
Statement registration.
*/
#ifdef HAVE_PSI_STATEMENT_INTERFACE
#define mysql_statement_register(P1, P2, P3) \
inline_mysql_statement_register(P1, P2, P3)
#else
#define mysql_statement_register(P1, P2, P3) \
do {} while (0)
#endif
#ifdef HAVE_PSI_STATEMENT_INTERFACE
#ifdef HAVE_PSI_STATEMENT_DIGEST_INTERFACE
#define MYSQL_DIGEST_START(LOCKER) \
inline_mysql_digest_start(LOCKER)
#else
#define MYSQL_DIGEST_START(LOCKER) \
NULL
#endif
#else
#define MYSQL_DIGEST_START(LOCKER) \
NULL
#endif
#ifdef HAVE_PSI_STATEMENT_DIGEST_INTERFACE
#define MYSQL_ADD_TOKEN(LOCKER, T, Y) \
inline_mysql_add_token(LOCKER, T, Y)
#else
#define MYSQL_ADD_TOKEN(LOCKER, T, Y) \
NULL
#endif
#ifdef HAVE_PSI_STATEMENT_INTERFACE
#define MYSQL_START_STATEMENT(STATE, K, DB, DB_LEN) \
inline_mysql_start_statement(STATE, K, DB, DB_LEN, __FILE__, __LINE__)
#else
#define MYSQL_START_STATEMENT(STATE, K, DB, DB_LEN) \
NULL
#endif
#ifdef HAVE_PSI_STATEMENT_INTERFACE
#define MYSQL_REFINE_STATEMENT(LOCKER, K) \
inline_mysql_refine_statement(LOCKER, K)
#else
#define MYSQL_REFINE_STATEMENT(LOCKER, K) \
NULL
#endif
#ifdef HAVE_PSI_STATEMENT_INTERFACE
#define MYSQL_SET_STATEMENT_TEXT(LOCKER, P1, P2) \
inline_mysql_set_statement_text(LOCKER, P1, P2)
#else
#define MYSQL_SET_STATEMENT_TEXT(LOCKER, P1, P2) \
do {} while (0)
#endif
#ifdef HAVE_PSI_STATEMENT_INTERFACE
#define MYSQL_SET_STATEMENT_LOCK_TIME(LOCKER, P1) \
inline_mysql_set_statement_lock_time(LOCKER, P1)
#else
#define MYSQL_SET_STATEMENT_LOCK_TIME(LOCKER, P1) \
do {} while (0)
#endif
#ifdef HAVE_PSI_STATEMENT_INTERFACE
#define MYSQL_SET_STATEMENT_ROWS_SENT(LOCKER, P1) \
inline_mysql_set_statement_rows_sent(LOCKER, P1)
#else
#define MYSQL_SET_STATEMENT_ROWS_SENT(LOCKER, P1) \
do {} while (0)
#endif
#ifdef HAVE_PSI_STATEMENT_INTERFACE
#define MYSQL_SET_STATEMENT_ROWS_EXAMINED(LOCKER, P1) \
inline_mysql_set_statement_rows_examined(LOCKER, P1)
#else
#define MYSQL_SET_STATEMENT_ROWS_EXAMINED(LOCKER, P1) \
do {} while (0)
#endif
#ifdef HAVE_PSI_STATEMENT_INTERFACE
#define MYSQL_END_STATEMENT(LOCKER, DA) \
inline_mysql_end_statement(LOCKER, DA)
#else
#define MYSQL_END_STATEMENT(LOCKER, DA) \
do {} while (0)
#endif
#ifdef HAVE_PSI_STATEMENT_INTERFACE
static inline void inline_mysql_statement_register(
const char *category, PSI_statement_info *info, int count)
{
PSI_CALL(register_statement)(category, info, count);
}
#ifdef HAVE_PSI_STATEMENT_DIGEST_INTERFACE
static inline struct PSI_digest_locker *
inline_mysql_digest_start(PSI_statement_locker *locker)
{
PSI_digest_locker* digest_locker= NULL;
if (likely(locker != NULL))
digest_locker= PSI_CALL(digest_start)(locker);
return digest_locker;
}
#endif
#ifdef HAVE_PSI_STATEMENT_DIGEST_INTERFACE
static inline struct PSI_digest_locker *
inline_mysql_add_token(PSI_digest_locker *locker, uint token,
void *yylval)
{
if (likely(locker != NULL))
locker= PSI_CALL(digest_add_token)(locker, token,
(OPAQUE_LEX_YYSTYPE*)yylval);
return locker;
}
#endif
static inline struct PSI_statement_locker *
inline_mysql_start_statement(PSI_statement_locker_state *state,
PSI_statement_key key,
const char *db, uint db_len,
const char *src_file, int src_line)
{
PSI_statement_locker *locker;
locker= PSI_CALL(get_thread_statement_locker)(state, key);
if (likely(locker != NULL))
PSI_CALL(start_statement)(locker, db, db_len, src_file, src_line);
return locker;
}
static inline struct PSI_statement_locker *
inline_mysql_refine_statement(PSI_statement_locker *locker,
PSI_statement_key key)
{
if (likely(locker != NULL))
{
locker= PSI_CALL(refine_statement)(locker, key);
}
return locker;
}
static inline void
inline_mysql_set_statement_text(PSI_statement_locker *locker,
const char *text, uint text_len)
{
if (likely(locker != NULL))
{
PSI_CALL(set_statement_text)(locker, text, text_len);
}
}
static inline void
inline_mysql_set_statement_lock_time(PSI_statement_locker *locker,
ulonglong count)
{
if (likely(locker != NULL))
{
PSI_CALL(set_statement_lock_time)(locker, count);
}
}
static inline void
inline_mysql_set_statement_rows_sent(PSI_statement_locker *locker,
ulonglong count)
{
if (likely(locker != NULL))
{
PSI_CALL(set_statement_rows_sent)(locker, count);
}
}
static inline void
inline_mysql_set_statement_rows_examined(PSI_statement_locker *locker,
ulonglong count)
{
if (likely(locker != NULL))
{
PSI_CALL(set_statement_rows_examined)(locker, count);
}
}
static inline void
inline_mysql_end_statement(struct PSI_statement_locker *locker,
Diagnostics_area *stmt_da)
{
PSI_CALL(end_stage)();
if (likely(locker != NULL))
PSI_CALL(end_statement)(locker, stmt_da);
}
#endif
/** @} (end of group Statement_instrumentation) */
#endif

View file

@ -0,0 +1,188 @@
/* Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
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
the Free Software Foundation; version 2 of the License.
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.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
#ifndef MYSQL_TABLE_H
#define MYSQL_TABLE_H
/**
@file mysql/psi/mysql_table.h
Instrumentation helpers for table io.
*/
#include "mysql/psi/psi.h"
/**
@defgroup Table_instrumentation Table Instrumentation
@ingroup Instrumentation_interface
@{
*/
/**
@def MYSQL_TABLE_WAIT_VARIABLES
Instrumentation helper for table waits.
This instrumentation declares local variables.
Do not use a ';' after this macro
@param LOCKER the locker
@param STATE the locker state
@sa MYSQL_START_TABLE_IO_WAIT.
@sa MYSQL_END_TABLE_IO_WAIT.
@sa MYSQL_START_TABLE_LOCK_WAIT.
@sa MYSQL_END_TABLE_LOCK_WAIT.
*/
#ifdef HAVE_PSI_TABLE_INTERFACE
#define MYSQL_TABLE_WAIT_VARIABLES(LOCKER, STATE) \
struct PSI_table_locker* LOCKER; \
PSI_table_locker_state STATE;
#else
#define MYSQL_TABLE_WAIT_VARIABLES(LOCKER, STATE)
#endif
/**
@def MYSQL_TABLE_IO_WAIT
Instrumentation helper for table io_waits.
This instrumentation marks the start of a wait event.
@param PSI the instrumented table
@param OP the table operation to be performed
@param INDEX the table index used if any, or MAY_KEY.
@param FLAGS per table operation flags.
@sa MYSQL_END_TABLE_WAIT.
*/
#ifdef HAVE_PSI_TABLE_INTERFACE
#define MYSQL_TABLE_IO_WAIT(PSI, OP, INDEX, FLAGS, PAYLOAD) \
{ \
if (PSI != NULL) \
{ \
PSI_table_locker *locker; \
PSI_table_locker_state state; \
locker= PSI_CALL(start_table_io_wait)(& state, PSI, OP, INDEX, \
__FILE__, __LINE__); \
PAYLOAD \
if (locker != NULL) \
PSI_CALL(end_table_io_wait)(locker); \
} \
else \
{ \
PAYLOAD \
} \
}
#else
#define MYSQL_TABLE_IO_WAIT(PSI, OP, INDEX, FLAGS, PAYLOAD) \
PAYLOAD
#endif
/**
@def MYSQL_TABLE_LOCK_WAIT
Instrumentation helper for table io_waits.
This instrumentation marks the start of a wait event.
@param PSI the instrumented table
@param OP the table operation to be performed
@param INDEX the table index used if any, or MAY_KEY.
@param FLAGS per table operation flags.
@sa MYSQL_END_TABLE_WAIT.
*/
#ifdef HAVE_PSI_TABLE_INTERFACE
#define MYSQL_TABLE_LOCK_WAIT(PSI, OP, FLAGS, PAYLOAD) \
{ \
if (PSI != NULL) \
{ \
PSI_table_locker *locker; \
PSI_table_locker_state state; \
locker= PSI_CALL(start_table_lock_wait)(& state, PSI, OP, FLAGS, \
__FILE__, __LINE__); \
PAYLOAD \
if (locker != NULL) \
PSI_CALL(end_table_lock_wait)(locker); \
} \
else \
{ \
PAYLOAD \
} \
}
#else
#define MYSQL_TABLE_LOCK_WAIT(PSI, OP, FLAGS, PAYLOAD) \
PAYLOAD
#endif
/**
@def MYSQL_START_TABLE_LOCK_WAIT
Instrumentation helper for table lock waits.
This instrumentation marks the start of a wait event.
@param LOCKER the locker
@param STATE the locker state
@param PSI the instrumented table
@param OP the table operation to be performed
@param FLAGS per table operation flags.
@sa MYSQL_END_TABLE_LOCK_WAIT.
*/
#ifdef HAVE_PSI_TABLE_INTERFACE
#define MYSQL_START_TABLE_LOCK_WAIT(LOCKER, STATE, PSI, OP, FLAGS) \
LOCKER= inline_mysql_start_table_lock_wait(STATE, PSI, \
OP, FLAGS, __FILE__, __LINE__)
#else
#define MYSQL_START_TABLE_LOCK_WAIT(LOCKER, STATE, PSI, OP, FLAGS) \
do {} while (0)
#endif
/**
@def MYSQL_END_TABLE_LOCK_WAIT
Instrumentation helper for table lock waits.
This instrumentation marks the end of a wait event.
@param LOCKER the locker
@sa MYSQL_START_TABLE_LOCK_WAIT.
*/
#ifdef HAVE_PSI_TABLE_INTERFACE
#define MYSQL_END_TABLE_LOCK_WAIT(LOCKER) \
inline_mysql_end_table_lock_wait(LOCKER)
#else
#define MYSQL_END_TABLE_LOCK_WAIT(LOCKER) \
do {} while (0)
#endif
#ifdef HAVE_PSI_TABLE_INTERFACE
/**
Instrumentation calls for MYSQL_START_TABLE_LOCK_WAIT.
@sa MYSQL_END_TABLE_LOCK_WAIT.
*/
static inline struct PSI_table_locker *
inline_mysql_start_table_lock_wait(PSI_table_locker_state *state,
struct PSI_table *psi,
enum PSI_table_lock_operation op,
ulong flags, const char *src_file, int src_line)
{
if (psi != NULL)
{
struct PSI_table_locker *locker;
locker= PSI_CALL(start_table_lock_wait)(state, psi, op, flags, src_file, src_line);
return locker;
}
return NULL;
}
/**
Instrumentation calls for MYSQL_END_TABLE_LOCK_WAIT.
@sa MYSQL_START_TABLE_LOCK_WAIT.
*/
static inline void
inline_mysql_end_table_lock_wait(struct PSI_table_locker *locker)
{
if (locker != NULL)
PSI_CALL(end_table_lock_wait)(locker);
}
#endif
/** @} (end of group Table_instrumentation) */
#endif

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,24 @@
/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
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
the Free Software Foundation; version 2 of the License.
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.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
/**
@file mysql/psi/psi_abi_v0.h
ABI check for mysql/psi/psi.h, when compiling without instrumentation.
This file is only used to automate detection of changes between versions.
Do not include this file, include mysql/psi/psi.h instead.
*/
#define _global_h
#include "mysql/psi/psi.h"

View file

@ -0,0 +1,47 @@
#include "mysql/psi/psi.h"
C_MODE_START
struct TABLE_SHARE;
struct OPAQUE_LEX_YYSTYPE;
struct PSI_mutex;
typedef struct PSI_mutex PSI_mutex;
struct PSI_rwlock;
typedef struct PSI_rwlock PSI_rwlock;
struct PSI_cond;
typedef struct PSI_cond PSI_cond;
struct PSI_table_share;
typedef struct PSI_table_share PSI_table_share;
struct PSI_table;
typedef struct PSI_table PSI_table;
struct PSI_thread;
typedef struct PSI_thread PSI_thread;
struct PSI_file;
typedef struct PSI_file PSI_file;
struct PSI_socket;
typedef struct PSI_socket PSI_socket;
struct PSI_table_locker;
typedef struct PSI_table_locker PSI_table_locker;
struct PSI_statement_locker;
typedef struct PSI_statement_locker PSI_statement_locker;
struct PSI_idle_locker;
typedef struct PSI_idle_locker PSI_idle_locker;
struct PSI_digest_locker;
typedef struct PSI_digest_locker PSI_digest_locker;
struct PSI_bootstrap
{
void* (*get_interface)(int version);
};
typedef struct PSI_bootstrap PSI_bootstrap;
struct PSI_none
{
int opaque;
};
typedef struct PSI_none PSI;
struct PSI_stage_info_none
{
unsigned int m_key;
const char *m_name;
int m_flags;
};
typedef struct PSI_stage_info_none PSI_stage_info;
extern MYSQL_PLUGIN_IMPORT PSI *PSI_server;
C_MODE_END

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
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
@ -21,6 +21,6 @@
*/
#define USE_PSI_1
#define HAVE_PSI_INTERFACE
#define _global_h
#define MY_GLOBAL_INCLUDED
#include "mysql/psi/psi.h"

View file

@ -1,25 +1,52 @@
#include "mysql/psi/psi.h"
C_MODE_START
struct TABLE_SHARE;
struct OPAQUE_LEX_YYSTYPE;
struct PSI_mutex;
typedef struct PSI_mutex PSI_mutex;
struct PSI_rwlock;
typedef struct PSI_rwlock PSI_rwlock;
struct PSI_cond;
typedef struct PSI_cond PSI_cond;
struct PSI_table_share;
typedef struct PSI_table_share PSI_table_share;
struct PSI_table;
typedef struct PSI_table PSI_table;
struct PSI_thread;
typedef struct PSI_thread PSI_thread;
struct PSI_file;
typedef struct PSI_file PSI_file;
struct PSI_socket;
typedef struct PSI_socket PSI_socket;
struct PSI_table_locker;
typedef struct PSI_table_locker PSI_table_locker;
struct PSI_statement_locker;
typedef struct PSI_statement_locker PSI_statement_locker;
struct PSI_idle_locker;
typedef struct PSI_idle_locker PSI_idle_locker;
struct PSI_digest_locker;
typedef struct PSI_digest_locker PSI_digest_locker;
struct PSI_bootstrap
{
void* (*get_interface)(int version);
};
typedef struct PSI_bootstrap PSI_bootstrap;
struct PSI_mutex_locker;
typedef struct PSI_mutex_locker PSI_mutex_locker;
struct PSI_rwlock_locker;
typedef struct PSI_rwlock_locker PSI_rwlock_locker;
struct PSI_cond_locker;
typedef struct PSI_cond_locker PSI_cond_locker;
struct PSI_file_locker;
typedef struct PSI_file_locker PSI_file_locker;
struct PSI_socket_locker;
typedef struct PSI_socket_locker PSI_socket_locker;
enum PSI_mutex_operation
{
PSI_MUTEX_LOCK= 0,
PSI_MUTEX_TRYLOCK= 1
};
typedef enum PSI_mutex_operation PSI_mutex_operation;
enum PSI_rwlock_operation
{
PSI_RWLOCK_READLOCK= 0,
@ -27,11 +54,13 @@ enum PSI_rwlock_operation
PSI_RWLOCK_TRYREADLOCK= 2,
PSI_RWLOCK_TRYWRITELOCK= 3
};
typedef enum PSI_rwlock_operation PSI_rwlock_operation;
enum PSI_cond_operation
{
PSI_COND_WAIT= 0,
PSI_COND_TIMEDWAIT= 1
};
typedef enum PSI_cond_operation PSI_cond_operation;
enum PSI_file_operation
{
PSI_FILE_CREATE= 0,
@ -52,12 +81,54 @@ enum PSI_file_operation
PSI_FILE_RENAME= 15,
PSI_FILE_SYNC= 16
};
struct PSI_table_locker;
typedef enum PSI_file_operation PSI_file_operation;
enum PSI_table_io_operation
{
PSI_TABLE_FETCH_ROW= 0,
PSI_TABLE_WRITE_ROW= 1,
PSI_TABLE_UPDATE_ROW= 2,
PSI_TABLE_DELETE_ROW= 3
};
typedef enum PSI_table_io_operation PSI_table_io_operation;
enum PSI_table_lock_operation
{
PSI_TABLE_LOCK= 0,
PSI_TABLE_EXTERNAL_LOCK= 1
};
typedef enum PSI_table_lock_operation PSI_table_lock_operation;
enum PSI_socket_state
{
PSI_SOCKET_STATE_IDLE= 1,
PSI_SOCKET_STATE_ACTIVE= 2
};
typedef enum PSI_socket_state PSI_socket_state;
enum PSI_socket_operation
{
PSI_SOCKET_CREATE= 0,
PSI_SOCKET_CONNECT= 1,
PSI_SOCKET_BIND= 2,
PSI_SOCKET_CLOSE= 3,
PSI_SOCKET_SEND= 4,
PSI_SOCKET_RECV= 5,
PSI_SOCKET_SENDTO= 6,
PSI_SOCKET_RECVFROM= 7,
PSI_SOCKET_SENDMSG= 8,
PSI_SOCKET_RECVMSG= 9,
PSI_SOCKET_SEEK= 10,
PSI_SOCKET_OPT= 11,
PSI_SOCKET_STAT= 12,
PSI_SOCKET_SHUTDOWN= 13,
PSI_SOCKET_SELECT= 14
};
typedef enum PSI_socket_operation PSI_socket_operation;
typedef unsigned int PSI_mutex_key;
typedef unsigned int PSI_rwlock_key;
typedef unsigned int PSI_cond_key;
typedef unsigned int PSI_thread_key;
typedef unsigned int PSI_file_key;
typedef unsigned int PSI_stage_key;
typedef unsigned int PSI_statement_key;
typedef unsigned int PSI_socket_key;
struct PSI_mutex_info_v1
{
PSI_mutex_key *m_key;
@ -88,67 +159,135 @@ struct PSI_file_info_v1
const char *m_name;
int m_flags;
};
struct PSI_stage_info_v1
{
PSI_stage_key m_key;
const char *m_name;
int m_flags;
};
struct PSI_statement_info_v1
{
PSI_statement_key m_key;
const char *m_name;
int m_flags;
};
struct PSI_socket_info_v1
{
PSI_socket_key *m_key;
const char *m_name;
int m_flags;
};
struct PSI_idle_locker_state_v1
{
uint m_flags;
struct PSI_thread *m_thread;
ulonglong m_timer_start;
ulonglong (*m_timer)(void);
void *m_wait;
};
struct PSI_mutex_locker_state_v1
{
uint m_flags;
enum PSI_mutex_operation m_operation;
struct PSI_mutex *m_mutex;
struct PSI_thread *m_thread;
ulonglong m_timer_start;
ulonglong (*m_timer)(void);
enum PSI_mutex_operation m_operation;
const char* m_src_file;
int m_src_line;
void *m_wait;
};
struct PSI_rwlock_locker_state_v1
{
uint m_flags;
enum PSI_rwlock_operation m_operation;
struct PSI_rwlock *m_rwlock;
struct PSI_thread *m_thread;
ulonglong m_timer_start;
ulonglong (*m_timer)(void);
enum PSI_rwlock_operation m_operation;
const char* m_src_file;
int m_src_line;
void *m_wait;
};
struct PSI_cond_locker_state_v1
{
uint m_flags;
enum PSI_cond_operation m_operation;
struct PSI_cond *m_cond;
struct PSI_mutex *m_mutex;
struct PSI_thread *m_thread;
ulonglong m_timer_start;
ulonglong (*m_timer)(void);
enum PSI_cond_operation m_operation;
const char* m_src_file;
int m_src_line;
void *m_wait;
};
struct PSI_file_locker_state_v1
{
uint m_flags;
enum PSI_file_operation m_operation;
struct PSI_file *m_file;
struct PSI_thread *m_thread;
size_t m_number_of_bytes;
ulonglong m_timer_start;
ulonglong (*m_timer)(void);
enum PSI_file_operation m_operation;
const char* m_src_file;
int m_src_line;
void *m_wait;
};
struct PSI_table_locker_state_v1
{
uint m_flags;
enum PSI_table_io_operation m_io_operation;
struct PSI_table *m_table;
struct PSI_table_share *m_table_share;
struct PSI_thread *m_thread;
ulonglong m_timer_start;
ulonglong (*m_timer)(void);
void *m_wait;
uint m_index;
};
struct PSI_digest_storage
{
my_bool m_full;
int m_byte_count;
unsigned char m_token_array[1024];
};
typedef struct PSI_digest_storage PSI_digest_storage;
struct PSI_digest_locker_state
{
int m_last_id_index;
PSI_digest_storage m_digest_storage;
};
typedef struct PSI_digest_locker_state PSI_digest_locker_state;
struct PSI_statement_locker_state_v1
{
my_bool m_discarded;
uchar m_no_index_used;
uchar m_no_good_index_used;
uint m_flags;
void *m_class;
struct PSI_thread *m_thread;
ulonglong m_timer_start;
ulonglong (*m_timer)(void);
uint m_index;
uint m_lock_index;
void *m_statement;
ulonglong m_lock_time;
ulonglong m_rows_sent;
ulonglong m_rows_examined;
ulong m_created_tmp_disk_tables;
ulong m_created_tmp_tables;
ulong m_select_full_join;
ulong m_select_full_range_join;
ulong m_select_range;
ulong m_select_range_check;
ulong m_select_scan;
ulong m_sort_merge_passes;
ulong m_sort_range;
ulong m_sort_rows;
ulong m_sort_scan;
PSI_digest_locker_state m_digest_state;
};
struct PSI_socket_locker_state_v1
{
uint m_flags;
struct PSI_socket *m_socket;
struct PSI_thread *m_thread;
size_t m_number_of_bytes;
ulonglong m_timer_start;
ulonglong (*m_timer)(void);
enum PSI_socket_operation m_operation;
const char* m_src_file;
int m_src_line;
void *m_wait;
@ -163,6 +302,12 @@ typedef void (*register_thread_v1_t)
(const char *category, struct PSI_thread_info_v1 *info, int count);
typedef void (*register_file_v1_t)
(const char *category, struct PSI_file_info_v1 *info, int count);
typedef void (*register_stage_v1_t)
(const char *category, struct PSI_stage_info_v1 **info, int count);
typedef void (*register_statement_v1_t)
(const char *category, struct PSI_statement_info_v1 *info, int count);
typedef void (*register_socket_v1_t)
(const char *category, struct PSI_socket_info_v1 *info, int count);
typedef struct PSI_mutex* (*init_mutex_v1_t)
(PSI_mutex_key key, const void *identity);
typedef void (*destroy_mutex_v1_t)(struct PSI_mutex *mutex);
@ -172,12 +317,21 @@ typedef void (*destroy_rwlock_v1_t)(struct PSI_rwlock *rwlock);
typedef struct PSI_cond* (*init_cond_v1_t)
(PSI_cond_key key, const void *identity);
typedef void (*destroy_cond_v1_t)(struct PSI_cond *cond);
typedef struct PSI_socket* (*init_socket_v1_t)
(PSI_socket_key key, const my_socket *fd);
typedef void (*destroy_socket_v1_t)(struct PSI_socket *socket);
typedef struct PSI_table_share* (*get_table_share_v1_t)
(const char *schema_name, int schema_name_length, const char *table_name,
int table_name_length, const void *identity);
(my_bool temporary, struct TABLE_SHARE *share);
typedef void (*release_table_share_v1_t)(struct PSI_table_share *share);
typedef void (*drop_table_share_v1_t)
(my_bool temporary, const char *schema_name, int schema_name_length,
const char *table_name, int table_name_length);
typedef struct PSI_table* (*open_table_v1_t)
(struct PSI_table_share *share, const void *identity);
typedef void (*unbind_table_v1_t)
(struct PSI_table *table);
typedef PSI_table* (*rebind_table_v1_t)
(PSI_table_share *share, const void *identity, PSI_table *table);
typedef void (*close_table_v1_t)(struct PSI_table *table);
typedef void (*create_file_v1_t)(PSI_file_key key, const char *name,
File file);
@ -190,24 +344,17 @@ typedef struct PSI_thread* (*new_thread_v1_t)
typedef void (*set_thread_id_v1_t)(struct PSI_thread *thread,
unsigned long id);
typedef struct PSI_thread* (*get_thread_v1_t)(void);
typedef void (*set_thread_user_v1_t)(const char *user, int user_len);
typedef void (*set_thread_user_host_v1_t)(const char *user, int user_len,
const char *host, int host_len);
typedef void (*set_thread_db_v1_t)(const char* db, int db_len);
typedef void (*set_thread_command_v1_t)(int command);
typedef void (*set_thread_start_time_v1_t)(time_t start_time);
typedef void (*set_thread_state_v1_t)(const char* state);
typedef void (*set_thread_info_v1_t)(const char* info, int info_len);
typedef void (*set_thread_v1_t)(struct PSI_thread *thread);
typedef void (*delete_current_thread_v1_t)(void);
typedef void (*delete_thread_v1_t)(struct PSI_thread *thread);
typedef struct PSI_mutex_locker* (*get_thread_mutex_locker_v1_t)
(struct PSI_mutex_locker_state_v1 *state,
struct PSI_mutex *mutex,
enum PSI_mutex_operation op);
typedef struct PSI_rwlock_locker* (*get_thread_rwlock_locker_v1_t)
(struct PSI_rwlock_locker_state_v1 *state,
struct PSI_rwlock *rwlock,
enum PSI_rwlock_operation op);
typedef struct PSI_cond_locker* (*get_thread_cond_locker_v1_t)
(struct PSI_cond_locker_state_v1 *state,
struct PSI_cond *cond, struct PSI_mutex *mutex,
enum PSI_cond_operation op);
typedef struct PSI_table_locker* (*get_thread_table_locker_v1_t)
(struct PSI_table_locker_state_v1 *state,
struct PSI_table *table);
typedef struct PSI_file_locker* (*get_thread_file_name_locker_v1_t)
(struct PSI_file_locker_state_v1 *state,
PSI_file_key key, enum PSI_file_operation op, const char *name,
@ -226,25 +373,53 @@ typedef void (*signal_cond_v1_t)
(struct PSI_cond *cond);
typedef void (*broadcast_cond_v1_t)
(struct PSI_cond *cond);
typedef void (*start_mutex_wait_v1_t)
(struct PSI_mutex_locker *locker, const char *src_file, uint src_line);
typedef struct PSI_idle_locker* (*start_idle_wait_v1_t)
(struct PSI_idle_locker_state_v1 *state, const char *src_file, uint src_line);
typedef void (*end_idle_wait_v1_t)
(struct PSI_idle_locker *locker);
typedef struct PSI_mutex_locker* (*start_mutex_wait_v1_t)
(struct PSI_mutex_locker_state_v1 *state,
struct PSI_mutex *mutex,
enum PSI_mutex_operation op,
const char *src_file, uint src_line);
typedef void (*end_mutex_wait_v1_t)
(struct PSI_mutex_locker *locker, int rc);
typedef void (*start_rwlock_rdwait_v1_t)
(struct PSI_rwlock_locker *locker, const char *src_file, uint src_line);
typedef struct PSI_rwlock_locker* (*start_rwlock_rdwait_v1_t)
(struct PSI_rwlock_locker_state_v1 *state,
struct PSI_rwlock *rwlock,
enum PSI_rwlock_operation op,
const char *src_file, uint src_line);
typedef void (*end_rwlock_rdwait_v1_t)
(struct PSI_rwlock_locker *locker, int rc);
typedef void (*start_rwlock_wrwait_v1_t)
(struct PSI_rwlock_locker *locker, const char *src_file, uint src_line);
typedef struct PSI_rwlock_locker* (*start_rwlock_wrwait_v1_t)
(struct PSI_rwlock_locker_state_v1 *state,
struct PSI_rwlock *rwlock,
enum PSI_rwlock_operation op,
const char *src_file, uint src_line);
typedef void (*end_rwlock_wrwait_v1_t)
(struct PSI_rwlock_locker *locker, int rc);
typedef void (*start_cond_wait_v1_t)
(struct PSI_cond_locker *locker, const char *src_file, uint src_line);
typedef struct PSI_cond_locker* (*start_cond_wait_v1_t)
(struct PSI_cond_locker_state_v1 *state,
struct PSI_cond *cond,
struct PSI_mutex *mutex,
enum PSI_cond_operation op,
const char *src_file, uint src_line);
typedef void (*end_cond_wait_v1_t)
(struct PSI_cond_locker *locker, int rc);
typedef void (*start_table_wait_v1_t)
(struct PSI_table_locker *locker, const char *src_file, uint src_line);
typedef void (*end_table_wait_v1_t)(struct PSI_table_locker *locker);
typedef struct PSI_table_locker* (*start_table_io_wait_v1_t)
(struct PSI_table_locker_state_v1 *state,
struct PSI_table *table,
enum PSI_table_io_operation op,
uint index,
const char *src_file, uint src_line);
typedef void (*end_table_io_wait_v1_t)(struct PSI_table_locker *locker);
typedef struct PSI_table_locker* (*start_table_lock_wait_v1_t)
(struct PSI_table_locker_state_v1 *state,
struct PSI_table *table,
enum PSI_table_lock_operation op,
ulong flags,
const char *src_file, uint src_line);
typedef void (*end_table_lock_wait_v1_t)(struct PSI_table_locker *locker);
typedef struct PSI_file* (*start_file_open_wait_v1_t)
(struct PSI_file_locker *locker, const char *src_file, uint src_line);
typedef void (*end_file_open_wait_v1_t)(struct PSI_file_locker *locker);
@ -255,6 +430,75 @@ typedef void (*start_file_wait_v1_t)
const char *src_file, uint src_line);
typedef void (*end_file_wait_v1_t)
(struct PSI_file_locker *locker, size_t count);
typedef void (*start_stage_v1_t)
(PSI_stage_key key, const char *src_file, int src_line);
typedef void (*end_stage_v1_t) (void);
typedef struct PSI_statement_locker* (*get_thread_statement_locker_v1_t)
(struct PSI_statement_locker_state_v1 *state,
PSI_statement_key key);
typedef struct PSI_statement_locker* (*refine_statement_v1_t)
(struct PSI_statement_locker *locker,
PSI_statement_key key);
typedef void (*start_statement_v1_t)
(struct PSI_statement_locker *locker,
const char *db, uint db_length,
const char *src_file, uint src_line);
typedef void (*set_statement_text_v1_t)
(struct PSI_statement_locker *locker,
const char *text, uint text_len);
typedef void (*set_statement_lock_time_t)
(struct PSI_statement_locker *locker, ulonglong lock_time);
typedef void (*set_statement_rows_sent_t)
(struct PSI_statement_locker *locker, ulonglong count);
typedef void (*set_statement_rows_examined_t)
(struct PSI_statement_locker *locker, ulonglong count);
typedef void (*inc_statement_created_tmp_disk_tables_t)
(struct PSI_statement_locker *locker, ulong count);
typedef void (*inc_statement_created_tmp_tables_t)
(struct PSI_statement_locker *locker, ulong count);
typedef void (*inc_statement_select_full_join_t)
(struct PSI_statement_locker *locker, ulong count);
typedef void (*inc_statement_select_full_range_join_t)
(struct PSI_statement_locker *locker, ulong count);
typedef void (*inc_statement_select_range_t)
(struct PSI_statement_locker *locker, ulong count);
typedef void (*inc_statement_select_range_check_t)
(struct PSI_statement_locker *locker, ulong count);
typedef void (*inc_statement_select_scan_t)
(struct PSI_statement_locker *locker, ulong count);
typedef void (*inc_statement_sort_merge_passes_t)
(struct PSI_statement_locker *locker, ulong count);
typedef void (*inc_statement_sort_range_t)
(struct PSI_statement_locker *locker, ulong count);
typedef void (*inc_statement_sort_rows_t)
(struct PSI_statement_locker *locker, ulong count);
typedef void (*inc_statement_sort_scan_t)
(struct PSI_statement_locker *locker, ulong count);
typedef void (*set_statement_no_index_used_t)
(struct PSI_statement_locker *locker);
typedef void (*set_statement_no_good_index_used_t)
(struct PSI_statement_locker *locker);
typedef void (*end_statement_v1_t)
(struct PSI_statement_locker *locker, void *stmt_da);
typedef struct PSI_socket_locker* (*start_socket_wait_v1_t)
(struct PSI_socket_locker_state_v1 *state,
struct PSI_socket *socket,
enum PSI_socket_operation op,
size_t count,
const char *src_file, uint src_line);
typedef void (*end_socket_wait_v1_t)
(struct PSI_socket_locker *locker, size_t count);
typedef void (*set_socket_state_v1_t)(struct PSI_socket *socket,
enum PSI_socket_state state);
typedef void (*set_socket_info_v1_t)(struct PSI_socket *socket,
const my_socket *fd,
const struct sockaddr *addr,
socklen_t addr_len);
typedef void (*set_socket_thread_owner_v1_t)(struct PSI_socket *socket);
typedef struct PSI_digest_locker * (*digest_start_v1_t)
(struct PSI_statement_locker *locker);
typedef struct PSI_digest_locker* (*digest_add_token_v1_t)
(struct PSI_digest_locker *locker, uint token, struct OPAQUE_LEX_YYSTYPE *yylval);
struct PSI_v1
{
register_mutex_v1_t register_mutex;
@ -262,28 +506,39 @@ struct PSI_v1
register_cond_v1_t register_cond;
register_thread_v1_t register_thread;
register_file_v1_t register_file;
register_stage_v1_t register_stage;
register_statement_v1_t register_statement;
register_socket_v1_t register_socket;
init_mutex_v1_t init_mutex;
destroy_mutex_v1_t destroy_mutex;
init_rwlock_v1_t init_rwlock;
destroy_rwlock_v1_t destroy_rwlock;
init_cond_v1_t init_cond;
destroy_cond_v1_t destroy_cond;
init_socket_v1_t init_socket;
destroy_socket_v1_t destroy_socket;
get_table_share_v1_t get_table_share;
release_table_share_v1_t release_table_share;
drop_table_share_v1_t drop_table_share;
open_table_v1_t open_table;
unbind_table_v1_t unbind_table;
rebind_table_v1_t rebind_table;
close_table_v1_t close_table;
create_file_v1_t create_file;
spawn_thread_v1_t spawn_thread;
new_thread_v1_t new_thread;
set_thread_id_v1_t set_thread_id;
get_thread_v1_t get_thread;
set_thread_user_v1_t set_thread_user;
set_thread_user_host_v1_t set_thread_user_host;
set_thread_db_v1_t set_thread_db;
set_thread_command_v1_t set_thread_command;
set_thread_start_time_v1_t set_thread_start_time;
set_thread_state_v1_t set_thread_state;
set_thread_info_v1_t set_thread_info;
set_thread_v1_t set_thread;
delete_current_thread_v1_t delete_current_thread;
delete_thread_v1_t delete_thread;
get_thread_mutex_locker_v1_t get_thread_mutex_locker;
get_thread_rwlock_locker_v1_t get_thread_rwlock_locker;
get_thread_cond_locker_v1_t get_thread_cond_locker;
get_thread_table_locker_v1_t get_thread_table_locker;
get_thread_file_name_locker_v1_t get_thread_file_name_locker;
get_thread_file_stream_locker_v1_t get_thread_file_stream_locker;
get_thread_file_descriptor_locker_v1_t get_thread_file_descriptor_locker;
@ -291,6 +546,8 @@ struct PSI_v1
unlock_rwlock_v1_t unlock_rwlock;
signal_cond_v1_t signal_cond;
broadcast_cond_v1_t broadcast_cond;
start_idle_wait_v1_t start_idle_wait;
end_idle_wait_v1_t end_idle_wait;
start_mutex_wait_v1_t start_mutex_wait;
end_mutex_wait_v1_t end_mutex_wait;
start_rwlock_rdwait_v1_t start_rwlock_rdwait;
@ -299,14 +556,46 @@ struct PSI_v1
end_rwlock_wrwait_v1_t end_rwlock_wrwait;
start_cond_wait_v1_t start_cond_wait;
end_cond_wait_v1_t end_cond_wait;
start_table_wait_v1_t start_table_wait;
end_table_wait_v1_t end_table_wait;
start_table_io_wait_v1_t start_table_io_wait;
end_table_io_wait_v1_t end_table_io_wait;
start_table_lock_wait_v1_t start_table_lock_wait;
end_table_lock_wait_v1_t end_table_lock_wait;
start_file_open_wait_v1_t start_file_open_wait;
end_file_open_wait_v1_t end_file_open_wait;
end_file_open_wait_and_bind_to_descriptor_v1_t
end_file_open_wait_and_bind_to_descriptor;
start_file_wait_v1_t start_file_wait;
end_file_wait_v1_t end_file_wait;
start_stage_v1_t start_stage;
end_stage_v1_t end_stage;
get_thread_statement_locker_v1_t get_thread_statement_locker;
refine_statement_v1_t refine_statement;
start_statement_v1_t start_statement;
set_statement_text_v1_t set_statement_text;
set_statement_lock_time_t set_statement_lock_time;
set_statement_rows_sent_t set_statement_rows_sent;
set_statement_rows_examined_t set_statement_rows_examined;
inc_statement_created_tmp_disk_tables_t inc_statement_created_tmp_disk_tables;
inc_statement_created_tmp_tables_t inc_statement_created_tmp_tables;
inc_statement_select_full_join_t inc_statement_select_full_join;
inc_statement_select_full_range_join_t inc_statement_select_full_range_join;
inc_statement_select_range_t inc_statement_select_range;
inc_statement_select_range_check_t inc_statement_select_range_check;
inc_statement_select_scan_t inc_statement_select_scan;
inc_statement_sort_merge_passes_t inc_statement_sort_merge_passes;
inc_statement_sort_range_t inc_statement_sort_range;
inc_statement_sort_rows_t inc_statement_sort_rows;
inc_statement_sort_scan_t inc_statement_sort_scan;
set_statement_no_index_used_t set_statement_no_index_used;
set_statement_no_good_index_used_t set_statement_no_good_index_used;
end_statement_v1_t end_statement;
start_socket_wait_v1_t start_socket_wait;
end_socket_wait_v1_t end_socket_wait;
set_socket_state_v1_t set_socket_state;
set_socket_info_v1_t set_socket_info;
set_socket_thread_owner_v1_t set_socket_thread_owner;
digest_start_v1_t digest_start;
digest_add_token_v1_t digest_add_token;
};
typedef struct PSI_v1 PSI;
typedef struct PSI_mutex_info_v1 PSI_mutex_info;
@ -314,10 +603,16 @@ typedef struct PSI_rwlock_info_v1 PSI_rwlock_info;
typedef struct PSI_cond_info_v1 PSI_cond_info;
typedef struct PSI_thread_info_v1 PSI_thread_info;
typedef struct PSI_file_info_v1 PSI_file_info;
typedef struct PSI_stage_info_v1 PSI_stage_info;
typedef struct PSI_statement_info_v1 PSI_statement_info;
typedef struct PSI_socket_info_v1 PSI_socket_info;
typedef struct PSI_idle_locker_state_v1 PSI_idle_locker_state;
typedef struct PSI_mutex_locker_state_v1 PSI_mutex_locker_state;
typedef struct PSI_rwlock_locker_state_v1 PSI_rwlock_locker_state;
typedef struct PSI_cond_locker_state_v1 PSI_cond_locker_state;
typedef struct PSI_file_locker_state_v1 PSI_file_locker_state;
typedef struct PSI_table_locker_state_v1 PSI_table_locker_state;
typedef struct PSI_statement_locker_state_v1 PSI_statement_locker_state;
typedef struct PSI_socket_locker_state_v1 PSI_socket_locker_state;
extern MYSQL_PLUGIN_IMPORT PSI *PSI_server;
C_MODE_END

View file

@ -1,25 +1,52 @@
#include "mysql/psi/psi.h"
C_MODE_START
struct TABLE_SHARE;
struct OPAQUE_LEX_YYSTYPE;
struct PSI_mutex;
typedef struct PSI_mutex PSI_mutex;
struct PSI_rwlock;
typedef struct PSI_rwlock PSI_rwlock;
struct PSI_cond;
typedef struct PSI_cond PSI_cond;
struct PSI_table_share;
typedef struct PSI_table_share PSI_table_share;
struct PSI_table;
typedef struct PSI_table PSI_table;
struct PSI_thread;
typedef struct PSI_thread PSI_thread;
struct PSI_file;
typedef struct PSI_file PSI_file;
struct PSI_socket;
typedef struct PSI_socket PSI_socket;
struct PSI_table_locker;
typedef struct PSI_table_locker PSI_table_locker;
struct PSI_statement_locker;
typedef struct PSI_statement_locker PSI_statement_locker;
struct PSI_idle_locker;
typedef struct PSI_idle_locker PSI_idle_locker;
struct PSI_digest_locker;
typedef struct PSI_digest_locker PSI_digest_locker;
struct PSI_bootstrap
{
void* (*get_interface)(int version);
};
typedef struct PSI_bootstrap PSI_bootstrap;
struct PSI_mutex_locker;
typedef struct PSI_mutex_locker PSI_mutex_locker;
struct PSI_rwlock_locker;
typedef struct PSI_rwlock_locker PSI_rwlock_locker;
struct PSI_cond_locker;
typedef struct PSI_cond_locker PSI_cond_locker;
struct PSI_file_locker;
typedef struct PSI_file_locker PSI_file_locker;
struct PSI_socket_locker;
typedef struct PSI_socket_locker PSI_socket_locker;
enum PSI_mutex_operation
{
PSI_MUTEX_LOCK= 0,
PSI_MUTEX_TRYLOCK= 1
};
typedef enum PSI_mutex_operation PSI_mutex_operation;
enum PSI_rwlock_operation
{
PSI_RWLOCK_READLOCK= 0,
@ -27,11 +54,13 @@ enum PSI_rwlock_operation
PSI_RWLOCK_TRYREADLOCK= 2,
PSI_RWLOCK_TRYWRITELOCK= 3
};
typedef enum PSI_rwlock_operation PSI_rwlock_operation;
enum PSI_cond_operation
{
PSI_COND_WAIT= 0,
PSI_COND_TIMEDWAIT= 1
};
typedef enum PSI_cond_operation PSI_cond_operation;
enum PSI_file_operation
{
PSI_FILE_CREATE= 0,
@ -52,12 +81,54 @@ enum PSI_file_operation
PSI_FILE_RENAME= 15,
PSI_FILE_SYNC= 16
};
struct PSI_table_locker;
typedef enum PSI_file_operation PSI_file_operation;
enum PSI_table_io_operation
{
PSI_TABLE_FETCH_ROW= 0,
PSI_TABLE_WRITE_ROW= 1,
PSI_TABLE_UPDATE_ROW= 2,
PSI_TABLE_DELETE_ROW= 3
};
typedef enum PSI_table_io_operation PSI_table_io_operation;
enum PSI_table_lock_operation
{
PSI_TABLE_LOCK= 0,
PSI_TABLE_EXTERNAL_LOCK= 1
};
typedef enum PSI_table_lock_operation PSI_table_lock_operation;
enum PSI_socket_state
{
PSI_SOCKET_STATE_IDLE= 1,
PSI_SOCKET_STATE_ACTIVE= 2
};
typedef enum PSI_socket_state PSI_socket_state;
enum PSI_socket_operation
{
PSI_SOCKET_CREATE= 0,
PSI_SOCKET_CONNECT= 1,
PSI_SOCKET_BIND= 2,
PSI_SOCKET_CLOSE= 3,
PSI_SOCKET_SEND= 4,
PSI_SOCKET_RECV= 5,
PSI_SOCKET_SENDTO= 6,
PSI_SOCKET_RECVFROM= 7,
PSI_SOCKET_SENDMSG= 8,
PSI_SOCKET_RECVMSG= 9,
PSI_SOCKET_SEEK= 10,
PSI_SOCKET_OPT= 11,
PSI_SOCKET_STAT= 12,
PSI_SOCKET_SHUTDOWN= 13,
PSI_SOCKET_SELECT= 14
};
typedef enum PSI_socket_operation PSI_socket_operation;
typedef unsigned int PSI_mutex_key;
typedef unsigned int PSI_rwlock_key;
typedef unsigned int PSI_cond_key;
typedef unsigned int PSI_thread_key;
typedef unsigned int PSI_file_key;
typedef unsigned int PSI_stage_key;
typedef unsigned int PSI_statement_key;
typedef unsigned int PSI_socket_key;
struct PSI_v2
{
int placeholder;
@ -82,6 +153,18 @@ struct PSI_file_info_v2
{
int placeholder;
};
struct PSI_stage_info_v2
{
int placeholder;
};
struct PSI_statement_info_v2
{
int placeholder;
};
struct PSI_idle_locker_state_v2
{
int placeholder;
};
struct PSI_mutex_locker_state_v2
{
int placeholder;
@ -102,16 +185,30 @@ struct PSI_table_locker_state_v2
{
int placeholder;
};
struct PSI_statement_locker_state_v2
{
int placeholder;
};
struct PSI_socket_locker_state_v2
{
int placeholder;
};
typedef struct PSI_v2 PSI;
typedef struct PSI_mutex_info_v2 PSI_mutex_info;
typedef struct PSI_rwlock_info_v2 PSI_rwlock_info;
typedef struct PSI_cond_info_v2 PSI_cond_info;
typedef struct PSI_thread_info_v2 PSI_thread_info;
typedef struct PSI_file_info_v2 PSI_file_info;
typedef struct PSI_stage_info_v2 PSI_stage_info;
typedef struct PSI_statement_info_v2 PSI_statement_info;
typedef struct PSI_socket_info_v2 PSI_socket_info;
typedef struct PSI_idle_locker_state_v2 PSI_idle_locker_state;
typedef struct PSI_mutex_locker_state_v2 PSI_mutex_locker_state;
typedef struct PSI_rwlock_locker_state_v2 PSI_rwlock_locker_state;
typedef struct PSI_cond_locker_state_v2 PSI_cond_locker_state;
typedef struct PSI_file_locker_state_v2 PSI_file_locker_state;
typedef struct PSI_table_locker_state_v2 PSI_table_locker_state;
typedef struct PSI_statement_locker_state_v2 PSI_statement_locker_state;
typedef struct PSI_socket_locker_state_v2 PSI_socket_locker_state;
extern MYSQL_PLUGIN_IMPORT PSI *PSI_server;
C_MODE_END

View file

@ -337,10 +337,16 @@ extern void (*debug_sync_C_callback_ptr)(MYSQL_THD, const char *, size_t);
#define DEBUG_SYNC(thd, name) \
do { \
if (debug_sync_service) \
debug_sync_service(thd, name, sizeof(name)-1); \
debug_sync_service(thd, STRING_WITH_LEN(name)); \
} while(0)
#define DEBUG_SYNC_C_IF_THD(thd, name) \
do { \
if (debug_sync_service && thd) \
(*debug_sync_service)(thd, STRING_WITH_LEN(name)); } \
while(0)
#else
#define DEBUG_SYNC(thd,name) do { } while(0)
#define DEBUG_SYNC(thd,name) do { } while(0)
#define DEBUG_SYNC_C_IF_THD(thd, name) do { } while(0)
#endif
/* compatibility macro */

View file

@ -69,7 +69,8 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc
../sql/sql_lex.cc ../sql/keycaches.cc
../sql/sql_list.cc ../sql/sql_load.cc ../sql/sql_locale.cc
../sql/sql_binlog.cc ../sql/sql_manager.cc
../sql/sql_parse.cc ../sql/sql_partition.cc ../sql/sql_plugin.cc
../sql/sql_parse.cc ../sql/sql_bootstrap.cc
../sql/sql_partition.cc ../sql/sql_plugin.cc
../sql/debug_sync.cc ../sql/opt_table_elimination.cc
../sql/sql_prepare.cc ../sql/sql_rename.cc ../sql/sql_repl.cc
../sql/sql_select.cc ../sql/sql_servers.cc

View file

@ -3516,7 +3516,7 @@ sub mysql_install_db {
{
my $sql_dir= dirname($path_sql);
# Use the mysql database for system tables
mtr_tofile($bootstrap_sql_file, "use mysql\n");
mtr_tofile($bootstrap_sql_file, "use mysql;\n");
# Add the offical mysql system tables
# for a production system

View file

@ -16,7 +16,9 @@
INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR} ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/mysys)
SET(MYSYS_SOURCES array.c charset-def.c charset.c checksum.c default.c
errors.c hash.c list.c md5.c mf_cache.c mf_dirname.c mf_fn_ext.c
errors.c hash.c list.c
md5.c md5_compute.cc
mf_cache.c mf_dirname.c mf_fn_ext.c
mf_format.c mf_getdate.c mf_iocache.c mf_iocache2.c mf_keycache.c
mf_keycaches.c mf_loadpath.c mf_pack.c mf_path.c mf_qsort.c mf_qsort2.c
mf_radix.c mf_same.c mf_sort.c mf_soundex.c mf_arr_appstr.c mf_tempdir.c
@ -37,7 +39,7 @@ SET(MYSYS_SOURCES array.c charset-def.c charset.c checksum.c default.c
safemalloc.c my_new.cc
my_atomic.c my_getncpus.c my_safehash.c my_chmod.c my_rnd.c
my_uuid.c wqueue.c waiting_threads.c ma_dyncol.c
my_rdtsc.c my_context.c)
my_rdtsc.c my_context.c psi_noop.c)
IF (WIN32)
SET (MYSYS_SOURCES ${MYSYS_SOURCES} my_winthread.c my_wincond.c my_winerr.c my_winfile.c my_windac.c my_conio.c)

View file

@ -87,9 +87,9 @@ my_bool init_dynamic_array(DYNAMIC_ARRAY *array, uint element_size,
FALSE Ok
*/
my_bool insert_dynamic(DYNAMIC_ARRAY *array, const uchar* element)
my_bool insert_dynamic(DYNAMIC_ARRAY *array, const void * element)
{
uchar* buffer;
void *buffer;
if (array->elements == array->max_element)
{ /* Call only when nessesary */
if (!(buffer=alloc_dynamic(array)))
@ -122,7 +122,7 @@ my_bool insert_dynamic(DYNAMIC_ARRAY *array, const uchar* element)
0 Error
*/
uchar *alloc_dynamic(DYNAMIC_ARRAY *array)
void *alloc_dynamic(DYNAMIC_ARRAY *array)
{
DBUG_ENTER("alloc_dynamic");
if (array->elements == array->max_element)
@ -167,7 +167,7 @@ uchar *alloc_dynamic(DYNAMIC_ARRAY *array)
0 Array is empty
*/
uchar *pop_dynamic(DYNAMIC_ARRAY *array)
void *pop_dynamic(DYNAMIC_ARRAY *array)
{
if (array->elements)
return array->buffer+(--array->elements * array->size_of_element);
@ -192,7 +192,7 @@ uchar *pop_dynamic(DYNAMIC_ARRAY *array)
FALSE Ok
*/
my_bool set_dynamic(DYNAMIC_ARRAY *array, uchar* element, uint idx)
my_bool set_dynamic(DYNAMIC_ARRAY *array, const void *element, uint idx)
{
if (idx >= array->elements)
{
@ -268,7 +268,7 @@ my_bool allocate_dynamic(DYNAMIC_ARRAY *array, uint max_elements)
idx Index of element wanted.
*/
void get_dynamic(DYNAMIC_ARRAY *array, uchar* element, uint idx)
void get_dynamic(DYNAMIC_ARRAY *array, void *element, uint idx)
{
if (idx >= array->elements)
{
@ -363,13 +363,13 @@ void freeze_size(DYNAMIC_ARRAY *array)
*/
int get_index_dynamic(DYNAMIC_ARRAY *array, uchar* element)
int get_index_dynamic(DYNAMIC_ARRAY *array, void* element)
{
size_t ret;
if (array->buffer > element)
if (array->buffer > (uchar*) element)
return -1;
ret= (element - array->buffer) / array->size_of_element;
ret= ((uchar*) element - array->buffer) / array->size_of_element;
if (ret > array->elements)
return -1;

View file

@ -38,13 +38,15 @@
copyright in any changes I have made; this code remains in the
public domain. */
/*
Skip entirely if built with OpenSSL/YaSSL support.
*/
#if !defined(HAVE_OPENSSL) && !defined(HAVE_YASSL)
#include <my_global.h>
#include <m_string.h>
#include "my_md5.h"
#include <string.h> /* for memcpy() and memset() */
static void
my_MD5Transform (cvs_uint32 buf[4], const unsigned char in[64]);
@ -323,3 +325,5 @@ main (int argc, char **argv)
return 0;
}
#endif /* TEST */
#endif /* !defined(HAVE_OPENSSL) && !defined(HAVE_YASSL) */

68
mysys/md5_compute.cc Normal file
View file

@ -0,0 +1,68 @@
/* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
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
the Free Software Foundation; version 2 of the License.
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.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
/**
@file
@brief
Wrapper functions for OpenSSL, YaSSL and MySQL's MD5
implementations. Also provides a Compatibility layer
to make available YaSSL's MD5 implementation.
*/
#include <my_global.h>
#include <my_md5.h>
#ifdef HAVE_YASSL
#include "md5.hpp"
/**
Compute MD5 message digest.
@param digest [out] Computed MD5 digest
@param buf [in] Message to be computed
@param len [in] Length of the message
@return void
*/
void my_md5_hash(char *digest, const char *buf, int len)
{
TaoCrypt::MD5 hasher;
hasher.Update((TaoCrypt::byte *) buf, len);
hasher.Final((TaoCrypt::byte *) digest);
}
#endif /* HAVE_YASSL */
/**
Wrapper function to compute MD5 message digest.
@param digest [out] Computed MD5 digest
@param buf [in] Message to be computed
@param len [in] Length of the message
@return void
*/
void compute_md5_hash(char *digest, const char *buf, int len)
{
#ifdef HAVE_YASSL
my_md5_hash(digest, buf, len);
#else
MY_MD5_HASH((unsigned char *) digest, (unsigned char const *) buf, len);
#endif /* HAVE_YASSL */
}

View file

@ -21,6 +21,7 @@
#include <m_string.h>
#include <m_ctype.h>
#include <signal.h>
#include <mysql/psi/mysql_stage.h>
#ifdef __WIN__
#ifdef _MSC_VER
#include <locale.h>
@ -442,6 +443,9 @@ static my_bool win32_init_tcp_ip()
#ifdef HAVE_PSI_INTERFACE
PSI_stage_info stage_waiting_for_table_level_lock=
{0, "Waiting for table level lock", 0};
#if !defined(HAVE_PREAD) && !defined(_WIN32)
PSI_mutex_key key_my_file_info_mutex;
#endif /* !defined(HAVE_PREAD) && !defined(_WIN32) */
@ -531,30 +535,34 @@ static PSI_file_info all_mysys_files[]=
{ &key_file_cnf, "cnf", 0}
};
PSI_stage_info *all_mysys_stages[]=
{
& stage_waiting_for_table_level_lock
};
void my_init_mysys_psi_keys()
{
const char* category= "mysys";
int count;
if (PSI_server == NULL)
return;
count= sizeof(all_mysys_mutexes)/sizeof(all_mysys_mutexes[0]);
PSI_server->register_mutex(category, all_mysys_mutexes, count);
mysql_mutex_register(category, all_mysys_mutexes, count);
count= sizeof(all_mysys_conds)/sizeof(all_mysys_conds[0]);
PSI_server->register_cond(category, all_mysys_conds, count);
mysql_cond_register(category, all_mysys_conds, count);
count= sizeof(all_mysys_rwlocks)/sizeof(all_mysys_rwlocks[0]);
PSI_server->register_rwlock(category, all_mysys_rwlocks, count);
mysql_rwlock_register(category, all_mysys_rwlocks, count);
#ifdef USE_ALARM_THREAD
count= sizeof(all_mysys_threads)/sizeof(all_mysys_threads[0]);
PSI_server->register_thread(category, all_mysys_threads, count);
mysql_thread_register(category, all_mysys_threads, count);
#endif /* USE_ALARM_THREAD */
count= sizeof(all_mysys_files)/sizeof(all_mysys_files[0]);
PSI_server->register_file(category, all_mysys_files, count);
mysql_file_register(category, all_mysys_files, count);
count= array_elements(all_mysys_stages);
mysql_stage_register(category, all_mysys_stages, count);
}
#endif /* HAVE_PSI_INTERFACE */

View file

@ -98,31 +98,3 @@ my_bool my_disable_sync=0;
my_bool my_disable_async_io=0;
my_bool my_disable_flush_key_blocks=0;
my_bool my_disable_symlinks=0;
/*
Note that PSI_hook and PSI_server are unconditionally
(no ifdef HAVE_PSI_INTERFACE) defined.
This is to ensure binary compatibility between the server and plugins,
in the case when:
- the server is not compiled with HAVE_PSI_INTERFACE
- a plugin is compiled with HAVE_PSI_INTERFACE
See the doxygen documentation for the performance schema.
*/
/**
Hook for the instrumentation interface.
Code implementing the instrumentation interface should register here.
*/
struct PSI_bootstrap *PSI_hook= NULL;
/**
Instance of the instrumentation interface for the MySQL server.
@todo This is currently a global variable, which is handy when
compiling instrumented code that is bundled with the server.
When dynamic plugin are truly supported, this variable will need
to be replaced by a macro, so that each XYZ plugin can have it's own
xyz_psi_server variable, obtained from PSI_bootstrap::get_interface()
with the version used at compile time for plugin XYZ.
*/
PSI *PSI_server= NULL;

746
mysys/psi_noop.c Normal file
View file

@ -0,0 +1,746 @@
/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
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
the Free Software Foundation; version 2 of the License.
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.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
/*
Always provide the noop performance interface, for plugins.
*/
#define USE_PSI_V1
#define HAVE_PSI_INTERFACE
#include "my_global.h"
#include "my_pthread.h"
#include "my_sys.h"
#include "mysql/psi/psi.h"
C_MODE_START
#define NNN __attribute__((unused))
static void register_mutex_noop(const char *category NNN,
PSI_mutex_info *info NNN,
int count NNN)
{
return;
}
static void register_rwlock_noop(const char *category NNN,
PSI_rwlock_info *info NNN,
int count NNN)
{
return;
}
static void register_cond_noop(const char *category NNN,
PSI_cond_info *info NNN,
int count NNN)
{
return;
}
static void register_thread_noop(const char *category NNN,
PSI_thread_info *info NNN,
int count NNN)
{
return;
}
static void register_file_noop(const char *category NNN,
PSI_file_info *info NNN,
int count NNN)
{
return;
}
static void register_stage_noop(const char *category NNN,
PSI_stage_info **info_array NNN,
int count NNN)
{
return;
}
static void register_statement_noop(const char *category NNN,
PSI_statement_info *info NNN,
int count NNN)
{
return;
}
static void register_socket_noop(const char *category NNN,
PSI_socket_info *info NNN,
int count NNN)
{
return;
}
static PSI_mutex*
init_mutex_noop(PSI_mutex_key key NNN, const void *identity NNN)
{
return NULL;
}
static void destroy_mutex_noop(PSI_mutex* mutex NNN)
{
return;
}
static PSI_rwlock*
init_rwlock_noop(PSI_rwlock_key key NNN, const void *identity NNN)
{
return NULL;
}
static void destroy_rwlock_noop(PSI_rwlock* rwlock NNN)
{
return;
}
static PSI_cond*
init_cond_noop(PSI_cond_key key NNN, const void *identity NNN)
{
return NULL;
}
static void destroy_cond_noop(PSI_cond* cond NNN)
{
return;
}
static PSI_socket*
init_socket_noop(PSI_socket_key key NNN, const my_socket *fd NNN)
{
return NULL;
}
static void destroy_socket_noop(PSI_socket* socket NNN)
{
return;
}
static PSI_table_share*
get_table_share_noop(my_bool temporary NNN, struct TABLE_SHARE *share NNN)
{
return NULL;
}
static void release_table_share_noop(PSI_table_share* share NNN)
{
return;
}
static void
drop_table_share_noop(my_bool temporary NNN, const char *schema_name NNN,
int schema_name_length NNN, const char *table_name NNN,
int table_name_length NNN)
{
return;
}
static PSI_table*
open_table_noop(PSI_table_share *share NNN, const void *identity NNN)
{
return NULL;
}
static void unbind_table_noop(PSI_table *table NNN)
{
return;
}
static PSI_table*
rebind_table_noop(PSI_table_share *share NNN,
const void *identity NNN,
PSI_table *table NNN)
{
return NULL;
}
static void close_table_noop(PSI_table *table NNN)
{
return;
}
static void create_file_noop(PSI_file_key key NNN,
const char *name NNN, File file NNN)
{
return;
}
static int spawn_thread_noop(PSI_thread_key key NNN,
pthread_t *thread NNN,
const pthread_attr_t *attr NNN,
void *(*start_routine)(void*) NNN, void *arg NNN)
{
return pthread_create(thread, attr, start_routine, arg);
}
static PSI_thread*
new_thread_noop(PSI_thread_key key NNN,
const void *identity NNN, ulong thread_id NNN)
{
return NULL;
}
static void set_thread_id_noop(PSI_thread *thread NNN, unsigned long id NNN)
{
return;
}
static PSI_thread*
get_thread_noop(void NNN)
{
return NULL;
}
static void set_thread_user_noop(const char *user NNN, int user_len NNN)
{
return;
}
static void set_thread_user_host_noop(const char *user NNN, int user_len NNN,
const char *host NNN, int host_len NNN)
{
return;
}
static void set_thread_db_noop(const char* db NNN, int db_len NNN)
{
return;
}
static void set_thread_command_noop(int command NNN)
{
return;
}
static void set_thread_start_time_noop(time_t start_time NNN)
{
return;
}
static void set_thread_state_noop(const char* state NNN)
{
return;
}
static void set_thread_info_noop(const char* info NNN, int info_len NNN)
{
return;
}
static void set_thread_noop(PSI_thread* thread NNN)
{
return;
}
static void delete_current_thread_noop(void)
{
return;
}
static void delete_thread_noop(PSI_thread *thread NNN)
{
return;
}
static PSI_file_locker*
get_thread_file_name_locker_noop(PSI_file_locker_state *state NNN,
PSI_file_key key NNN,
enum PSI_file_operation op NNN,
const char *name NNN, const void *identity NNN)
{
return NULL;
}
static PSI_file_locker*
get_thread_file_stream_locker_noop(PSI_file_locker_state *state NNN,
PSI_file *file NNN,
enum PSI_file_operation op NNN)
{
return NULL;
}
static PSI_file_locker*
get_thread_file_descriptor_locker_noop(PSI_file_locker_state *state NNN,
File file NNN,
enum PSI_file_operation op NNN)
{
return NULL;
}
static void unlock_mutex_noop(PSI_mutex *mutex NNN)
{
return;
}
static void unlock_rwlock_noop(PSI_rwlock *rwlock NNN)
{
return;
}
static void signal_cond_noop(PSI_cond* cond NNN)
{
return;
}
static void broadcast_cond_noop(PSI_cond* cond NNN)
{
return;
}
static PSI_idle_locker*
start_idle_wait_noop(PSI_idle_locker_state* state NNN,
const char *src_file NNN, uint src_line NNN)
{
return NULL;
}
static void end_idle_wait_noop(PSI_idle_locker* locker NNN)
{
return;
}
static PSI_mutex_locker*
start_mutex_wait_noop(PSI_mutex_locker_state *state NNN,
PSI_mutex *mutex NNN,
PSI_mutex_operation op NNN,
const char *src_file NNN, uint src_line NNN)
{
return NULL;
}
static void end_mutex_wait_noop(PSI_mutex_locker* locker NNN, int rc NNN)
{
return;
}
static PSI_rwlock_locker*
start_rwlock_rdwait_noop(struct PSI_rwlock_locker_state_v1 *state NNN,
struct PSI_rwlock *rwlock NNN,
enum PSI_rwlock_operation op NNN,
const char *src_file NNN, uint src_line NNN)
{
return NULL;
}
static void end_rwlock_rdwait_noop(PSI_rwlock_locker* locker NNN, int rc NNN)
{
return;
}
static struct PSI_rwlock_locker*
start_rwlock_wrwait_noop(struct PSI_rwlock_locker_state_v1 *state NNN,
struct PSI_rwlock *rwlock NNN,
enum PSI_rwlock_operation op NNN,
const char *src_file NNN, uint src_line NNN)
{
return NULL;
}
static void end_rwlock_wrwait_noop(PSI_rwlock_locker* locker NNN, int rc NNN)
{
return;
}
static struct PSI_cond_locker*
start_cond_wait_noop(struct PSI_cond_locker_state_v1 *state NNN,
struct PSI_cond *cond NNN,
struct PSI_mutex *mutex NNN,
enum PSI_cond_operation op NNN,
const char *src_file NNN, uint src_line NNN)
{
return NULL;
}
static void end_cond_wait_noop(PSI_cond_locker* locker NNN, int rc NNN)
{
return;
}
static struct PSI_table_locker*
start_table_io_wait_noop(struct PSI_table_locker_state_v1 *state NNN,
struct PSI_table *table NNN,
enum PSI_table_io_operation op NNN,
uint index NNN,
const char *src_file NNN, uint src_line NNN)
{
return NULL;
}
static void end_table_io_wait_noop(PSI_table_locker* locker NNN)
{
return;
}
static struct PSI_table_locker*
start_table_lock_wait_noop(struct PSI_table_locker_state_v1 *state NNN,
struct PSI_table *table NNN,
enum PSI_table_lock_operation op NNN,
ulong flags NNN,
const char *src_file NNN, uint src_line NNN)
{
return NULL;
}
static void end_table_lock_wait_noop(PSI_table_locker* locker NNN)
{
return;
}
static PSI_file* start_file_open_wait_noop(PSI_file_locker *locker NNN,
const char *src_file NNN,
uint src_line NNN)
{
return NULL;
}
static void end_file_open_wait_noop(PSI_file_locker *locker NNN)
{
return;
}
static void end_file_open_wait_and_bind_to_descriptor_noop
(PSI_file_locker *locker NNN, File file NNN)
{
return;
}
static void start_file_wait_noop(PSI_file_locker *locker NNN,
size_t count NNN,
const char *src_file NNN,
uint src_line NNN)
{
return;
}
static void end_file_wait_noop(PSI_file_locker *locker NNN,
size_t count NNN)
{
return;
}
static void start_stage_noop(PSI_stage_key key NNN,
const char *src_file NNN, int src_line NNN)
{
return;
}
static void end_stage_noop(void)
{
return;
}
static PSI_statement_locker*
get_thread_statement_locker_noop(PSI_statement_locker_state *state NNN,
PSI_statement_key key NNN)
{
return NULL;
}
static PSI_statement_locker*
refine_statement_noop(PSI_statement_locker *locker NNN,
PSI_statement_key key NNN)
{
return NULL;
}
static void start_statement_noop(PSI_statement_locker *locker NNN,
const char *db NNN, uint db_len NNN,
const char *src_file NNN, uint src_line NNN)
{
return;
}
static void set_statement_text_noop(PSI_statement_locker *locker NNN,
const char *text NNN, uint text_len NNN)
{
return;
}
static void set_statement_lock_time_noop(PSI_statement_locker *locker NNN,
ulonglong count NNN)
{
return;
}
static void set_statement_rows_sent_noop(PSI_statement_locker *locker NNN,
ulonglong count NNN)
{
return;
}
static void set_statement_rows_examined_noop(PSI_statement_locker *locker NNN,
ulonglong count NNN)
{
return;
}
static void inc_statement_created_tmp_disk_tables_noop(PSI_statement_locker *locker NNN,
ulong count NNN)
{
return;
}
static void inc_statement_created_tmp_tables_noop(PSI_statement_locker *locker NNN,
ulong count NNN)
{
return;
}
static void inc_statement_select_full_join_noop(PSI_statement_locker *locker NNN,
ulong count NNN)
{
return;
}
static void inc_statement_select_full_range_join_noop(PSI_statement_locker *locker NNN,
ulong count NNN)
{
return;
}
static void inc_statement_select_range_noop(PSI_statement_locker *locker NNN,
ulong count NNN)
{
return;
}
static void inc_statement_select_range_check_noop(PSI_statement_locker *locker NNN,
ulong count NNN)
{
return;
}
static void inc_statement_select_scan_noop(PSI_statement_locker *locker NNN,
ulong count NNN)
{
return;
}
static void inc_statement_sort_merge_passes_noop(PSI_statement_locker *locker NNN,
ulong count NNN)
{
return;
}
static void inc_statement_sort_range_noop(PSI_statement_locker *locker NNN,
ulong count NNN)
{
return;
}
static void inc_statement_sort_rows_noop(PSI_statement_locker *locker NNN,
ulong count NNN)
{
return;
}
static void inc_statement_sort_scan_noop(PSI_statement_locker *locker NNN,
ulong count NNN)
{
return;
}
static void set_statement_no_index_used_noop(PSI_statement_locker *locker NNN)
{
return;
}
static void set_statement_no_good_index_used_noop(PSI_statement_locker *locker NNN)
{
return;
}
static void end_statement_noop(PSI_statement_locker *locker NNN,
void *stmt_da NNN)
{
return;
}
static PSI_socket_locker*
start_socket_wait_noop(PSI_socket_locker_state *state NNN,
PSI_socket *socket NNN,
PSI_socket_operation op NNN,
size_t count NNN,
const char *src_file NNN,
uint src_line NNN)
{
return NULL;
}
static void end_socket_wait_noop(PSI_socket_locker *locker NNN,
size_t count NNN)
{
return;
}
static void set_socket_state_noop(PSI_socket *socket NNN,
enum PSI_socket_state state NNN)
{
return;
}
static void set_socket_info_noop(PSI_socket *socket NNN,
const my_socket *fd NNN,
const struct sockaddr *addr NNN,
socklen_t addr_len NNN)
{
return;
}
static void set_socket_thread_owner_noop(PSI_socket *socket NNN)
{
return;
}
static struct PSI_digest_locker*
digest_start_noop(PSI_statement_locker *locker NNN)
{
return NULL;
}
static PSI_digest_locker*
digest_add_token_noop(PSI_digest_locker *locker NNN,
uint token NNN,
struct OPAQUE_LEX_YYSTYPE *yylval NNN)
{
return NULL;
}
static PSI PSI_noop=
{
register_mutex_noop,
register_rwlock_noop,
register_cond_noop,
register_thread_noop,
register_file_noop,
register_stage_noop,
register_statement_noop,
register_socket_noop,
init_mutex_noop,
destroy_mutex_noop,
init_rwlock_noop,
destroy_rwlock_noop,
init_cond_noop,
destroy_cond_noop,
init_socket_noop,
destroy_socket_noop,
get_table_share_noop,
release_table_share_noop,
drop_table_share_noop,
open_table_noop,
unbind_table_noop,
rebind_table_noop,
close_table_noop,
create_file_noop,
spawn_thread_noop,
new_thread_noop,
set_thread_id_noop,
get_thread_noop,
set_thread_user_noop,
set_thread_user_host_noop,
set_thread_db_noop,
set_thread_command_noop,
set_thread_start_time_noop,
set_thread_state_noop,
set_thread_info_noop,
set_thread_noop,
delete_current_thread_noop,
delete_thread_noop,
get_thread_file_name_locker_noop,
get_thread_file_stream_locker_noop,
get_thread_file_descriptor_locker_noop,
unlock_mutex_noop,
unlock_rwlock_noop,
signal_cond_noop,
broadcast_cond_noop,
start_idle_wait_noop,
end_idle_wait_noop,
start_mutex_wait_noop,
end_mutex_wait_noop,
start_rwlock_rdwait_noop,
end_rwlock_rdwait_noop,
start_rwlock_wrwait_noop,
end_rwlock_wrwait_noop,
start_cond_wait_noop,
end_cond_wait_noop,
start_table_io_wait_noop,
end_table_io_wait_noop,
start_table_lock_wait_noop,
end_table_lock_wait_noop,
start_file_open_wait_noop,
end_file_open_wait_noop,
end_file_open_wait_and_bind_to_descriptor_noop,
start_file_wait_noop,
end_file_wait_noop,
start_stage_noop,
end_stage_noop,
get_thread_statement_locker_noop,
refine_statement_noop,
start_statement_noop,
set_statement_text_noop,
set_statement_lock_time_noop,
set_statement_rows_sent_noop,
set_statement_rows_examined_noop,
inc_statement_created_tmp_disk_tables_noop,
inc_statement_created_tmp_tables_noop,
inc_statement_select_full_join_noop,
inc_statement_select_full_range_join_noop,
inc_statement_select_range_noop,
inc_statement_select_range_check_noop,
inc_statement_select_scan_noop,
inc_statement_sort_merge_passes_noop,
inc_statement_sort_range_noop,
inc_statement_sort_rows_noop,
inc_statement_sort_scan_noop,
set_statement_no_index_used_noop,
set_statement_no_good_index_used_noop,
end_statement_noop,
start_socket_wait_noop,
end_socket_wait_noop,
set_socket_state_noop,
set_socket_info_noop,
set_socket_thread_owner_noop,
digest_start_noop,
digest_add_token_noop
};
/**
Hook for the instrumentation interface.
Code implementing the instrumentation interface should register here.
*/
struct PSI_bootstrap *PSI_hook= NULL;
/**
Instance of the instrumentation interface for the MySQL server.
@todo This is currently a global variable, which is handy when
compiling instrumented code that is bundled with the server.
When dynamic plugin are truly supported, this variable will need
to be replaced by a macro, so that each XYZ plugin can have it's own
xyz_psi_server variable, obtained from PSI_bootstrap::get_interface()
with the version used at compile time for plugin XYZ.
*/
PSI *PSI_server= & PSI_noop;
void set_psi_server(PSI *psi)
{
PSI_server= psi;
}
C_MODE_END

View file

@ -1,4 +1,5 @@
/* Copyright (C) 2004 MySQL AB
/* Copyright (c) 2004, 2010, Oracle and/or its affiliates.
Copyright (c) 2012 Monty Program Ab
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
@ -11,10 +12,10 @@
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 */
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
/*
Written by Magnus Svensson
Originally written by Magnus Svensson
*/
/*
@ -25,10 +26,18 @@
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/stat.h>
/* Compiler-dependent constant for maximum string constant */
#define MAX_STRING_CONSTANT_LENGTH 65535
#include "../sql/sql_bootstrap.h"
/*
This is an internal tool used during the build process only,
- do not make a library just for this,
which would make the Makefiles and the server link
more complex than necessary,
- do not duplicate the code either.
so just add the sql_bootstrap.cc code as is.
*/
#include "../sql/sql_bootstrap.cc"
FILE *in, *out;
@ -58,15 +67,60 @@ static void die(const char *fmt, ...)
exit(1);
}
char *fgets_fn(char *buffer, size_t size, fgets_input_t input)
{
return fgets(buffer, size, (FILE*) input);
}
static void print_query(FILE *out, const char *query)
{
const char *ptr= query;
int column= 0;
fprintf(out, "\"");
while (*ptr)
{
if (column >= 120)
{
/* Wrap to the next line, tabulated. */
fprintf(out, "\"\n \"");
column= 2;
}
switch(*ptr)
{
case '\n':
/*
Preserve the \n character in the query text,
and wrap to the next line, tabulated.
*/
fprintf(out, "\\n\"\n \"");
column= 2;
break;
case '\r':
/* Skipped */
break;
case '\"':
fprintf(out, "\\\"");
column++;
break;
default:
putc(*ptr, out);
column++;
break;
}
ptr++;
}
fprintf(out, "\\n\",\n");
}
int main(int argc, char *argv[])
{
char buff[512];
struct stat st;
char query[MAX_BOOTSTRAP_QUERY_SIZE];
char* struct_name= argv[1];
char* infile_name= argv[2];
char* outfile_name= argv[3];
int rc;
int query_length;
if (argc != 4)
die("Usage: comp_sql <struct_name> <sql_filename> <c_filename>");
@ -74,86 +128,31 @@ int main(int argc, char *argv[])
/* Open input and output file */
if (!(in= fopen(infile_name, "r")))
die("Failed to open SQL file '%s'", infile_name);
if (!(out= fopen(outfile_name, "w")))
die("Failed to open output file '%s'", outfile_name);
fprintf(out, "const char %s[]={\n",struct_name);
/*
Some compilers have limitations how long a string constant can be.
We'll output very long strings as hexadecimal arrays, and short ones
as strings (prettier)
*/
stat(infile_name, &st);
if (st.st_size > MAX_STRING_CONSTANT_LENGTH)
fprintf(out, "/*\n");
fprintf(out, " Do not edit this file, it is automatically generated from:\n");
fprintf(out, " <%s>\n", infile_name);
fprintf(out, "*/\n");
fprintf(out, "const char* %s[]={\n", struct_name);
for ( ; ; )
{
int cnt=0;
int c;
for(cnt=0;;cnt++)
{
c= fgetc(in);
if (c== -1)
break;
rc= read_bootstrap_query(query, &query_length,
(fgets_input_t) in, fgets_fn);
if(cnt != 0)
fputc(',', out);
if (rc == READ_BOOTSTRAP_ERROR)
die("Failed to read the bootstrap input file.\n");
if (rc == READ_BOOTSTRAP_EOF)
break;
/* Put line break after each 16 hex characters */
if(cnt && (cnt%16 == 0))
fputc('\n', out);
fprintf(out,"0x%02x",c);
}
fprintf(out,",0x00");
print_query(out, query);
}
else
{
fprintf(out,"\"");
while (fgets(buff, sizeof(buff), in))
{
char *curr= buff;
while (*curr)
{
if (*curr == '\n')
{
/*
Reached end of line, add escaped newline, escaped
backslash and a newline to outfile
*/
fprintf(out, "\\n \"\n\"");
curr++;
}
else if (*curr == '\r')
{
curr++; /* Skip */
}
else
{
if (*curr == '"')
{
/* Needs escape */
fputc('\\', out);
}
fputc(*curr, out);
curr++;
}
}
if (*(curr-1) != '\n')
{
/*
Some compilers have a max string length,
insert a newline at every 512th char in long
strings
*/
fprintf(out, "\"\n\"");
}
}
fprintf(out, "\\\n\"");
}
fprintf(out, "};\n");
fprintf(out, "NULL\n};\n");
fclose(in);
fclose(out);

File diff suppressed because it is too large Load diff

View file

@ -59,7 +59,8 @@ SET (SQL_SOURCE
sql_cache.cc sql_class.cc sql_client.cc sql_crypt.cc sql_crypt.h
sql_cursor.cc sql_db.cc sql_delete.cc sql_derived.cc sql_do.cc
sql_error.cc sql_handler.cc sql_help.cc sql_insert.cc sql_lex.cc
sql_list.cc sql_load.cc sql_manager.cc sql_parse.cc
sql_list.cc sql_load.cc sql_manager.cc
sql_parse.cc sql_bootstrap.cc sql_bootstrap.h
sql_partition.cc sql_plugin.cc sql_prepare.cc sql_rename.cc
debug_sync.cc debug_sync.h
sql_repl.cc sql_select.cc sql_show.cc sql_state.c sql_string.cc

View file

@ -1069,7 +1069,22 @@ inline LEX_STRING *hton_name(const handlerton *hton)
#define HTON_NOT_USER_SELECTABLE (1 << 5)
#define HTON_TEMPORARY_NOT_SUPPORTED (1 << 6) //Having temporary tables not supported
#define HTON_SUPPORT_LOG_TABLES (1 << 7) //Engine supports log tables
#define HTON_NO_PARTITION (1 << 8) //You can not partition these tables
#define HTON_NO_PARTITION (1 << 8) //Not partition of these tables
/*
This flag should be set when deciding that the engine does not allow
row based binary logging (RBL) optimizations.
Currently, setting this flag, means that table's read/write_set will
be left untouched when logging changes to tables in this engine. In
practice this means that the server will not mess around with
table->write_set and/or table->read_set when using RBL and deciding
whether to log full or minimal rows.
It's valuable for instance for virtual tables, eg: Performance
Schema which have no meaning for replication.
*/
#define HTON_NO_BINLOG_ROW_OPT (1 << 9)
class Ha_trx_info;
@ -1446,21 +1461,24 @@ typedef struct st_range_seq_if
typedef bool (*SKIP_INDEX_TUPLE_FUNC) (range_seq_t seq, range_id_t range_info);
class COST_VECT
class Cost_estimate
{
public:
double io_count; /* number of I/O */
double avg_io_cost; /* cost of an average I/O oper. */
double cpu_cost; /* cost of operations in CPU */
double mem_cost; /* cost of used memory */
double import_cost; /* cost of remote operations */
double mem_cost; /* cost of used memory */
enum { IO_COEFF=1 };
enum { CPU_COEFF=1 };
enum { MEM_COEFF=1 };
enum { IMPORT_COEFF=1 };
COST_VECT() {} // keep gcc happy
Cost_estimate()
{
reset();
}
double total_cost()
{
@ -1468,7 +1486,17 @@ public:
MEM_COEFF*mem_cost + IMPORT_COEFF*import_cost;
}
void zero()
/**
Whether or not all costs in the object are zero
@return true if all costs are zero, false otherwise
*/
bool is_zero() const
{
return !(io_count || cpu_cost || import_cost || mem_cost);
}
void reset()
{
avg_io_cost= 1.0;
io_count= cpu_cost= mem_cost= import_cost= 0.0;
@ -1482,13 +1510,14 @@ public:
/* Don't multiply mem_cost */
}
void add(const COST_VECT* cost)
void add(const Cost_estimate* cost)
{
double io_count_sum= io_count + cost->io_count;
add_io(cost->io_count, cost->avg_io_cost);
io_count= io_count_sum;
cpu_cost += cost->cpu_cost;
}
void add_io(double add_io_cnt, double add_avg_cost)
{
/* In edge cases add_io_cnt may be zero */
@ -1501,20 +1530,28 @@ public:
}
}
/// Add to CPU cost
void add_cpu(double add_cpu_cost) { cpu_cost+= add_cpu_cost; }
/// Add to import cost
void add_import(double add_import_cost) { import_cost+= add_import_cost; }
/// Add to memory cost
void add_mem(double add_mem_cost) { mem_cost+= add_mem_cost; }
/*
To be used when we go from old single value-based cost calculations to
the new COST_VECT-based.
the new Cost_estimate-based.
*/
void convert_from_cost(double cost)
{
zero();
avg_io_cost= 1.0;
reset();
io_count= cost;
}
};
void get_sweep_read_cost(TABLE *table, ha_rows nrows, bool interrupted,
COST_VECT *cost);
Cost_estimate *cost);
/*
Indicates that all scanned ranges will be singlepoint (aka equality) ranges.
@ -2156,10 +2193,11 @@ public:
virtual ha_rows multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
void *seq_init_param,
uint n_ranges, uint *bufsz,
uint *mrr_mode, COST_VECT *cost);
uint *mrr_mode,
Cost_estimate *cost);
virtual ha_rows multi_range_read_info(uint keyno, uint n_ranges, uint keys,
uint key_parts, uint *bufsz,
uint *mrr_mode, COST_VECT *cost);
uint *mrr_mode, Cost_estimate *cost);
virtual int multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param,
uint n_ranges, uint mrr_mode,
HANDLER_BUFFER *buf);

View file

@ -32,9 +32,15 @@
class hash_filo_element
{
private:
hash_filo_element *next_used,*prev_used;
public:
hash_filo_element() {}
hash_filo_element *next()
{ return next_used; }
hash_filo_element *prev()
{ return prev_used; }
friend class hash_filo;
};

View file

@ -50,7 +50,7 @@
#include "password.h" // my_make_scrambled_password,
// my_make_scrambled_password_323
#include <m_ctype.h>
#include "my_md5.h"
#include <my_md5.h>
#include "sha1.h"
#include "my_aes.h"
#include <zlib.h>
@ -180,7 +180,8 @@ String *Item_func_md5::val_str_ascii(String *str)
uchar digest[16];
null_value=0;
MY_MD5_HASH(digest,(uchar *) sptr->ptr(), sptr->length());
compute_md5_hash((char *) digest, (const char *) sptr->ptr(),
sptr->length());
if (str->alloc(32)) // Ensure that memory is free
{
null_value=1;

View file

@ -56,7 +56,7 @@
ha_rows
handler::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
void *seq_init_param, uint n_ranges_arg,
uint *bufsz, uint *flags, COST_VECT *cost)
uint *bufsz, uint *flags, Cost_estimate *cost)
{
KEY_MULTI_RANGE range;
range_seq_t seq_it;
@ -106,7 +106,7 @@ handler::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
{
/* The following calculation is the same as in multi_range_read_info(): */
*flags |= HA_MRR_USE_DEFAULT_IMPL;
cost->zero();
cost->reset();
cost->avg_io_cost= 1; /* assume random seeks */
if ((*flags & HA_MRR_INDEX_ONLY) && total_rows > 2)
cost->io_count= keyread_time(keyno, n_ranges, (uint)total_rows);
@ -154,7 +154,7 @@ handler::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
ha_rows handler::multi_range_read_info(uint keyno, uint n_ranges, uint n_rows,
uint key_parts, uint *bufsz,
uint *flags, COST_VECT *cost)
uint *flags, Cost_estimate *cost)
{
/*
Currently we expect this function to be called only in preparation of scan
@ -165,7 +165,7 @@ ha_rows handler::multi_range_read_info(uint keyno, uint n_ranges, uint n_rows,
*bufsz= 0; /* Default implementation doesn't need a buffer */
*flags |= HA_MRR_USE_DEFAULT_IMPL;
cost->zero();
cost->reset();
cost->avg_io_cost= 1; /* assume random seeks */
/* Produce the same cost as non-MRR code does */
@ -1402,7 +1402,7 @@ int DsMrr_impl::dsmrr_next(range_id_t *range_info)
*/
ha_rows DsMrr_impl::dsmrr_info(uint keyno, uint n_ranges, uint rows,
uint key_parts,
uint *bufsz, uint *flags, COST_VECT *cost)
uint *bufsz, uint *flags, Cost_estimate *cost)
{
ha_rows __attribute__((unused)) res;
uint def_flags= *flags;
@ -1437,7 +1437,7 @@ ha_rows DsMrr_impl::dsmrr_info(uint keyno, uint n_ranges, uint rows,
ha_rows DsMrr_impl::dsmrr_info_const(uint keyno, RANGE_SEQ_IF *seq,
void *seq_init_param, uint n_ranges,
uint *bufsz, uint *flags, COST_VECT *cost)
uint *bufsz, uint *flags, Cost_estimate *cost)
{
ha_rows rows;
uint def_flags= *flags;
@ -1551,9 +1551,9 @@ bool DsMrr_impl::check_cpk_scan(THD *thd, uint keyno, uint mrr_flags)
bool DsMrr_impl::choose_mrr_impl(uint keyno, ha_rows rows, uint *flags,
uint *bufsz, COST_VECT *cost)
uint *bufsz, Cost_estimate *cost)
{
COST_VECT dsmrr_cost;
Cost_estimate dsmrr_cost;
bool res;
THD *thd= current_thd;
@ -1655,7 +1655,7 @@ int DsMrr_impl::dsmrr_explain_info(uint mrr_mode, char *str, size_t size)
}
static void get_sort_and_sweep_cost(TABLE *table, ha_rows nrows, COST_VECT *cost);
static void get_sort_and_sweep_cost(TABLE *table, ha_rows nrows, Cost_estimate *cost);
/**
@ -1673,7 +1673,7 @@ static void get_sort_and_sweep_cost(TABLE *table, ha_rows nrows, COST_VECT *cost
*/
bool DsMrr_impl::get_disk_sweep_mrr_cost(uint keynr, ha_rows rows, uint flags,
uint *buffer_size, COST_VECT *cost)
uint *buffer_size, Cost_estimate *cost)
{
ulong max_buff_entries, elem_size;
ha_rows rows_in_full_step;
@ -1707,13 +1707,13 @@ bool DsMrr_impl::get_disk_sweep_mrr_cost(uint keynr, ha_rows rows, uint flags,
}
else
{
cost->zero();
cost->reset();
*buffer_size= max(*buffer_size,
(size_t)(1.2*rows_in_last_step) * elem_size +
primary_file->ref_length + table->key_info[keynr].key_length);
}
COST_VECT last_step_cost;
Cost_estimate last_step_cost;
get_sort_and_sweep_cost(table, rows_in_last_step, &last_step_cost);
cost->add(&last_step_cost);
@ -1742,7 +1742,7 @@ bool DsMrr_impl::get_disk_sweep_mrr_cost(uint keynr, ha_rows rows, uint flags,
*/
static
void get_sort_and_sweep_cost(TABLE *table, ha_rows nrows, COST_VECT *cost)
void get_sort_and_sweep_cost(TABLE *table, ha_rows nrows, Cost_estimate *cost)
{
if (nrows)
{
@ -1754,7 +1754,7 @@ void get_sort_and_sweep_cost(TABLE *table, ha_rows nrows, COST_VECT *cost)
cost->cpu_cost += cmp_op * log2(cmp_op);
}
else
cost->zero();
cost->reset();
}
@ -1802,11 +1802,11 @@ void get_sort_and_sweep_cost(TABLE *table, ha_rows nrows, COST_VECT *cost)
*/
void get_sweep_read_cost(TABLE *table, ha_rows nrows, bool interrupted,
COST_VECT *cost)
Cost_estimate *cost)
{
DBUG_ENTER("get_sweep_read_cost");
cost->zero();
cost->reset();
if (table->file->primary_key_is_clustered())
{
cost->io_count= table->file->read_time(table->s->primary_key,

View file

@ -562,11 +562,11 @@ public:
int dsmrr_next(range_id_t *range_info);
ha_rows dsmrr_info(uint keyno, uint n_ranges, uint keys, uint key_parts,
uint *bufsz, uint *flags, COST_VECT *cost);
uint *bufsz, uint *flags, Cost_estimate *cost);
ha_rows dsmrr_info_const(uint keyno, RANGE_SEQ_IF *seq,
void *seq_init_param, uint n_ranges, uint *bufsz,
uint *flags, COST_VECT *cost);
uint *flags, Cost_estimate *cost);
int dsmrr_explain_info(uint mrr_mode, char *str, size_t size);
private:
@ -624,9 +624,9 @@ private:
Forward_lifo_buffer rowid_buffer;
bool choose_mrr_impl(uint keyno, ha_rows rows, uint *flags, uint *bufsz,
COST_VECT *cost);
Cost_estimate *cost);
bool get_disk_sweep_mrr_cost(uint keynr, ha_rows rows, uint flags,
uint *buffer_size, COST_VECT *cost);
uint *buffer_size, Cost_estimate *cost);
bool check_cpk_scan(THD *thd, uint keyno, uint mrr_flags);
bool setup_buffer_sharing(uint key_size_in_keybuf, key_part_map key_tuple_map);

View file

@ -207,6 +207,7 @@ extern int bootstrap_error;
extern I_List<THD> threads;
extern char err_shared_dir[];
extern TYPELIB thread_handling_typelib;
extern ulong log_warnings;
/*
THR_MALLOC is a key which will be used to set/get MEM_ROOT** for a thread,

View file

@ -890,7 +890,7 @@ static bool is_key_scan_ror(PARAM *param, uint keynr, uint8 nparts);
static ha_rows check_quick_select(PARAM *param, uint idx, bool index_only,
SEL_ARG *tree, bool update_tbl_stats,
uint *mrr_flags, uint *bufsize,
COST_VECT *cost);
Cost_estimate *cost);
QUICK_RANGE_SELECT *get_quick_select(PARAM *param,uint index,
SEL_ARG *key_tree, uint mrr_flags,
@ -6691,7 +6691,7 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree,
if (*key)
{
ha_rows found_records;
COST_VECT cost;
Cost_estimate cost;
double found_read_time;
uint mrr_flags, buf_size;
INDEX_SCAN_INFO *index_scan;
@ -9941,7 +9941,7 @@ void SEL_ARG::test_use_count(SEL_ARG *root)
static
ha_rows check_quick_select(PARAM *param, uint idx, bool index_only,
SEL_ARG *tree, bool update_tbl_stats,
uint *mrr_flags, uint *bufsize, COST_VECT *cost)
uint *mrr_flags, uint *bufsize, Cost_estimate *cost)
{
SEL_ARG_RANGE_SEQ seq;
RANGE_SEQ_IF seq_if = {NULL, sel_arg_range_seq_init, sel_arg_range_seq_next, 0, 0};
@ -10430,7 +10430,7 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
QUICK_RANGE *range;
uint part;
bool create_err= FALSE;
COST_VECT cost;
Cost_estimate cost;
old_root= thd->mem_root;
/* The following call may change thd->mem_root */
@ -12103,7 +12103,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree, double read_time)
cur_index_tree= get_index_range_tree(cur_index, tree, param,
&cur_param_idx);
/* Check if this range tree can be used for prefix retrieval. */
COST_VECT dummy_cost;
Cost_estimate dummy_cost;
uint mrr_flags= HA_MRR_USE_DEFAULT_IMPL;
uint mrr_bufsize=0;
cur_quick_prefix_records= check_quick_select(param, cur_param_idx,

View file

@ -2198,7 +2198,7 @@ bool optimize_semijoin_nests(JOIN *join, table_map all_table_map)
Set the cost to do a full scan of the temptable (will need this to
consider doing sjm-scan):
*/
sjm->scan_cost.zero();
sjm->scan_cost.reset();
sjm->scan_cost.add_io(sjm->rows, lookup_cost);
sjm->lookup_cost.convert_from_cost(lookup_cost);
@ -2633,12 +2633,12 @@ bool Sj_materialization_picker::check_qep(JOIN *join,
else
{
/* This is SJ-Materialization with lookups */
COST_VECT prefix_cost;
Cost_estimate prefix_cost;
signed int first_tab= (int)idx - mat_info->tables;
double prefix_rec_count;
if (first_tab < (int)join->const_tables)
{
prefix_cost.zero();
prefix_cost.reset();
prefix_rec_count= 1.0;
}
else

View file

@ -6508,6 +6508,225 @@ ER_BINLOG_UNSAFE_AUTOINC_NOT_FIRST
# End of 5.5 error messages.
#
ER_COL_COUNT_DOESNT_MATCH_CORRUPTED_V2
eng "Column count of %s.%s is wrong. Expected %d, found %d. The table is probably corrupted"
ger "Spaltenanzahl von %s.%s falsch. %d erwartet, aber %d gefunden. Tabelle ist wahrscheinlich beschädigt"
ER_CANNOT_LOAD_FROM_TABLE_V2
eng "Cannot load from %s.%s. The table is probably corrupted"
ger "Kann %s.%s nicht einlesen. Tabelle ist wahrscheinlich beschädigt"
ER_MASTER_DELAY_VALUE_OUT_OF_RANGE
eng "The requested value %u for the master delay exceeds the maximum %u"
ER_ONLY_FD_AND_RBR_EVENTS_ALLOWED_IN_BINLOG_STATEMENT
eng "Only Format_description_log_event and row events are allowed in BINLOG statements (but %s was provided)"
ER_PARTITION_EXCHANGE_DIFFERENT_OPTION
eng "Non matching attribute '%-.64s' between partition and table"
swe "Attributet '%-.64s' är olika mellan partition och tabell"
ER_PARTITION_EXCHANGE_PART_TABLE
eng "Table to exchange with partition is partitioned: '%-.64s'"
swe "Tabellen att byta ut mot partition är partitionerad: '%-.64s'"
ER_PARTITION_EXCHANGE_TEMP_TABLE
eng "Table to exchange with partition is temporary: '%-.64s'"
swe "Tabellen att byta ut mot partition är temporär: '%-.64s'"
ER_PARTITION_INSTEAD_OF_SUBPARTITION
eng "Subpartitioned table, use subpartition instead of partition"
swe "Subpartitionerad tabell, använd subpartition istället för partition"
ER_UNKNOWN_PARTITION
eng "Unknown partition '%-.64s' in table '%-.64s'"
swe "Okänd partition '%-.64s' i tabell '%-.64s'"
ER_TABLES_DIFFERENT_METADATA
eng "Tables have different definitions"
swe "Tabellerna har olika definitioner"
ER_ROW_DOES_NOT_MATCH_PARTITION
eng "Found a row that does not match the partition"
swe "Hittade en rad som inte passar i partitionen"
ER_BINLOG_CACHE_SIZE_GREATER_THAN_MAX
eng "Option binlog_cache_size (%lu) is greater than max_binlog_cache_size (%lu); setting binlog_cache_size equal to max_binlog_cache_size."
ER_WARN_INDEX_NOT_APPLICABLE
eng "Cannot use %-.64s access on index '%-.64s' due to type or collation conversion on field '%-.64s'"
ER_PARTITION_EXCHANGE_FOREIGN_KEY
eng "Table to exchange with partition has foreign key references: '%-.64s'"
swe "Tabellen att byta ut mot partition har foreign key referenser: '%-.64s'"
ER_NO_SUCH_KEY_VALUE
eng "Key value '%-.192s' was not found in table '%-.192s.%-.192s'"
ER_RPL_INFO_DATA_TOO_LONG
eng "Data for column '%s' too long"
ER_NETWORK_READ_EVENT_CHECKSUM_FAILURE
eng "Replication event checksum verification failed while reading from network."
ER_BINLOG_READ_EVENT_CHECKSUM_FAILURE
eng "Replication event checksum verification failed while reading from a log file."
ER_BINLOG_STMT_CACHE_SIZE_GREATER_THAN_MAX
eng "Option binlog_stmt_cache_size (%lu) is greater than max_binlog_stmt_cache_size (%lu); setting binlog_stmt_cache_size equal to max_binlog_stmt_cache_size."
ER_CANT_UPDATE_TABLE_IN_CREATE_TABLE_SELECT
eng "Can't update table '%-.192s' while '%-.192s' is being created."
ER_PARTITION_CLAUSE_ON_NONPARTITIONED
eng "PARTITION () clause on non partitioned table"
swe "PARTITION () klausul för en icke partitionerad tabell"
ER_ROW_DOES_NOT_MATCH_GIVEN_PARTITION_SET
eng "Found a row not matching the given partition set"
swe "Hittade en rad som inte passar i någon given partition"
ER_NO_SUCH_PARTITION
cze "partion '%-.64s' neexistuje"
dan "partition '%-.64s' eksisterer ikke"
nla "partition '%-.64s' bestaat niet"
eng "partition '%-.64s' doesn't exist"
est "partition '%-.64s' ei eksisteeri"
fre "La partition '%-.64s' n'existe pas"
ger "Die partition '%-.64s' existiert nicht"
hun "A '%-.64s' partition nem letezik"
ita "La tabella particione '%-.64s' non esiste"
nor "Partition '%-.64s' doesn't exist"
norwegian-ny "Partition '%-.64s' doesn't exist"
pol "Partition '%-.64s' doesn't exist"
por "Particion '%-.64s' n<>o existe"
rum "Partition '%-.64s' nu exista"
serbian "Partition '%-.64s' ne postoji"
slo "Partition '%-.64s' doesn't exist"
spa "Particion '%-.64s' no existe"
swe "Det finns ingen partition som heter '%-.64s'"
ER_CHANGE_RPL_INFO_REPOSITORY_FAILURE
eng "Failure while changing the type of replication repository: %s."
ER_WARNING_NOT_COMPLETE_ROLLBACK_WITH_CREATED_TEMP_TABLE
eng "The creation of some temporary tables could not be rolled back."
ER_WARNING_NOT_COMPLETE_ROLLBACK_WITH_DROPPED_TEMP_TABLE
eng "Some temporary tables were dropped, but these operations could not be rolled back."
ER_MTS_FEATURE_IS_NOT_SUPPORTED
eng "%s is not supported in multi-threaded slave mode. %s"
ER_MTS_UPDATED_DBS_GREATER_MAX
eng "The number of modified databases exceeds the maximum %d; the database names will not be included in the replication event metadata."
ER_MTS_CANT_PARALLEL
eng "Cannot execute the current event group in the parallel mode. Encountered event %s, relay-log name %s, position %s which prevents execution of this event group in parallel mode. Reason: %s."
ER_MTS_INCONSISTENT_DATA
eng "%s"
ER_FULLTEXT_NOT_SUPPORTED_WITH_PARTITIONING
eng "FULLTEXT index is not supported for partitioned tables."
swe "FULLTEXT index stöds ej för partitionerade tabeller."
ER_DA_INVALID_CONDITION_NUMBER 35000
eng "Invalid condition number"
por "Número de condição inválido"
ER_INSECURE_PLAIN_TEXT
eng "Sending passwords in plain text without SSL/TLS is extremely insecure."
ER_INSECURE_CHANGE_MASTER
eng "Storing MySQL user name or password information in the master.info repository is not secure and is therefore not recommended. Please see the MySQL Manual for more about this issue and possible alternatives."
ER_FOREIGN_DUPLICATE_KEY_WITH_CHILD_INFO 23000 S1009
eng "Foreign key constraint for table '%.192s', record '%-.192s' would lead to a duplicate entry in table '%.192s', key '%.192s'"
ger "Fremdschlüssel-Beschränkung für Tabelle '%.192s', Datensatz '%-.192s' würde zu einem doppelten Eintrag in Tabelle '%.192s', Schlüssel '%.192s' führen"
swe "FOREIGN KEY constraint för tabell '%.192s', posten '%-.192s' kan inte uppdatera barntabell '%.192s' på grund av nyckel '%.192s'"
ER_FOREIGN_DUPLICATE_KEY_WITHOUT_CHILD_INFO 23000 S1009
eng "Foreign key constraint for table '%.192s', record '%-.192s' would lead to a duplicate entry in a child table"
ger "Fremdschlüssel-Beschränkung für Tabelle '%.192s', Datensatz '%-.192s' würde zu einem doppelten Eintrag in einer Kind-Tabelle führen"
swe "FOREIGN KEY constraint för tabell '%.192s', posten '%-.192s' kan inte uppdatera en barntabell på grund av UNIQUE-test"
ER_SQLTHREAD_WITH_SECURE_SLAVE
eng "Setting authentication options is not possible when only the Slave SQL Thread is being started."
ER_TABLE_HAS_NO_FT
eng "The table does not have FULLTEXT index to support this query"
ER_INNODB_FT_LIMIT
eng "InnoDB presently supports one FULLTEXT index per table"
ER_INNODB_NO_FT_TEMP_TABLE
eng "Cannot create FULLTEXT index on temporary InnoDB table"
ER_VARIABLE_NOT_SETTABLE_IN_SF_OR_TRIGGER
eng "The system variable %.200s cannot be set in stored functions or triggers."
ER_VARIABLE_NOT_SETTABLE_IN_TRANSACTION
eng "The system variable %.200s cannot be set when there is an ongoing transaction."
ER_GTID_NEXT_IS_NOT_IN_GTID_NEXT_LIST
eng "The system variable @@SESSION.GTID_NEXT has the value %.200s, which is not listed in @@SESSION.GTID_NEXT_LIST."
ER_CANT_CHANGE_GTID_NEXT_IN_TRANSACTION_WHEN_GTID_NEXT_LIST_IS_NULL
eng "When @@SESSION.GTID_NEXT_LIST == NULL, the system variable @@SESSION.GTID_NEXT cannot change inside a transaction."
ER_SET_STATEMENT_CANNOT_INVOKE_FUNCTION
eng "The statement 'SET %.200s' cannot invoke a stored function."
ER_GTID_NEXT_CANT_BE_AUTOMATIC_IF_GTID_NEXT_LIST_IS_NON_NULL
eng "The system variable @@SESSION.GTID_NEXT cannot be 'AUTOMATIC' when @@SESSION.GTID_NEXT_LIST is non-NULL."
ER_SKIPPING_LOGGED_TRANSACTION
eng "Skipping transaction %.200s because it has already been executed and logged."
ER_MALFORMED_GTID_SET_SPECIFICATION
eng "Malformed GTID set specification '%.200s'."
ER_MALFORMED_GTID_SET_ENCODING
eng "Malformed GTID set encoding."
ER_MALFORMED_GTID_SPECIFICATION
eng "Malformed GTID specification '%.200s'."
ER_GNO_EXHAUSTED
eng "Impossible to generate Global Transaction Identifier: the integer component reached the maximal value. Restart the server with a new server_uuid."
ER_BAD_SLAVE_AUTO_POSITION
eng "Parameters MASTER_LOG_FILE, MASTER_LOG_POS, RELAY_LOG_FILE and RELAY_LOG_POS cannot be set when MASTER_AUTO_POSITION is active."
ER_AUTO_POSITION_REQUIRES_GTID_MODE_ON
eng "CHANGE MASTER TO AUTO_POSITION = 1 can only be executed when GTID_MODE = ON."
ER_CANT_DO_IMPLICIT_COMMIT_IN_TRX_WHEN_GTID_NEXT_IS_SET
eng "Cannot execute statements with implicit commit inside a transaction when GTID_NEXT != AUTOMATIC or GTID_NEXT_LIST != NULL."
ER_GTID_MODE_2_OR_3_REQUIRES_DISABLE_GTID_UNSAFE_STATEMENTS_ON
eng "GTID_MODE = ON or GTID_MODE = UPGRADE_STEP_2 requires DISABLE_GTID_UNSAFE_STATEMENTS = 1."
ER_GTID_MODE_REQUIRES_BINLOG
eng "GTID_MODE = ON or UPGRADE_STEP_1 or UPGRADE_STEP_2 requires --log-bin and --log-slave-updates."
ER_CANT_SET_GTID_NEXT_TO_GTID_WHEN_GTID_MODE_IS_OFF
eng "GTID_NEXT cannot be set to UUID:NUMBER when GTID_MODE = OFF."
ER_CANT_SET_GTID_NEXT_TO_ANONYMOUS_WHEN_GTID_MODE_IS_ON
eng "GTID_NEXT cannot be set to ANONYMOUS when GTID_MODE = ON."
ER_CANT_SET_GTID_NEXT_LIST_TO_NON_NULL_WHEN_GTID_MODE_IS_OFF
eng "GTID_NEXT_LIST cannot be set to a non-NULL value when GTID_MODE = OFF."
ER_FOUND_GTID_EVENT_WHEN_GTID_MODE_IS_OFF
eng "Found a Gtid_log_event or Previous_gtids_log_event when GTID_MODE = OFF."
ER_GTID_UNSAFE_NON_TRANSACTIONAL_TABLE
eng "Updates to non-transactional tables are forbidden when DISABLE_GTID_UNSAFE_STATEMENTS = 1."
ER_GTID_UNSAFE_CREATE_SELECT
eng "CREATE TABLE ... SELECT is forbidden when DISABLE_GTID_UNSAFE_STATEMENTS = 1."
ER_GTID_UNSAFE_CREATE_DROP_TEMPORARY_TABLE_IN_TRANSACTION
eng "When DISABLE_GTID_UNSAFE_STATEMENTS = 1, the statements CREATE TEMPORARY TABLE and DROP TEMPORARY TABLE can be executed in a non-transactional context only, and require that AUTOCOMMIT = 1."
ER_GTID_MODE_CAN_ONLY_CHANGE_ONE_STEP_AT_A_TIME
eng "The value of GTID_MODE can only change one step at a time: OFF <-> UPGRADE_STEP_1 <-> UPGRADE_STEP_2 <-> ON. Also note that this value must be stepped up or down simultaneously on all servers; see the Manual for instructions."
ER_MASTER_HAS_PURGED_REQUIRED_GTIDS
eng "The slave is connecting using CHANGE MASTER TO MASTER_AUTO_POSITION = 1, but the master has purged binary logs containing GTIDs that the slave requires."
ER_CANT_SET_GTID_NEXT_WHEN_OWNING_GTID
eng "GTID_NEXT cannot be changed by a client that owns a GTID. The client owns %s. Ownership is released on COMMIT or ROLLBACK."
ER_UNKNOWN_EXPLAIN_FORMAT
eng "Unknown EXPLAIN format name: '%s'"
rus "Неизвестное имя формата команды EXPLAIN: '%s'"
ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION 25006
eng "Cannot execute statement in a READ ONLY transaction."
#
# MariaDB error messages section starts here
#
@ -6547,10 +6766,10 @@ ER_UNKNOWN_OPTION
eng "Unknown option '%-.64s'"
ER_BAD_OPTION_VALUE
eng "Incorrect value '%-.64s' for option '%-.64s'"
ER_NETWORK_READ_EVENT_CHECKSUM_FAILURE
eng "Replication event checksum verification failed while reading from network."
ER_BINLOG_READ_EVENT_CHECKSUM_FAILURE
eng "Replication event checksum verification failed while reading from a log file."
ER_NOT_USED_ERROR_MESSAGE
eng ""
ER_NOT_USED_ERROR_MESSAGE2
eng ""
ER_CANT_DO_ONLINE
eng "Can't execute the given '%s' command as online"
ER_DATA_OVERFLOW 22003

99
sql/sql_bootstrap.cc Normal file
View file

@ -0,0 +1,99 @@
/* Copyright (c) 2010, Oracle and/or its affiliates.
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
the Free Software Foundation; version 2 of the License.
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.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
#include <ctype.h>
#include <string.h>
#include "sql_bootstrap.h"
int read_bootstrap_query(char *query, int *query_length,
fgets_input_t input, fgets_fn_t fgets_fn)
{
char line_buffer[MAX_BOOTSTRAP_LINE_SIZE];
const char *line;
int len;
int query_len= 0;
for ( ; ; )
{
line= (*fgets_fn)(line_buffer, sizeof(line_buffer), input);
if (line == NULL)
return (query_len ? READ_BOOTSTRAP_ERROR : READ_BOOTSTRAP_EOF);
len= strlen(line);
/*
Remove trailing whitespace characters.
This assumes:
- no multibyte encoded character can be found at the very end of a line,
- whitespace characters from the "C" locale only.
which is sufficient for the kind of queries found
in the bootstrap scripts.
*/
while (len && (isspace(line[len - 1])))
len--;
/*
Cleanly end the string, so we don't have to test len > x
all the time before reading line[x], in the code below.
*/
line_buffer[len]= '\0';
/* Skip blank lines */
if (len == 0)
continue;
/* Skip # comments */
if (line[0] == '#')
continue;
/* Skip -- comments */
if ((line[0] == '-') && (line[1] == '-'))
continue;
/* Skip delimiter, ignored. */
if (strncmp(line, "delimiter", 9) == 0)
continue;
/* Append the current line to a multi line query. */
if (query_len + len + 1 >= MAX_BOOTSTRAP_QUERY_SIZE)
return READ_BOOTSTRAP_ERROR;
if (query_len != 0)
{
/*
Append a \n to the current line, if any,
to preserve the intended presentation.
*/
query[query_len]= '\n';
query_len++;
}
memcpy(query + query_len, line, len);
query_len+= len;
if (line[len - 1] == ';')
{
/*
The last line is terminated by ';'.
Return the query found.
*/
query[query_len]= '\0';
*query_length= query_len;
return 0;
}
}
}

44
sql/sql_bootstrap.h Normal file
View file

@ -0,0 +1,44 @@
/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
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
the Free Software Foundation; version 2 of the License.
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.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
#ifndef SQL_BOOTSTRAP_H
#define SQL_BOOTSTRAP_H
/**
The maximum size of a bootstrap query.
Increase this size if parsing a longer query during bootstrap is necessary.
The longest query in use depends on the documentation content,
see the file fill_help_tables.sql
*/
#define MAX_BOOTSTRAP_QUERY_SIZE 20000
/**
The maximum size of a bootstrap query, expressed in a single line.
Do not increase this size, use the multiline syntax instead.
*/
#define MAX_BOOTSTRAP_LINE_SIZE 20000
#define READ_BOOTSTRAP_EOF 1
#define READ_BOOTSTRAP_ERROR 2
typedef void *fgets_input_t;
typedef char * (*fgets_fn_t)(char *, size_t, fgets_input_t);
int read_bootstrap_query(char *query, int *query_length,
fgets_input_t input, fgets_fn_t fgets_fn);
#endif

View file

@ -3695,13 +3695,13 @@ public:
/*
Cost to materialize - execute the sub-join and write rows into temp.table
*/
COST_VECT materialization_cost;
Cost_estimate materialization_cost;
/* Cost to make one lookup in the temptable */
COST_VECT lookup_cost;
Cost_estimate lookup_cost;
/* Cost of scanning the materialized table */
COST_VECT scan_cost;
Cost_estimate scan_cost;
/* --- Execution structures ---------- */

View file

@ -20,6 +20,8 @@
#include "m_string.h" /* LEX_STRING */
#include "sql_string.h" /* String */
#include "mysql_com.h" /* MYSQL_ERRMSG_SIZE */
#include "my_time.h" /* MYSQL_TIME */
#include "decimal.h"
class THD;
@ -319,6 +321,14 @@ private:
MEM_ROOT *m_mem_root;
};
class Sql_condition : public MYSQL_ERROR
{
/*
Wrapper class to allow one to use Sql_condition in handlers instead of
MYSQL_ERROR
*/
};
///////////////////////////////////////////////////////////////////////////
/**

View file

@ -95,6 +95,7 @@
#include "probes_mysql.h"
#include "set_var.h"
#include "log_slow.h"
#include "sql_bootstrap.h"
#define FLAGSTR(V,F) ((V)&(F)?#F" ":"")
@ -481,11 +482,16 @@ void execute_init_command(THD *thd, LEX_STRING *init_command,
}
static char *fgets_fn(char *buffer, size_t size, fgets_input_t input)
{
MYSQL_FILE *in= static_cast<MYSQL_FILE*> (input);
return mysql_file_fgets(buffer, size, in);
}
static void handle_bootstrap_impl(THD *thd)
{
MYSQL_FILE *file= bootstrap_file;
char *buff, *res;
DBUG_ENTER("handle_bootstrap");
#ifndef EMBEDDED_LIBRARY
@ -503,50 +509,30 @@ static void handle_bootstrap_impl(THD *thd)
*/
thd->client_capabilities|= CLIENT_MULTI_RESULTS;
buff= (char*) thd->net.buff;
thd->init_for_queries();
while (mysql_file_fgets(buff, thd->net.max_packet, file))
for ( ; ; )
{
char buffer[MAX_BOOTSTRAP_QUERY_SIZE];
int rc, length;
char *query;
/* strlen() can't be deleted because mysql_file_fgets() doesn't return length */
ulong length= (ulong) strlen(buff);
while (buff[length-1] != '\n' && !mysql_file_feof(file))
rc= read_bootstrap_query(buffer, &length, file, fgets_fn);
if (rc == READ_BOOTSTRAP_ERROR)
{
/*
We got only a part of the current string. Will try to increase
net buffer then read the rest of the current string.
*/
/* purecov: begin tested */
if (net_realloc(&(thd->net), 2 * thd->net.max_packet))
{
thd->protocol->end_statement();
bootstrap_error= 1;
break;
}
buff= (char*) thd->net.buff;
res= mysql_file_fgets(buff + length, thd->net.max_packet - length, file);
if (!res && !mysql_file_feof(file))
{
thd->protocol->end_statement();
bootstrap_error= 1;
break;
}
length+= (ulong) strlen(buff + length);
/* purecov: end */
thd->raise_error(ER_SYNTAX_ERROR);
thd->protocol->end_statement();
bootstrap_error= 1;
break;
}
if (bootstrap_error)
break; /* purecov: inspected */
while (length && (my_isspace(thd->charset(), buff[length-1]) ||
buff[length-1] == ';'))
length--;
buff[length]=0;
if (rc == READ_BOOTSTRAP_EOF)
break;
/* Skip lines starting with delimiter */
if (strncmp(buff, STRING_WITH_LEN("delimiter")) == 0)
continue;
DBUG_ASSERT(rc == 0);
query= (char *) thd->memdup_w_gap(buff, length + 1,
query= (char *) thd->memdup_w_gap(buffer, length + 1,
thd->db_length + 1 +
QUERY_CACHE_DB_LENGTH_SIZE +
QUERY_CACHE_FLAGS_SIZE);

View file

@ -9588,7 +9588,7 @@ uint check_join_cache_usage(JOIN_TAB *tab,
uint table_index,
JOIN_TAB *prev_tab)
{
COST_VECT cost;
Cost_estimate cost;
uint flags= 0;
ha_rows rows= 0;
uint bufsz= 4096;

View file

@ -763,7 +763,7 @@ typedef struct st_position :public Sql_alloc
double read_time;
/* Cumulative cost and record count for the join prefix */
COST_VECT prefix_cost;
Cost_estimate prefix_cost;
double prefix_record_count;
/*

View file

@ -4018,7 +4018,8 @@ void TABLE::reset_item_list(List<Item> *item_list) const
void TABLE_LIST::calc_md5(char *buffer)
{
uchar digest[16];
MY_MD5_HASH(digest, (uchar *) select_stmt.str, select_stmt.length);
compute_md5_hash((char*) digest, select_stmt.str,
select_stmt.length);
sprintf((char *) buffer,
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
digest[0], digest[1], digest[2], digest[3],

View file

@ -1,14 +1,14 @@
# Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
#
#
# 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
# the Free Software Foundation; version 2 of the License.
#
#
# 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.
#
#
# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
@ -30,19 +30,29 @@ IF(UNIX)
LINK_LIBRARIES(aio)
ENDIF()
ELSEIF(CMAKE_SYSTEM_NAME MATCHES "HP*")
ADD_DEFINITIONS("-DUNIV_HPUX -DUNIV_MUST_NOT_INLINE")
ADD_DEFINITIONS("-DUNIV_HPUX")
ELSEIF(CMAKE_SYSTEM_NAME STREQUAL "AIX")
ADD_DEFINITIONS("-DUNIV_AIX -DUNIX_MUST_NOT_INLINE")
ADD_DEFINITIONS("-DUNIV_AIX")
ELSEIF(CMAKE_SYSTEM_NAME STREQUAL "SunOS")
ADD_DEFINITIONS("-DUNIV_SOLARIS")
ELSE()
ADD_DEFINITIONS("-DUNIV_MUST_NOT_INLINE")
ENDIF()
ENDIF()
# Enable InnoDB's UNIV_DEBUG for debug builds
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DUNIV_DEBUG")
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DUNIV_DEBUG")
IF(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
# After: WL#5825 Using C++ Standard Library with MySQL code
# we no longer use -fno-exceptions
# SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions")
ENDIF()
# Enable InnoDB's UNIV_DEBUG and UNIV_SYNC_DEBUG in debug builds
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DUNIV_DEBUG -DUNIV_SYNC_DEBUG")
# Add -Wconversion if compiling with GCC
## As of Mar 15 2011 this flag causes 3573+ warnings. If you are reading this
## please fix them and enable the following code:
#IF(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
#SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wconversion")
#ENDIF()
IF(NOT MSVC)
# either define HAVE_IB_GCC_ATOMIC_BUILTINS or not
@ -119,6 +129,8 @@ ENDIF()
ENDIF(NOT MSVC)
SET(LINKER_SCRIPT)
# Solaris atomics
IF(CMAKE_SYSTEM_NAME STREQUAL "SunOS")
CHECK_FUNCTION_EXISTS(atomic_cas_ulong HAVE_ATOMIC_CAS_ULONG)
@ -133,11 +145,15 @@ IF(CMAKE_SYSTEM_NAME STREQUAL "SunOS")
HAVE_ATOMIC_SWAP_UCHAR)
SET(HAVE_IB_SOLARIS_ATOMICS 1)
ENDIF()
IF(HAVE_IB_SOLARIS_ATOMICS)
ADD_DEFINITIONS(-DHAVE_IB_SOLARIS_ATOMICS=1)
ENDIF()
IF(CMAKE_COMPILER_IS_GNUCC AND NOT HAVE_VISIBILITY_HIDDEN)
SET(LINKER_SCRIPT "-Wl,-M${CMAKE_CURRENT_SOURCE_DIR}/plugin_exports")
ENDIF()
IF(NOT CMAKE_CROSSCOMPILING)
# either define HAVE_IB_ATOMIC_PTHREAD_T_SOLARIS or not
CHECK_C_SOURCE_COMPILES(
@ -154,15 +170,15 @@ IF(CMAKE_SYSTEM_NAME STREQUAL "SunOS")
memset(&x3, 0x0, sizeof(x3));
if (sizeof(pthread_t) == 4) {
atomic_cas_32(&x1, x2, x3);
} else if (sizeof(pthread_t) == 8) {
atomic_cas_64(&x1, x2, x3);
} else {
return(1);
}
@ -198,81 +214,148 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/storage/innobase/include
${CMAKE_SOURCE_DIR}/storage/innobase/handler)
# Sun Studio bug with -xO2
IF(CMAKE_C_COMPILER_ID MATCHES "SunPro"
AND CMAKE_C_FLAGS_RELEASE MATCHES "O2"
IF(CMAKE_CXX_COMPILER_ID MATCHES "SunPro"
AND CMAKE_CXX_FLAGS_RELEASE MATCHES "O2"
AND NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
# Sun Studio 12 crashes with -xO2 flag, but not with higher optimization
# -xO3
SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_SOURCE_DIR}/rem/rem0rec.c
SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_SOURCE_DIR}/rem/rem0rec.cc
PROPERTIES COMPILE_FLAGS -xO3)
ENDIF()
# Removing compiler optimizations for innodb/mem/* files on 64-bit Windows
# due to 64-bit compiler error, See MySQL Bug #19424, #36366, #34297
IF (MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 8)
SET_SOURCE_FILES_PROPERTIES(mem/mem0mem.c mem/mem0pool.c
SET_SOURCE_FILES_PROPERTIES(mem/mem0mem.cc mem/mem0pool.cc
PROPERTIES COMPILE_FLAGS -Od)
ENDIF()
IF(MSVC)
# Avoid "unreferenced label" warning in generated file
GET_FILENAME_COMPONENT(_SRC_DIR ${CMAKE_CURRENT_LIST_FILE} PATH)
SET_SOURCE_FILES_PROPERTIES(${_SRC_DIR}/pars/pars0grm.c
SET_SOURCE_FILES_PROPERTIES(${_SRC_DIR}/pars/pars0grm.cc
PROPERTIES COMPILE_FLAGS "/wd4102")
SET_SOURCE_FILES_PROPERTIES(${_SRC_DIR}/pars/lexyy.c
SET_SOURCE_FILES_PROPERTIES(${_SRC_DIR}/pars/lexyy.cc
PROPERTIES COMPILE_FLAGS "/wd4003")
ENDIF()
SET(INNOBASE_SOURCES btr/btr0btr.c btr/btr0cur.c btr/btr0pcur.c btr/btr0sea.c
buf/buf0buddy.c buf/buf0buf.c buf/buf0flu.c buf/buf0lru.c buf/buf0rea.c
data/data0data.c data/data0type.c
dict/dict0boot.c dict/dict0crea.c dict/dict0dict.c dict/dict0load.c dict/dict0mem.c
dyn/dyn0dyn.c
eval/eval0eval.c eval/eval0proc.c
fil/fil0fil.c
fsp/fsp0fsp.c
fut/fut0fut.c fut/fut0lst.c
ha/ha0ha.c ha/hash0hash.c ha/ha0storage.c
ibuf/ibuf0ibuf.c
pars/lexyy.c pars/pars0grm.c pars/pars0opt.c pars/pars0pars.c pars/pars0sym.c
lock/lock0lock.c lock/lock0iter.c
log/log0log.c log/log0recv.c
mach/mach0data.c
mem/mem0mem.c mem/mem0pool.c
mtr/mtr0log.c mtr/mtr0mtr.c
os/os0file.c os/os0proc.c os/os0sync.c os/os0thread.c
page/page0cur.c page/page0page.c page/page0zip.c
que/que0que.c
handler/ha_innodb.cc handler/handler0alter.cc handler/i_s.cc
read/read0read.c
rem/rem0cmp.c rem/rem0rec.c
row/row0ext.c row/row0ins.c row/row0merge.c row/row0mysql.c row/row0purge.c row/row0row.c
row/row0sel.c row/row0uins.c row/row0umod.c row/row0undo.c row/row0upd.c row/row0vers.c
srv/srv0srv.c srv/srv0start.c
sync/sync0arr.c sync/sync0rw.c sync/sync0sync.c
trx/trx0i_s.c trx/trx0purge.c trx/trx0rec.c trx/trx0roll.c trx/trx0rseg.c
trx/trx0sys.c trx/trx0trx.c trx/trx0undo.c
usr/usr0sess.c
ut/ut0byte.c ut/ut0dbg.c ut/ut0list.c ut/ut0mem.c ut/ut0rbt.c ut/ut0rnd.c
ut/ut0ut.c ut/ut0vec.c ut/ut0wqueue.c ut/ut0bh.c)
SET(INNOBASE_SOURCES
btr/btr0btr.cc
btr/btr0cur.cc
btr/btr0pcur.cc
btr/btr0sea.cc
buf/buf0buddy.cc
buf/buf0buf.cc
buf/buf0dblwr.cc
buf/buf0checksum.cc
buf/buf0dump.cc
buf/buf0flu.cc
buf/buf0lru.cc
buf/buf0rea.cc
data/data0data.cc
data/data0type.cc
dict/dict0boot.cc
dict/dict0crea.cc
dict/dict0dict.cc
dict/dict0load.cc
dict/dict0mem.cc
dict/dict0stats.cc
dyn/dyn0dyn.cc
eval/eval0eval.cc
eval/eval0proc.cc
fil/fil0fil.cc
fsp/fsp0fsp.cc
fut/fut0fut.cc
fut/fut0lst.cc
ha/ha0ha.cc
ha/ha0storage.cc
ha/hash0hash.cc
fts/fts0fts.cc
fts/fts0ast.cc
fts/fts0blex.cc
fts/fts0config.cc
fts/fts0opt.cc
fts/fts0pars.cc
fts/fts0que.cc
fts/fts0sql.cc
fts/fts0tlex.cc
handler/ha_innodb.cc
handler/handler0alter.cc
handler/i_s.cc
ibuf/ibuf0ibuf.cc
lock/lock0iter.cc
lock/lock0lock.cc
lock/lock0wait.cc
log/log0log.cc
log/log0recv.cc
mach/mach0data.cc
mem/mem0mem.cc
mem/mem0pool.cc
mtr/mtr0log.cc
mtr/mtr0mtr.cc
os/os0file.cc
os/os0proc.cc
os/os0sync.cc
os/os0thread.cc
page/page0cur.cc
page/page0page.cc
page/page0zip.cc
pars/lexyy.cc
pars/pars0grm.cc
pars/pars0opt.cc
pars/pars0pars.cc
pars/pars0sym.cc
que/que0que.cc
read/read0read.cc
rem/rem0cmp.cc
rem/rem0rec.cc
row/row0ext.cc
row/row0ftsort.cc
row/row0ins.cc
row/row0merge.cc
row/row0mysql.cc
row/row0purge.cc
row/row0row.cc
row/row0sel.cc
row/row0uins.cc
row/row0umod.cc
row/row0undo.cc
row/row0upd.cc
row/row0vers.cc
srv/srv0conc.cc
srv/srv0mon.cc
srv/srv0srv.cc
srv/srv0start.cc
sync/sync0arr.cc
sync/sync0rw.cc
sync/sync0sync.cc
trx/trx0i_s.cc
trx/trx0purge.cc
trx/trx0rec.cc
trx/trx0roll.cc
trx/trx0rseg.cc
trx/trx0sys.cc
trx/trx0trx.cc
trx/trx0undo.cc
usr/usr0sess.cc
ut/ut0bh.cc
ut/ut0byte.cc
ut/ut0crc32.cc
ut/ut0dbg.cc
ut/ut0list.cc
ut/ut0mem.cc
ut/ut0rbt.cc
ut/ut0rnd.cc
ut/ut0ut.cc
ut/ut0vec.cc
ut/ut0wqueue.cc)
IF(WITH_INNODB)
# Legacy option
SET(WITH_INNOBASE_STORAGE_ENGINE TRUE)
ENDIF()
# On solaris, reduce symbol visibility, so loader does not mix
# the same symbols from builtin innodb and from shared one.
# Only required for old GCC (3.4.3) that does not support hidden visibility
IF(CMAKE_SYSTEM_NAME MATCHES "SunOS" AND CMAKE_COMPILER_IS_GNUCC
AND NOT HAVE_VISIBILITY_HIDDEN)
SET(LINKER_SCRIPT "-Wl,-M${CMAKE_CURRENT_SOURCE_DIR}/plugin_exports")
ELSE()
SET(LINKER_SCRIPT)
ENDIF()
MYSQL_ADD_PLUGIN(innobase ${INNOBASE_SOURCES} STORAGE_ENGINE
MODULE_ONLY
MYSQL_ADD_PLUGIN(innobase ${INNOBASE_SOURCES} STORAGE_ENGINE
DEFAULT
MODULE_OUTPUT_NAME ha_innodb
LINK_LIBRARIES ${ZLIB_LIBRARY} ${LINKER_SCRIPT})
LINK_LIBRARIES ${ZLIB_LIBRARY})

View file

@ -17,7 +17,7 @@ this program; if not, write to the Free Software Foundation, Inc.,
*****************************************************************************/
/**************************************************//**
@file btr/btr0btr.c
@file btr/btr0btr.cc
The B-tree
Created 6/2/1994 Heikki Tuuri
@ -41,6 +41,7 @@ Created 6/2/1994 Heikki Tuuri
#include "lock0lock.h"
#include "ibuf0ibuf.h"
#include "trx0trx.h"
#include "srv0mon.h"
/**************************************************************//**
Report that an index page is corrupted. */
@ -132,8 +133,8 @@ btr_blob_dbg_cmp(
const void* a, /*!< in: first btr_blob_dbg_t to compare */
const void* b) /*!< in: second btr_blob_dbg_t to compare */
{
const btr_blob_dbg_t* aa = a;
const btr_blob_dbg_t* bb = b;
const btr_blob_dbg_t* aa = static_cast<const btr_blob_dbg_t*>(a);
const btr_blob_dbg_t* bb = static_cast<const btr_blob_dbg_t*>(b);
ut_ad(aa != NULL);
ut_ad(bb != NULL);
@ -418,7 +419,7 @@ btr_blob_dbg_op(
rec = page_rec_get_next_const(rec);
} while (!page_rec_is_supremum(rec));
if (UNIV_LIKELY_NULL(heap)) {
if (heap) {
mem_heap_free(heap);
}
@ -874,7 +875,7 @@ btr_page_create(
ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
btr_blob_dbg_assert_empty(index, buf_block_get_page_no(block));
if (UNIV_LIKELY_NULL(page_zip)) {
if (page_zip) {
page_create_zip(block, index, level, mtr);
} else {
page_create(block, mtr, dict_table_is_comp(index->table));
@ -1123,6 +1124,15 @@ btr_page_free_low(
fseg_free_page(seg_header,
buf_block_get_space(block),
buf_block_get_page_no(block), mtr);
/* The page was marked free in the allocation bitmap, but it
should remain buffer-fixed until mtr_commit(mtr) or until it
is explicitly freed from the mini-transaction. */
ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
/* TODO: Discard any operations on the page from the redo log
and remove the block from the flush list and the buffer pool.
This would free up buffer pool earlier and reduce writes to
both the tablespace and the redo log. */
}
/**************************************************************//**
@ -1169,7 +1179,7 @@ btr_node_ptr_set_child_page_no(
ut_ad(len == REC_NODE_PTR_SIZE);
if (UNIV_LIKELY_NULL(page_zip)) {
if (page_zip) {
page_zip_write_node_ptr(page_zip, rec,
rec_offs_data_size(offsets),
page_no, mtr);
@ -1249,8 +1259,7 @@ btr_page_get_father_node_ptr_func(
offsets = rec_get_offsets(node_ptr, index, offsets,
ULINT_UNDEFINED, &heap);
if (UNIV_UNLIKELY(btr_node_ptr_get_child_page_no(node_ptr, offsets)
!= page_no)) {
if (btr_node_ptr_get_child_page_no(node_ptr, offsets) != page_no) {
rec_t* print_rec;
fputs("InnoDB: Dump of the child page:\n", stderr);
buf_page_print(page_align(user_rec), 0,
@ -1437,7 +1446,7 @@ btr_create(
/* Create a new index page on the allocated segment page */
page_zip = buf_block_get_page_zip(block);
if (UNIV_LIKELY_NULL(page_zip)) {
if (page_zip) {
page = page_create_zip(block, index, 0, mtr);
} else {
page = page_create(block, mtr,
@ -1556,7 +1565,9 @@ btr_free_root(
ut_a(btr_root_fseg_validate(header, space));
#endif /* UNIV_BTR_DEBUG */
while (!fseg_free_step(header, mtr));
while (!fseg_free_step(header, mtr)) {
/* Free the entire segment in small steps. */
}
}
#endif /* !UNIV_HOTBACKUP */
@ -1575,7 +1586,9 @@ btr_page_reorganize_low(
dict_index_t* index, /*!< in: record descriptor */
mtr_t* mtr) /*!< in: mtr */
{
#ifndef UNIV_HOTBACKUP
buf_pool_t* buf_pool = buf_pool_from_bpage(&block->page);
#endif /* !UNIV_HOTBACKUP */
page_t* page = buf_block_get_frame(block);
page_zip_des_t* page_zip = buf_block_get_page_zip(block);
buf_block_t* temp_block;
@ -1617,7 +1630,7 @@ btr_page_reorganize_low(
buf_frame_copy(temp_page, page);
#ifndef UNIV_HOTBACKUP
if (UNIV_LIKELY(!recovery)) {
if (!recovery) {
btr_search_drop_page_hash_index(block);
}
@ -1647,9 +1660,7 @@ btr_page_reorganize_low(
ut_ad(max_trx_id != 0 || recovery);
}
if (UNIV_LIKELY_NULL(page_zip)
&& UNIV_UNLIKELY
(!page_zip_compress(page_zip, page, index, NULL))) {
if (page_zip && !page_zip_compress(page_zip, page, index, NULL)) {
/* Restore the old page and exit. */
btr_blob_dbg_restore(page, temp_page, index,
@ -1679,7 +1690,7 @@ btr_page_reorganize_low(
}
#ifndef UNIV_HOTBACKUP
if (UNIV_LIKELY(!recovery)) {
if (!recovery) {
/* Update the record lock bitmaps */
lock_move_reorganize_page(block, temp_block);
}
@ -1688,10 +1699,10 @@ btr_page_reorganize_low(
data_size2 = page_get_data_size(page);
max_ins_size2 = page_get_max_insert_size_after_reorganize(page, 1);
if (UNIV_UNLIKELY(data_size1 != data_size2)
|| UNIV_UNLIKELY(max_ins_size1 != max_ins_size2)) {
if (data_size1 != data_size2 || max_ins_size1 != max_ins_size2) {
buf_page_print(page, 0, BUF_PAGE_PRINT_NO_CRASH);
buf_page_print(temp_page, 0, BUF_PAGE_PRINT_NO_CRASH);
fprintf(stderr,
"InnoDB: Error: page old data size %lu"
" new data size %lu\n"
@ -1759,7 +1770,7 @@ btr_parse_page_reorganize(
/* The record is empty, except for the record initial part */
if (UNIV_LIKELY(block != NULL)) {
if (block != NULL) {
btr_page_reorganize_low(TRUE, block, index, mtr);
}
@ -1793,7 +1804,7 @@ btr_page_empty(
/* Recreate the page: note that global data on page (possible
segment headers, next page-field, etc.) is preserved intact */
if (UNIV_LIKELY_NULL(page_zip)) {
if (page_zip) {
page_create_zip(block, index, level, mtr);
} else {
page_create(block, mtr, dict_table_is_comp(index->table));
@ -1886,10 +1897,9 @@ btr_root_raise_and_insert(
#ifdef UNIV_ZIP_COPY
|| new_page_zip
#endif /* UNIV_ZIP_COPY */
|| UNIV_UNLIKELY
(!page_copy_rec_list_end(new_block, root_block,
|| !page_copy_rec_list_end(new_block, root_block,
page_get_infimum_rec(root),
index, mtr))) {
index, mtr)) {
ut_a(new_page_zip);
/* Copy the page byte for byte. */
@ -2044,8 +2054,7 @@ btr_page_get_split_rec_to_right(
the previous insert on the same page, we assume that there is a
pattern of sequential inserts here. */
if (UNIV_LIKELY(page_header_get_ptr(page, PAGE_LAST_INSERT)
== insert_point)) {
if (page_header_get_ptr(page, PAGE_LAST_INSERT) == insert_point) {
rec_t* next_rec;
@ -2113,13 +2122,13 @@ btr_page_get_split_rec(
free_space = page_get_free_space_of_empty(page_is_comp(page));
page_zip = btr_cur_get_page_zip(cursor);
if (UNIV_LIKELY_NULL(page_zip)) {
if (page_zip) {
/* Estimate the free space of an empty compressed page. */
ulint free_space_zip = page_zip_empty_size(
cursor->index->n_fields,
page_zip_get_size(page_zip));
if (UNIV_LIKELY(free_space > (ulint) free_space_zip)) {
if (free_space > (ulint) free_space_zip) {
free_space = (ulint) free_space_zip;
}
}
@ -2192,7 +2201,7 @@ btr_page_get_split_rec(
}
func_exit:
if (UNIV_LIKELY_NULL(heap)) {
if (heap) {
mem_heap_free(heap);
}
return(rec);
@ -2337,7 +2346,7 @@ btr_attach_half_pages(
/*==================*/
dict_index_t* index, /*!< in: the index tree */
buf_block_t* block, /*!< in/out: page to be split */
rec_t* split_rec, /*!< in: first record on upper
const rec_t* split_rec, /*!< in: first record on upper
half page */
buf_block_t* new_block, /*!< in/out: the new half page */
ulint direction, /*!< in: FSP_UP or FSP_DOWN */
@ -2568,7 +2577,7 @@ func_start:
hint_page_no = page_no + 1;
split_rec = btr_page_get_split_rec(cursor, tuple, n_ext);
if (UNIV_UNLIKELY(split_rec == NULL)) {
if (split_rec == NULL) {
insert_left = btr_page_tuple_smaller(
cursor, tuple, offsets, n_uniq, &heap);
}
@ -2620,15 +2629,14 @@ func_start:
insert_left = cmp_dtuple_rec(tuple, split_rec, offsets) < 0;
if (UNIV_UNLIKELY(!insert_left && new_page_zip
&& n_iterations > 0)) {
if (!insert_left && new_page_zip && n_iterations > 0) {
/* If a compressed page has already been split,
avoid further splits by inserting the record
to an empty page. */
split_rec = NULL;
goto insert_empty;
}
} else if (UNIV_UNLIKELY(insert_left)) {
} else if (insert_left) {
ut_a(n_iterations > 0);
first_rec = page_rec_get_next(page_get_infimum_rec(page));
move_limit = page_rec_get_next(btr_cur_get_rec(cursor));
@ -2636,8 +2644,8 @@ func_start:
insert_empty:
ut_ad(!split_rec);
ut_ad(!insert_left);
buf = mem_alloc(rec_get_converted_size(cursor->index,
tuple, n_ext));
buf = (byte*) mem_alloc(rec_get_converted_size(cursor->index,
tuple, n_ext));
first_rec = rec_convert_dtuple_to_rec(buf, cursor->index,
tuple, n_ext);
@ -2683,9 +2691,8 @@ insert_empty:
#ifdef UNIV_ZIP_COPY
|| page_zip
#endif /* UNIV_ZIP_COPY */
|| UNIV_UNLIKELY
(!page_move_rec_list_start(new_block, block, move_limit,
cursor->index, mtr))) {
|| !page_move_rec_list_start(new_block, block, move_limit,
cursor->index, mtr)) {
/* For some reason, compressing new_page failed,
even though it should contain fewer records than
the original page. Copy the page byte for byte
@ -2726,9 +2733,8 @@ insert_empty:
#ifdef UNIV_ZIP_COPY
|| page_zip
#endif /* UNIV_ZIP_COPY */
|| UNIV_UNLIKELY
(!page_move_rec_list_end(new_block, block, move_limit,
cursor->index, mtr))) {
|| !page_move_rec_list_end(new_block, block, move_limit,
cursor->index, mtr)) {
/* For some reason, compressing new_page failed,
even though it should contain fewer records than
the original page. Copy the page byte for byte
@ -2764,7 +2770,7 @@ insert_empty:
}
#ifdef UNIV_ZIP_DEBUG
if (UNIV_LIKELY_NULL(page_zip)) {
if (page_zip) {
ut_a(page_zip_validate(page_zip, page));
ut_a(page_zip_validate(new_page_zip, new_page));
}
@ -2804,15 +2810,14 @@ insert_empty:
}
#endif /* UNIV_ZIP_DEBUG */
if (UNIV_LIKELY(rec != NULL)) {
if (rec != NULL) {
goto func_exit;
}
/* 8. If insert did not fit, try page reorganization */
if (UNIV_UNLIKELY
(!btr_page_reorganize(insert_block, cursor->index, mtr))) {
if (!btr_page_reorganize(insert_block, cursor->index, mtr)) {
goto insert_failed;
}
@ -2822,7 +2827,7 @@ insert_empty:
rec = page_cur_tuple_insert(page_cursor, tuple, cursor->index,
n_ext, mtr);
if (UNIV_UNLIKELY(rec == NULL)) {
if (rec == NULL) {
/* The insert did not fit on the page: loop back to the
start of the function for a new split */
insert_failed:
@ -2856,6 +2861,7 @@ func_exit:
buf_block_get_page_no(left_block),
buf_block_get_page_no(right_block));
#endif
MONITOR_INC(MONITOR_INDEX_SPLIT);
ut_ad(page_validate(buf_block_get_frame(left_block), cursor->index));
ut_ad(page_validate(buf_block_get_frame(right_block), cursor->index));
@ -3012,7 +3018,7 @@ btr_set_min_rec_mark(
{
ulint info_bits;
if (UNIV_LIKELY(page_rec_is_comp(rec))) {
if (page_rec_is_comp(rec)) {
info_bits = rec_get_info_bits(rec, TRUE);
rec_set_info_bits_new(rec, info_bits | REC_INFO_MIN_REC_FLAG);
@ -3131,10 +3137,9 @@ btr_lift_page_up(
#ifdef UNIV_ZIP_COPY
|| father_page_zip
#endif /* UNIV_ZIP_COPY */
|| UNIV_UNLIKELY
(!page_copy_rec_list_end(father_block, block,
page_get_infimum_rec(page),
index, mtr))) {
|| !page_copy_rec_list_end(father_block, block,
page_get_infimum_rec(page),
index, mtr)) {
const page_zip_des_t* page_zip
= buf_block_get_page_zip(block);
ut_a(father_page_zip);
@ -3310,12 +3315,11 @@ err_exit:
max_ins_size = page_get_max_insert_size(merge_page, n_recs);
if (UNIV_UNLIKELY(data_size > max_ins_size)) {
if (data_size > max_ins_size) {
/* We have to reorganize merge_page */
if (UNIV_UNLIKELY(!btr_page_reorganize(merge_block,
index, mtr))) {
if (!btr_page_reorganize(merge_block, index, mtr)) {
goto err_exit;
}
@ -3325,7 +3329,7 @@ err_exit:
ut_ad(page_validate(merge_page, index));
ut_ad(max_ins_size == max_ins_size_reorg);
if (UNIV_UNLIKELY(data_size > max_ins_size)) {
if (data_size > max_ins_size) {
/* Add fault tolerance, though this should
never happen */
@ -3336,7 +3340,7 @@ err_exit:
merge_page_zip = buf_block_get_page_zip(merge_block);
#ifdef UNIV_ZIP_DEBUG
if (UNIV_LIKELY_NULL(merge_page_zip)) {
if (merge_page_zip) {
const page_zip_des_t* page_zip
= buf_block_get_page_zip(block);
ut_a(page_zip);
@ -3351,7 +3355,7 @@ err_exit:
merge_block, block, page_get_supremum_rec(page),
index, mtr);
if (UNIV_UNLIKELY(!orig_pred)) {
if (!orig_pred) {
goto err_exit;
}
@ -3372,7 +3376,7 @@ err_exit:
byte fil_page_prev[4];
#endif /* UNIV_BTR_DEBUG */
if (UNIV_LIKELY_NULL(merge_page_zip)) {
if (merge_page_zip) {
/* The function page_zip_compress(), which will be
invoked by page_copy_rec_list_end() below,
requires that FIL_PAGE_PREV be FIL_NULL.
@ -3390,7 +3394,7 @@ err_exit:
page_get_infimum_rec(page),
cursor->index, mtr);
if (UNIV_UNLIKELY(!orig_succ)) {
if (!orig_succ) {
ut_a(merge_page_zip);
#ifdef UNIV_BTR_DEBUG
/* FIL_PAGE_PREV was restored from merge_page_zip. */
@ -3403,7 +3407,7 @@ err_exit:
btr_search_drop_page_hash_index(block);
#ifdef UNIV_BTR_DEBUG
if (UNIV_LIKELY_NULL(merge_page_zip)) {
if (merge_page_zip) {
/* Restore FIL_PAGE_PREV in order to avoid an assertion
failure in btr_level_list_remove(), which will set
the field again to FIL_NULL. Even though this makes
@ -3706,7 +3710,7 @@ btr_print_size(
fputs("INFO OF THE NON-LEAF PAGE SEGMENT\n", stderr);
fseg_print(seg, &mtr);
if (!(index->type & DICT_UNIVERSAL)) {
if (!dict_index_is_univ(index)) {
seg = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
@ -3804,7 +3808,7 @@ btr_print_index(
root = btr_root_block_get(index, &mtr);
btr_print_recursive(index, root, width, &heap, &offsets, &mtr);
if (UNIV_LIKELY_NULL(heap)) {
if (heap) {
mem_heap_free(heap);
}
@ -3900,7 +3904,7 @@ btr_index_rec_validate(
page = page_align(rec);
if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
if (dict_index_is_univ(index)) {
/* The insert buffer index tree can contain records from any
other index: we cannot check the number of fields or
their length */
@ -3908,8 +3912,7 @@ btr_index_rec_validate(
return(TRUE);
}
if (UNIV_UNLIKELY((ibool)!!page_is_comp(page)
!= dict_table_is_comp(index->table))) {
if ((ibool)!!page_is_comp(page) != dict_table_is_comp(index->table)) {
btr_index_rec_validate_report(page, rec, index);
fprintf(stderr, "InnoDB: compact flag=%lu, should be %lu\n",
(ulong) !!page_is_comp(page),
@ -3920,8 +3923,7 @@ btr_index_rec_validate(
n = dict_index_get_n_fields(index);
if (!page_is_comp(page)
&& UNIV_UNLIKELY(rec_get_n_fields_old(rec) != n)) {
if (!page_is_comp(page) && rec_get_n_fields_old(rec) != n) {
btr_index_rec_validate_report(page, rec, index);
fprintf(stderr, "InnoDB: has %lu fields, should have %lu\n",
(ulong) rec_get_n_fields_old(rec), (ulong) n);
@ -3972,14 +3974,14 @@ btr_index_rec_validate(
rec_print_new(stderr, rec, offsets);
putc('\n', stderr);
}
if (UNIV_LIKELY_NULL(heap)) {
if (heap) {
mem_heap_free(heap);
}
return(FALSE);
}
}
if (UNIV_LIKELY_NULL(heap)) {
if (heap) {
mem_heap_free(heap);
}
return(TRUE);
@ -4171,8 +4173,9 @@ loop:
right_block = btr_block_get(space, zip_size, right_page_no,
RW_X_LATCH, index, &mtr);
right_page = buf_block_get_frame(right_block);
if (UNIV_UNLIKELY(btr_page_get_prev(right_page, &mtr)
!= page_get_page_no(page))) {
if (btr_page_get_prev(right_page, &mtr)
!= page_get_page_no(page)) {
btr_validate_report2(index, level, block, right_block);
fputs("InnoDB: broken FIL_PAGE_NEXT"
" or FIL_PAGE_PREV links\n", stderr);
@ -4182,8 +4185,7 @@ loop:
ret = FALSE;
}
if (UNIV_UNLIKELY(page_is_comp(right_page)
!= page_is_comp(page))) {
if (page_is_comp(right_page) != page_is_comp(page)) {
btr_validate_report2(index, level, block, right_block);
fputs("InnoDB: 'compact' flag mismatch\n", stderr);
buf_page_print(page, 0, BUF_PAGE_PRINT_NO_CRASH);
@ -4201,9 +4203,8 @@ loop:
offsets, ULINT_UNDEFINED, &heap);
offsets2 = rec_get_offsets(right_rec, index,
offsets2, ULINT_UNDEFINED, &heap);
if (UNIV_UNLIKELY(cmp_rec_rec(rec, right_rec,
offsets, offsets2,
index) >= 0)) {
if (cmp_rec_rec(rec, right_rec, offsets, offsets2,
index) >= 0) {
btr_validate_report2(index, level, block, right_block);
@ -4250,10 +4251,9 @@ loop:
offsets = btr_page_get_father_node_ptr(offsets, heap,
&node_cur, &mtr);
if (UNIV_UNLIKELY(node_ptr != btr_cur_get_rec(&node_cur))
|| UNIV_UNLIKELY(btr_node_ptr_get_child_page_no(node_ptr,
offsets)
!= buf_block_get_page_no(block))) {
if (node_ptr != btr_cur_get_rec(&node_cur)
|| btr_node_ptr_get_child_page_no(node_ptr, offsets)
!= buf_block_get_page_no(block)) {
btr_validate_report1(index, level, block);
@ -4444,6 +4444,12 @@ btr_validate_index(
ulint i;
ulint n;
/* Full Text index are implemented by auxiliary tables,
not the B-tree */
if (index->type & DICT_FTS) {
return(TRUE);
}
mtr_start(&mtr);
mtr_x_lock(dict_index_get_lock(index), &mtr);

View file

@ -24,7 +24,7 @@ this program; if not, write to the Free Software Foundation, Inc.,
*****************************************************************************/
/**************************************************//**
@file btr/btr0cur.c
@file btr/btr0cur.cc
The index tree cursor
All changes that row operations make to a B-tree or the records
@ -129,7 +129,12 @@ can be released by page reorganize, then it is reorganized */
/** A BLOB field reference full of zero, for use in assertions and tests.
Initially, BLOB field references are set to zero, in
dtuple_convert_big_rec(). */
UNIV_INTERN const byte field_ref_zero[BTR_EXTERN_FIELD_REF_SIZE];
const byte field_ref_zero[BTR_EXTERN_FIELD_REF_SIZE] = {
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
};
#ifndef UNIV_HOTBACKUP
/*******************************************************************//**
@ -408,6 +413,7 @@ btr_cur_search_to_nth_level(
ut_ad(dict_index_check_search_tuple(index, tuple));
ut_ad(!dict_index_is_ibuf(index) || ibuf_inside(mtr));
ut_ad(dtuple_check_typed(tuple));
ut_ad(!(index->type & DICT_FTS));
ut_ad(index->page != FIL_NULL);
UNIV_MEM_INVALID(&cursor->up_match, sizeof cursor->up_match);
@ -930,7 +936,7 @@ btr_cur_open_at_index_side_func(
page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets);
}
if (UNIV_LIKELY_NULL(heap)) {
if (heap) {
mem_heap_free(heap);
}
}
@ -1101,29 +1107,27 @@ btr_cur_ins_lock_and_undo(
btr_cur_get_block(cursor),
index, thr, mtr, inherit);
if (err != DB_SUCCESS
|| !dict_index_is_clust(index) || dict_index_is_ibuf(index)) {
return(err);
}
err = trx_undo_report_row_operation(flags, TRX_UNDO_INSERT_OP,
thr, index, entry,
NULL, 0, NULL,
&roll_ptr);
if (err != DB_SUCCESS) {
return(err);
}
if (dict_index_is_clust(index) && !dict_index_is_ibuf(index)) {
/* Now we can fill in the roll ptr field in entry */
err = trx_undo_report_row_operation(flags, TRX_UNDO_INSERT_OP,
thr, index, entry,
NULL, 0, NULL,
&roll_ptr);
if (err != DB_SUCCESS) {
if (!(flags & BTR_KEEP_SYS_FLAG)) {
return(err);
}
/* Now we can fill in the roll ptr field in entry */
if (!(flags & BTR_KEEP_SYS_FLAG)) {
row_upd_index_entry_sys_field(entry, index,
DATA_ROLL_PTR, roll_ptr);
}
row_upd_index_entry_sys_field(entry, index,
DATA_ROLL_PTR, roll_ptr);
}
return(DB_SUCCESS);
@ -1140,8 +1144,7 @@ btr_cur_trx_report(
const dict_index_t* index, /*!< in: index */
const char* op) /*!< in: operation */
{
fprintf(stderr, "Trx with id " TRX_ID_FMT " going to ",
(ullint) trx->id);
fprintf(stderr, "Trx with id " TRX_ID_FMT " going to ", trx->id);
fputs(op, stderr);
dict_index_name_print(stderr, trx, index);
putc('\n', stderr);
@ -1238,7 +1241,7 @@ btr_cur_optimistic_insert(
rec_size = rec_get_converted_size(index, entry, n_ext);
}
if (UNIV_UNLIKELY(zip_size)) {
if (zip_size) {
/* Estimate the free space of an empty compressed page.
Subtract one byte for the encoded heap_no in the
modification log. */
@ -1346,7 +1349,7 @@ fail_err:
n_ext, mtr);
if (UNIV_UNLIKELY(!*rec)) {
if (UNIV_LIKELY(zip_size != 0)) {
if (zip_size != 0) {
goto fail;
}
@ -1498,7 +1501,7 @@ btr_cur_pessimistic_insert(
if (page_zip_rec_needs_ext(rec_get_converted_size(index, entry, n_ext),
dict_table_is_comp(index->table),
dict_index_get_n_fields(index),
dtuple_get_n_fields(entry),
zip_size)) {
/* The record is so big that we have to store some fields
externally on separate database pages */
@ -1923,8 +1926,8 @@ btr_cur_update_in_place(
trx, roll_ptr, mtr);
if (was_delete_marked
&& !rec_get_deleted_flag(rec, page_is_comp(
buf_block_get_frame(block)))) {
&& !rec_get_deleted_flag(
rec, page_is_comp(buf_block_get_frame(block)))) {
/* The new updated record owns its possible externally
stored fields */
@ -1975,7 +1978,6 @@ btr_cur_optimistic_update(
ulint old_rec_size;
dtuple_t* new_entry;
roll_ptr_t roll_ptr;
trx_t* trx;
mem_heap_t* heap;
ulint i;
ulint n_ext;
@ -1992,9 +1994,10 @@ btr_cur_optimistic_update(
heap = mem_heap_create(1024);
offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED, &heap);
#ifdef UNIV_BLOB_NULL_DEBUG
ut_a(!rec_offs_any_null_extern(rec, offsets));
#endif /* UNIV_BLOB_NULL_DEBUG */
#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
ut_a(!rec_offs_any_null_extern(rec, offsets)
|| trx_is_recv(thr_get_trx(thr)));
#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
#ifdef UNIV_DEBUG
if (btr_cur_print_record_ops && thr) {
@ -2117,13 +2120,11 @@ any_extern:
page_cur_move_to_prev(page_cursor);
trx = thr_get_trx(thr);
if (!(flags & BTR_KEEP_SYS_FLAG)) {
row_upd_index_entry_sys_field(new_entry, index, DATA_ROLL_PTR,
roll_ptr);
row_upd_index_entry_sys_field(new_entry, index, DATA_TRX_ID,
trx->id);
thr_get_trx(thr)->id);
}
/* There are no externally stored columns in new_entry */
@ -3463,8 +3464,6 @@ btr_estimate_n_rows_in_range(
n_rows = n_rows * 2;
}
DBUG_EXECUTE_IF("bug14007649", return(n_rows););
/* Do not estimate the number of rows in the range
to over 1 / 2 of the estimated rows in the whole
table */
@ -3574,7 +3573,8 @@ btr_record_not_null_field_in_rec(
/*******************************************************************//**
Estimates the number of different key values in a given index, for
each n-column prefix of the index where n <= dict_index_get_n_unique(index).
The estimates are stored in the array index->stat_n_diff_key_vals.
The estimates are stored in the array index->stat_n_diff_key_vals[] and
the number of pages that were sampled is saved in index->stat_n_sample_sizes[].
If innodb_stats_method is "nulls_ignored", we also record the number of
non-null values for each prefix and store the estimates in
array index->stat_n_non_null_key_vals. */
@ -3612,7 +3612,8 @@ btr_estimate_number_of_different_key_vals(
* (sizeof *offsets_rec
+ sizeof *offsets_next_rec));
n_diff = mem_heap_zalloc(heap, (n_cols + 1) * sizeof(ib_int64_t));
n_diff = (ib_int64_t*) mem_heap_zalloc(heap, (n_cols + 1)
* sizeof(ib_int64_t));
n_not_null = NULL;
@ -3621,7 +3622,7 @@ btr_estimate_number_of_different_key_vals(
considered equal (by setting stats_null_not_equal value) */
switch (srv_innodb_stats_method) {
case SRV_STATS_NULLS_IGNORED:
n_not_null = mem_heap_zalloc(heap, (n_cols + 1)
n_not_null = (ib_int64_t*) mem_heap_zalloc(heap, (n_cols + 1)
* sizeof *n_not_null);
/* fall through */
@ -3641,14 +3642,14 @@ btr_estimate_number_of_different_key_vals(
/* It makes no sense to test more pages than are contained
in the index, thus we lower the number if it is too high */
if (srv_stats_sample_pages > index->stat_index_size) {
if (srv_stats_transient_sample_pages > index->stat_index_size) {
if (index->stat_index_size > 0) {
n_sample_pages = index->stat_index_size;
} else {
n_sample_pages = 1;
}
} else {
n_sample_pages = srv_stats_sample_pages;
n_sample_pages = srv_stats_transient_sample_pages;
}
/* We sample some pages in the index to get an estimate */
@ -3762,7 +3763,7 @@ btr_estimate_number_of_different_key_vals(
index->stat_n_diff_key_vals[j]
= BTR_TABLE_STATS_FROM_SAMPLE(
n_diff[j], index, n_sample_pages,
total_external_size, not_empty_flag);
total_external_size, not_empty_flag);
/* If the tree is small, smaller than
10 * n_sample_pages + total_external_size, then
@ -3782,6 +3783,8 @@ btr_estimate_number_of_different_key_vals(
index->stat_n_diff_key_vals[j] += add_on;
index->stat_n_sample_sizes[j] = n_sample_pages;
/* Update the stat_n_non_null_key_vals[] with our
sampled result. stat_n_non_null_key_vals[] is created
and initialized to zero in dict_index_add_to_cache(),
@ -4040,10 +4043,11 @@ btr_push_update_extern_fields(
will have to be copied. */
ut_a(uf->orig_len > BTR_EXTERN_FIELD_REF_SIZE);
data = dfield_get_data(field);
data = (byte*) dfield_get_data(field);
len = dfield_get_len(field);
buf = mem_heap_alloc(heap, uf->orig_len);
buf = (byte*) mem_heap_alloc(heap,
uf->orig_len);
/* Copy the locally stored prefix. */
memcpy(buf, data,
uf->orig_len
@ -4107,7 +4111,6 @@ btr_blob_free(
mtr_commit(mtr);
buf_pool_mutex_enter(buf_pool);
mutex_enter(&block->mutex);
/* Only free the block if it is still allocated to
the same file page. */
@ -4127,7 +4130,6 @@ btr_blob_free(
}
buf_pool_mutex_exit(buf_pool);
mutex_exit(&block->mutex);
}
/*******************************************************************//**
@ -4217,10 +4219,11 @@ btr_store_big_rec_extern_fields(
* sizeof *freed_pages);
}
freed_pages = mem_heap_alloc(
heap,
btr_mtr->n_freed_pages
* sizeof *freed_pages);
freed_pages = static_cast<buf_block_t**>(
mem_heap_alloc(
heap,
btr_mtr->n_freed_pages
* sizeof *freed_pages));
n_freed_pages = 0;
}
@ -4286,7 +4289,8 @@ btr_store_big_rec_extern_fields(
int err = deflateReset(&c_stream);
ut_a(err == Z_OK);
c_stream.next_in = (void*) big_rec_vec->fields[i].data;
c_stream.next_in = (Bytef*)
big_rec_vec->fields[i].data;
c_stream.avail_in = extern_len;
}
@ -4636,8 +4640,7 @@ btr_check_blob_fil_page_type(
ulint flags = fil_space_get_flags(space_id);
#ifndef UNIV_DEBUG /* Improve debug test coverage */
if (UNIV_LIKELY
((flags & DICT_TF_FORMAT_MASK) == DICT_TF_FORMAT_51)) {
if (dict_tf_get_format(flags) == UNIV_FORMAT_A) {
/* Old versions of InnoDB did not initialize
FIL_PAGE_TYPE on BLOB pages. Do not print
anything about the type mismatch when reading
@ -4816,7 +4819,7 @@ btr_free_externally_stored_field(
btr_page_free_low(index, ext_block, 0, &mtr);
if (page_zip) {
if (page_zip != NULL) {
mach_write_to_4(field_ref + BTR_EXTERN_PAGE_NO,
next_page_no);
mach_write_to_4(field_ref + BTR_EXTERN_LEN + 4,
@ -5037,8 +5040,8 @@ btr_copy_zblob_prefix(
page_zip_set_alloc(&d_stream, heap);
ut_ad(ut_is_2pow(zip_size));
ut_ad(zip_size >= PAGE_ZIP_MIN_SIZE);
ut_ad(zip_size <= UNIV_PAGE_SIZE);
ut_ad(zip_size >= UNIV_ZIP_SIZE_MIN);
ut_ad(zip_size <= UNIV_ZIP_SIZE_MAX);
ut_ad(space_id);
err = inflateInit(&d_stream);
@ -5179,7 +5182,7 @@ btr_copy_externally_stored_field_prefix_low(
return(0);
}
if (UNIV_UNLIKELY(zip_size)) {
if (zip_size) {
return(btr_copy_zblob_prefix(buf, len, zip_size,
space_id, page_no, offset));
} else {
@ -5251,7 +5254,7 @@ btr_copy_externally_stored_field_prefix(
Copies an externally stored field of a record to mem heap. The
clustered index record must be protected by a lock or a page latch.
@return the whole field copied to heap */
static
UNIV_INTERN
byte*
btr_copy_externally_stored_field(
/*=============================*/
@ -5286,7 +5289,7 @@ btr_copy_externally_stored_field(
extern_len = mach_read_from_4(data + local_len + BTR_EXTERN_LEN + 4);
buf = mem_heap_alloc(heap, local_len + extern_len);
buf = (byte*) mem_heap_alloc(heap, local_len + extern_len);
memcpy(buf, data, local_len);
*len = local_len

View file

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved.
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 the Free Software
@ -11,13 +11,13 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
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
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
/**************************************************//**
@file btr/btr0pcur.c
@file btr/btr0pcur.cc
The index tree persistent cursor
Created 2/23/1996 Heikki Tuuri
@ -43,7 +43,7 @@ btr_pcur_create_for_mysql(void)
{
btr_pcur_t* pcur;
pcur = mem_alloc(sizeof(btr_pcur_t));
pcur = (btr_pcur_t*) mem_alloc(sizeof(btr_pcur_t));
pcur->btr_cur.index = NULL;
btr_pcur_init(pcur);
@ -133,8 +133,6 @@ btr_pcur_store_position(
ut_a(btr_page_get_next(page, mtr) == FIL_NULL);
ut_a(btr_page_get_prev(page, mtr) == FIL_NULL);
ut_ad(page_is_leaf(page));
ut_ad(page_get_page_no(page) == index->page);
cursor->old_stored = BTR_PCUR_OLD_STORED;
@ -191,7 +189,8 @@ btr_pcur_copy_stored_position(
if (pcur_donate->old_rec_buf) {
pcur_receive->old_rec_buf = mem_alloc(pcur_donate->buf_size);
pcur_receive->old_rec_buf = (byte*)
mem_alloc(pcur_donate->buf_size);
ut_memcpy(pcur_receive->old_rec_buf, pcur_donate->old_rec_buf,
pcur_donate->buf_size);
@ -327,19 +326,13 @@ btr_pcur_restore_position_func(
/* Save the old search mode of the cursor */
old_mode = cursor->search_mode;
switch (cursor->rel_pos) {
case BTR_PCUR_ON:
if (UNIV_LIKELY(cursor->rel_pos == BTR_PCUR_ON)) {
mode = PAGE_CUR_LE;
break;
case BTR_PCUR_AFTER:
} else if (cursor->rel_pos == BTR_PCUR_AFTER) {
mode = PAGE_CUR_G;
break;
case BTR_PCUR_BEFORE:
} else {
ut_ad(cursor->rel_pos == BTR_PCUR_BEFORE);
mode = PAGE_CUR_L;
break;
default:
ut_error;
mode = 0;
}
btr_pcur_open_with_no_init_func(index, tuple, mode, latch_mode,
@ -348,44 +341,25 @@ btr_pcur_restore_position_func(
/* Restore the old search mode */
cursor->search_mode = old_mode;
if (btr_pcur_is_on_user_rec(cursor)) {
switch (cursor->rel_pos) {
case BTR_PCUR_ON:
if (!cmp_dtuple_rec(
tuple, btr_pcur_get_rec(cursor),
rec_get_offsets(btr_pcur_get_rec(cursor),
index, NULL,
ULINT_UNDEFINED, &heap))) {
if (cursor->rel_pos == BTR_PCUR_ON
&& btr_pcur_is_on_user_rec(cursor)
&& 0 == cmp_dtuple_rec(tuple, btr_pcur_get_rec(cursor),
rec_get_offsets(
btr_pcur_get_rec(cursor), index,
NULL, ULINT_UNDEFINED, &heap))) {
/* We have to store the NEW value for
the modify clock, since the cursor can
now be on a different page! But we can
retain the value of old_rec */
/* We have to store the NEW value for the modify clock, since
the cursor can now be on a different page! But we can retain
the value of old_rec */
cursor->block_when_stored =
btr_pcur_get_block(cursor);
cursor->modify_clock =
buf_block_get_modify_clock(
cursor->block_when_stored);
cursor->old_stored = BTR_PCUR_OLD_STORED;
cursor->block_when_stored = btr_pcur_get_block(cursor);
cursor->modify_clock = buf_block_get_modify_clock(
cursor->block_when_stored);
cursor->old_stored = BTR_PCUR_OLD_STORED;
mem_heap_free(heap);
mem_heap_free(heap);
return(TRUE);
}
break;
case BTR_PCUR_BEFORE:
page_cur_move_to_next(btr_pcur_get_page_cur(cursor));
break;
case BTR_PCUR_AFTER:
page_cur_move_to_prev(btr_pcur_get_page_cur(cursor));
break;
#ifdef UNIV_DEBUG
default:
ut_error;
#endif /* UNIV_DEBUG */
}
return(TRUE);
}
mem_heap_free(heap);
@ -587,8 +561,8 @@ btr_pcur_open_on_user_rec_func(
ulint line, /*!< in: line where called */
mtr_t* mtr) /*!< in: mtr */
{
btr_pcur_open_func(index, tuple, mode, latch_mode, cursor,
file, line, mtr);
btr_pcur_open_low(index, 0, tuple, mode, latch_mode, cursor,
file, line, mtr);
if ((mode == PAGE_CUR_GE) || (mode == PAGE_CUR_G)) {

View file

@ -18,13 +18,13 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
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
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
/********************************************************************//**
@file btr/btr0sea.c
@file btr/btr0sea.cc
The index tree adaptive search
Created 2/17/1996 Heikki Tuuri
@ -42,16 +42,12 @@ Created 2/17/1996 Heikki Tuuri
#include "btr0pcur.h"
#include "btr0btr.h"
#include "ha0ha.h"
#include "srv0mon.h"
/** Flag: has the search system been enabled?
Protected by btr_search_latch. */
UNIV_INTERN char btr_search_enabled = TRUE;
#ifdef UNIV_PFS_MUTEX
/* Key to register btr_search_enabled_mutex with performance schema */
UNIV_INTERN mysql_pfs_key_t btr_search_enabled_mutex_key;
#endif /* UNIV_PFS_MUTEX */
/** A dummy variable to fool the compiler */
UNIV_INTERN ulint btr_search_this_is_zero = 0;
@ -172,14 +168,20 @@ btr_search_sys_create(
/* We allocate the search latch from dynamic memory:
see above at the global variable definition */
btr_search_latch_temp = mem_alloc(sizeof(rw_lock_t));
btr_search_latch_temp = (rw_lock_t*) mem_alloc(sizeof(rw_lock_t));
rw_lock_create(btr_search_latch_key, &btr_search_latch,
SYNC_SEARCH_SYS);
btr_search_sys = mem_alloc(sizeof(btr_search_sys_t));
btr_search_sys = (btr_search_sys_t*)
mem_alloc(sizeof(btr_search_sys_t));
btr_search_sys->hash_index = ha_create(hash_size, 0,
MEM_HEAP_FOR_BTR_SEARCH, 0);
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
btr_search_sys->hash_index->adaptive = TRUE;
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
btr_search_sys->hash_index = ha_create(hash_size, 0, 0);
}
/*****************************************************************//**
@ -198,6 +200,28 @@ btr_search_sys_free(void)
btr_search_sys = NULL;
}
/********************************************************************//**
Set index->ref_count = 0 on all indexes of a table. */
static
void
btr_search_disable_ref_count(
/*=========================*/
dict_table_t* table) /*!< in/out: table */
{
dict_index_t* index;
ut_ad(mutex_own(&dict_sys->mutex));
#ifdef UNIV_SYNC_DEBUG
ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
for (index = dict_table_get_first_index(table); index;
index = dict_table_get_next_index(index)) {
index->search_info->ref_count = 0;
}
}
/********************************************************************//**
Disable the adaptive hash search system and empty the index. */
UNIV_INTERN
@ -217,13 +241,13 @@ btr_search_disable(void)
for (table = UT_LIST_GET_FIRST(dict_sys->table_LRU); table;
table = UT_LIST_GET_NEXT(table_LRU, table)) {
dict_index_t* index;
btr_search_disable_ref_count(table);
}
for (index = dict_table_get_first_index(table); index;
index = dict_table_get_next_index(index)) {
for (table = UT_LIST_GET_FIRST(dict_sys->table_non_LRU); table;
table = UT_LIST_GET_NEXT(table_LRU, table)) {
index->search_info->ref_count = 0;
}
btr_search_disable_ref_count(table);
}
mutex_exit(&dict_sys->mutex);
@ -263,7 +287,7 @@ btr_search_info_create(
{
btr_search_t* info;
info = mem_heap_alloc(heap, sizeof(btr_search_t));
info = (btr_search_t*) mem_heap_alloc(heap, sizeof(btr_search_t));
#ifdef UNIV_DEBUG
info->magic_n = BTR_SEARCH_MAGIC_N;
@ -585,6 +609,8 @@ btr_search_update_hash_ref(
ha_insert_for_fold(btr_search_sys->hash_index, fold,
block, rec);
MONITOR_INC(MONITOR_ADAPTIVE_HASH_ROW_ADDED);
}
}
@ -646,7 +672,7 @@ btr_search_info_update_slow(
inside the called function. It might be that the compiler
would optimize the call just to pass pointers to block. */
params = mem_alloc(3 * sizeof(ulint));
params = (ulint*) mem_alloc(3 * sizeof(ulint));
params[0] = block->n_fields;
params[1] = block->n_bytes;
params[2] = block->left_side;
@ -889,7 +915,7 @@ btr_search_guess_on_hash(
ut_ad(rw_lock_get_writer(&btr_search_latch) != RW_LOCK_EX);
ut_ad(rw_lock_get_reader_count(&btr_search_latch) > 0);
rec = ha_search_and_get_data(btr_search_sys->hash_index, fold);
rec = (rec_t*) ha_search_and_get_data(btr_search_sys->hash_index, fold);
if (UNIV_UNLIKELY(!rec)) {
goto failure_unlock;
@ -1030,7 +1056,11 @@ btr_search_drop_page_hash_index(
buf_block_t* block) /*!< in: block containing index page,
s- or x-latched, or an index page
for which we know that
block->buf_fix_count == 0 */
block->buf_fix_count == 0 or it is an
index page which has already been
removed from the buf_pool->page_hash
i.e.: it is in state
BUF_BLOCK_REMOVE_HASH */
{
hash_table_t* table;
ulint n_fields;
@ -1053,6 +1083,13 @@ btr_search_drop_page_hash_index(
ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
/* Do a dirty check on block->index, return if the block is
not in the adaptive hash index. This is to avoid acquiring
shared btr_search_latch for performance consideration. */
if (!block->index) {
return;
}
retry:
rw_lock_s_lock(&btr_search_latch);
index = block->index;
@ -1070,7 +1107,8 @@ retry:
#ifdef UNIV_SYNC_DEBUG
ut_ad(rw_lock_own(&(block->lock), RW_LOCK_SHARED)
|| rw_lock_own(&(block->lock), RW_LOCK_EX)
|| (block->page.buf_fix_count == 0));
|| block->page.buf_fix_count == 0
|| buf_block_get_state(block) == BUF_BLOCK_REMOVE_HASH);
#endif /* UNIV_SYNC_DEBUG */
n_fields = block->curr_n_fields;
@ -1090,7 +1128,7 @@ retry:
/* Calculate and cache fold values into an array for fast deletion
from the hash index */
folds = mem_alloc(n_recs * sizeof(ulint));
folds = (ulint*) mem_alloc(n_recs * sizeof(ulint));
n_cached = 0;
@ -1163,6 +1201,9 @@ next_rec:
block->index = NULL;
MONITOR_INC(MONITOR_ADAPTIVE_HASH_PAGE_REMOVED);
MONITOR_INC_VALUE(MONITOR_ADAPTIVE_HASH_ROW_REMOVED, n_cached);
cleanup:
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
if (UNIV_UNLIKELY(block->n_pointers)) {
@ -1309,8 +1350,8 @@ btr_search_build_page_hash_index(
/* Calculate and cache fold values and corresponding records into
an array for fast insertion to the hash index */
folds = mem_alloc(n_recs * sizeof(ulint));
recs = mem_alloc(n_recs * sizeof(rec_t*));
folds = (ulint*) mem_alloc(n_recs * sizeof(ulint));
recs = (rec_t**) mem_alloc(n_recs * sizeof(rec_t*));
n_cached = 0;
@ -1412,6 +1453,8 @@ btr_search_build_page_hash_index(
ha_insert_for_fold(table, folds[i], block, recs[i]);
}
MONITOR_INC(MONITOR_ADAPTIVE_HASH_PAGE_ADDED);
MONITOR_INC_VALUE(MONITOR_ADAPTIVE_HASH_ROW_ADDED, n_cached);
exit_func:
rw_lock_x_unlock(&btr_search_latch);
@ -1541,7 +1584,12 @@ btr_search_update_hash_on_delete(
if (block->index) {
ut_a(block->index == index);
ha_search_and_delete_if_found(table, fold, rec);
if (ha_search_and_delete_if_found(table, fold, rec)) {
MONITOR_INC(MONITOR_ADAPTIVE_HASH_ROW_REMOVED);
} else {
MONITOR_INC(
MONITOR_ADAPTIVE_HASH_ROW_REMOVE_NOT_FOUND);
}
}
rw_lock_x_unlock(&btr_search_latch);
@ -1597,8 +1645,11 @@ btr_search_update_hash_node_on_insert(
table = btr_search_sys->hash_index;
ha_search_and_update_if_found(table, cursor->fold, rec,
block, page_rec_get_next(rec));
if (ha_search_and_update_if_found(
table, cursor->fold, rec, block,
page_rec_get_next(rec))) {
MONITOR_INC(MONITOR_ADAPTIVE_HASH_ROW_UPDATED);
}
func_exit:
rw_lock_x_unlock(&btr_search_latch);
@ -1623,9 +1674,9 @@ btr_search_update_hash_on_insert(
hash_table_t* table;
buf_block_t* block;
dict_index_t* index;
rec_t* rec;
rec_t* ins_rec;
rec_t* next_rec;
const rec_t* rec;
const rec_t* ins_rec;
const rec_t* next_rec;
ulint fold;
ulint ins_fold;
ulint next_fold = 0; /* remove warning (??? bug ???) */
@ -1638,12 +1689,6 @@ btr_search_update_hash_on_insert(
ulint* offsets = offsets_;
rec_offs_init(offsets_);
table = btr_search_sys->hash_index;
btr_search_check_free_space_in_heap();
rec = btr_cur_get_rec(cursor);
block = btr_cur_get_block(cursor);
#ifdef UNIV_SYNC_DEBUG
@ -1657,6 +1702,12 @@ btr_search_update_hash_on_insert(
return;
}
btr_search_check_free_space_in_heap();
table = btr_search_sys->hash_index;
rec = btr_cur_get_rec(cursor);
ut_a(index == cursor->index);
ut_a(!dict_index_is_ibuf(index));
@ -1664,8 +1715,8 @@ btr_search_update_hash_on_insert(
n_bytes = block->curr_n_bytes;
left_side = block->curr_left_side;
ins_rec = page_rec_get_next(rec);
next_rec = page_rec_get_next(ins_rec);
ins_rec = page_rec_get_next_const(rec);
next_rec = page_rec_get_next_const(ins_rec);
offsets = rec_get_offsets(ins_rec, index, offsets,
ULINT_UNDEFINED, &heap);
@ -1815,11 +1866,12 @@ btr_search_validate(void)
buf_pool_mutex_enter_all();
}
node = hash_get_nth_cell(btr_search_sys->hash_index, i)->node;
node = (ha_node_t*)
hash_get_nth_cell(btr_search_sys->hash_index, i)->node;
for (; node != NULL; node = node->next) {
const buf_block_t* block
= buf_block_align(node->data);
= buf_block_align((byte*) node->data);
const buf_block_t* hash_block;
buf_pool_t* buf_pool;
index_id_t page_index_id;

View file

@ -11,13 +11,13 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
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
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
/**************************************************//**
@file buf/buf0buddy.c
@file buf/buf0buddy.cc
Binary buddy allocator for compressed pages
Created December 2006 by Marko Makela
@ -46,7 +46,9 @@ buf_buddy_get(
{
ut_ad(ut_is_2pow(size));
ut_ad(size >= BUF_BUDDY_LOW);
ut_ad(BUF_BUDDY_LOW <= UNIV_ZIP_SIZE_MIN);
ut_ad(size < BUF_BUDDY_HIGH);
ut_ad(BUF_BUDDY_HIGH == UNIV_PAGE_SIZE);
ut_ad(!ut_align_offset(page, size));
if (((ulint) page) & size) {
@ -57,12 +59,15 @@ buf_buddy_get(
}
/** Validate a given zip_free list. */
#define BUF_BUDDY_LIST_VALIDATE(b, i) \
UT_LIST_VALIDATE(list, buf_page_t, \
b->zip_free[i], \
ut_ad(buf_page_get_state( \
ut_list_node_313) \
== BUF_BLOCK_ZIP_FREE))
struct CheckZipFree {
void operator()(const buf_page_t* elem) const
{
ut_a(buf_page_get_state(elem) == BUF_BLOCK_ZIP_FREE);
}
};
#define BUF_BUDDY_LIST_VALIDATE(bp, i) \
UT_LIST_VALIDATE(list, buf_page_t, bp->zip_free[i], CheckZipFree())
/**********************************************************************//**
Add a block to the head of the appropriate buddy free list. */
@ -119,7 +124,7 @@ buf_buddy_alloc_zip(
ut_ad(buf_pool_mutex_own(buf_pool));
ut_a(i < BUF_BUDDY_SIZES);
ut_a(i >= buf_buddy_get_slot(PAGE_ZIP_MIN_SIZE));
ut_a(i >= buf_buddy_get_slot(UNIV_ZIP_SIZE_MIN));
ut_d(BUF_BUDDY_LIST_VALIDATE(buf_pool, i));
@ -131,7 +136,7 @@ buf_buddy_alloc_zip(
buf_buddy_remove_from_free(buf_pool, bpage, i);
} else if (i + 1 < BUF_BUDDY_SIZES) {
/* Attempt to split. */
bpage = buf_buddy_alloc_zip(buf_pool, i + 1);
bpage = (buf_page_t*) buf_buddy_alloc_zip(buf_pool, i + 1);
if (bpage) {
buf_page_t* buddy = (buf_page_t*)
@ -235,7 +240,7 @@ buf_buddy_alloc_from(
{
ulint offs = BUF_BUDDY_LOW << j;
ut_ad(j <= BUF_BUDDY_SIZES);
ut_ad(i >= buf_buddy_get_slot(PAGE_ZIP_MIN_SIZE));
ut_ad(i >= buf_buddy_get_slot(UNIV_ZIP_SIZE_MIN));
ut_ad(j >= i);
ut_ad(!ut_align_offset(buf, offs));
@ -279,11 +284,11 @@ buf_buddy_alloc_low(
ut_ad(lru);
ut_ad(buf_pool_mutex_own(buf_pool));
ut_ad(!mutex_own(&buf_pool->zip_mutex));
ut_ad(i >= buf_buddy_get_slot(PAGE_ZIP_MIN_SIZE));
ut_ad(i >= buf_buddy_get_slot(UNIV_ZIP_SIZE_MIN));
if (i < BUF_BUDDY_SIZES) {
/* Try to allocate from the buddy system. */
block = buf_buddy_alloc_zip(buf_pool, i);
block = (buf_block_t*) buf_buddy_alloc_zip(buf_pool, i);
if (block) {
goto func_exit;
@ -307,7 +312,7 @@ buf_buddy_alloc_low(
alloc_big:
buf_buddy_block_register(block);
block = buf_buddy_alloc_from(
block = (buf_block_t*) buf_buddy_alloc_from(
buf_pool, block->frame, i, BUF_BUDDY_SIZES);
func_exit:
@ -338,7 +343,7 @@ buf_buddy_relocate(
ut_ad(!mutex_own(&buf_pool->zip_mutex));
ut_ad(!ut_align_offset(src, size));
ut_ad(!ut_align_offset(dst, size));
ut_ad(i >= buf_buddy_get_slot(PAGE_ZIP_MIN_SIZE));
ut_ad(i >= buf_buddy_get_slot(UNIV_ZIP_SIZE_MIN));
UNIV_MEM_ASSERT_W(dst, size);
/* We assume that all memory from buf_buddy_alloc()
@ -358,9 +363,9 @@ buf_buddy_relocate(
pool), so there is nothing wrong about this. The
mach_read_from_4() calls here will only trigger bogus
Valgrind memcheck warnings in UNIV_DEBUG_VALGRIND builds. */
space = mach_read_from_4((const byte *) src
space = mach_read_from_4((const byte*) src
+ FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
page_no = mach_read_from_4((const byte *) src
page_no = mach_read_from_4((const byte*) src
+ FIL_PAGE_OFFSET);
/* Suppress Valgrind warnings about conditional jump
on uninitialized value. */
@ -399,7 +404,7 @@ buf_buddy_relocate(
ullint usec = ut_time_us(NULL);
ut_a(bpage->zip.data == src);
memcpy(dst, src, size);
bpage->zip.data = dst;
bpage->zip.data = (page_zip_t*) dst;
mutex_exit(mutex);
UNIV_MEM_INVALID(src, size);
{
@ -434,7 +439,7 @@ buf_buddy_free_low(
ut_ad(buf_pool_mutex_own(buf_pool));
ut_ad(!mutex_own(&buf_pool->zip_mutex));
ut_ad(i <= BUF_BUDDY_SIZES);
ut_ad(i >= buf_buddy_get_slot(PAGE_ZIP_MIN_SIZE));
ut_ad(i >= buf_buddy_get_slot(UNIV_ZIP_SIZE_MIN));
ut_ad(buf_pool->buddy_stat[i].used > 0);
buf_pool->buddy_stat[i].used--;
@ -521,7 +526,7 @@ buddy_nonfree:
func_exit:
/* Free the block to the buddy list. */
bpage = buf;
bpage = (buf_page_t*) buf;
/* Fill large blocks with a constant pattern. */
ut_d(memset(bpage, i, BUF_BUDDY_LOW << i));

View file

@ -0,0 +1,155 @@
/*****************************************************************************
Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
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 the Free Software
Foundation; version 2 of the License.
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.
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.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
/**************************************************//**
@file buf/buf0checksum.cc
Buffer pool checksum functions, also linked from /extra/innochecksum.cc
Created Aug 11, 2011 Vasil Dimov
*******************************************************/
#include "univ.i"
#include "fil0fil.h" /* FIL_* */
#include "ut0crc32.h" /* ut_crc32() */
#include "ut0rnd.h" /* ut_fold_binary() */
#ifndef UNIV_INNOCHECKSUM
#include "srv0srv.h" /* SRV_CHECKSUM_* */
#include "buf0types.h"
/** the macro MYSQL_SYSVAR_ENUM() requires "long unsigned int" and if we
use srv_checksum_algorithm_t here then we get a compiler error:
ha_innodb.cc:12251: error: cannot convert 'srv_checksum_algorithm_t*' to
'long unsigned int*' in initialization */
UNIV_INTERN ulong srv_checksum_algorithm = SRV_CHECKSUM_ALGORITHM_INNODB;
#endif /* !UNIV_INNOCHECKSUM */
/********************************************************************//**
Calculates a page CRC32 which is stored to the page when it is written
to a file. Note that we must be careful to calculate the same value on
32-bit and 64-bit architectures.
@return checksum */
UNIV_INTERN
ib_uint32_t
buf_calc_page_crc32(
/*================*/
const byte* page) /*!< in: buffer page */
{
ib_uint32_t checksum;
/* Since the field FIL_PAGE_FILE_FLUSH_LSN, and in versions <= 4.1.x
FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, are written outside the buffer pool
to the first pages of data files, we have to skip them in the page
checksum calculation.
We must also skip the field FIL_PAGE_SPACE_OR_CHKSUM where the
checksum is stored, and also the last 8 bytes of page because
there we store the old formula checksum. */
checksum = ut_crc32(page + FIL_PAGE_OFFSET,
FIL_PAGE_FILE_FLUSH_LSN - FIL_PAGE_OFFSET)
^ ut_crc32(page + FIL_PAGE_DATA,
UNIV_PAGE_SIZE - FIL_PAGE_DATA
- FIL_PAGE_END_LSN_OLD_CHKSUM);
return(checksum);
}
/********************************************************************//**
Calculates a page checksum which is stored to the page when it is written
to a file. Note that we must be careful to calculate the same value on
32-bit and 64-bit architectures.
@return checksum */
UNIV_INTERN
ulint
buf_calc_page_new_checksum(
/*=======================*/
const byte* page) /*!< in: buffer page */
{
ulint checksum;
/* Since the field FIL_PAGE_FILE_FLUSH_LSN, and in versions <= 4.1.x
FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, are written outside the buffer pool
to the first pages of data files, we have to skip them in the page
checksum calculation.
We must also skip the field FIL_PAGE_SPACE_OR_CHKSUM where the
checksum is stored, and also the last 8 bytes of page because
there we store the old formula checksum. */
checksum = ut_fold_binary(page + FIL_PAGE_OFFSET,
FIL_PAGE_FILE_FLUSH_LSN - FIL_PAGE_OFFSET)
+ ut_fold_binary(page + FIL_PAGE_DATA,
UNIV_PAGE_SIZE - FIL_PAGE_DATA
- FIL_PAGE_END_LSN_OLD_CHKSUM);
checksum = checksum & 0xFFFFFFFFUL;
return(checksum);
}
/********************************************************************//**
In versions < 4.0.14 and < 4.1.1 there was a bug that the checksum only
looked at the first few bytes of the page. This calculates that old
checksum.
NOTE: we must first store the new formula checksum to
FIL_PAGE_SPACE_OR_CHKSUM before calculating and storing this old checksum
because this takes that field as an input!
@return checksum */
UNIV_INTERN
ulint
buf_calc_page_old_checksum(
/*=======================*/
const byte* page) /*!< in: buffer page */
{
ulint checksum;
checksum = ut_fold_binary(page, FIL_PAGE_FILE_FLUSH_LSN);
checksum = checksum & 0xFFFFFFFFUL;
return(checksum);
}
#ifndef UNIV_INNOCHECKSUM
/********************************************************************//**
Return a printable string describing the checksum algorithm.
@return algorithm name */
UNIV_INTERN
const char*
buf_checksum_algorithm_name(
/*========================*/
srv_checksum_algorithm_t algo) /*!< in: algorithm */
{
switch (algo) {
case SRV_CHECKSUM_ALGORITHM_CRC32:
case SRV_CHECKSUM_ALGORITHM_STRICT_CRC32:
return("crc32");
case SRV_CHECKSUM_ALGORITHM_INNODB:
case SRV_CHECKSUM_ALGORITHM_STRICT_INNODB:
return("innodb");
case SRV_CHECKSUM_ALGORITHM_NONE:
case SRV_CHECKSUM_ALGORITHM_STRICT_NONE:
return("none");
}
ut_error;
return(NULL);
}
#endif /* !UNIV_INNOCHECKSUM */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,620 @@
/*****************************************************************************
Copyright (c) 2011, 2011, Oracle and/or its affiliates. All Rights Reserved.
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 the Free Software
Foundation; version 2 of the License.
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.
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.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
/**************************************************//**
@file buf/buf0dump.cc
Implements a buffer pool dump/load.
Created April 08, 2011 Vasil Dimov
*******************************************************/
#include <stdarg.h> /* va_* */
#include <string.h> /* strerror() */
#include "univ.i"
#include "buf0buf.h" /* buf_pool_mutex_enter(), srv_buf_pool_instances */
#include "buf0dump.h"
#include "db0err.h" /* enum db_err */
#include "dict0dict.h" /* dict_operation_lock */
#include "os0file.h" /* OS_FILE_MAX_PATH */
#include "os0sync.h" /* os_event* */
#include "os0thread.h" /* os_thread_* */
#include "srv0srv.h" /* srv_fast_shutdown, srv_buf_dump* */
#include "srv0start.h" /* srv_shutdown_state */
#include "sync0rw.h" /* rw_lock_s_lock() */
#include "ut0byte.h" /* ut_ull_create() */
#include "ut0sort.h" /* UT_SORT_FUNCTION_BODY */
#include "buf0rea.h" /* buf_read_page_async() */
enum status_severity {
STATUS_INFO,
STATUS_NOTICE,
STATUS_ERR
};
#define SHUTTING_DOWN() (UNIV_UNLIKELY(srv_shutdown_state \
!= SRV_SHUTDOWN_NONE))
/* Flags that tell the buffer pool dump/load thread which action should it
take after being waked up. */
static ibool buf_dump_should_start = FALSE;
static ibool buf_load_should_start = FALSE;
static ibool buf_load_abort_flag = FALSE;
/* Used to temporary store dump info in order to avoid IO while holding
buffer pool mutex during dump and also to sort the contents of the dump
before reading the pages from disk during load.
We store the space id in the high 32 bits and page no in low 32 bits. */
typedef ib_uint64_t buf_dump_t;
/* Aux macros to create buf_dump_t and to extract space and page from it */
#define BUF_DUMP_CREATE(space, page) ut_ull_create(space, page)
#define BUF_DUMP_SPACE(a) ((ulint) ((a) >> 32))
#define BUF_DUMP_PAGE(a) ((ulint) ((a) & 0xFFFFFFFFUL))
/*****************************************************************//**
Wakes up the buffer pool dump/load thread and instructs it to start
a dump. This function is called by MySQL code via buffer_pool_dump_now()
and it should return immediately because the whole MySQL is frozen during
its execution. */
UNIV_INTERN
void
buf_dump_start()
/*============*/
{
buf_dump_should_start = TRUE;
os_event_set(srv_buf_dump_event);
}
/*****************************************************************//**
Wakes up the buffer pool dump/load thread and instructs it to start
a load. This function is called by MySQL code via buffer_pool_load_now()
and it should return immediately because the whole MySQL is frozen during
its execution. */
UNIV_INTERN
void
buf_load_start()
/*============*/
{
buf_load_should_start = TRUE;
os_event_set(srv_buf_dump_event);
}
/*****************************************************************//**
Sets the global variable that feeds MySQL's innodb_buffer_pool_dump_status
to the specified string. The format and the following parameters are the
same as the ones used for printf(3). The value of this variable can be
retrieved by:
SELECT variable_value FROM information_schema.global_status WHERE
variable_name = 'INNODB_BUFFER_POOL_DUMP_STATUS';
or by:
SHOW STATUS LIKE 'innodb_buffer_pool_dump_status'; */
static __attribute__((nonnull, format(printf, 2, 3)))
void
buf_dump_status(
/*============*/
enum status_severity severity,/*!< in: status severity */
const char* fmt, /*!< in: format */
...) /*!< in: extra parameters according
to fmt */
{
va_list ap;
va_start(ap, fmt);
ut_vsnprintf(
export_vars.innodb_buffer_pool_dump_status,
sizeof(export_vars.innodb_buffer_pool_dump_status),
fmt, ap);
if (severity == STATUS_NOTICE || severity == STATUS_ERR) {
ut_print_timestamp(stderr);
fprintf(stderr, " InnoDB: %s\n",
export_vars.innodb_buffer_pool_dump_status);
}
va_end(ap);
}
/*****************************************************************//**
Sets the global variable that feeds MySQL's innodb_buffer_pool_load_status
to the specified string. The format and the following parameters are the
same as the ones used for printf(3). The value of this variable can be
retrieved by:
SELECT variable_value FROM information_schema.global_status WHERE
variable_name = 'INNODB_BUFFER_POOL_LOAD_STATUS';
or by:
SHOW STATUS LIKE 'innodb_buffer_pool_load_status'; */
static __attribute__((nonnull, format(printf, 2, 3)))
void
buf_load_status(
/*============*/
enum status_severity severity,/*!< in: status severity */
const char* fmt, /*!< in: format */
...) /*!< in: extra parameters according to fmt */
{
va_list ap;
va_start(ap, fmt);
ut_vsnprintf(
export_vars.innodb_buffer_pool_load_status,
sizeof(export_vars.innodb_buffer_pool_load_status),
fmt, ap);
if (severity == STATUS_NOTICE || severity == STATUS_ERR) {
ut_print_timestamp(stderr);
fprintf(stderr, " InnoDB: %s\n",
export_vars.innodb_buffer_pool_load_status);
}
va_end(ap);
}
/*****************************************************************//**
Perform a buffer pool dump into the file specified by
innodb_buffer_pool_filename. If any errors occur then the value of
innodb_buffer_pool_dump_status will be set accordingly, see buf_dump_status().
The dump filename can be specified by (relative to srv_data_home):
SET GLOBAL innodb_buffer_pool_filename='filename'; */
static
void
buf_dump(
/*=====*/
ibool obey_shutdown) /*!< in: quit if we are in a shutting down
state */
{
#define SHOULD_QUIT() (SHUTTING_DOWN() && obey_shutdown)
char full_filename[OS_FILE_MAX_PATH];
char tmp_filename[OS_FILE_MAX_PATH];
char now[32];
FILE* f;
ulint i;
int ret;
ut_snprintf(full_filename, sizeof(full_filename),
"%s%c%s", srv_data_home, SRV_PATH_SEPARATOR,
srv_buf_dump_filename);
ut_snprintf(tmp_filename, sizeof(tmp_filename),
"%s.incomplete", full_filename);
buf_dump_status(STATUS_NOTICE, "Dumping buffer pool(s) to %s",
full_filename);
f = fopen(tmp_filename, "w");
if (f == NULL) {
buf_dump_status(STATUS_ERR,
"Cannot open '%s' for writing: %s",
tmp_filename, strerror(errno));
return;
}
/* else */
/* walk through each buffer pool */
for (i = 0; i < srv_buf_pool_instances && !SHOULD_QUIT(); i++) {
buf_pool_t* buf_pool;
const buf_page_t* bpage;
buf_dump_t* dump;
ulint n_pages;
ulint j;
buf_pool = buf_pool_from_array(i);
/* obtain buf_pool mutex before allocate, since
UT_LIST_GET_LEN(buf_pool->LRU) could change */
buf_pool_mutex_enter(buf_pool);
n_pages = UT_LIST_GET_LEN(buf_pool->LRU);
/* skip empty buffer pools */
if (n_pages == 0) {
buf_pool_mutex_exit(buf_pool);
continue;
}
dump = static_cast<buf_dump_t*>(
ut_malloc(n_pages * sizeof(*dump))) ;
if (dump == NULL) {
buf_pool_mutex_exit(buf_pool);
fclose(f);
buf_dump_status(STATUS_ERR,
"Cannot allocate " ULINTPF " bytes: %s",
(ulint) (n_pages * sizeof(*dump)),
strerror(errno));
/* leave tmp_filename to exist */
return;
}
for (bpage = UT_LIST_GET_LAST(buf_pool->LRU), j = 0;
bpage != NULL;
bpage = UT_LIST_GET_PREV(LRU, bpage), j++) {
ut_a(buf_page_in_file(bpage));
dump[j] = BUF_DUMP_CREATE(buf_page_get_space(bpage),
buf_page_get_page_no(bpage));
}
ut_a(j == n_pages);
buf_pool_mutex_exit(buf_pool);
for (j = 0; j < n_pages && !SHOULD_QUIT(); j++) {
ret = fprintf(f, ULINTPF "," ULINTPF "\n",
BUF_DUMP_SPACE(dump[j]),
BUF_DUMP_PAGE(dump[j]));
if (ret < 0) {
ut_free(dump);
fclose(f);
buf_dump_status(STATUS_ERR,
"Cannot write to '%s': %s",
tmp_filename, strerror(errno));
/* leave tmp_filename to exist */
return;
}
if (j % 128 == 0) {
buf_dump_status(
STATUS_INFO,
"Dumping buffer pool "
ULINTPF "/" ULINTPF ", "
"page " ULINTPF "/" ULINTPF,
i + 1, srv_buf_pool_instances,
j + 1, n_pages);
}
}
ut_free(dump);
}
ret = fclose(f);
if (ret != 0) {
buf_dump_status(STATUS_ERR,
"Cannot close '%s': %s",
tmp_filename, strerror(errno));
return;
}
/* else */
ret = unlink(full_filename);
if (ret != 0 && errno != ENOENT) {
buf_dump_status(STATUS_ERR,
"Cannot delete '%s': %s",
full_filename, strerror(errno));
/* leave tmp_filename to exist */
return;
}
/* else */
ret = rename(tmp_filename, full_filename);
if (ret != 0) {
buf_dump_status(STATUS_ERR,
"Cannot rename '%s' to '%s': %s",
tmp_filename, full_filename,
strerror(errno));
/* leave tmp_filename to exist */
return;
}
/* else */
/* success */
ut_sprintf_timestamp(now);
buf_dump_status(STATUS_NOTICE,
"Buffer pool(s) dump completed at %s", now);
}
/*****************************************************************//**
Compare two buffer pool dump entries, used to sort the dump on
space_no,page_no before loading in order to increase the chance for
sequential IO.
@return -1/0/1 if entry 1 is smaller/equal/bigger than entry 2 */
static
lint
buf_dump_cmp(
/*=========*/
const buf_dump_t d1, /*!< in: buffer pool dump entry 1 */
const buf_dump_t d2) /*!< in: buffer pool dump entry 2 */
{
if (d1 < d2) {
return(-1);
} else if (d1 == d2) {
return(0);
} else {
return(1);
}
}
/*****************************************************************//**
Sort a buffer pool dump on space_no, page_no. */
static
void
buf_dump_sort(
/*==========*/
buf_dump_t* dump, /*!< in/out: buffer pool dump to sort */
buf_dump_t* tmp, /*!< in/out: temp storage */
ulint low, /*!< in: lowest index (inclusive) */
ulint high) /*!< in: highest index (non-inclusive) */
{
UT_SORT_FUNCTION_BODY(buf_dump_sort, dump, tmp, low, high,
buf_dump_cmp);
}
/*****************************************************************//**
Perform a buffer pool load from the file specified by
innodb_buffer_pool_filename. If any errors occur then the value of
innodb_buffer_pool_load_status will be set accordingly, see buf_load_status().
The dump filename can be specified by (relative to srv_data_home):
SET GLOBAL innodb_buffer_pool_filename='filename'; */
static
void
buf_load()
/*======*/
{
char full_filename[OS_FILE_MAX_PATH];
char now[32];
FILE* f;
buf_dump_t* dump;
buf_dump_t* dump_tmp;
ulint dump_n;
ulint total_buffer_pools_pages;
ulint i;
ulint space_id;
ulint page_no;
int fscanf_ret;
/* Ignore any leftovers from before */
buf_load_abort_flag = FALSE;
ut_snprintf(full_filename, sizeof(full_filename),
"%s%c%s", srv_data_home, SRV_PATH_SEPARATOR,
srv_buf_dump_filename);
buf_load_status(STATUS_NOTICE,
"Loading buffer pool(s) from %s", full_filename);
f = fopen(full_filename, "r");
if (f == NULL) {
buf_load_status(STATUS_ERR,
"Cannot open '%s' for reading: %s",
full_filename, strerror(errno));
return;
}
/* else */
/* First scan the file to estimate how many entries are in it.
This file is tiny (approx 500KB per 1GB buffer pool), reading it
two times is fine. */
dump_n = 0;
while (fscanf(f, ULINTPF "," ULINTPF, &space_id, &page_no) == 2
&& !SHUTTING_DOWN()) {
dump_n++;
}
if (!SHUTTING_DOWN() && !feof(f)) {
/* fscanf() returned != 2 */
const char* what;
if (ferror(f)) {
what = "reading";
} else {
what = "parsing";
}
fclose(f);
buf_load_status(STATUS_ERR, "Error %s '%s', "
"unable to load buffer pool (stage 1)",
what, full_filename);
return;
}
/* If dump is larger than the buffer pool(s), then we ignore the
extra trailing. This could happen if a dump is made, then buffer
pool is shrunk and then load it attempted. */
total_buffer_pools_pages = buf_pool_get_n_pages()
* srv_buf_pool_instances;
if (dump_n > total_buffer_pools_pages) {
dump_n = total_buffer_pools_pages;
}
dump = static_cast<buf_dump_t*>(ut_malloc(dump_n * sizeof(*dump)));
if (dump == NULL) {
fclose(f);
buf_load_status(STATUS_ERR,
"Cannot allocate " ULINTPF " bytes: %s",
(ulint) (dump_n * sizeof(*dump)),
strerror(errno));
return;
}
dump_tmp = static_cast<buf_dump_t*>(
ut_malloc(dump_n * sizeof(*dump_tmp)));
if (dump_tmp == NULL) {
ut_free(dump);
fclose(f);
buf_load_status(STATUS_ERR,
"Cannot allocate " ULINTPF " bytes: %s",
(ulint) (dump_n * sizeof(*dump_tmp)),
strerror(errno));
return;
}
rewind(f);
for (i = 0; i < dump_n && !SHUTTING_DOWN(); i++) {
fscanf_ret = fscanf(f, ULINTPF "," ULINTPF,
&space_id, &page_no);
if (fscanf_ret != 2) {
if (feof(f)) {
break;
}
/* else */
ut_free(dump);
ut_free(dump_tmp);
fclose(f);
buf_load_status(STATUS_ERR,
"Error parsing '%s', unable "
"to load buffer pool (stage 2)",
full_filename);
return;
}
if (space_id > ULINT32_MASK || page_no > ULINT32_MASK) {
ut_free(dump);
ut_free(dump_tmp);
fclose(f);
buf_load_status(STATUS_ERR,
"Error parsing '%s': bogus "
"space,page " ULINTPF "," ULINTPF
" at line " ULINTPF ", "
"unable to load buffer pool",
full_filename,
space_id, page_no,
i);
return;
}
dump[i] = BUF_DUMP_CREATE(space_id, page_no);
}
/* Set dump_n to the actual number of initialized elements,
i could be smaller than dump_n here if the file got truncated after
we read it the first time. */
dump_n = i;
fclose(f);
if (dump_n == 0) {
ut_free(dump);
ut_sprintf_timestamp(now);
buf_load_status(STATUS_NOTICE,
"Buffer pool(s) load completed at %s "
"(%s was empty)", now, full_filename);
return;
}
if (!SHUTTING_DOWN()) {
buf_dump_sort(dump, dump_tmp, 0, dump_n);
}
ut_free(dump_tmp);
for (i = 0; i < dump_n && !SHUTTING_DOWN(); i++) {
buf_read_page_async(BUF_DUMP_SPACE(dump[i]),
BUF_DUMP_PAGE(dump[i]));
if (i % 64 == 63) {
os_aio_simulated_wake_handler_threads();
}
if (i % 128 == 0) {
buf_load_status(STATUS_INFO,
"Loaded " ULINTPF "/" ULINTPF " pages",
i + 1, dump_n);
}
if (buf_load_abort_flag) {
buf_load_abort_flag = FALSE;
ut_free(dump);
buf_load_status(
STATUS_NOTICE,
"Buffer pool(s) load aborted on request");
return;
}
}
ut_free(dump);
ut_sprintf_timestamp(now);
buf_load_status(STATUS_NOTICE,
"Buffer pool(s) load completed at %s", now);
}
/*****************************************************************//**
Aborts a currently running buffer pool load. This function is called by
MySQL code via buffer_pool_load_abort() and it should return immediately
because the whole MySQL is frozen during its execution. */
UNIV_INTERN
void
buf_load_abort()
/*============*/
{
buf_load_abort_flag = TRUE;
}
/*****************************************************************//**
This is the main thread for buffer pool dump/load. It waits for an
event and when waked up either performs a dump or load and sleeps
again.
@return this function does not return, it calls os_thread_exit() */
extern "C" UNIV_INTERN
os_thread_ret_t
DECLARE_THREAD(buf_dump_thread)(
/*============================*/
void* arg __attribute__((unused))) /*!< in: a dummy parameter
required by os_thread_create */
{
srv_buf_dump_thread_active = TRUE;
buf_dump_status(STATUS_INFO, "not started");
buf_load_status(STATUS_INFO, "not started");
if (srv_buffer_pool_load_at_startup) {
buf_load();
}
while (!SHUTTING_DOWN()) {
os_event_wait(srv_buf_dump_event);
if (buf_dump_should_start) {
buf_dump_should_start = FALSE;
buf_dump(TRUE /* quit on shutdown */);
}
if (buf_load_should_start) {
buf_load_should_start = FALSE;
buf_load();
}
os_event_reset(srv_buf_dump_event);
}
if (srv_buffer_pool_dump_at_shutdown && srv_fast_shutdown != 2) {
buf_dump(FALSE /* ignore shutdown down flag,
keep going even if we are in a shutdown state */);
}
srv_buf_dump_thread_active = FALSE;
/* We count the number of threads in os_thread_exit(). A created
thread should always use that to exit and not use return() to exit. */
os_thread_exit(NULL);
OS_THREAD_DUMMY_RETURN;
}

View file

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved.
Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
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 the Free Software
@ -11,13 +11,13 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
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
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
/**************************************************//**
@file buf/buf0rea.c
@file buf/buf0rea.cc
The database buffer read
Created 11/5/1995 Heikki Tuuri
@ -31,6 +31,7 @@ Created 11/5/1995 Heikki Tuuri
#include "buf0buf.h"
#include "buf0flu.h"
#include "buf0lru.h"
#include "buf0dblwr.h"
#include "ibuf0ibuf.h"
#include "log0recv.h"
#include "trx0sys.h"
@ -58,7 +59,7 @@ flag is cleared and the x-lock released by an i/o-handler thread.
@return 1 if a read request was queued, 0 if the page already resided
in buf_pool, or if the page is in the doublewrite buffer blocks in
which case it is never read into the pool, or if the tablespace does
not exist or is being dropped
not exist or is being dropped
@return 1 if read request is issued. 0 if it is not */
static
ulint
@ -83,19 +84,17 @@ buf_read_page_low(
{
buf_page_t* bpage;
ulint wake_later;
ibool ignore_nonexistent_pages;
*err = DB_SUCCESS;
wake_later = mode & OS_AIO_SIMULATED_WAKE_LATER;
mode = mode & ~OS_AIO_SIMULATED_WAKE_LATER;
if (trx_doublewrite && space == TRX_SYS_SPACE
&& ( (offset >= trx_doublewrite->block1
&& offset < trx_doublewrite->block1
+ TRX_SYS_DOUBLEWRITE_BLOCK_SIZE)
|| (offset >= trx_doublewrite->block2
&& offset < trx_doublewrite->block2
+ TRX_SYS_DOUBLEWRITE_BLOCK_SIZE))) {
ignore_nonexistent_pages = mode & BUF_READ_IGNORE_NONEXISTENT_PAGES;
mode &= ~BUF_READ_IGNORE_NONEXISTENT_PAGES;
if (space == TRX_SYS_SPACE && buf_dblwr_page_inside(offset)) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Warning: trying to read"
@ -141,18 +140,27 @@ buf_read_page_low(
thd_wait_begin(NULL, THD_WAIT_DISKIO);
if (zip_size) {
*err = fil_io(OS_FILE_READ | wake_later,
*err = fil_io(OS_FILE_READ | wake_later
| ignore_nonexistent_pages,
sync, space, zip_size, offset, 0, zip_size,
bpage->zip.data, bpage);
} else {
ut_a(buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE);
*err = fil_io(OS_FILE_READ | wake_later,
*err = fil_io(OS_FILE_READ | wake_later
| ignore_nonexistent_pages,
sync, space, 0, offset, 0, UNIV_PAGE_SIZE,
((buf_block_t*) bpage)->frame, bpage);
}
thd_wait_end(NULL);
ut_a(*err == DB_SUCCESS);
if (*err != DB_SUCCESS) {
if (ignore_nonexistent_pages) {
return(0);
}
/* else */
ut_error;
}
if (sync) {
/* The i/o is already completed when we arrive from
@ -342,7 +350,6 @@ buf_read_page(
ulint zip_size,/*!< in: compressed page size in bytes, or 0 */
ulint offset) /*!< in: page number */
{
buf_pool_t* buf_pool = buf_pool_get(space, offset);
ib_int64_t tablespace_version;
ulint count;
ulint err;
@ -366,15 +373,55 @@ buf_read_page(
(ulong) space, (ulong) offset);
}
/* Flush pages from the end of the LRU list if necessary */
buf_flush_free_margin(buf_pool);
/* Increment number of I/O operations used for LRU policy. */
buf_LRU_stat_inc_io();
return(count > 0);
}
/********************************************************************//**
High-level function which reads a page asynchronously from a file to the
buffer buf_pool if it is not already there. Sets the io_fix flag and sets
an exclusive lock on the buffer frame. The flag is cleared and the x-lock
released by the i/o-handler thread.
@return TRUE if page has been read in, FALSE in case of failure */
UNIV_INTERN
ibool
buf_read_page_async(
/*================*/
ulint space, /*!< in: space id */
ulint offset) /*!< in: page number */
{
ulint zip_size;
ib_int64_t tablespace_version;
ulint count;
ulint err;
zip_size = fil_space_get_zip_size(space);
if (zip_size == ULINT_UNDEFINED) {
return(FALSE);
}
tablespace_version = fil_space_get_version(space);
count = buf_read_page_low(&err, TRUE, BUF_READ_ANY_PAGE
| OS_AIO_SIMULATED_WAKE_LATER
| BUF_READ_IGNORE_NONEXISTENT_PAGES,
space, zip_size, FALSE,
tablespace_version, offset);
srv_buf_pool_reads += count;
/* We do not increment number of I/O operations used for LRU policy
here (buf_LRU_stat_inc_io()). We use this in heuristics to decide
about evicting uncompressed version of compressed pages from the
buffer pool. Since this function is called from buffer pool load
these IOs are deliberate and are not part of normal workload we can
ignore these in our heuristics. */
return(count > 0);
}
/********************************************************************//**
Applies linear read-ahead if in the buf_pool the page is a border page of
a linear read-ahead area and all the pages in the area have been accessed.
@ -427,6 +474,11 @@ buf_read_ahead_linear(
= BUF_READ_AHEAD_AREA(buf_pool);
ulint threshold;
/* check if readahead is disabled */
if (!srv_read_ahead_threshold) {
return(0);
}
if (UNIV_UNLIKELY(srv_startup_is_before_trx_rollback_phase)) {
/* No read-ahead to avoid thread deadlocks */
return(0);
@ -636,9 +688,6 @@ buf_read_ahead_linear(
os_aio_simulated_wake_handler_threads();
/* Flush pages from the end of the LRU list if necessary */
buf_flush_free_margin(buf_pool);
#ifdef UNIV_DEBUG
if (buf_debug_prints && (count > 0)) {
fprintf(stderr,
@ -724,9 +773,6 @@ tablespace_deleted:
os_aio_simulated_wake_handler_threads();
/* Flush pages from the end of all the LRU lists if necessary */
buf_flush_free_margins();
#ifdef UNIV_DEBUG
if (buf_debug_prints) {
fprintf(stderr,
@ -796,7 +842,7 @@ buf_read_recv_pages(
"InnoDB: Number of pending reads %lu,"
" pending pread calls %lu\n",
(ulong) buf_pool->n_pend_reads,
(ulong)os_file_n_pending_preads);
(ulong) os_file_n_pending_preads);
os_aio_print_debug = TRUE;
}
@ -818,9 +864,6 @@ buf_read_recv_pages(
os_aio_simulated_wake_handler_threads();
/* Flush pages from the end of all the LRU lists if necessary */
buf_flush_free_margins();
#ifdef UNIV_DEBUG
if (buf_debug_prints) {
fprintf(stderr,

View file

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved.
Copyright (c) 1994, 2012, Oracle and/or its affiliates. All Rights Reserved.
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 the Free Software
@ -11,13 +11,13 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
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
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
/********************************************************************//**
@file data/data0data.c
@file data/data0data.cc
SQL data field and tuple
Created 5/30/1994 Heikki Tuuri
@ -53,35 +53,6 @@ UNIV_INTERN ulint data_dummy;
#endif /* UNIV_DEBUG */
#ifndef UNIV_HOTBACKUP
/*********************************************************************//**
Tests if dfield data length and content is equal to the given.
@return TRUE if equal */
UNIV_INTERN
ibool
dfield_data_is_binary_equal(
/*========================*/
const dfield_t* field, /*!< in: field */
ulint len, /*!< in: data length or UNIV_SQL_NULL */
const byte* data) /*!< in: data */
{
if (len != dfield_get_len(field)) {
return(FALSE);
}
if (len == UNIV_SQL_NULL) {
return(TRUE);
}
if (0 != memcmp(dfield_get_data(field), data, len)) {
return(FALSE);
}
return(TRUE);
}
/************************************************************//**
Compare two data tuples, respecting the collation of character fields.
@return 1, 0 , -1 if tuple1 is greater, equal, less, respectively,
@ -274,7 +245,9 @@ dtuple_validate(
if (!dfield_is_null(field)) {
const byte* data = dfield_get_data(field);
const byte* data;
data = static_cast<const byte*>(dfield_get_data(field));
#ifndef UNIV_DEBUG_VALGRIND
ulint j;
@ -311,7 +284,7 @@ dfield_print(
ulint i;
len = dfield_get_len(dfield);
data = dfield_get_data(dfield);
data = static_cast<const byte*>(dfield_get_data(dfield));
if (dfield_is_null(dfield)) {
fputs("NULL", stderr);
@ -333,7 +306,7 @@ dfield_print(
break;
case DATA_INT:
ut_a(len == 4); /* only works for 32-bit integers */
fprintf(stderr, "%d", (int)mach_read_from_4(data));
fprintf(stderr, "%d", (int) mach_read_from_4(data));
break;
default:
ut_error;
@ -356,7 +329,7 @@ dfield_print_also_hex(
ibool print_also_hex;
len = dfield_get_len(dfield);
data = dfield_get_data(dfield);
data = static_cast<const byte*>(dfield_get_data(dfield));
if (dfield_is_null(dfield)) {
fputs("NULL", stderr);
@ -438,25 +411,25 @@ dfield_print_also_hex(
case DATA_TRX_ID:
id = mach_read_from_6(data);
fprintf(stderr, "trx_id " TRX_ID_FMT, (ullint) id);
fprintf(stderr, "trx_id " TRX_ID_FMT, id);
break;
case DATA_ROLL_PTR:
id = mach_read_from_7(data);
fprintf(stderr, "roll_ptr " TRX_ID_FMT, (ullint) id);
fprintf(stderr, "roll_ptr " TRX_ID_FMT, id);
break;
case DATA_ROW_ID:
id = mach_read_from_6(data);
fprintf(stderr, "row_id " TRX_ID_FMT, (ullint) id);
fprintf(stderr, "row_id " TRX_ID_FMT, id);
break;
default:
id = mach_ull_read_compressed(data);
fprintf(stderr, "mix_id " TRX_ID_FMT, (ullint) id);
fprintf(stderr, "mix_id " TRX_ID_FMT, id);
}
break;
@ -484,7 +457,7 @@ dfield_print_also_hex(
break;
}
data = dfield_get_data(dfield);
data = static_cast<byte*>(dfield_get_data(dfield));
/* fall through */
case DATA_BINARY:
@ -579,11 +552,11 @@ dtuple_convert_big_rec(
ulint local_len;
ulint local_prefix_len;
if (UNIV_UNLIKELY(!dict_index_is_clust(index))) {
if (!dict_index_is_clust(index)) {
return(NULL);
}
if (dict_table_get_format(index->table) < DICT_TF_FORMAT_ZIP) {
if (dict_table_get_format(index->table) < UNIV_FORMAT_B) {
/* up to MySQL 5.1: store a 768-byte prefix locally */
local_len = BTR_EXTERN_FIELD_REF_SIZE
+ DICT_ANTELOPE_MAX_INDEX_COL_LEN;
@ -608,11 +581,15 @@ dtuple_convert_big_rec(
heap = mem_heap_create(size + dtuple_get_n_fields(entry)
* sizeof(big_rec_field_t) + 1000);
vector = mem_heap_alloc(heap, sizeof(big_rec_t));
vector = static_cast<big_rec_t*>(
mem_heap_alloc(heap, sizeof(big_rec_t)));
vector->heap = heap;
vector->fields = mem_heap_alloc(heap, dtuple_get_n_fields(entry)
* sizeof(big_rec_field_t));
vector->fields = static_cast<big_rec_field_t*>(
mem_heap_alloc(
heap,
dtuple_get_n_fields(entry) * sizeof(big_rec_field_t)));
/* Decide which fields to shorten: the algorithm is to look for
a variable-length field that yields the biggest savings when
@ -703,7 +680,7 @@ skip_field:
b->data = (char*) dfield_get_data(dfield) + local_prefix_len;
/* Allocate the locally stored part of the column. */
data = mem_heap_alloc(heap, local_len);
data = static_cast<byte*>(mem_heap_alloc(heap, local_len));
/* Copy the local prefix. */
memcpy(data, dfield_get_data(dfield), local_prefix_len);

View file

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved.
Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved.
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 the Free Software
@ -11,13 +11,13 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
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
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
/**************************************************//**
@file data/data0type.c
@file data/data0type.cc
Data types
Created 1/16/1996 Heikki Tuuri
@ -158,7 +158,7 @@ dtype_form_prtype(
ulint charset_coll) /*!< in: MySQL charset-collation code */
{
ut_a(old_prtype < 256 * 256);
ut_a(charset_coll < 256);
ut_a(charset_coll <= MAX_CHAR_COLL_NUM);
return(old_prtype + (charset_coll << 16));
}

View file

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved.
Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved.
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 the Free Software
@ -11,13 +11,13 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
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
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
/**************************************************//**
@file dict/dict0boot.c
@file dict/dict0boot.cc
Data dictionary creation and booting
Created 4/18/1996 Heikki Tuuri
@ -254,6 +254,24 @@ dict_boot(void)
mtr_t mtr;
ulint error;
/* Be sure these constants do not ever change. To avoid bloat,
only check the *NUM_FIELDS* in each table */
ut_ad(DICT_NUM_COLS__SYS_TABLES == 8);
ut_ad(DICT_NUM_FIELDS__SYS_TABLES == 10);
ut_ad(DICT_NUM_FIELDS__SYS_TABLE_IDS == 2);
ut_ad(DICT_NUM_COLS__SYS_COLUMNS == 7);
ut_ad(DICT_NUM_FIELDS__SYS_COLUMNS == 9);
ut_ad(DICT_NUM_COLS__SYS_INDEXES == 7);
ut_ad(DICT_NUM_FIELDS__SYS_INDEXES == 9);
ut_ad(DICT_NUM_COLS__SYS_FIELDS == 3);
ut_ad(DICT_NUM_FIELDS__SYS_FIELDS == 5);
ut_ad(DICT_NUM_COLS__SYS_FOREIGN == 4);
ut_ad(DICT_NUM_FIELDS__SYS_FOREIGN == 6);
ut_ad(DICT_NUM_FIELDS__SYS_FOREIGN_FOR_NAME == 2);
ut_ad(DICT_NUM_COLS__SYS_FOREIGN_COLS == 4);
ut_ad(DICT_NUM_FIELDS__SYS_FOREIGN_COLS == 6);
mtr_start(&mtr);
/* Create the hash tables etc. */
@ -283,14 +301,16 @@ dict_boot(void)
/* Insert into the dictionary cache the descriptions of the basic
system tables */
/*-------------------------*/
table = dict_mem_table_create("SYS_TABLES", DICT_HDR_SPACE, 8, 0);
table = dict_mem_table_create("SYS_TABLES", DICT_HDR_SPACE, 8, 0, 0);
dict_mem_table_add_col(table, heap, "NAME", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, heap, "ID", DATA_BINARY, 0, 0);
/* ROW_FORMAT = (N_COLS >> 31) ? COMPACT : REDUNDANT */
dict_mem_table_add_col(table, heap, "N_COLS", DATA_INT, 0, 4);
/* TYPE is either DICT_TABLE_ORDINARY, or (TYPE & DICT_TF_COMPACT)
and (TYPE & DICT_TF_FORMAT_MASK) are nonzero and TYPE = table->flags */
/* If the format is UNIV_FORMAT_A, table->flags == 0, and
TYPE == 1, which is defined as SYS_TABLE_TYPE_ANTELOPE.
The low order bit of TYPE is always set to 1. If the format
is UNIV_FORMAT_B or higher, this field matches table->flags. */
dict_mem_table_add_col(table, heap, "TYPE", DATA_INT, 0, 4);
dict_mem_table_add_col(table, heap, "MIX_ID", DATA_BINARY, 0, 0);
/* MIX_LEN may contain additional table flags when
@ -302,7 +322,7 @@ dict_boot(void)
table->id = DICT_TABLES_ID;
dict_table_add_to_cache(table, heap);
dict_table_add_to_cache(table, FALSE, heap);
dict_sys->sys_tables = table;
mem_heap_empty(heap);
@ -335,7 +355,7 @@ dict_boot(void)
ut_a(error == DB_SUCCESS);
/*-------------------------*/
table = dict_mem_table_create("SYS_COLUMNS", DICT_HDR_SPACE, 7, 0);
table = dict_mem_table_create("SYS_COLUMNS", DICT_HDR_SPACE, 7, 0, 0);
dict_mem_table_add_col(table, heap, "TABLE_ID", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, heap, "POS", DATA_INT, 0, 4);
@ -347,7 +367,7 @@ dict_boot(void)
table->id = DICT_COLUMNS_ID;
dict_table_add_to_cache(table, heap);
dict_table_add_to_cache(table, FALSE, heap);
dict_sys->sys_columns = table;
mem_heap_empty(heap);
@ -367,7 +387,7 @@ dict_boot(void)
ut_a(error == DB_SUCCESS);
/*-------------------------*/
table = dict_mem_table_create("SYS_INDEXES", DICT_HDR_SPACE, 7, 0);
table = dict_mem_table_create("SYS_INDEXES", DICT_HDR_SPACE, 7, 0, 0);
dict_mem_table_add_col(table, heap, "TABLE_ID", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, heap, "ID", DATA_BINARY, 0, 0);
@ -377,22 +397,9 @@ dict_boot(void)
dict_mem_table_add_col(table, heap, "SPACE", DATA_INT, 0, 4);
dict_mem_table_add_col(table, heap, "PAGE_NO", DATA_INT, 0, 4);
/* The '+ 2' below comes from the fields DB_TRX_ID, DB_ROLL_PTR */
#if DICT_SYS_INDEXES_PAGE_NO_FIELD != 6 + 2
#error "DICT_SYS_INDEXES_PAGE_NO_FIELD != 6 + 2"
#endif
#if DICT_SYS_INDEXES_SPACE_NO_FIELD != 5 + 2
#error "DICT_SYS_INDEXES_SPACE_NO_FIELD != 5 + 2"
#endif
#if DICT_SYS_INDEXES_TYPE_FIELD != 4 + 2
#error "DICT_SYS_INDEXES_TYPE_FIELD != 4 + 2"
#endif
#if DICT_SYS_INDEXES_NAME_FIELD != 2 + 2
#error "DICT_SYS_INDEXES_NAME_FIELD != 2 + 2"
#endif
table->id = DICT_INDEXES_ID;
dict_table_add_to_cache(table, heap);
dict_table_add_to_cache(table, FALSE, heap);
dict_sys->sys_indexes = table;
mem_heap_empty(heap);
@ -412,14 +419,15 @@ dict_boot(void)
ut_a(error == DB_SUCCESS);
/*-------------------------*/
table = dict_mem_table_create("SYS_FIELDS", DICT_HDR_SPACE, 3, 0);
table = dict_mem_table_create("SYS_FIELDS", DICT_HDR_SPACE, 3, 0, 0);
dict_mem_table_add_col(table, heap, "INDEX_ID", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, heap, "POS", DATA_INT, 0, 4);
dict_mem_table_add_col(table, heap, "COL_NAME", DATA_BINARY, 0, 0);
table->id = DICT_FIELDS_ID;
dict_table_add_to_cache(table, heap);
dict_table_add_to_cache(table, FALSE, heap);
dict_sys->sys_fields = table;
mem_heap_free(heap);
@ -439,6 +447,7 @@ dict_boot(void)
ut_a(error == DB_SUCCESS);
mtr_commit(&mtr);
/*-------------------------*/
/* Initialize the insert buffer table and index for each tablespace */

View file

@ -11,13 +11,13 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
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
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
/**************************************************//**
@file dict/dict0crea.c
@file dict/dict0crea.cc
Database object creation
Created 1/8/1996 Heikki Tuuri
@ -42,6 +42,7 @@ Created 1/8/1996 Heikki Tuuri
#include "trx0roll.h"
#include "usr0sess.h"
#include "ut0vec.h"
#include "dict0priv.h"
/*****************************************************************//**
Based on a table object, this function builds the entry to be inserted
@ -60,6 +61,7 @@ dict_create_sys_tables_tuple(
dtuple_t* entry;
dfield_t* dfield;
byte* ptr;
ulint type;
ut_ad(table);
ut_ad(heap);
@ -71,65 +73,74 @@ dict_create_sys_tables_tuple(
dict_table_copy_types(entry, sys_tables);
/* 0: NAME -----------------------------*/
dfield = dtuple_get_nth_field(entry, 0/*NAME*/);
dfield = dtuple_get_nth_field(
entry, DICT_COL__SYS_TABLES__NAME);
dfield_set_data(dfield, table->name, ut_strlen(table->name));
/* 3: ID -------------------------------*/
dfield = dtuple_get_nth_field(entry, 1/*ID*/);
ptr = mem_heap_alloc(heap, 8);
/* 1: DB_TRX_ID added later */
/* 2: DB_ROLL_PTR added later */
/* 3: ID -------------------------------*/
dfield = dtuple_get_nth_field(
entry, DICT_COL__SYS_TABLES__ID);
ptr = static_cast<byte*>(mem_heap_alloc(heap, 8));
mach_write_to_8(ptr, table->id);
dfield_set_data(dfield, ptr, 8);
/* 4: N_COLS ---------------------------*/
dfield = dtuple_get_nth_field(entry, 2/*N_COLS*/);
dfield = dtuple_get_nth_field(
entry, DICT_COL__SYS_TABLES__N_COLS);
#if DICT_TF_COMPACT != 1
#error
#endif
ptr = mem_heap_alloc(heap, 4);
ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
mach_write_to_4(ptr, table->n_def
| ((table->flags & DICT_TF_COMPACT) << 31));
dfield_set_data(dfield, ptr, 4);
/* 5: TYPE -----------------------------*/
dfield = dtuple_get_nth_field(entry, 3/*TYPE*/);
ptr = mem_heap_alloc(heap, 4);
if (table->flags & (~DICT_TF_COMPACT & ~(~0 << DICT_TF_BITS))) {
ut_a(table->flags & DICT_TF_COMPACT);
ut_a(dict_table_get_format(table) >= DICT_TF_FORMAT_ZIP);
ut_a((table->flags & DICT_TF_ZSSIZE_MASK)
<= (DICT_TF_ZSSIZE_MAX << DICT_TF_ZSSIZE_SHIFT));
ut_a(!(table->flags & (~0 << DICT_TF2_BITS)));
mach_write_to_4(ptr, table->flags & ~(~0 << DICT_TF_BITS));
} else {
mach_write_to_4(ptr, DICT_TABLE_ORDINARY);
}
/* 5: TYPE (table flags) -----------------------------*/
dfield = dtuple_get_nth_field(
entry, DICT_COL__SYS_TABLES__TYPE);
ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
/* Validate the table flags and convert them to what is saved in
SYS_TABLES.TYPE. Table flag values 0 and 1 are both written to
SYS_TABLES.TYPE as 1. */
type = dict_tf_to_sys_tables_type(table->flags);
mach_write_to_4(ptr, type);
dfield_set_data(dfield, ptr, 4);
/* 6: MIX_ID (obsolete) ---------------------------*/
dfield = dtuple_get_nth_field(entry, 4/*MIX_ID*/);
ptr = mem_heap_zalloc(heap, 8);
/* 6: MIX_ID (obsolete) ---------------------------*/
dfield = dtuple_get_nth_field(
entry, DICT_COL__SYS_TABLES__MIX_ID);
ptr = static_cast<byte*>(mem_heap_zalloc(heap, 8));
dfield_set_data(dfield, ptr, 8);
/* 7: MIX_LEN (additional flags) --------------------------*/
dfield = dtuple_get_nth_field(
entry, DICT_COL__SYS_TABLES__MIX_LEN);
dfield = dtuple_get_nth_field(entry, 5/*MIX_LEN*/);
ptr = mem_heap_alloc(heap, 4);
mach_write_to_4(ptr, table->flags >> DICT_TF2_SHIFT);
ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
/* Be sure all non-used bits are zero. */
ut_a(!(table->flags2 & ~DICT_TF2_BIT_MASK));
mach_write_to_4(ptr, table->flags2);
dfield_set_data(dfield, ptr, 4);
/* 8: CLUSTER_NAME ---------------------*/
dfield = dtuple_get_nth_field(entry, 6/*CLUSTER_NAME*/);
dfield = dtuple_get_nth_field(
entry, DICT_COL__SYS_TABLES__CLUSTER_ID);
dfield_set_null(dfield); /* not supported */
/* 9: SPACE ----------------------------*/
dfield = dtuple_get_nth_field(entry, 7/*SPACE*/);
dfield = dtuple_get_nth_field(
entry, DICT_COL__SYS_TABLES__SPACE);
ptr = mem_heap_alloc(heap, 4);
ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
mach_write_to_4(ptr, table->space);
dfield_set_data(dfield, ptr, 4);
@ -171,49 +182,57 @@ dict_create_sys_columns_tuple(
dict_table_copy_types(entry, sys_columns);
/* 0: TABLE_ID -----------------------*/
dfield = dtuple_get_nth_field(entry, 0/*TABLE_ID*/);
dfield = dtuple_get_nth_field(entry, DICT_COL__SYS_COLUMNS__TABLE_ID);
ptr = mem_heap_alloc(heap, 8);
ptr = static_cast<byte*>(mem_heap_alloc(heap, 8));
mach_write_to_8(ptr, table->id);
dfield_set_data(dfield, ptr, 8);
/* 1: POS ----------------------------*/
dfield = dtuple_get_nth_field(entry, 1/*POS*/);
ptr = mem_heap_alloc(heap, 4);
/* 1: POS ----------------------------*/
dfield = dtuple_get_nth_field(entry, DICT_COL__SYS_COLUMNS__POS);
ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
mach_write_to_4(ptr, i);
dfield_set_data(dfield, ptr, 4);
/* 2: DB_TRX_ID added later */
/* 3: DB_ROLL_PTR added later */
/* 4: NAME ---------------------------*/
dfield = dtuple_get_nth_field(entry, 2/*NAME*/);
dfield = dtuple_get_nth_field(entry, DICT_COL__SYS_COLUMNS__NAME);
col_name = dict_table_get_col_name(table, i);
dfield_set_data(dfield, col_name, ut_strlen(col_name));
/* 5: MTYPE --------------------------*/
dfield = dtuple_get_nth_field(entry, 3/*MTYPE*/);
ptr = mem_heap_alloc(heap, 4);
/* 5: MTYPE --------------------------*/
dfield = dtuple_get_nth_field(entry, DICT_COL__SYS_COLUMNS__MTYPE);
ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
mach_write_to_4(ptr, column->mtype);
dfield_set_data(dfield, ptr, 4);
/* 6: PRTYPE -------------------------*/
dfield = dtuple_get_nth_field(entry, 4/*PRTYPE*/);
ptr = mem_heap_alloc(heap, 4);
/* 6: PRTYPE -------------------------*/
dfield = dtuple_get_nth_field(entry, DICT_COL__SYS_COLUMNS__PRTYPE);
ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
mach_write_to_4(ptr, column->prtype);
dfield_set_data(dfield, ptr, 4);
/* 7: LEN ----------------------------*/
dfield = dtuple_get_nth_field(entry, 5/*LEN*/);
ptr = mem_heap_alloc(heap, 4);
/* 7: LEN ----------------------------*/
dfield = dtuple_get_nth_field(entry, DICT_COL__SYS_COLUMNS__LEN);
ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
mach_write_to_4(ptr, column->len);
dfield_set_data(dfield, ptr, 4);
/* 8: PREC ---------------------------*/
dfield = dtuple_get_nth_field(entry, 6/*PREC*/);
ptr = mem_heap_alloc(heap, 4);
/* 8: PREC ---------------------------*/
dfield = dtuple_get_nth_field(entry, DICT_COL__SYS_COLUMNS__PREC);
ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
mach_write_to_4(ptr, 0/* unused */);
dfield_set_data(dfield, ptr, 4);
@ -235,32 +254,24 @@ dict_build_table_def_step(
dict_table_t* table;
dtuple_t* row;
ulint error;
ulint flags;
const char* path_or_name;
ibool is_path;
mtr_t mtr;
ulint space = 0;
ibool file_per_table;
bool use_tablespace;
ut_ad(mutex_own(&(dict_sys->mutex)));
table = node->table;
/* Cache the global variable "srv_file_per_table" to
a local variable before using it. Please note
"srv_file_per_table" is not under dict_sys mutex
protection, and could be changed while executing
this function. So better to cache the current value
to a local variable, and all future reference to
"srv_file_per_table" should use this local variable. */
file_per_table = srv_file_per_table;
use_tablespace = !!(table->flags2 & DICT_TF2_USE_TABLESPACE);
dict_hdr_get_new_id(&table->id, NULL, NULL);
thr_get_trx(thr)->table_id = table->id;
if (file_per_table) {
/* Get a new space id if srv_file_per_table is set */
if (use_tablespace) {
/* This table will not use the system tablespace.
Get a new space id. */
dict_hdr_get_new_id(NULL, NULL, &space);
if (UNIV_UNLIKELY(space == ULINT_UNDEFINED)) {
@ -286,14 +297,14 @@ dict_build_table_def_step(
is_path = FALSE;
}
ut_ad(dict_table_get_format(table) <= DICT_TF_FORMAT_MAX);
ut_ad(dict_table_get_format(table) <= UNIV_FORMAT_MAX);
ut_ad(!dict_table_zip_size(table)
|| dict_table_get_format(table) >= DICT_TF_FORMAT_ZIP);
|| dict_table_get_format(table) >= UNIV_FORMAT_B);
flags = table->flags & ~(~0 << DICT_TF_BITS);
error = fil_create_new_single_table_tablespace(
space, path_or_name, is_path,
flags == DICT_TF_COMPACT ? 0 : flags,
dict_tf_to_fsp_flags(table->flags),
table->flags2,
FIL_IBD_FILE_INITIAL_SIZE);
table->space = (unsigned int) space;
@ -308,8 +319,10 @@ dict_build_table_def_step(
mtr_commit(&mtr);
} else {
/* Create in the system tablespace: disallow new features */
table->flags &= (~0 << DICT_TF_BITS) | DICT_TF_COMPACT;
/* Create in the system tablespace: disallow Barracuda
features by keeping only the first bit which says whether
the row format is redundant or compact */
table->flags &= DICT_TF_COMPACT;
}
row = dict_create_sys_tables_tuple(table, node->heap);
@ -369,61 +382,69 @@ dict_create_sys_indexes_tuple(
dict_table_copy_types(entry, sys_indexes);
/* 0: TABLE_ID -----------------------*/
dfield = dtuple_get_nth_field(entry, 0/*TABLE_ID*/);
dfield = dtuple_get_nth_field(
entry, DICT_COL__SYS_INDEXES__TABLE_ID);
ptr = mem_heap_alloc(heap, 8);
ptr = static_cast<byte*>(mem_heap_alloc(heap, 8));
mach_write_to_8(ptr, table->id);
dfield_set_data(dfield, ptr, 8);
/* 1: ID ----------------------------*/
dfield = dtuple_get_nth_field(entry, 1/*ID*/);
ptr = mem_heap_alloc(heap, 8);
/* 1: ID ----------------------------*/
dfield = dtuple_get_nth_field(
entry, DICT_COL__SYS_INDEXES__ID);
ptr = static_cast<byte*>(mem_heap_alloc(heap, 8));
mach_write_to_8(ptr, index->id);
dfield_set_data(dfield, ptr, 8);
/* 2: DB_TRX_ID added later */
/* 3: DB_ROLL_PTR added later */
/* 4: NAME --------------------------*/
dfield = dtuple_get_nth_field(entry, 2/*NAME*/);
dfield = dtuple_get_nth_field(
entry, DICT_COL__SYS_INDEXES__NAME);
dfield_set_data(dfield, index->name, ut_strlen(index->name));
/* 5: N_FIELDS ----------------------*/
dfield = dtuple_get_nth_field(entry, 3/*N_FIELDS*/);
ptr = mem_heap_alloc(heap, 4);
/* 5: N_FIELDS ----------------------*/
dfield = dtuple_get_nth_field(
entry, DICT_COL__SYS_INDEXES__N_FIELDS);
ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
mach_write_to_4(ptr, index->n_fields);
dfield_set_data(dfield, ptr, 4);
/* 6: TYPE --------------------------*/
dfield = dtuple_get_nth_field(entry, 4/*TYPE*/);
ptr = mem_heap_alloc(heap, 4);
/* 6: TYPE --------------------------*/
dfield = dtuple_get_nth_field(
entry, DICT_COL__SYS_INDEXES__TYPE);
ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
mach_write_to_4(ptr, index->type);
dfield_set_data(dfield, ptr, 4);
/* 7: SPACE --------------------------*/
#if DICT_SYS_INDEXES_SPACE_NO_FIELD != 7
#error "DICT_SYS_INDEXES_SPACE_NO_FIELD != 7"
#endif
dfield = dtuple_get_nth_field(
entry, DICT_COL__SYS_INDEXES__SPACE);
dfield = dtuple_get_nth_field(entry, 5/*SPACE*/);
ptr = mem_heap_alloc(heap, 4);
ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
mach_write_to_4(ptr, index->space);
dfield_set_data(dfield, ptr, 4);
/* 8: PAGE_NO --------------------------*/
#if DICT_SYS_INDEXES_PAGE_NO_FIELD != 8
#error "DICT_SYS_INDEXES_PAGE_NO_FIELD != 8"
#endif
dfield = dtuple_get_nth_field(
entry, DICT_COL__SYS_INDEXES__PAGE_NO);
dfield = dtuple_get_nth_field(entry, 6/*PAGE_NO*/);
ptr = mem_heap_alloc(heap, 4);
ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
mach_write_to_4(ptr, FIL_NULL);
dfield_set_data(dfield, ptr, 4);
/*--------------------------------*/
return(entry);
@ -438,7 +459,7 @@ dtuple_t*
dict_create_sys_fields_tuple(
/*=========================*/
const dict_index_t* index, /*!< in: index */
ulint i, /*!< in: field number */
ulint fld_no, /*!< in: field number */
mem_heap_t* heap) /*!< in: memory heap from
which the memory for the built
tuple is allocated */
@ -461,7 +482,7 @@ dict_create_sys_fields_tuple(
}
}
field = dict_index_get_nth_field(index, i);
field = dict_index_get_nth_field(index, fld_no);
sys_fields = dict_sys->sys_fields;
@ -470,35 +491,39 @@ dict_create_sys_fields_tuple(
dict_table_copy_types(entry, sys_fields);
/* 0: INDEX_ID -----------------------*/
dfield = dtuple_get_nth_field(entry, 0/*INDEX_ID*/);
dfield = dtuple_get_nth_field(entry, DICT_COL__SYS_FIELDS__INDEX_ID);
ptr = mem_heap_alloc(heap, 8);
ptr = static_cast<byte*>(mem_heap_alloc(heap, 8));
mach_write_to_8(ptr, index->id);
dfield_set_data(dfield, ptr, 8);
/* 1: POS + PREFIX LENGTH ----------------------------*/
dfield = dtuple_get_nth_field(entry, 1/*POS*/);
/* 1: POS; FIELD NUMBER & PREFIX LENGTH -----------------------*/
ptr = mem_heap_alloc(heap, 4);
dfield = dtuple_get_nth_field(entry, DICT_COL__SYS_FIELDS__POS);
ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
if (index_contains_column_prefix_field) {
/* If there are column prefix fields in the index, then
we store the number of the field to the 2 HIGH bytes
and the prefix length to the 2 low bytes, */
mach_write_to_4(ptr, (i << 16) + field->prefix_len);
mach_write_to_4(ptr, (fld_no << 16) + field->prefix_len);
} else {
/* Else we store the number of the field to the 2 LOW bytes.
This is to keep the storage format compatible with
InnoDB versions < 4.0.14. */
mach_write_to_4(ptr, i);
mach_write_to_4(ptr, fld_no);
}
dfield_set_data(dfield, ptr, 4);
/* 2: DB_TRX_ID added later */
/* 3: DB_ROLL_PTR added later */
/* 4: COL_NAME -------------------------*/
dfield = dtuple_get_nth_field(entry, 2/*COL_NAME*/);
dfield = dtuple_get_nth_field(entry, DICT_COL__SYS_FIELDS__COL_NAME);
dfield_set_data(dfield, field->name,
ut_strlen(field->name));
@ -638,6 +663,11 @@ dict_create_index_tree_step(
sys_indexes = dict_sys->sys_indexes;
if (index->type == DICT_FTS) {
/* FTS index does not need an index tree */
return(DB_SUCCESS);
}
/* Run a mini-transaction in which the index tree is allocated for
the index and its root address is written to the index entry in
sys_indexes */
@ -657,10 +687,10 @@ dict_create_index_tree_step(
node->page_no = btr_create(index->type, index->space, zip_size,
index->id, index, &mtr);
/* printf("Created a new index tree in space %lu root page %lu\n",
index->space, index->page_no); */
index->space, node->page_no); */
page_rec_write_field(btr_pcur_get_rec(&pcur),
DICT_SYS_INDEXES_PAGE_NO_FIELD,
DICT_FLD__SYS_INDEXES__PAGE_NO,
node->page_no, &mtr);
btr_pcur_close(&pcur);
mtr_commit(&mtr);
@ -691,7 +721,8 @@ dict_drop_index_tree(
ut_ad(mutex_own(&(dict_sys->mutex)));
ut_a(!dict_table_is_comp(dict_sys->sys_indexes));
ptr = rec_get_nth_field_old(rec, DICT_SYS_INDEXES_PAGE_NO_FIELD, &len);
ptr = rec_get_nth_field_old(
rec, DICT_FLD__SYS_INDEXES__PAGE_NO, &len);
ut_ad(len == 4);
@ -703,8 +734,8 @@ dict_drop_index_tree(
return;
}
ptr = rec_get_nth_field_old(rec,
DICT_SYS_INDEXES_SPACE_NO_FIELD, &len);
ptr = rec_get_nth_field_old(
rec, DICT_FLD__SYS_INDEXES__SPACE, &len);
ut_ad(len == 4);
@ -731,7 +762,7 @@ dict_drop_index_tree(
root_page_no); */
btr_free_root(space, zip_size, root_page_no, mtr);
page_rec_write_field(rec, DICT_SYS_INDEXES_PAGE_NO_FIELD,
page_rec_write_field(rec, DICT_FLD__SYS_INDEXES__PAGE_NO,
FIL_NULL, mtr);
}
@ -767,7 +798,8 @@ dict_truncate_index_tree(
ut_ad(mutex_own(&(dict_sys->mutex)));
ut_a(!dict_table_is_comp(dict_sys->sys_indexes));
rec = btr_pcur_get_rec(pcur);
ptr = rec_get_nth_field_old(rec, DICT_SYS_INDEXES_PAGE_NO_FIELD, &len);
ptr = rec_get_nth_field_old(
rec, DICT_FLD__SYS_INDEXES__PAGE_NO, &len);
ut_ad(len == 4);
@ -782,8 +814,8 @@ dict_truncate_index_tree(
drop = FALSE;
}
ptr = rec_get_nth_field_old(rec,
DICT_SYS_INDEXES_SPACE_NO_FIELD, &len);
ptr = rec_get_nth_field_old(
rec, DICT_FLD__SYS_INDEXES__SPACE, &len);
ut_ad(len == 4);
@ -803,12 +835,12 @@ dict_truncate_index_tree(
return(FIL_NULL);
}
ptr = rec_get_nth_field_old(rec,
DICT_SYS_INDEXES_TYPE_FIELD, &len);
ptr = rec_get_nth_field_old(
rec, DICT_FLD__SYS_INDEXES__TYPE, &len);
ut_ad(len == 4);
type = mach_read_from_4(ptr);
ptr = rec_get_nth_field_old(rec, 1, &len);
ptr = rec_get_nth_field_old(rec, DICT_FLD__SYS_INDEXES__ID, &len);
ut_ad(len == 8);
index_id = mach_read_from_8(ptr);
@ -835,7 +867,7 @@ create:
in SYS_INDEXES, so that the database will not get into an
inconsistent state in case it crashes between the mtr_commit()
below and the following mtr_commit() call. */
page_rec_write_field(rec, DICT_SYS_INDEXES_PAGE_NO_FIELD,
page_rec_write_field(rec, DICT_FLD__SYS_INDEXES__PAGE_NO,
FIL_NULL, mtr);
/* We will need to commit the mini-transaction in order to avoid
@ -882,7 +914,8 @@ tab_create_graph_create(
{
tab_node_t* node;
node = mem_heap_alloc(heap, sizeof(tab_node_t));
node = static_cast<tab_node_t*>(
mem_heap_alloc(heap, sizeof(tab_node_t)));
node->common.type = QUE_NODE_CREATE_TABLE;
@ -899,7 +932,7 @@ tab_create_graph_create(
heap);
node->col_def->common.parent = node;
node->commit_node = commit_node_create(heap);
node->commit_node = trx_commit_node_create(heap);
node->commit_node->common.parent = node;
return(node);
@ -918,7 +951,8 @@ ind_create_graph_create(
{
ind_node_t* node;
node = mem_heap_alloc(heap, sizeof(ind_node_t));
node = static_cast<ind_node_t*>(
mem_heap_alloc(heap, sizeof(ind_node_t)));
node->common.type = QUE_NODE_CREATE_INDEX;
@ -936,7 +970,7 @@ ind_create_graph_create(
dict_sys->sys_fields, heap);
node->field_def->common.parent = node;
node->commit_node = commit_node_create(heap);
node->commit_node = trx_commit_node_create(heap);
node->commit_node->common.parent = node;
return(node);
@ -960,7 +994,7 @@ dict_create_table_step(
trx = thr_get_trx(thr);
node = thr->run_node;
node = static_cast<tab_node_t*>(thr->run_node);
ut_ad(que_node_get_type(node) == QUE_NODE_CREATE_TABLE);
@ -1023,13 +1057,13 @@ dict_create_table_step(
if (node->state == TABLE_ADD_TO_CACHE) {
dict_table_add_to_cache(node->table, node->heap);
dict_table_add_to_cache(node->table, TRUE, node->heap);
err = DB_SUCCESS;
}
function_exit:
trx->error_state = err;
trx->error_state = (enum db_err) err;
if (err == DB_SUCCESS) {
/* Ok: do nothing */
@ -1067,7 +1101,7 @@ dict_create_index_step(
trx = thr_get_trx(thr);
node = thr->run_node;
node = static_cast<ind_node_t*>(thr->run_node);
ut_ad(que_node_get_type(node) == QUE_NODE_CREATE_INDEX);
@ -1121,7 +1155,7 @@ dict_create_index_step(
node->table, node->index, FIL_NULL,
trx_is_strict(trx)
|| dict_table_get_format(node->table)
>= DICT_TF_FORMAT_ZIP);
>= UNIV_FORMAT_B);
node->index = dict_index_get_if_in_cache_low(index_id);
ut_a(!node->index == (err != DB_SUCCESS));
@ -1163,7 +1197,7 @@ dict_create_index_step(
}
function_exit:
trx->error_state = err;
trx->error_state = static_cast<enum db_err>(err);
if (err == DB_SUCCESS) {
/* Ok: do nothing */
@ -1182,6 +1216,46 @@ function_exit:
return(thr);
}
/****************************************************************//**
Check whether the system foreign key tables exist. Additionally, If
they exist then move them to non-LRU end of the table LRU list.
@return TRUE if they exist. */
static
ibool
dict_check_sys_foreign_tables_exist(void)
/*=====================================*/
{
dict_table_t* sys_foreign;
ibool exists = FALSE;
dict_table_t* sys_foreign_cols;
ut_a(srv_get_active_thread_type() == SRV_NONE);
mutex_enter(&dict_sys->mutex);
sys_foreign = dict_table_get_low("SYS_FOREIGN");
sys_foreign_cols = dict_table_get_low("SYS_FOREIGN_COLS");
if (sys_foreign != NULL
&& sys_foreign_cols != NULL
&& UT_LIST_GET_LEN(sys_foreign->indexes) == 3
&& UT_LIST_GET_LEN(sys_foreign_cols->indexes) == 1) {
/* Foreign constraint system tables have already been
created, and they are ok. Ensure that they can't be
evicted from the table LRU cache. */
dict_table_move_from_lru_to_non_lru(sys_foreign);
dict_table_move_from_lru_to_non_lru(sys_foreign_cols);
exists = TRUE;
}
mutex_exit(&dict_sys->mutex);
return(exists);
}
/****************************************************************//**
Creates the foreign key constraints system tables inside InnoDB
at database creation or database start if they are not found or are
@ -1192,47 +1266,39 @@ ulint
dict_create_or_check_foreign_constraint_tables(void)
/*================================================*/
{
dict_table_t* table1;
dict_table_t* table2;
ulint error;
trx_t* trx;
ulint error;
ibool success;
ibool srv_file_per_table_backup;
mutex_enter(&(dict_sys->mutex));
ut_a(srv_get_active_thread_type() == SRV_NONE);
table1 = dict_table_get_low("SYS_FOREIGN");
table2 = dict_table_get_low("SYS_FOREIGN_COLS");
if (table1 && table2
&& UT_LIST_GET_LEN(table1->indexes) == 3
&& UT_LIST_GET_LEN(table2->indexes) == 1) {
/* Foreign constraint system tables have already been
created, and they are ok */
mutex_exit(&(dict_sys->mutex));
/* Note: The master thread has not been started at this point. */
if (dict_check_sys_foreign_tables_exist()) {
return(DB_SUCCESS);
}
mutex_exit(&(dict_sys->mutex));
trx = trx_allocate_for_mysql();
trx->op_info = "creating foreign key sys tables";
row_mysql_lock_data_dictionary(trx);
if (table1) {
/* Check which incomplete table definition to drop. */
if (dict_table_get_low("SYS_FOREIGN") != NULL) {
fprintf(stderr,
"InnoDB: dropping incompletely created"
" SYS_FOREIGN table\n");
row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE);
}
if (table2) {
if (dict_table_get_low("SYS_FOREIGN_COLS") != NULL) {
fprintf(stderr,
"InnoDB: dropping incompletely created"
" SYS_FOREIGN_COLS table\n");
row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE);
}
@ -1249,6 +1315,13 @@ dict_create_or_check_foreign_constraint_tables(void)
VARBINARY, like in other InnoDB system tables, to get a clean
design. */
srv_file_per_table_backup = (ibool) srv_file_per_table;
/* We always want SYSTEM tables to be created inside the system
tablespace. */
srv_file_per_table = 0;
error = que_eval_sql(NULL,
"PROCEDURE CREATE_FOREIGN_SYS_TABLES_PROC () IS\n"
"BEGIN\n"
@ -1300,6 +1373,14 @@ dict_create_or_check_foreign_constraint_tables(void)
" created\n");
}
/* Note: The master thread has not been started at this point. */
/* Confirm and move to the non-LRU part of the table LRU list. */
success = dict_check_sys_foreign_tables_exist();
ut_a(success);
srv_file_per_table = (my_bool) srv_file_per_table_backup;
return(error);
}
@ -1428,8 +1509,12 @@ dict_create_add_foreign_to_dictionary(
if (foreign->id == NULL) {
/* Generate a new constraint id */
char* id;
ulint namelen = strlen(table->name);
char* id = mem_heap_alloc(foreign->heap, namelen + 20);
id = static_cast<char*>(mem_heap_alloc(
foreign->heap, namelen + 20));
/* no overflow if number < 1e13 */
sprintf(id, "%s_ibfk_%lu", table->name, (ulong) (*id_nr)++);
foreign->id = id;
@ -1468,12 +1553,11 @@ dict_create_add_foreign_to_dictionary(
}
}
error = dict_foreign_eval_sql(NULL,
"PROCEDURE P () IS\n"
"BEGIN\n"
"COMMIT WORK;\n"
"END;\n"
, table, foreign, trx);
trx->op_info = "committing foreign key definitions";
trx_commit(trx);
trx->op_info = "";
return(error);
}

View file

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved.
Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved.
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 the Free Software
@ -11,13 +11,13 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
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
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
/******************************************************************//**
@file dict/dict0mem.c
@file dict/dict0mem.cc
Data dictionary memory object creation
Created 1/8/1996 Heikki Tuuri
@ -33,8 +33,10 @@ Created 1/8/1996 Heikki Tuuri
#include "data0type.h"
#include "mach0data.h"
#include "dict0dict.h"
#include "ha_prototypes.h" /* innobase_casedn_str()*/
#include "fts0priv.h"
#ifndef UNIV_HOTBACKUP
#include "ha_prototypes.h" /* innobase_casedn_str(),
innobase_get_lower_case_table_names */
# include "lock0lock.h"
#endif /* !UNIV_HOTBACKUP */
#ifdef UNIV_BLOB_DEBUG
@ -62,31 +64,40 @@ dict_mem_table_create(
ignored if the table is made a member of
a cluster */
ulint n_cols, /*!< in: number of columns */
ulint flags) /*!< in: table flags */
ulint flags, /*!< in: table flags */
ulint flags2) /*!< in: table flags2 */
{
dict_table_t* table;
mem_heap_t* heap;
ut_ad(name);
ut_a(!(flags & (~0 << DICT_TF2_BITS)));
dict_tf_validate(flags);
ut_a(!(flags2 & ~DICT_TF2_BIT_MASK));
heap = mem_heap_create(DICT_HEAP_SIZE);
table = mem_heap_zalloc(heap, sizeof(dict_table_t));
table = static_cast<dict_table_t*>(
mem_heap_zalloc(heap, sizeof(dict_table_t)));
table->heap = heap;
table->flags = (unsigned int) flags;
table->name = ut_malloc(strlen(name) + 1);
table->flags2 = (unsigned int) flags2;
table->name = static_cast<char*>(ut_malloc(strlen(name) + 1));
memcpy(table->name, name, strlen(name) + 1);
table->space = (unsigned int) space;
table->n_cols = (unsigned int) (n_cols + DATA_N_SYS_COLS);
table->cols = mem_heap_alloc(heap, (n_cols + DATA_N_SYS_COLS)
* sizeof(dict_col_t));
table->cols = static_cast<dict_col_t*>(
mem_heap_alloc(heap,
(n_cols + DATA_N_SYS_COLS)
* sizeof(dict_col_t)));
ut_d(table->magic_n = DICT_TABLE_MAGIC_N);
#ifndef UNIV_HOTBACKUP
table->autoinc_lock = mem_heap_alloc(heap, lock_get_size());
table->autoinc_lock = static_cast<ib_lock_t*>(
mem_heap_alloc(heap, lock_get_size()));
mutex_create(autoinc_mutex_key,
&table->autoinc_mutex, SYNC_DICT_AUTOINC_MUTEX);
@ -96,9 +107,20 @@ dict_mem_table_create(
/* The number of transactions that are either waiting on the
AUTOINC lock or have been granted the lock. */
table->n_waiting_or_granted_auto_inc_locks = 0;
/* If the table has an FTS index or we are in the process
of building one, create the table->fts */
if (dict_table_has_fts_index(table)
|| DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_HAS_DOC_ID)
|| DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_ADD_DOC_ID)) {
table->fts = fts_create(table);
table->fts->cache = fts_cache_create(table);
fts_optimize_add_table(table);
} else {
table->fts = NULL;
}
#endif /* !UNIV_HOTBACKUP */
ut_d(table->magic_n = DICT_TABLE_MAGIC_N);
return(table);
}
@ -114,6 +136,15 @@ dict_mem_table_free(
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
ut_d(table->cached = FALSE);
if (dict_table_has_fts_index(table)
|| DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_HAS_DOC_ID)
|| DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_ADD_DOC_ID)) {
if (table->fts) {
fts_free(table);
}
fts_optimize_remove_table(table);
}
#ifndef UNIV_HOTBACKUP
mutex_free(&(table->autoinc_mutex));
#endif /* UNIV_HOTBACKUP */
@ -158,7 +189,7 @@ dict_add_col_name(
new_len = strlen(name) + 1;
total_len = old_len + new_len;
res = mem_heap_alloc(heap, total_len);
res = static_cast<char*>(mem_heap_alloc(heap, total_len));
if (old_len > 0) {
memcpy(res, col_names, old_len);
@ -197,7 +228,9 @@ dict_mem_table_add_col(
}
if (UNIV_LIKELY(i) && UNIV_UNLIKELY(!table->col_names)) {
/* All preceding column names are empty. */
char* s = mem_heap_zalloc(heap, table->n_def);
char* s = static_cast<char*>(
mem_heap_zalloc(heap, table->n_def));
table->col_names = s;
}
@ -264,7 +297,9 @@ dict_mem_index_create(
ut_ad(table_name && index_name);
heap = mem_heap_create(DICT_HEAP_SIZE);
index = mem_heap_zalloc(heap, sizeof(dict_index_t));
index = static_cast<dict_index_t*>(
mem_heap_zalloc(heap, sizeof(*index)));
dict_mem_fill_index_struct(index, heap, table_name, index_name,
space, type, n_fields);
@ -272,6 +307,7 @@ dict_mem_index_create(
return(index);
}
#ifndef UNIV_HOTBACKUP
/**********************************************************************//**
Creates and initializes a foreign constraint memory object.
@return own: foreign constraint struct */
@ -285,7 +321,8 @@ dict_mem_foreign_create(void)
heap = mem_heap_create(100);
foreign = mem_heap_zalloc(heap, sizeof(dict_foreign_t));
foreign = static_cast<dict_foreign_t*>(
mem_heap_zalloc(heap, sizeof(dict_foreign_t)));
foreign->heap = heap;
@ -306,9 +343,13 @@ dict_mem_foreign_table_name_lookup_set(
{
if (innobase_get_lower_case_table_names() == 2) {
if (do_alloc) {
foreign->foreign_table_name_lookup = mem_heap_alloc(
foreign->heap,
strlen(foreign->foreign_table_name) + 1);
ulint len;
len = strlen(foreign->foreign_table_name) + 1;
foreign->foreign_table_name_lookup =
static_cast<char*>(
mem_heap_alloc(foreign->heap, len));
}
strcpy(foreign->foreign_table_name_lookup,
foreign->foreign_table_name);
@ -333,9 +374,13 @@ dict_mem_referenced_table_name_lookup_set(
{
if (innobase_get_lower_case_table_names() == 2) {
if (do_alloc) {
foreign->referenced_table_name_lookup = mem_heap_alloc(
foreign->heap,
strlen(foreign->referenced_table_name) + 1);
ulint len;
len = strlen(foreign->referenced_table_name) + 1;
foreign->referenced_table_name_lookup =
static_cast<char*>(
mem_heap_alloc(foreign->heap, len));
}
strcpy(foreign->referenced_table_name_lookup,
foreign->referenced_table_name);
@ -345,6 +390,7 @@ dict_mem_referenced_table_name_lookup_set(
= foreign->referenced_table_name;
}
}
#endif /* !UNIV_HOTBACKUP */
/**********************************************************************//**
Adds a field definition to an index. NOTE: does not take a copy

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved.
Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved.
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 the Free Software
@ -11,13 +11,13 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
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
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
/**************************************************//**
@file dyn/dyn0dyn.c
@file dyn/dyn0dyn.cc
The dynamically allocated array
Created 2/5/1996 Heikki Tuuri
@ -55,7 +55,8 @@ dyn_array_add_block(
heap = arr->heap;
block = mem_heap_alloc(heap, sizeof(dyn_block_t));
block = static_cast<dyn_block_t*>(
mem_heap_alloc(heap, sizeof(dyn_block_t)));
block->used = 0;

View file

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 1997, 2009, Innobase Oy. All Rights Reserved.
Copyright (c) 1997, 2011, Oracle and/or its affiliates. All Rights Reserved.
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 the Free Software
@ -11,13 +11,13 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
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
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
/**************************************************//**
@file eval/eval0eval.c
@file eval/eval0eval.cc
SQL evaluator: evaluates simple data structures, like expressions, in
a query graph
@ -32,6 +32,7 @@ Created 12/29/1997 Heikki Tuuri
#include "data0data.h"
#include "row0sel.h"
#include "rem0cmp.h"
/** The RND function seed */
static ulint eval_rnd = 128367121;
@ -41,6 +42,18 @@ eval_node_alloc_val_buf */
static byte eval_dummy;
/*************************************************************************
Gets the like node from the node */
UNIV_INLINE
que_node_t*
que_node_get_like_node(
/*===================*/
/* out: next node in a list of nodes */
que_node_t* node) /* in: node in a list */
{
return(((sym_node_t*) node)->like_node);
}
/*****************************************************************//**
Allocate a buffer from global dynamic memory for a value of a que_node.
NOTE that this memory must be explicitly freed when the query graph is
@ -65,7 +78,7 @@ eval_node_alloc_val_buf(
dfield = que_node_get_val(node);
data = dfield_get_data(dfield);
data = static_cast<byte*>(dfield_get_data(dfield));
if (data && data != &eval_dummy) {
mem_free(data);
@ -74,7 +87,7 @@ eval_node_alloc_val_buf(
if (size == 0) {
data = &eval_dummy;
} else {
data = mem_alloc(size);
data = static_cast<byte*>(mem_alloc(size));
}
que_node_set_val_buf_size(node, size);
@ -102,7 +115,7 @@ eval_node_free_val_buf(
dfield = que_node_get_val(node);
data = dfield_get_data(dfield);
data = static_cast<byte*>(dfield_get_data(dfield));
if (que_node_get_val_buf_size(node) > 0) {
ut_a(data);
@ -111,10 +124,80 @@ eval_node_free_val_buf(
}
}
/*****************************************************************//**
/*********************************************************************
Evaluates a LIKE comparison node.
@return the result of the comparison */
UNIV_INLINE
ibool
eval_cmp_like(
/*==========*/
que_node_t* arg1, /* !< in: left operand */
que_node_t* arg2) /* !< in: right operand */
{
ib_like_t op;
int res;
que_node_t* arg3;
que_node_t* arg4;
dfield_t* dfield;
dtype_t* dtype;
ibool val = TRUE;
arg3 = que_node_get_like_node(arg2);
/* Get the comparison type operator */
ut_a(arg3);
dfield = que_node_get_val(arg3);
dtype = dfield_get_type(dfield);
ut_a(dtype_get_mtype(dtype) == DATA_INT);
op = static_cast<ib_like_t>(mach_read_from_4(static_cast<const unsigned char*>(dfield_get_data(dfield))));
switch (op) {
case IB_LIKE_PREFIX:
arg4 = que_node_get_next(arg3);
res = cmp_dfield_dfield_like_prefix(
que_node_get_val(arg1),
que_node_get_val(arg4));
break;
case IB_LIKE_SUFFIX:
arg4 = que_node_get_next(arg3);
res = cmp_dfield_dfield_like_suffix(
que_node_get_val(arg1),
que_node_get_val(arg4));
break;
case IB_LIKE_SUBSTR:
arg4 = que_node_get_next(arg3);
res = cmp_dfield_dfield_like_substr(
que_node_get_val(arg1),
que_node_get_val(arg4));
break;
case IB_LIKE_EXACT:
res = cmp_dfield_dfield(
que_node_get_val(arg1),
que_node_get_val(arg2));
break;
default:
ut_error;
}
if (res != 0) {
val = FALSE;
}
return(val);
}
/*********************************************************************
Evaluates a comparison node.
@return the result of the comparison */
UNIV_INTERN
@return the result of the comparison */
ibool
eval_cmp(
/*=====*/
@ -123,45 +206,52 @@ eval_cmp(
que_node_t* arg1;
que_node_t* arg2;
int res;
ibool val;
int func;
ibool val = TRUE;
ut_ad(que_node_get_type(cmp_node) == QUE_NODE_FUNC);
arg1 = cmp_node->args;
arg2 = que_node_get_next(arg1);
res = cmp_dfield_dfield(que_node_get_val(arg1),
que_node_get_val(arg2));
val = TRUE;
func = cmp_node->func;
if (func == '=') {
if (res != 0) {
val = FALSE;
}
} else if (func == '<') {
if (res != -1) {
val = FALSE;
}
} else if (func == PARS_LE_TOKEN) {
if (res == 1) {
val = FALSE;
}
} else if (func == PARS_NE_TOKEN) {
if (res == 0) {
val = FALSE;
}
} else if (func == PARS_GE_TOKEN) {
if (res == -1) {
val = FALSE;
}
} else {
ut_ad(func == '>');
if (func == PARS_LIKE_TOKEN_EXACT
|| func == PARS_LIKE_TOKEN_PREFIX
|| func == PARS_LIKE_TOKEN_SUFFIX
|| func == PARS_LIKE_TOKEN_SUBSTR) {
if (res != 1) {
val = FALSE;
val = eval_cmp_like(arg1, arg2);
} else {
res = cmp_dfield_dfield(
que_node_get_val(arg1), que_node_get_val(arg2));
if (func == '=') {
if (res != 0) {
val = FALSE;
}
} else if (func == '<') {
if (res != -1) {
val = FALSE;
}
} else if (func == PARS_LE_TOKEN) {
if (res == 1) {
val = FALSE;
}
} else if (func == PARS_NE_TOKEN) {
if (res == 0) {
val = FALSE;
}
} else if (func == PARS_GE_TOKEN) {
if (res == -1) {
val = FALSE;
}
} else {
ut_ad(func == '>');
if (res != 1) {
val = FALSE;
}
}
}
@ -344,8 +434,8 @@ eval_predefined_2(
} else if (func == PARS_RND_TOKEN) {
len1 = (ulint)eval_node_get_int_val(arg1);
len2 = (ulint)eval_node_get_int_val(arg2);
len1 = (ulint) eval_node_get_int_val(arg1);
len2 = (ulint) eval_node_get_int_val(arg2);
ut_ad(len2 >= len1);
@ -362,7 +452,7 @@ eval_predefined_2(
} else if (func == PARS_RND_STR_TOKEN) {
len1 = (ulint)eval_node_get_int_val(arg1);
len1 = (ulint) eval_node_get_int_val(arg1);
data = eval_node_ensure_val_buf(func_node, len1);
@ -390,7 +480,7 @@ eval_notfound(
ut_ad(func_node->func == PARS_NOTFOUND_TOKEN);
cursor = func_node->args;
cursor = static_cast<sym_node_t*>(func_node->args);
ut_ad(que_node_get_type(cursor) == QUE_NODE_SYMBOL);
@ -436,10 +526,10 @@ eval_substr(
arg3 = que_node_get_next(arg2);
str1 = dfield_get_data(que_node_get_val(arg1));
str1 = static_cast<byte*>(dfield_get_data(que_node_get_val(arg1)));
len1 = (ulint)eval_node_get_int_val(arg2);
len2 = (ulint)eval_node_get_int_val(arg3);
len1 = (ulint) eval_node_get_int_val(arg2);
len2 = (ulint) eval_node_get_int_val(arg3);
dfield = que_node_get_val(func_node);
@ -471,11 +561,11 @@ eval_replstr(
arg3 = que_node_get_next(arg2);
arg4 = que_node_get_next(arg3);
str1 = dfield_get_data(que_node_get_val(arg1));
str2 = dfield_get_data(que_node_get_val(arg2));
str1 = static_cast<byte*>(dfield_get_data(que_node_get_val(arg1)));
str2 = static_cast<byte*>(dfield_get_data(que_node_get_val(arg2)));
len1 = (ulint)eval_node_get_int_val(arg3);
len2 = (ulint)eval_node_get_int_val(arg4);
len1 = (ulint) eval_node_get_int_val(arg3);
len2 = (ulint) eval_node_get_int_val(arg4);
if ((dfield_get_len(que_node_get_val(arg1)) < len1 + len2)
|| (dfield_get_len(que_node_get_val(arg2)) < len2)) {
@ -513,8 +603,8 @@ eval_instr(
dfield1 = que_node_get_val(arg1);
dfield2 = que_node_get_val(arg2);
str1 = dfield_get_data(dfield1);
str2 = dfield_get_data(dfield2);
str1 = static_cast<byte*>(dfield_get_data(dfield1));
str2 = static_cast<byte*>(dfield_get_data(dfield2));
len1 = dfield_get_len(dfield1);
len2 = dfield_get_len(dfield2);
@ -577,7 +667,7 @@ eval_binary_to_number(
dfield = que_node_get_val(arg1);
str1 = dfield_get_data(dfield);
str1 = static_cast<byte*>(dfield_get_data(dfield));
len1 = dfield_get_len(dfield);
if (len1 > 4) {
@ -588,7 +678,7 @@ eval_binary_to_number(
str2 = str1;
} else {
int_val = 0;
str2 = (byte*)&int_val;
str2 = (byte*) &int_val;
ut_memcpy(str2 + (4 - len1), str1, len1);
}
@ -659,7 +749,7 @@ eval_to_binary(
arg1 = func_node->args;
str1 = dfield_get_data(que_node_get_val(arg1));
str1 = static_cast<byte*>(dfield_get_data(que_node_get_val(arg1)));
if (dtype_get_mtype(que_node_get_data_type(arg1)) != DATA_INT) {
@ -674,7 +764,7 @@ eval_to_binary(
arg2 = que_node_get_next(arg1);
len1 = (ulint)eval_node_get_int_val(arg2);
len1 = (ulint) eval_node_get_int_val(arg2);
if (len1 > 4) {
@ -705,7 +795,7 @@ eval_predefined(
if (func == PARS_LENGTH_TOKEN) {
int_val = (lint)dfield_get_len(que_node_get_val(arg1));
int_val = (lint) dfield_get_len(que_node_get_val(arg1));
} else if (func == PARS_TO_CHAR_TOKEN) {
@ -768,7 +858,7 @@ eval_predefined(
dfield_get_data(que_node_get_val(arg1)));
} else if (func == PARS_SYSDATE_TOKEN) {
int_val = (lint)ut_time();
int_val = (lint) ut_time();
} else {
eval_predefined_2(func_node);
@ -787,12 +877,12 @@ eval_func(
func_node_t* func_node) /*!< in: function node */
{
que_node_t* arg;
ulint class;
ulint fclass;
ulint func;
ut_ad(que_node_get_type(func_node) == QUE_NODE_FUNC);
class = func_node->class;
fclass = func_node->fclass;
func = func_node->func;
arg = func_node->args;
@ -805,7 +895,7 @@ eval_func(
values, except for eval_cmp and notfound */
if (dfield_is_null(que_node_get_val(arg))
&& (class != PARS_FUNC_CMP)
&& (fclass != PARS_FUNC_CMP)
&& (func != PARS_NOTFOUND_TOKEN)
&& (func != PARS_PRINTF_TOKEN)) {
ut_error;
@ -814,34 +904,47 @@ eval_func(
arg = que_node_get_next(arg);
}
if (class == PARS_FUNC_CMP) {
switch (fclass) {
case PARS_FUNC_CMP:
eval_cmp(func_node);
} else if (class == PARS_FUNC_ARITH) {
return;
case PARS_FUNC_ARITH:
eval_arith(func_node);
} else if (class == PARS_FUNC_AGGREGATE) {
return;
case PARS_FUNC_AGGREGATE:
eval_aggregate(func_node);
} else if (class == PARS_FUNC_PREDEFINED) {
if (func == PARS_NOTFOUND_TOKEN) {
return;
case PARS_FUNC_PREDEFINED:
switch (func) {
case PARS_NOTFOUND_TOKEN:
eval_notfound(func_node);
} else if (func == PARS_SUBSTR_TOKEN) {
return;
case PARS_SUBSTR_TOKEN:
eval_substr(func_node);
} else if (func == PARS_REPLSTR_TOKEN) {
return;
case PARS_REPLSTR_TOKEN:
eval_replstr(func_node);
} else if (func == PARS_INSTR_TOKEN) {
return;
case PARS_INSTR_TOKEN:
eval_instr(func_node);
} else if (func == PARS_BINARY_TO_NUMBER_TOKEN) {
return;
case PARS_BINARY_TO_NUMBER_TOKEN:
eval_binary_to_number(func_node);
} else if (func == PARS_CONCAT_TOKEN) {
return;
case PARS_CONCAT_TOKEN:
eval_concat(func_node);
} else if (func == PARS_TO_BINARY_TOKEN) {
return;
case PARS_TO_BINARY_TOKEN:
eval_to_binary(func_node);
} else {
return;
default:
eval_predefined(func_node);
return;
}
} else {
ut_ad(class == PARS_FUNC_LOGICAL);
case PARS_FUNC_LOGICAL:
eval_logical(func_node);
return;
}
ut_error;
}

View file

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 1998, 2009, Innobase Oy. All Rights Reserved.
Copyright (c) 1998, 2011, Oracle and/or its affiliates. All Rights Reserved.
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 the Free Software
@ -11,13 +11,13 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
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
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
/**************************************************//**
@file eval/eval0proc.c
@file eval/eval0proc.cc
Executes SQL stored procedures and their control structures
Created 1/20/1998 Heikki Tuuri
@ -43,7 +43,7 @@ if_step(
ut_ad(thr);
node = thr->run_node;
node = static_cast<if_node_t*>(thr->run_node);
ut_ad(que_node_get_type(node) == QUE_NODE_IF);
if (thr->prev_node == que_node_get_parent(node)) {
@ -80,7 +80,8 @@ if_step(
break;
}
elsif_node = que_node_get_next(elsif_node);
elsif_node = static_cast<elsif_node_t*>(
que_node_get_next(elsif_node));
if (elsif_node == NULL) {
thr->run_node = NULL;
@ -118,7 +119,7 @@ while_step(
ut_ad(thr);
node = thr->run_node;
node = static_cast<while_node_t*>(thr->run_node);
ut_ad(que_node_get_type(node) == QUE_NODE_WHILE);
ut_ad((thr->prev_node == que_node_get_parent(node))
@ -154,7 +155,7 @@ assign_step(
ut_ad(thr);
node = thr->run_node;
node = static_cast<assign_node_t*>(thr->run_node);
ut_ad(que_node_get_type(node) == QUE_NODE_ASSIGNMENT);
/* Evaluate the value to assign */
@ -183,7 +184,7 @@ for_step(
ut_ad(thr);
node = thr->run_node;
node = static_cast<for_node_t*>(thr->run_node);
ut_ad(que_node_get_type(node) == QUE_NODE_FOR);
@ -244,7 +245,7 @@ exit_step(
ut_ad(thr);
node = thr->run_node;
node = static_cast<exit_node_t*>(thr->run_node);
ut_ad(que_node_get_type(node) == QUE_NODE_EXIT);
@ -276,7 +277,7 @@ return_step(
ut_ad(thr);
node = thr->run_node;
node = static_cast<return_node_t*>(thr->run_node);
ut_ad(que_node_get_type(node) == QUE_NODE_RETURN);

View file

@ -0,0 +1,32 @@
LEX=flex
YACC=bison
PREFIX=fts
all: fts0pars.cc fts0blex.cc fts0tlex.cc
fts0par.cc: fts0pars.y
fts0blex.cc: fts0blex.l
fts0tlex.cc: fts0tlex.l
.l.cc:
$(LEX) -P$(subst lex,,$*) -o $*.cc --header-file=../include/$*.h $<
.y.cc:
$(YACC) -p $(PREFIX) -o $*.cc -d $<
mv $*.h ../include
LEX=flex
YACC=bison
PREFIX=fts
all: fts0pars.cc fts0blex.cc fts0tlex.cc
fts0par.cc: fts0pars.y
fts0blex.cc: fts0blex.l
fts0tlex.cc: fts0tlex.l
.l.cc:
$(LEX) -P$(subst lex,,$*) -o $*.cc --header-file=../include/$*.h $<
.y.cc:
$(YACC) -p $(PREFIX) -o $*.cc -d $<
mv $*.h ../include

View file

@ -0,0 +1,416 @@
/*****************************************************************************
Copyright (c) 2007, 2011, Oracle and/or its affiliates. All Rights Reserved.
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 the Free Software
Foundation; version 2 of the License.
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.
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.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
/**************************************************//**
@file fts/fts0ast.cc
Full Text Search parser helper file.
Created 2007/3/16 Sunny Bains.
***********************************************************************/
#include "mem0mem.h"
#include "fts0ast.h"
#include "fts0pars.h"
/******************************************************************//**
Create an empty fts_ast_node_t.
@return Create a new node */
static
fts_ast_node_t*
fts_ast_node_create(void)
/*=====================*/
{
fts_ast_node_t* node;
node = (fts_ast_node_t*) ut_malloc(sizeof(*node));
memset(node, 0x0, sizeof(*node));
return(node);
}
/******************************************************************//**
Create a operator fts_ast_node_t.
@return new node */
UNIV_INTERN
fts_ast_node_t*
fts_ast_create_node_oper(
/*=====================*/
void* arg, /*!< in: ast state instance */
fts_ast_oper_t oper) /*!< in: ast operator */
{
fts_ast_node_t* node = fts_ast_node_create();
node->type = FTS_AST_OPER;
node->oper = oper;
fts_ast_state_add_node((fts_ast_state_t*) arg, node);
return(node);
}
/******************************************************************//**
This function takes ownership of the ptr and is responsible
for free'ing it
@return new node */
UNIV_INTERN
fts_ast_node_t*
fts_ast_create_node_term(
/*=====================*/
void* arg, /*!< in: ast state instance */
const char* ptr) /*!< in: ast term string */
{
ulint len = strlen(ptr);
fts_ast_node_t* node = fts_ast_node_create();
node->type = FTS_AST_TERM;
node->term.ptr = static_cast<byte*>(ut_malloc(len + 1));
memcpy(node->term.ptr, ptr, len + 1);
fts_ast_state_add_node((fts_ast_state_t*) arg, node);
return(node);
}
/******************************************************************//**
This function takes ownership of the ptr and is responsible
for free'ing it.
@return new node */
UNIV_INTERN
fts_ast_node_t*
fts_ast_create_node_text(
/*=====================*/
void* arg, /*!< in: ast state instance */
const char* ptr) /*!< in: ast text string */
{
/*!< We ignore the actual quotes "" */
ulint len = strlen(ptr) - 2;
fts_ast_node_t* node = fts_ast_node_create();
node->type = FTS_AST_TEXT;
node->text.ptr = static_cast<byte*>(ut_malloc(len + 1));
/*!< Skip copying the first quote */
memcpy(node->text.ptr, ptr + 1, len);
node->text.ptr[len] = 0;
node->text.distance = ULINT_UNDEFINED;
fts_ast_state_add_node((fts_ast_state_t*) arg, node);
return(node);
}
/******************************************************************//**
This function takes ownership of the expr and is responsible
for free'ing it.
@return new node */
UNIV_INTERN
fts_ast_node_t*
fts_ast_create_node_list(
/*=====================*/
void* arg, /*!< in: ast state instance */
fts_ast_node_t* expr) /*!< in: ast expr instance */
{
fts_ast_node_t* node = fts_ast_node_create();
node->type = FTS_AST_LIST;
node->list.head = node->list.tail = expr;
fts_ast_state_add_node((fts_ast_state_t*) arg, node);
return(node);
}
/******************************************************************//**
Create a sub-expression list node. This function takes ownership of
expr and is responsible for deleting it.
@return new node */
UNIV_INTERN
fts_ast_node_t*
fts_ast_create_node_subexp_list(
/*============================*/
void* arg, /*!< in: ast state instance */
fts_ast_node_t* expr) /*!< in: ast expr instance */
{
fts_ast_node_t* node = fts_ast_node_create();
node->type = FTS_AST_SUBEXP_LIST;
node->list.head = node->list.tail = expr;
fts_ast_state_add_node((fts_ast_state_t*) arg, node);
return(node);
}
/******************************************************************//**
Free an expr list node elements. */
static
void
fts_ast_free_list(
/*==============*/
fts_ast_node_t* node) /*!< in: ast node to free */
{
ut_a(node->type == FTS_AST_LIST
|| node->type == FTS_AST_SUBEXP_LIST);
for (node = node->list.head;
node != NULL;
node = fts_ast_free_node(node)) {
/*!< No op */
}
}
/********************************************************************//**
Free a fts_ast_node_t instance.
@return next node to free */
UNIV_INTERN
fts_ast_node_t*
fts_ast_free_node(
/*==============*/
fts_ast_node_t* node) /*!< in: the node to free */
{
fts_ast_node_t* next_node;
switch (node->type) {
case FTS_AST_TEXT:
if (node->text.ptr) {
ut_free(node->text.ptr);
node->text.ptr = NULL;
}
break;
case FTS_AST_TERM:
if (node->term.ptr) {
ut_free(node->term.ptr);
node->term.ptr = NULL;
}
break;
case FTS_AST_LIST:
case FTS_AST_SUBEXP_LIST:
fts_ast_free_list(node);
node->list.head = node->list.tail = NULL;
break;
case FTS_AST_OPER:
break;
default:
ut_error;
}
/*!< Get next node before freeing the node itself */
next_node = node->next;
ut_free(node);
return(next_node);
}
/******************************************************************//**
This AST takes ownership of the expr and is responsible
for free'ing it.
@return in param "list" */
UNIV_INTERN
fts_ast_node_t*
fts_ast_add_node(
/*=============*/
fts_ast_node_t* node, /*!< in: list instance */
fts_ast_node_t* elem) /*!< in: node to add to list */
{
if (!elem) {
return(NULL);
}
ut_a(!elem->next);
ut_a(node->type == FTS_AST_LIST
|| node->type == FTS_AST_SUBEXP_LIST);
if (!node->list.head) {
ut_a(!node->list.tail);
node->list.head = node->list.tail = elem;
} else {
ut_a(node->list.tail);
node->list.tail->next = elem;
node->list.tail = elem;
}
return(node);
}
/******************************************************************//**
For tracking node allocations, in case there is an error during
parsing. */
UNIV_INTERN
void
fts_ast_state_add_node(
/*===================*/
fts_ast_state_t*state, /*!< in: ast instance */
fts_ast_node_t* node) /*!< in: node to add to ast */
{
if (!state->list.head) {
ut_a(!state->list.tail);
state->list.head = state->list.tail = node;
} else {
state->list.tail->next_alloc = node;
state->list.tail = node;
}
}
/******************************************************************//**
Set the wildcard attribute of a term. */
UNIV_INTERN
void
fts_ast_term_set_wildcard(
/*======================*/
fts_ast_node_t* node) /*!< in/out: set attribute of
a term node */
{
ut_a(node->type == FTS_AST_TERM);
ut_a(!node->term.wildcard);
node->term.wildcard = TRUE;
}
/******************************************************************//**
Set the proximity attribute of a text node. */
UNIV_INTERN
void
fts_ast_term_set_distance(
/*======================*/
fts_ast_node_t* node, /*!< in/out: text node */
ulint distance) /*!< in: the text proximity
distance */
{
ut_a(node->type == FTS_AST_TEXT);
ut_a(node->text.distance == ULINT_UNDEFINED);
node->text.distance = distance;
}
/******************************************************************//**
Free node and expr allocations. */
UNIV_INTERN
void
fts_ast_state_free(
/*===============*/
fts_ast_state_t*state) /*!< in: ast state to free */
{
fts_ast_node_t* node = state->list.head;
/* Free the nodes that were allocated during parsing. */
while (node) {
fts_ast_node_t* next = node->next_alloc;
if (node->type == FTS_AST_TEXT && node->text.ptr) {
ut_free(node->text.ptr);
node->text.ptr = NULL;
} else if (node->type == FTS_AST_TERM && node->term.ptr) {
ut_free(node->term.ptr);
node->term.ptr = NULL;
}
ut_free(node);
node = next;
}
state->root = state->list.head = state->list.tail = NULL;
}
/******************************************************************//**
Print an ast node. */
UNIV_INTERN
void
fts_ast_node_print(
/*===============*/
fts_ast_node_t* node) /*!< in: ast node to print */
{
switch (node->type) {
case FTS_AST_TEXT:
printf("TEXT: %s\n", node->text.ptr);
break;
case FTS_AST_TERM:
printf("TERM: %s\n", node->term.ptr);
break;
case FTS_AST_LIST:
printf("LIST: ");
node = node->list.head;
while (node) {
fts_ast_node_print(node);
node = node->next;
}
break;
case FTS_AST_SUBEXP_LIST:
printf("SUBEXP_LIST: ");
node = node->list.head;
while (node) {
fts_ast_node_print(node);
node = node->next;
}
case FTS_AST_OPER:
printf("OPER: %d\n", node->oper);
break;
default:
ut_error;
}
}
/******************************************************************//**
Traverse the AST - in-order traversal.
@return DB_SUCCESS if all went well */
UNIV_INTERN
ulint
fts_ast_visit(
/*==========*/
fts_ast_oper_t oper, /*!< in: current operator */
fts_ast_node_t* node, /*!< in: current root node */
fts_ast_callback visitor, /*!< in: callback function */
void* arg) /*!< in: arg for callback */
{
ulint error = DB_SUCCESS;
ut_a(node->type == FTS_AST_LIST
|| node->type == FTS_AST_SUBEXP_LIST);
for (node = node->list.head;
node && error == DB_SUCCESS;
node = node->next) {
if (node->type == FTS_AST_LIST) {
error = fts_ast_visit(oper, node, visitor, arg);
} else if (node->type == FTS_AST_SUBEXP_LIST) {
error = fts_ast_visit_sub_exp(node, visitor, arg);
} else if (node->type == FTS_AST_OPER) {
oper = node->oper;
} else {
visitor(oper, node, arg);
}
}
return(error);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,73 @@
/*****************************************************************************
Copyright (c) 2007, 2011, Oracle and/or its affiliates. All Rights Reserved.
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 the Free Software
Foundation; version 2 of the License.
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.
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.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
/**
* @file fts/fts0blex.l
* FTS parser lexical analyzer
*
* Created 2007/5/9 Sunny Bains
*/
%{
#include "fts0ast.h"
#include "fts0pars.h"
/* Required for reentrant parser */
#define YY_DECL int fts_blexer(YYSTYPE* val, yyscan_t yyscanner)
%}
%option noinput
%option nounput
%option noyywrap
%option nostdinit
%option reentrant
%option never-interactive
%%
[\t ]+ /* Ignore whitespace */ ;
[*()+\-<>~@] {
val->oper = fts0bget_text(yyscanner)[0];
return(val->oper);
}
[0-9]+ {
val->token = strdup(fts0bget_text(yyscanner));
return(FTS_NUMB);
}
[^" \n*()+\-<>~@]* {
val->token = strdup(fts0bget_text(yyscanner));
return(FTS_TERM);
}
\"[^\"\n]*\" {
val->token = strdup(fts0bget_text(yyscanner));
return(FTS_TEXT);
}
\n
%%

View file

@ -0,0 +1,562 @@
/*****************************************************************************
Copyright (c) 2007, 2011, Oracle and/or its affiliates. All Rights Reserved.
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 the Free Software
Foundation; version 2 of the License.
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.
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.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
/******************************************************************//**
@file fts/fts0config.cc
Full Text Search configuration table.
Created 2007/5/9 Sunny Bains
***********************************************************************/
#include "trx0roll.h"
#include "row0sel.h"
#include "fts0priv.h"
#ifndef UNIV_NONINL
#include "fts0types.ic"
#include "fts0vlc.ic"
#endif
/******************************************************************//**
Callback function for fetching the config value.
@return always returns TRUE */
static
ibool
fts_config_fetch_value(
/*===================*/
void* row, /*!< in: sel_node_t* */
void* user_arg) /*!< in: pointer to
ib_vector_t */
{
sel_node_t* node = static_cast<sel_node_t*>(row);
fts_string_t* value = static_cast<fts_string_t*>(user_arg);
dfield_t* dfield = que_node_get_val(node->select_list);
dtype_t* type = dfield_get_type(dfield);
ulint len = dfield_get_len(dfield);
void* data = dfield_get_data(dfield);
ut_a(dtype_get_mtype(type) == DATA_VARCHAR);
if (len != UNIV_SQL_NULL) {
ulint max_len = ut_min(value->f_len - 1, len);
memcpy(value->f_str, data, max_len);
value->f_len = max_len;
value->f_str[value->f_len] = '\0';
}
return(TRUE);
}
/******************************************************************//**
Get value from the config table. The caller must ensure that enough
space is allocated for value to hold the column contents.
@return DB_SUCCESS or error code */
UNIV_INTERN
ulint
fts_config_get_value(
/*=================*/
trx_t* trx, /*!< transaction */
fts_table_t* fts_table, /*!< in: the indexed
FTS table */
const char* name, /*!< in: get config value for
this parameter name */
fts_string_t* value) /*!< out: value read from
config table */
{
pars_info_t* info;
que_t* graph;
ulint error;
ulint name_len = strlen(name);
info = pars_info_create();
*value->f_str = '\0';
ut_a(value->f_len > 0);
pars_info_bind_function(info, "my_func", fts_config_fetch_value,
value);
/* The len field of value must be set to the max bytes that
it can hold. On a successful read, the len field will be set
to the actual number of bytes copied to value. */
pars_info_bind_varchar_literal(info, "name", (byte*) name, name_len);
fts_table->suffix = "CONFIG";
graph = fts_parse_sql(
fts_table,
info,
"DECLARE FUNCTION my_func;\n"
"DECLARE CURSOR c IS SELECT value FROM %s"
" WHERE key = :name;\n"
"BEGIN\n"
""
"OPEN c;\n"
"WHILE 1 = 1 LOOP\n"
" FETCH c INTO my_func();\n"
" IF c % NOTFOUND THEN\n"
" EXIT;\n"
" END IF;\n"
"END LOOP;\n"
"CLOSE c;");
trx->op_info = "getting FTS config value";
error = fts_eval_sql(trx, graph);
mutex_enter(&dict_sys->mutex);
que_graph_free(graph);
mutex_exit(&dict_sys->mutex);
return(error);
}
/*********************************************************************//**
Create the config table name for retrieving index specific value.
@return index config parameter name */
UNIV_INTERN
char*
fts_config_create_index_param_name(
/*===============================*/
const char* param, /*!< in: base name of param */
const dict_index_t* index) /*!< in: index for config */
{
ulint len;
char* name;
/* The format of the config name is: name_<index_id>. */
len = strlen(param);
/* Caller is responsible for deleting name. */
name = static_cast<char*>(ut_malloc(
len + FTS_AUX_MIN_TABLE_ID_LENGTH + 2));
strcpy(name, param);
name[len] = '_';
fts_write_object_id(index->id, name + len + 1);
return(name);
}
/******************************************************************//**
Get value specific to an FTS index from the config table. The caller
must ensure that enough space is allocated for value to hold the
column contents.
@return DB_SUCCESS or error code */
UNIV_INTERN
ulint
fts_config_get_index_value(
/*=======================*/
trx_t* trx, /*!< transaction */
dict_index_t* index, /*!< in: index */
const char* param, /*!< in: get config value for
this parameter name */
fts_string_t* value) /*!< out: value read from
config table */
{
char* name;
ulint error;
fts_table_t fts_table;
FTS_INIT_FTS_TABLE(&fts_table, "CONFIG", FTS_COMMON_TABLE,
index->table);
/* We are responsible for free'ing name. */
name = fts_config_create_index_param_name(param, index);
error = fts_config_get_value(trx, &fts_table, name, value);
ut_free(name);
return(error);
}
/******************************************************************//**
Set the value in the config table for name.
@return DB_SUCCESS or error code */
UNIV_INTERN
ulint
fts_config_set_value(
/*=================*/
trx_t* trx, /*!< transaction */
fts_table_t* fts_table, /*!< in: the indexed
FTS table */
const char* name, /*!< in: get config value for
this parameter name */
const fts_string_t*
value) /*!< in: value to update */
{
pars_info_t* info;
que_t* graph;
ulint error;
undo_no_t undo_no;
undo_no_t n_rows_updated;
ulint name_len = strlen(name);
info = pars_info_create();
pars_info_bind_varchar_literal(info, "name", (byte*) name, name_len);
pars_info_bind_varchar_literal(info, "value",
value->f_str, value->f_len);
fts_table->suffix = "CONFIG";
graph = fts_parse_sql(
fts_table, info,
"BEGIN UPDATE %s SET value = :value WHERE key = :name;");
trx->op_info = "setting FTS config value";
undo_no = trx->undo_no;
error = fts_eval_sql(trx, graph);
fts_que_graph_free_check_lock(fts_table, NULL, graph);
n_rows_updated = trx->undo_no - undo_no;
/* Check if we need to do an insert. */
if (n_rows_updated == 0) {
info = pars_info_create();
pars_info_bind_varchar_literal(
info, "name", (byte*) name, name_len);
pars_info_bind_varchar_literal(
info, "value", value->f_str, value->f_len);
graph = fts_parse_sql(
fts_table, info,
"BEGIN\n"
"INSERT INTO %s VALUES(:name, :value);");
trx->op_info = "inserting FTS config value";
error = fts_eval_sql(trx, graph);
fts_que_graph_free_check_lock(fts_table, NULL, graph);
}
return(error);
}
/******************************************************************//**
Set the value specific to an FTS index in the config table.
@return DB_SUCCESS or error code */
UNIV_INTERN
ulint
fts_config_set_index_value(
/*=======================*/
trx_t* trx, /*!< transaction */
dict_index_t* index, /*!< in: index */
const char* param, /*!< in: get config value for
this parameter name */
fts_string_t* value) /*!< out: value read from
config table */
{
char* name;
ulint error;
fts_table_t fts_table;
FTS_INIT_FTS_TABLE(&fts_table, "CONFIG", FTS_COMMON_TABLE,
index->table);
/* We are responsible for free'ing name. */
name = fts_config_create_index_param_name(param, index);
error = fts_config_set_value(trx, &fts_table, name, value);
ut_free(name);
return(error);
}
/******************************************************************//**
Get an ulint value from the config table.
@return DB_SUCCESS if all OK else error code */
UNIV_INTERN
ulint
fts_config_get_index_ulint(
/*=======================*/
trx_t* trx, /*!< in: transaction */
dict_index_t* index, /*!< in: FTS index */
const char* name, /*!< in: param name */
ulint* int_value) /*!< out: value */
{
ulint error;
fts_string_t value;
/* We set the length of value to the max bytes it can hold. This
information is used by the callback that reads the value.*/
value.f_len = FTS_MAX_CONFIG_VALUE_LEN;
value.f_str = static_cast<byte*>(ut_malloc(value.f_len + 1));
error = fts_config_get_index_value(trx, index, name, &value);
if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
ut_print_timestamp(stderr);
fprintf(stderr, " InnoDB: Error: (%lu) reading `%s'\n",
error, name);
} else {
*int_value = strtoul((char*) value.f_str, NULL, 10);
}
ut_free(value.f_str);
return(error);
}
/******************************************************************//**
Set an ulint value in the config table.
@return DB_SUCCESS if all OK else error code */
UNIV_INTERN
ulint
fts_config_set_index_ulint(
/*=======================*/
trx_t* trx, /*!< in: transaction */
dict_index_t* index, /*!< in: FTS index */
const char* name, /*!< in: param name */
ulint int_value) /*!< in: value */
{
ulint error;
fts_string_t value;
/* We set the length of value to the max bytes it can hold. This
information is used by the callback that reads the value.*/
value.f_len = FTS_MAX_CONFIG_VALUE_LEN;
value.f_str = static_cast<byte*>(ut_malloc(value.f_len + 1));
// FIXME: Get rid of snprintf
ut_a(FTS_MAX_INT_LEN < FTS_MAX_CONFIG_VALUE_LEN);
value.f_len = ut_snprintf(
(char*) value.f_str, FTS_MAX_INT_LEN, "%lu", int_value);
error = fts_config_set_index_value(trx, index, name, &value);
if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
ut_print_timestamp(stderr);
fprintf(stderr, " InnoDB: Error: (%lu) writing `%s'\n",
error, name);
}
ut_free(value.f_str);
return(error);
}
/******************************************************************//**
Get an ulint value from the config table.
@return DB_SUCCESS if all OK else error code */
UNIV_INTERN
ulint
fts_config_get_ulint(
/*=================*/
trx_t* trx, /*!< in: transaction */
fts_table_t* fts_table, /*!< in: the indexed
FTS table */
const char* name, /*!< in: param name */
ulint* int_value) /*!< out: value */
{
ulint error;
fts_string_t value;
/* We set the length of value to the max bytes it can hold. This
information is used by the callback that reads the value.*/
value.f_len = FTS_MAX_CONFIG_VALUE_LEN;
value.f_str = static_cast<byte*>(ut_malloc(value.f_len + 1));
error = fts_config_get_value(trx, fts_table, name, &value);
if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
ut_print_timestamp(stderr);
fprintf(stderr, " InnoDB: Error: (%lu) reading `%s'\n",
error, name);
} else {
*int_value = strtoul((char*) value.f_str, NULL, 10);
}
ut_free(value.f_str);
return(error);
}
/******************************************************************//**
Set an ulint value in the config table.
@return DB_SUCCESS if all OK else error code */
UNIV_INTERN
ulint
fts_config_set_ulint(
/*=================*/
trx_t* trx, /*!< in: transaction */
fts_table_t* fts_table, /*!< in: the indexed
FTS table */
const char* name, /*!< in: param name */
ulint int_value) /*!< in: value */
{
ulint error;
fts_string_t value;
/* We set the length of value to the max bytes it can hold. This
information is used by the callback that reads the value.*/
value.f_len = FTS_MAX_CONFIG_VALUE_LEN;
value.f_str = static_cast<byte*>(ut_malloc(value.f_len + 1));
// FIXME: Get rid of snprintf
ut_a(FTS_MAX_INT_LEN < FTS_MAX_CONFIG_VALUE_LEN);
value.f_len = snprintf(
(char*) value.f_str, FTS_MAX_INT_LEN, "%lu", int_value);
error = fts_config_set_value(trx, fts_table, name, &value);
if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
ut_print_timestamp(stderr);
fprintf(stderr, " InnoDB: Error: (%lu) writing `%s'\n",
error, name);
}
ut_free(value.f_str);
return(error);
}
/******************************************************************//**
Increment the value in the config table for column name.
@return DB_SUCCESS or error code */
UNIV_INTERN
ulint
fts_config_increment_value(
/*=======================*/
trx_t* trx, /*!< transaction */
fts_table_t* fts_table, /*!< in: the indexed
FTS table */
const char* name, /*!< in: increment config value
for this parameter name */
ulint delta) /*!< in: increment by this
much */
{
ulint error;
fts_string_t value;
que_t* graph = NULL;
ulint name_len = strlen(name);
pars_info_t* info = pars_info_create();
/* We set the length of value to the max bytes it can hold. This
information is used by the callback that reads the value.*/
value.f_len = FTS_MAX_CONFIG_VALUE_LEN;
value.f_str = static_cast<byte*>(ut_malloc(value.f_len + 1));
*value.f_str = '\0';
pars_info_bind_varchar_literal(info, "name", (byte*) name, name_len);
pars_info_bind_function(
info, "my_func", fts_config_fetch_value, &value);
fts_table->suffix = "CONFIG";
graph = fts_parse_sql(
fts_table, info,
"DECLARE FUNCTION my_func;\n"
"DECLARE CURSOR c IS SELECT value FROM %s"
" WHERE key = :name FOR UPDATE;\n"
"BEGIN\n"
""
"OPEN c;\n"
"WHILE 1 = 1 LOOP\n"
" FETCH c INTO my_func();\n"
" IF c % NOTFOUND THEN\n"
" EXIT;\n"
" END IF;\n"
"END LOOP;\n"
"CLOSE c;");
trx->op_info = "read FTS config value";
error = fts_eval_sql(trx, graph);
fts_que_graph_free_check_lock(fts_table, NULL, graph);
if (UNIV_UNLIKELY(error == DB_SUCCESS)) {
ulint int_value;
int_value = strtoul((char*) value.f_str, NULL, 10);
int_value += delta;
ut_a(FTS_MAX_CONFIG_VALUE_LEN > FTS_MAX_INT_LEN);
// FIXME: Get rid of snprintf
value.f_len = snprintf(
(char*) value.f_str, FTS_MAX_INT_LEN, "%lu", int_value);
fts_config_set_value(trx, fts_table, name, &value);
}
if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
ut_print_timestamp(stderr);
fprintf(stderr, " InnoDB: Error: (%lu) "
"while incrementing %s.\n", error, name);
}
ut_free(value.f_str);
return(error);
}
/******************************************************************//**
Increment the per index value in the config table for column name.
@return DB_SUCCESS or error code */
UNIV_INTERN
ulint
fts_config_increment_index_value(
/*=============================*/
trx_t* trx, /*!< transaction */
dict_index_t* index, /*!< in: FTS index */
const char* param, /*!< in: increment config value
for this parameter name */
ulint delta) /*!< in: increment by this
much */
{
char* name;
ulint error;
fts_table_t fts_table;
FTS_INIT_FTS_TABLE(&fts_table, "CONFIG", FTS_COMMON_TABLE,
index->table);
/* We are responsible for free'ing name. */
name = fts_config_create_index_param_name(param, index);
error = fts_config_increment_value(trx, &fts_table, name, delta);
ut_free(name);
return(error);
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,285 @@
/*****************************************************************************
Copyright (c) 2007, 2011, Oracle and/or its affiliates. All Rights Reserved.
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 the Free Software
Foundation; version 2 of the License.
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.
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.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
/**
* @file fts/fts0pars.y
* FTS parser: input file for the GNU Bison parser generator
*
* Created 2007/5/9 Sunny Bains
*/
%{
#include "mem0mem.h"
#include "fts0ast.h"
#include "fts0blex.h"
#include "fts0tlex.h"
#include "fts0pars.h"
extern int fts_lexer(YYSTYPE*, fts_lexer_t*);
extern int fts_blexer(YYSTYPE*, yyscan_t);
extern int fts_tlexer(YYSTYPE*, yyscan_t);
typedef int (*fts_scan)();
extern int ftserror(const char* p);
/* Required for reentrant parser */
#define ftslex fts_lexer
#define YYERROR_VERBOSE
/* For passing an argument to yyparse() */
#define YYPARSE_PARAM state
#define YYLEX_PARAM ((fts_ast_state_t*) state)->lexer
typedef int (*fts_scanner_alt)(YYSTYPE* val, yyscan_t yyscanner);
typedef int (*fts_scanner)();
struct fts_lexer_struct {
fts_scanner scanner;
void* yyscanner;
};
%}
%union {
int oper;
char* token;
fts_ast_node_t* node;
};
/* Enable re-entrant parser */
%pure_parser
%token<oper> FTS_OPER
%token<token> FTS_TEXT FTS_TERM FTS_NUMB
%type<node> prefix term text expr sub_expr expr_lst query
%nonassoc '+' '-' '~' '<' '>'
%%
query : expr_lst {
$$ = $1;
((fts_ast_state_t*) state)->root = $$;
}
;
expr_lst: /* Empty */ {
$$ = NULL;
}
| expr_lst expr {
$$ = $1;
if (!$$) {
$$ = fts_ast_create_node_list(state, $2);
} else {
fts_ast_add_node($$, $2);
}
}
| expr_lst sub_expr {
$$ = $1;
$$ = fts_ast_create_node_list(state, $1);
if (!$$) {
$$ = fts_ast_create_node_subexp_list(state, $2);
} else {
fts_ast_add_node($$, $2);
}
}
;
sub_expr: '(' expr_lst ')' {
$$ = $2;
}
| prefix '(' expr_lst ')' {
$$ = fts_ast_create_node_subexp_list(state, $1);
if ($3) {
fts_ast_add_node($$, $3);
}
}
;
expr : term {
$$ = $1;
}
| text {
$$ = $1;
}
| term '*' {
fts_ast_term_set_wildcard($1);
}
| text '@' FTS_NUMB {
fts_ast_term_set_distance($1, strtoul($3, NULL, 10));
free($3);
}
| prefix term '*' {
$$ = fts_ast_create_node_list(state, $1);
fts_ast_add_node($$, $2);
fts_ast_term_set_wildcard($2);
}
| prefix term {
$$ = fts_ast_create_node_list(state, $1);
fts_ast_add_node($$, $2);
}
| prefix text '@' FTS_NUMB {
$$ = fts_ast_create_node_list(state, $1);
fts_ast_add_node($$, $2);
fts_ast_term_set_distance($2, strtoul($4, NULL, 10));
free($4);
}
| prefix text {
$$ = fts_ast_create_node_list(state, $1);
fts_ast_add_node($$, $2);
}
;
prefix : '-' {
$$ = fts_ast_create_node_oper(state, FTS_IGNORE);
}
| '+' {
$$ = fts_ast_create_node_oper(state, FTS_EXIST);
}
| '~' {
$$ = fts_ast_create_node_oper(state, FTS_NEGATE);
}
| '<' {
$$ = fts_ast_create_node_oper(state, FTS_DECR_RATING);
}
| '>' {
$$ = fts_ast_create_node_oper(state, FTS_INCR_RATING);
}
;
term : FTS_TERM {
$$ = fts_ast_create_node_term(state, $1);
free($1);
}
| FTS_NUMB {
$$ = fts_ast_create_node_term(state, $1);
free($1);
}
;
text : FTS_TEXT {
$$ = fts_ast_create_node_text(state, $1);
free($1);
}
;
%%
/********************************************************************
*/
int
ftserror(
/*=====*/
const char* p)
{
fprintf(stderr, "%s\n", p);
return(0);
}
/********************************************************************
Create a fts_lexer_t instance.*/
fts_lexer_t*
fts_lexer_create(
/*=============*/
ibool boolean_mode,
const byte* query,
ulint query_len)
{
fts_lexer_t* fts_lexer = static_cast<fts_lexer_t*>(
ut_malloc(sizeof(fts_lexer_t)));
if (boolean_mode) {
fts0blex_init(&fts_lexer->yyscanner);
fts0b_scan_bytes((char*) query, query_len, fts_lexer->yyscanner);
fts_lexer->scanner = (fts_scan) fts_blexer;
/* FIXME: Debugging */
/* fts0bset_debug(1 , fts_lexer->yyscanner); */
} else {
fts0tlex_init(&fts_lexer->yyscanner);
fts0t_scan_bytes((char*) query, query_len, fts_lexer->yyscanner);
fts_lexer->scanner = (fts_scan) fts_tlexer;
}
return(fts_lexer);
}
/********************************************************************
Free an fts_lexer_t instance.*/
void
fts_lexer_free(
/*===========*/
fts_lexer_t* fts_lexer)
{
if (fts_lexer->scanner == (fts_scan) fts_blexer) {
fts0blex_destroy(fts_lexer->yyscanner);
} else {
fts0tlex_destroy(fts_lexer->yyscanner);
}
ut_free(fts_lexer);
}
/********************************************************************
Call the appropaiate scanner.*/
int
fts_lexer(
/*======*/
YYSTYPE* val,
fts_lexer_t* fts_lexer)
{
fts_scanner_alt func_ptr;
func_ptr = (fts_scanner_alt) fts_lexer->scanner;
return(func_ptr(val, fts_lexer->yyscanner));
}
/********************************************************************
Parse the query.*/
int
fts_parse(
/*======*/
fts_ast_state_t* state)
{
return(ftsparse(state));
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,355 @@
/*****************************************************************************
Copyright (c) 2007, 2011, Oracle and/or its affiliates. All Rights Reserved.
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 the Free Software
Foundation; version 2 of the License.
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.
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.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
/**************************************************//**
@file fts/fts0sql.cc
Full Text Search functionality.
Created 2007-03-27 Sunny Bains
*******************************************************/
#include "que0que.h"
#include "trx0roll.h"
#include "pars0pars.h"
#include "dict0dict.h"
#include "fts0types.h"
#include "fts0priv.h"
#ifndef UNIV_NONINL
#include "fts0types.ic"
#include "fts0vlc.ic"
#endif
/** SQL statements for creating the ancillary FTS tables. %s must be replaced
with the indexed table's id. */
/** Preamble to all SQL statements. */
static const char* fts_sql_begin=
"PROCEDURE P() IS\n";
/** Postamble to non-committing SQL statements. */
static const char* fts_sql_end=
"\n"
"END;\n";
/******************************************************************//**
Get the table id.
@return number of bytes written */
UNIV_INTERN
int
fts_get_table_id(
/*=============*/
const fts_table_t*
fts_table, /*!< in: FTS Auxiliary table */
char* table_id) /*!< out: table id, must be at least
FTS_AUX_MIN_TABLE_ID_LENGTH bytes
long */
{
int len;
switch (fts_table->type) {
case FTS_COMMON_TABLE:
len = fts_write_object_id(fts_table->table_id, table_id);
break;
case FTS_INDEX_TABLE:
len = fts_write_object_id(fts_table->table_id, table_id);
table_id[len] = '_';
++len;
table_id += len;
len += fts_write_object_id(fts_table->index_id, table_id);
break;
default:
ut_error;
}
ut_a(len >= 16);
ut_a(len < FTS_AUX_MIN_TABLE_ID_LENGTH);
return(len);
}
/******************************************************************//**
Construct the prefix name of an FTS table.
@return own: table name, must be freed with mem_free() */
UNIV_INTERN
char*
fts_get_table_name_prefix(
/*======================*/
const fts_table_t*
fts_table) /*!< in: Auxiliary table type */
{
int len;
const char* slash;
char* prefix_name;
int dbname_len = 0;
int prefix_name_len;
char table_id[FTS_AUX_MIN_TABLE_ID_LENGTH];
slash = static_cast<const char*>(
memchr(fts_table->parent, '/', strlen(fts_table->parent)));
if (slash) {
/* Print up to and including the separator. */
dbname_len = (slash - fts_table->parent) + 1;
}
len = fts_get_table_id(fts_table, table_id);
prefix_name_len = dbname_len + 4 + len + 1;
prefix_name = static_cast<char*>(mem_alloc(prefix_name_len));
len = sprintf(prefix_name, "%.*sFTS_%s",
dbname_len, fts_table->parent, table_id);
ut_a(len > 0);
ut_a(len == prefix_name_len - 1);
return(prefix_name);
}
/******************************************************************//**
Construct the name of an ancillary FTS table.
@return own: table name, must be freed with mem_free() */
UNIV_INTERN
char*
fts_get_table_name(
/*===============*/
const fts_table_t* fts_table)
/*!< in: Auxiliary table type */
{
int len;
char* name;
int name_len;
char* prefix_name;
prefix_name = fts_get_table_name_prefix(fts_table);
name_len = strlen(prefix_name) + 1 + strlen(fts_table->suffix) + 1;
name = static_cast<char*>(mem_alloc(name_len));
len = sprintf(name, "%s_%s", prefix_name, fts_table->suffix);
ut_a(len > 0);
ut_a(len == name_len - 1);
mem_free(prefix_name);
return(name);
}
/******************************************************************//**
Parse an SQL string. %s is replaced with the table's id.
@return query graph */
UNIV_INTERN
que_t*
fts_parse_sql(
/*==========*/
fts_table_t* fts_table, /*!< in: FTS auxiliarry table info */
pars_info_t* info, /*!< in: info struct, or NULL */
const char* sql) /*!< in: SQL string to evaluate */
{
char* str;
que_t* graph;
char* str_tmp;
ibool dict_locked;
if (fts_table != NULL) {
char* table_name;
table_name = fts_get_table_name(fts_table);
str_tmp = ut_strreplace(sql, "%s", table_name);
mem_free(table_name);
} else {
ulint sql_len = strlen(sql) + 1;
str_tmp = static_cast<char*>(mem_alloc(sql_len));
strcpy(str_tmp, sql);
}
str = ut_str3cat(fts_sql_begin, str_tmp, fts_sql_end);
mem_free(str_tmp);
dict_locked = (fts_table && fts_table->table
&& (fts_table->table->fts->fts_status
& TABLE_DICT_LOCKED));
if (!dict_locked) {
ut_ad(!mutex_own(&(dict_sys->mutex)));
/* The InnoDB SQL parser is not re-entrant. */
mutex_enter(&dict_sys->mutex);
}
graph = pars_sql(info, str);
ut_a(graph);
if (!dict_locked) {
mutex_exit(&dict_sys->mutex);
}
mem_free(str);
return(graph);
}
/******************************************************************//**
Parse an SQL string. %s is replaced with the table's id.
@return query graph */
UNIV_INTERN
que_t*
fts_parse_sql_no_dict_lock(
/*=======================*/
fts_table_t* fts_table, /*!< in: FTS aux table info */
pars_info_t* info, /*!< in: info struct, or NULL */
const char* sql) /*!< in: SQL string to evaluate */
{
char* str;
que_t* graph;
char* str_tmp = NULL;
#ifdef UNIV_DEBUG
ut_ad(mutex_own(&dict_sys->mutex));
#endif
if (fts_table != NULL) {
char* table_name;
table_name = fts_get_table_name(fts_table);
str_tmp = ut_strreplace(sql, "%s", table_name);
mem_free(table_name);
}
if (str_tmp != NULL) {
str = ut_str3cat(fts_sql_begin, str_tmp, fts_sql_end);
mem_free(str_tmp);
} else {
str = ut_str3cat(fts_sql_begin, sql, fts_sql_end);
}
//fprintf(stderr, "%s\n", str);
graph = pars_sql(info, str);
ut_a(graph);
mem_free(str);
return(graph);
}
/******************************************************************//**
Evaluate an SQL query graph.
@return DB_SUCCESS or error code */
UNIV_INTERN
ulint
fts_eval_sql(
/*=========*/
trx_t* trx, /*!< in: transaction */
que_t* graph) /*!< in: Query graph to evaluate */
{
que_thr_t* thr;
graph->trx = trx;
graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
ut_a(thr = que_fork_start_command(graph));
que_run_threads(thr);
return(trx->error_state);
}
/******************************************************************//**
Construct the column specification part of the SQL string for selecting the
indexed FTS columns for the given table. Adds the necessary bound
ids to the given 'info' and returns the SQL string. Examples:
One indexed column named "text":
"$sel0",
info/ids: sel0 -> "text"
Two indexed columns named "subject" and "content":
"$sel0, $sel1",
info/ids: sel0 -> "subject", sel1 -> "content",
@return heap-allocated WHERE string */
UNIV_INTERN
const char*
fts_get_select_columns_str(
/*=======================*/
dict_index_t* index, /*!< in: index */
pars_info_t* info, /*!< in/out: parser info */
mem_heap_t* heap) /*!< in: memory heap */
{
ulint i;
const char* str = "";
for (i = 0; i < index->n_user_defined_cols; i++) {
char* sel_str;
dict_field_t* field = dict_index_get_nth_field(index, i);
sel_str = mem_heap_printf(heap, "sel%lu", (ulong) i);
/* Set copy_name to TRUE since it's dynamic. */
pars_info_bind_id(info, TRUE, sel_str, field->name);
str = mem_heap_printf(
heap, "%s%s$%s", str, (*str) ? ", " : "", sel_str);
}
return(str);
}
/******************************************************************//**
Commit a transaction.
@return DB_SUCCESS or error code */
UNIV_INTERN
ulint
fts_sql_commit(
/*===========*/
trx_t* trx) /*!< in: transaction */
{
ulint error;
error = trx_commit_for_mysql(trx);
/* Commit above returns 0 on success, it should always succeed */
ut_a(error == DB_SUCCESS);
return(DB_SUCCESS);
}
/******************************************************************//**
Rollback a transaction.
@return DB_SUCCESS or error code */
UNIV_INTERN
ulint
fts_sql_rollback(
/*=============*/
trx_t* trx) /*!< in: transaction */
{
return(trx_rollback_to_savepoint(trx, NULL));
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,68 @@
/*****************************************************************************
Copyright (c) 2007, 2011, Oracle and/or its affiliates. All Rights Reserved.
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 the Free Software
Foundation; version 2 of the License.
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.
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.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
/**
* @file fts/fts0tlex.l
* FTS parser lexical analyzer
*
* Created 2007/5/9 Sunny Bains
*/
%{
#include "fts0ast.h"
#include "fts0pars.h"
/* Required for reentrant parser */
#define YY_DECL int fts_tlexer(YYSTYPE* val, yyscan_t yyscanner)
%}
%option noinput
%option nounput
%option noyywrap
%option nostdinit
%option reentrant
%option never-interactive
%%
[\t ]+ /* Ignore whitespace */ ;
[*] {
val->oper = fts0tget_text(yyscanner)[0];
return(val->oper);
}
\"[^\"\n]*\" {
val->token = strdup(fts0tget_text(yyscanner));
return(FTS_TEXT);
}
[^" \n]* {
val->token = strdup(fts0tget_text(yyscanner));
return(FTS_TERM);
}
\n
%%

View file

@ -0,0 +1,49 @@
#!/bin/sh
#
# Copyright (c) 2007, 2011, Oracle and/or its affiliates. All Rights Reserved.
#
# 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 the Free Software
# Foundation; version 2 of the License.
#
# 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.
#
# 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.,
# 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
TMPF=t.$$
make -f Makefile.query
echo '#include "univ.i"' > $TMPF
# This is to avoid compiler warning about unused parameters.
# FIXME: gcc extension "__attribute__" causing compilation errors on windows
# platform. Quote them out for now.
sed -e '
s/^\(static.*void.*yy_fatal_error.*msg.*,\)\(.*yyscanner\)/\1 \2 __attribute__((unused))/;
s/^\(static.*void.*yy_flex_strncpy.*n.*,\)\(.*yyscanner\)/\1 \2 __attribute__((unused))/;
s/^\(static.*int.*yy_flex_strlen.*s.*,\)\(.*yyscanner\)/\1 \2 __attribute__((unused))/;
s/^\(\(static\|void\).*fts0[bt]alloc.*,\)\(.*yyscanner\)/\1 \3 __attribute__((unused))/;
s/^\(\(static\|void\).*fts0[bt]realloc.*,\)\(.*yyscanner\)/\1 \3 __attribute__((unused))/;
s/^\(\(static\|void\).*fts0[bt]free.*,\)\(.*yyscanner\)/\1 \3 __attribute__((unused))/;
' < fts0blex.cc >> $TMPF
mv $TMPF fts0blex.cc
echo '#include "univ.i"' > $TMPF
sed -e '
s/^\(static.*void.*yy_fatal_error.*msg.*,\)\(.*yyscanner\)/\1 \2 __attribute__((unused))/;
s/^\(static.*void.*yy_flex_strncpy.*n.*,\)\(.*yyscanner\)/\1 \2 __attribute__((unused))/;
s/^\(static.*int.*yy_flex_strlen.*s.*,\)\(.*yyscanner\)/\1 \2 __attribute__((unused))/;
s/^\(\(static\|void\).*fts0[bt]alloc.*,\)\(.*yyscanner\)/\1 \3 __attribute__((unused))/;
s/^\(\(static\|void\).*fts0[bt]realloc.*,\)\(.*yyscanner\)/\1 \3 __attribute__((unused))/;
s/^\(\(static\|void\).*fts0[bt]free.*,\)\(.*yyscanner\)/\1 \3 __attribute__((unused))/;
' < fts0tlex.cc >> $TMPF
mv $TMPF fts0tlex.cc

View file

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved.
Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
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 the Free Software
@ -11,13 +11,13 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
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
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
/******************************************************************//**
@file fut/fut0fut.c
@file fut/fut0fut.cc
File-based utilities
Created 12/13/1995 Heikki Tuuri

View file

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved.
Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
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 the Free Software
@ -11,13 +11,13 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
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
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
/******************************************************************//**
@file fut/fut0lst.c
@file fut/fut0lst.cc
File-based list utilities
Created 11/28/1995 Heikki Tuuri

View file

@ -11,13 +11,13 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
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
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
/********************************************************************//**
@file ha/ha0ha.c
@file ha/ha0ha.cc
The hash table with external chains
Created 8/22/1994 Heikki Tuuri
@ -31,7 +31,9 @@ Created 8/22/1994 Heikki Tuuri
#ifdef UNIV_DEBUG
# include "buf0buf.h"
#endif /* UNIV_DEBUG */
#include "btr0sea.h"
#ifndef UNIV_HOTBACKUP
# include "btr0sea.h"
#endif /* !UNIV_HOTBACKUP */
#include "page0page.h"
/*************************************************************//**
@ -44,43 +46,56 @@ ha_create_func(
/*===========*/
ulint n, /*!< in: number of array cells */
#ifdef UNIV_SYNC_DEBUG
ulint mutex_level, /*!< in: level of the mutexes in the latching
order: this is used in the debug version */
ulint sync_level, /*!< in: level of the mutexes or rw_locks
in the latching order: this is used in the
debug version */
#endif /* UNIV_SYNC_DEBUG */
ulint n_mutexes) /*!< in: number of mutexes to protect the
hash table: must be a power of 2, or 0 */
ulint n_sync_obj, /*!< in: number of mutexes or rw_locks
to protect the hash table: must be a
power of 2, or 0 */
ulint type) /*!< in: type of datastructure for which
the memory heap is going to be used e.g.:
MEM_HEAP_FOR_BTR_SEARCH or
MEM_HEAP_FOR_PAGE_HASH */
{
hash_table_t* table;
#ifndef UNIV_HOTBACKUP
ulint i;
#endif /* !UNIV_HOTBACKUP */
ut_ad(ut_is_2pow(n_mutexes));
ut_a(type == MEM_HEAP_FOR_BTR_SEARCH
|| type == MEM_HEAP_FOR_PAGE_HASH);
ut_ad(ut_is_2pow(n_sync_obj));
table = hash_create(n);
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
# ifndef UNIV_HOTBACKUP
table->adaptive = TRUE;
# endif /* !UNIV_HOTBACKUP */
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
/* Creating MEM_HEAP_BTR_SEARCH type heaps can potentially fail,
but in practise it never should in this case, hence the asserts. */
if (n_mutexes == 0) {
table->heap = mem_heap_create_in_btr_search(
ut_min(4096, MEM_MAX_ALLOC_IN_BUF));
if (n_sync_obj == 0) {
table->heap = mem_heap_create_typed(
ut_min(4096, MEM_MAX_ALLOC_IN_BUF), type);
ut_a(table->heap);
return(table);
}
#ifndef UNIV_HOTBACKUP
hash_create_mutexes(table, n_mutexes, mutex_level);
if (type == MEM_HEAP_FOR_PAGE_HASH) {
/* We create a hash table protected by rw_locks for
buf_pool->page_hash. */
hash_create_sync_obj(table, HASH_TABLE_SYNC_RW_LOCK,
n_sync_obj, sync_level);
} else {
hash_create_sync_obj(table, HASH_TABLE_SYNC_MUTEX,
n_sync_obj, sync_level);
}
table->heaps = mem_alloc(n_mutexes * sizeof(void*));
table->heaps = static_cast<mem_heap_t**>(
mem_alloc(n_sync_obj * sizeof(void*)));
for (i = 0; i < n_mutexes; i++) {
table->heaps[i] = mem_heap_create_in_btr_search(4096);
for (i = 0; i < n_sync_obj; i++) {
table->heaps[i] = mem_heap_create_typed(4096, type);
ut_a(table->heaps[i]);
}
#endif /* !UNIV_HOTBACKUP */
@ -88,6 +103,65 @@ ha_create_func(
return(table);
}
/*************************************************************//**
Empties a hash table and frees the memory heaps. */
UNIV_INTERN
void
ha_clear(
/*=====*/
hash_table_t* table) /*!< in, own: hash table */
{
ulint i;
ulint n;
ut_ad(table);
ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
#ifdef UNIV_SYNC_DEBUG
ut_ad(!table->adaptive
|| rw_lock_own(&btr_search_latch, RW_LOCK_EXCLUSIVE));
#endif /* UNIV_SYNC_DEBUG */
#ifndef UNIV_HOTBACKUP
/* Free the memory heaps. */
n = table->n_sync_obj;
for (i = 0; i < n; i++) {
mem_heap_free(table->heaps[i]);
}
if (table->heaps) {
mem_free(table->heaps);
}
switch (table->type) {
case HASH_TABLE_SYNC_MUTEX:
mem_free(table->sync_obj.mutexes);
table->sync_obj.mutexes = NULL;
break;
case HASH_TABLE_SYNC_RW_LOCK:
mem_free(table->sync_obj.rw_locks);
table->sync_obj.rw_locks = NULL;
break;
case HASH_TABLE_SYNC_NONE:
/* do nothing */
break;
}
table->n_sync_obj = 0;
table->type = HASH_TABLE_SYNC_NONE;
#endif /* !UNIV_HOTBACKUP */
/* Clear the hash table. */
n = hash_get_n_cells(table);
for (i = 0; i < n; i++) {
hash_get_nth_cell(table, i)->node = NULL;
}
}
/*************************************************************//**
Inserts an entry into a hash table. If an entry with the same fold number
is found, its node is updated to point to the new data, and no new node
@ -106,7 +180,7 @@ ha_insert_for_fold_func(
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
buf_block_t* block, /*!< in: buffer block containing the data */
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
rec_t* data) /*!< in: data, must not be NULL */
const rec_t* data) /*!< in: data, must not be NULL */
{
hash_cell_t* cell;
ha_node_t* node;
@ -119,17 +193,14 @@ ha_insert_for_fold_func(
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
ut_a(block->frame == page_align(data));
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
#ifdef UNIV_SYNC_DEBUG
ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
ASSERT_HASH_MUTEX_OWN(table, fold);
hash_assert_can_modify(table, fold);
ut_ad(btr_search_enabled);
hash = hash_calc_hash(fold, table);
cell = hash_get_nth_cell(table, hash);
prev_node = cell->node;
prev_node = static_cast<ha_node_t*>(cell->node);
while (prev_node != NULL) {
if (prev_node->fold == fold) {
@ -147,7 +218,7 @@ ha_insert_for_fold_func(
prev_node->block = block;
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
prev_node->data = data;
prev_node->data = (rec_t*) data;
return(TRUE);
}
@ -157,7 +228,8 @@ ha_insert_for_fold_func(
/* We have to allocate a new chain node */
node = mem_heap_alloc(hash_get_heap(table, fold), sizeof(ha_node_t));
node = static_cast<ha_node_t*>(
mem_heap_alloc(hash_get_heap(table, fold), sizeof(ha_node_t)));
if (node == NULL) {
/* It was a btr search type memory heap and at the moment
@ -168,7 +240,7 @@ ha_insert_for_fold_func(
return(FALSE);
}
ha_node_set_data(node, block, data);
ha_node_set_data(node, block, (rec_t*) data);
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
# ifndef UNIV_HOTBACKUP
@ -182,7 +254,7 @@ ha_insert_for_fold_func(
node->next = NULL;
prev_node = cell->node;
prev_node = static_cast<ha_node_t*>(cell->node);
if (prev_node == NULL) {
@ -231,9 +303,10 @@ ha_delete_hash_node(
/*********************************************************//**
Looks for an element when we know the pointer to the data, and updates
the pointer to data, if found. */
the pointer to data, if found.
@return TRUE if found */
UNIV_INTERN
void
ibool
ha_search_and_update_if_found_func(
/*===============================*/
hash_table_t* table, /*!< in/out: hash table */
@ -248,7 +321,7 @@ ha_search_and_update_if_found_func(
ut_ad(table);
ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
ASSERT_HASH_MUTEX_OWN(table, fold);
hash_assert_can_modify(table, fold);
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
ut_a(new_block->frame == page_align(new_data));
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
@ -257,7 +330,7 @@ ha_search_and_update_if_found_func(
#endif /* UNIV_SYNC_DEBUG */
if (!btr_search_enabled) {
return;
return(FALSE);
}
node = ha_search_with_data(table, fold, data);
@ -275,7 +348,11 @@ ha_search_and_update_if_found_func(
node->block = new_block;
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
node->data = new_data;
return(TRUE);
}
return(FALSE);
}
#ifndef UNIV_HOTBACKUP
@ -294,10 +371,7 @@ ha_remove_all_nodes_to_page(
ut_ad(table);
ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
ASSERT_HASH_MUTEX_OWN(table, fold);
#ifdef UNIV_SYNC_DEBUG
ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
hash_assert_can_modify(table, fold);
ut_ad(btr_search_enabled);
node = ha_chain_get_first(table, fold);
@ -343,8 +417,6 @@ ha_validate(
ulint start_index, /*!< in: start index */
ulint end_index) /*!< in: end index */
{
hash_cell_t* cell;
ha_node_t* node;
ibool ok = TRUE;
ulint i;
@ -355,12 +427,15 @@ ha_validate(
ut_a(end_index < hash_get_n_cells(table));
for (i = start_index; i <= end_index; i++) {
ha_node_t* node;
hash_cell_t* cell;
cell = hash_get_nth_cell(table, i);
node = cell->node;
for (node = static_cast<ha_node_t*>(cell->node);
node != 0;
node = node->next) {
while (node) {
if (hash_calc_hash(node->fold, table) != i) {
ut_print_timestamp(stderr);
fprintf(stderr,
@ -371,8 +446,6 @@ ha_validate(
ok = FALSE;
}
node = node->next;
}
}

View file

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 2007, 2009, Innobase Oy. All Rights Reserved.
Copyright (c) 2007, 2011, Oracle and/or its affiliates. All Rights Reserved.
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 the Free Software
@ -11,13 +11,13 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
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
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
/**************************************************//**
@file ha/ha0storage.c
@file ha/ha0storage.cc
Hash storage.
Provides a data structure that stores chunks of data in
its own storage, avoiding duplicates.
@ -51,7 +51,7 @@ ha_storage_get(
/* avoid repetitive calls to ut_fold_binary() in the HASH_SEARCH
macro */
fold = ut_fold_binary(data, data_len);
fold = ut_fold_binary(static_cast<const byte*>(data), data_len);
#define IS_FOUND \
node->data_len == data_len && memcmp(node->data, data, data_len) == 0
@ -128,7 +128,7 @@ ha_storage_put_memlim(
/* avoid repetitive calls to ut_fold_binary() in the HASH_INSERT
macro */
fold = ut_fold_binary(data, data_len);
fold = ut_fold_binary(static_cast<const byte*>(data), data_len);
HASH_INSERT(
ha_storage_node_t, /* type used in the hash chain */

View file

@ -1,184 +0,0 @@
/*****************************************************************************
Copyright (c) 1997, 2009, Innobase Oy. All Rights Reserved.
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 the Free Software
Foundation; version 2 of the License.
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.
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
*****************************************************************************/
/**************************************************//**
@file ha/hash0hash.c
The simple hash table utility
Created 5/20/1997 Heikki Tuuri
*******************************************************/
#include "hash0hash.h"
#ifdef UNIV_NONINL
#include "hash0hash.ic"
#endif
#include "mem0mem.h"
#ifndef UNIV_HOTBACKUP
# ifdef UNIV_PFS_MUTEX
UNIV_INTERN mysql_pfs_key_t hash_table_mutex_key;
# endif /* UNIV_PFS_MUTEX */
/************************************************************//**
Reserves the mutex for a fold value in a hash table. */
UNIV_INTERN
void
hash_mutex_enter(
/*=============*/
hash_table_t* table, /*!< in: hash table */
ulint fold) /*!< in: fold */
{
mutex_enter(hash_get_mutex(table, fold));
}
/************************************************************//**
Releases the mutex for a fold value in a hash table. */
UNIV_INTERN
void
hash_mutex_exit(
/*============*/
hash_table_t* table, /*!< in: hash table */
ulint fold) /*!< in: fold */
{
mutex_exit(hash_get_mutex(table, fold));
}
/************************************************************//**
Reserves all the mutexes of a hash table, in an ascending order. */
UNIV_INTERN
void
hash_mutex_enter_all(
/*=================*/
hash_table_t* table) /*!< in: hash table */
{
ulint i;
for (i = 0; i < table->n_mutexes; i++) {
mutex_enter(table->mutexes + i);
}
}
/************************************************************//**
Releases all the mutexes of a hash table. */
UNIV_INTERN
void
hash_mutex_exit_all(
/*================*/
hash_table_t* table) /*!< in: hash table */
{
ulint i;
for (i = 0; i < table->n_mutexes; i++) {
mutex_exit(table->mutexes + i);
}
}
#endif /* !UNIV_HOTBACKUP */
/*************************************************************//**
Creates a hash table with >= n array cells. The actual number of cells is
chosen to be a prime number slightly bigger than n.
@return own: created table */
UNIV_INTERN
hash_table_t*
hash_create(
/*========*/
ulint n) /*!< in: number of array cells */
{
hash_cell_t* array;
ulint prime;
hash_table_t* table;
prime = ut_find_prime(n);
table = mem_alloc(sizeof(hash_table_t));
array = ut_malloc(sizeof(hash_cell_t) * prime);
table->array = array;
table->n_cells = prime;
#ifndef UNIV_HOTBACKUP
# if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
table->adaptive = FALSE;
# endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
table->n_mutexes = 0;
table->mutexes = NULL;
table->heaps = NULL;
#endif /* !UNIV_HOTBACKUP */
table->heap = NULL;
ut_d(table->magic_n = HASH_TABLE_MAGIC_N);
/* Initialize the cell array */
hash_table_clear(table);
return(table);
}
/*************************************************************//**
Frees a hash table. */
UNIV_INTERN
void
hash_table_free(
/*============*/
hash_table_t* table) /*!< in, own: hash table */
{
ut_ad(table);
ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
#ifndef UNIV_HOTBACKUP
ut_a(table->mutexes == NULL);
#endif /* !UNIV_HOTBACKUP */
ut_free(table->array);
mem_free(table);
}
#ifndef UNIV_HOTBACKUP
/*************************************************************//**
Creates a mutex array to protect a hash table. */
UNIV_INTERN
void
hash_create_mutexes_func(
/*=====================*/
hash_table_t* table, /*!< in: hash table */
#ifdef UNIV_SYNC_DEBUG
ulint sync_level, /*!< in: latching order level of the
mutexes: used in the debug version */
#endif /* UNIV_SYNC_DEBUG */
ulint n_mutexes) /*!< in: number of mutexes, must be a
power of 2 */
{
ulint i;
ut_ad(table);
ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
ut_a(n_mutexes > 0);
ut_a(ut_is_2pow(n_mutexes));
table->mutexes = mem_alloc(n_mutexes * sizeof(mutex_t));
for (i = 0; i < n_mutexes; i++) {
mutex_create(hash_table_mutex_key,
table->mutexes + i, sync_level);
}
table->n_mutexes = n_mutexes;
}
#endif /* !UNIV_HOTBACKUP */

View file

@ -0,0 +1,403 @@
/*****************************************************************************
Copyright (c) 1997, 2011, Oracle and/or its affiliates. All Rights Reserved.
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 the Free Software
Foundation; version 2 of the License.
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.
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.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
/**************************************************//**
@file ha/hash0hash.cc
The simple hash table utility
Created 5/20/1997 Heikki Tuuri
*******************************************************/
#include "hash0hash.h"
#ifdef UNIV_NONINL
#include "hash0hash.ic"
#endif
#include "mem0mem.h"
#ifndef UNIV_HOTBACKUP
# ifdef UNIV_PFS_MUTEX
UNIV_INTERN mysql_pfs_key_t hash_table_mutex_key;
# endif /* UNIV_PFS_MUTEX */
# ifdef UNIV_PFS_RWLOCK
UNIV_INTERN mysql_pfs_key_t hash_table_rw_lock_key;
# endif /* UNIV_PFS_RWLOCK */
/************************************************************//**
Reserves the mutex for a fold value in a hash table. */
UNIV_INTERN
void
hash_mutex_enter(
/*=============*/
hash_table_t* table, /*!< in: hash table */
ulint fold) /*!< in: fold */
{
ut_ad(table->type == HASH_TABLE_SYNC_MUTEX);
mutex_enter(hash_get_mutex(table, fold));
}
/************************************************************//**
Releases the mutex for a fold value in a hash table. */
UNIV_INTERN
void
hash_mutex_exit(
/*============*/
hash_table_t* table, /*!< in: hash table */
ulint fold) /*!< in: fold */
{
ut_ad(table->type == HASH_TABLE_SYNC_MUTEX);
mutex_exit(hash_get_mutex(table, fold));
}
/************************************************************//**
Reserves all the mutexes of a hash table, in an ascending order. */
UNIV_INTERN
void
hash_mutex_enter_all(
/*=================*/
hash_table_t* table) /*!< in: hash table */
{
ulint i;
ut_ad(table->type == HASH_TABLE_SYNC_MUTEX);
for (i = 0; i < table->n_sync_obj; i++) {
mutex_enter(table->sync_obj.mutexes + i);
}
}
/************************************************************//**
Releases all the mutexes of a hash table. */
UNIV_INTERN
void
hash_mutex_exit_all(
/*================*/
hash_table_t* table) /*!< in: hash table */
{
ulint i;
ut_ad(table->type == HASH_TABLE_SYNC_MUTEX);
for (i = 0; i < table->n_sync_obj; i++) {
mutex_exit(table->sync_obj.mutexes + i);
}
}
/************************************************************//**
Releases all but the passed in mutex of a hash table. */
UNIV_INTERN
void
hash_mutex_exit_all_but(
/*====================*/
hash_table_t* table, /*!< in: hash table */
mutex_t* keep_mutex) /*!< in: mutex to keep */
{
ulint i;
ut_ad(table->type == HASH_TABLE_SYNC_MUTEX);
for (i = 0; i < table->n_sync_obj; i++) {
mutex_t* mutex = table->sync_obj.mutexes + i;
if (UNIV_LIKELY(keep_mutex != mutex)) {
mutex_exit(mutex);
}
}
ut_ad(mutex_own(keep_mutex));
}
/************************************************************//**
s-lock a lock for a fold value in a hash table. */
UNIV_INTERN
void
hash_lock_s(
/*========*/
hash_table_t* table, /*!< in: hash table */
ulint fold) /*!< in: fold */
{
rw_lock_t* lock = hash_get_lock(table, fold);
ut_ad(table->type == HASH_TABLE_SYNC_RW_LOCK);
ut_ad(lock);
#ifdef UNIV_SYNC_DEBUG
ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED));
ut_ad(!rw_lock_own(lock, RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
rw_lock_s_lock(lock);
}
/************************************************************//**
x-lock a lock for a fold value in a hash table. */
UNIV_INTERN
void
hash_lock_x(
/*========*/
hash_table_t* table, /*!< in: hash table */
ulint fold) /*!< in: fold */
{
rw_lock_t* lock = hash_get_lock(table, fold);
ut_ad(table->type == HASH_TABLE_SYNC_RW_LOCK);
ut_ad(lock);
#ifdef UNIV_SYNC_DEBUG
ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED));
ut_ad(!rw_lock_own(lock, RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
rw_lock_x_lock(lock);
}
/************************************************************//**
unlock an s-lock for a fold value in a hash table. */
UNIV_INTERN
void
hash_unlock_s(
/*==========*/
hash_table_t* table, /*!< in: hash table */
ulint fold) /*!< in: fold */
{
rw_lock_t* lock = hash_get_lock(table, fold);
ut_ad(table->type == HASH_TABLE_SYNC_RW_LOCK);
ut_ad(lock);
#ifdef UNIV_SYNC_DEBUG
ut_ad(rw_lock_own(lock, RW_LOCK_SHARED));
#endif /* UNIV_SYNC_DEBUG */
rw_lock_s_unlock(lock);
}
/************************************************************//**
unlock x-lock for a fold value in a hash table. */
UNIV_INTERN
void
hash_unlock_x(
/*==========*/
hash_table_t* table, /*!< in: hash table */
ulint fold) /*!< in: fold */
{
rw_lock_t* lock = hash_get_lock(table, fold);
ut_ad(table->type == HASH_TABLE_SYNC_RW_LOCK);
ut_ad(lock);
#ifdef UNIV_SYNC_DEBUG
ut_ad(rw_lock_own(lock, RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
rw_lock_x_unlock(lock);
}
/************************************************************//**
Reserves all the locks of a hash table, in an ascending order. */
UNIV_INTERN
void
hash_lock_x_all(
/*============*/
hash_table_t* table) /*!< in: hash table */
{
ulint i;
ut_ad(table->type == HASH_TABLE_SYNC_RW_LOCK);
for (i = 0; i < table->n_sync_obj; i++) {
rw_lock_t* lock = table->sync_obj.rw_locks + i;
#ifdef UNIV_SYNC_DEBUG
ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED));
ut_ad(!rw_lock_own(lock, RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
rw_lock_x_lock(lock);
}
}
/************************************************************//**
Releases all the locks of a hash table, in an ascending order. */
UNIV_INTERN
void
hash_unlock_x_all(
/*==============*/
hash_table_t* table) /*!< in: hash table */
{
ulint i;
ut_ad(table->type == HASH_TABLE_SYNC_RW_LOCK);
for (i = 0; i < table->n_sync_obj; i++) {
rw_lock_t* lock = table->sync_obj.rw_locks + i;
#ifdef UNIV_SYNC_DEBUG
ut_ad(rw_lock_own(lock, RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
rw_lock_x_unlock(lock);
}
}
/************************************************************//**
Releases all but passed in lock of a hash table, */
UNIV_INTERN
void
hash_unlock_x_all_but(
/*==================*/
hash_table_t* table, /*!< in: hash table */
rw_lock_t* keep_lock) /*!< in: lock to keep */
{
ulint i;
ut_ad(table->type == HASH_TABLE_SYNC_RW_LOCK);
for (i = 0; i < table->n_sync_obj; i++) {
rw_lock_t* lock = table->sync_obj.rw_locks + i;
#ifdef UNIV_SYNC_DEBUG
ut_ad(rw_lock_own(lock, RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
if (UNIV_LIKELY(keep_lock != lock)) {
rw_lock_x_unlock(lock);
}
}
}
#endif /* !UNIV_HOTBACKUP */
/*************************************************************//**
Creates a hash table with >= n array cells. The actual number of cells is
chosen to be a prime number slightly bigger than n.
@return own: created table */
UNIV_INTERN
hash_table_t*
hash_create(
/*========*/
ulint n) /*!< in: number of array cells */
{
hash_cell_t* array;
ulint prime;
hash_table_t* table;
prime = ut_find_prime(n);
table = static_cast<hash_table_t*>(mem_alloc(sizeof(hash_table_t)));
array = static_cast<hash_cell_t*>(
ut_malloc(sizeof(hash_cell_t) * prime));
/* The default type of hash_table is HASH_TABLE_SYNC_NONE i.e.:
the caller is responsible for access control to the table. */
table->type = HASH_TABLE_SYNC_NONE;
table->array = array;
table->n_cells = prime;
#ifndef UNIV_HOTBACKUP
# if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
table->adaptive = FALSE;
# endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
table->n_sync_obj = 0;
table->sync_obj.mutexes = NULL;
table->heaps = NULL;
#endif /* !UNIV_HOTBACKUP */
table->heap = NULL;
ut_d(table->magic_n = HASH_TABLE_MAGIC_N);
/* Initialize the cell array */
hash_table_clear(table);
return(table);
}
/*************************************************************//**
Frees a hash table. */
UNIV_INTERN
void
hash_table_free(
/*============*/
hash_table_t* table) /*!< in, own: hash table */
{
ut_ad(table);
ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
ut_free(table->array);
mem_free(table);
}
#ifndef UNIV_HOTBACKUP
/*************************************************************//**
Creates a sync object array to protect a hash table.
::sync_obj can be mutexes or rw_locks depening on the type of
hash table. */
UNIV_INTERN
void
hash_create_sync_obj_func(
/*======================*/
hash_table_t* table, /*!< in: hash table */
enum hash_table_sync_t type, /*!< in: HASH_TABLE_SYNC_MUTEX
or HASH_TABLE_SYNC_RW_LOCK */
#ifdef UNIV_SYNC_DEBUG
ulint sync_level,/*!< in: latching order level
of the mutexes: used in the
debug version */
#endif /* UNIV_SYNC_DEBUG */
ulint n_sync_obj)/*!< in: number of sync objects,
must be a power of 2 */
{
ulint i;
ut_ad(table);
ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
ut_a(n_sync_obj > 0);
ut_a(ut_is_2pow(n_sync_obj));
table->type = type;
switch (type) {
case HASH_TABLE_SYNC_MUTEX:
table->sync_obj.mutexes = static_cast<mutex_t*>(
mem_alloc(n_sync_obj * sizeof(mutex_t)));
for (i = 0; i < n_sync_obj; i++) {
mutex_create(hash_table_mutex_key,
table->sync_obj.mutexes + i, sync_level);
}
break;
case HASH_TABLE_SYNC_RW_LOCK:
table->sync_obj.rw_locks = static_cast<rw_lock_t*>(
mem_alloc(n_sync_obj * sizeof(rw_lock_t)));
for (i = 0; i < n_sync_obj; i++) {
rw_lock_create(hash_table_rw_lock_key,
table->sync_obj.rw_locks + i, sync_level);
}
break;
case HASH_TABLE_SYNC_NONE:
ut_error;
}
table->n_sync_obj = n_sync_obj;
}
#endif /* !UNIV_HOTBACKUP */

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 2000, 2010, MySQL AB & Innobase Oy. All Rights Reserved.
Copyright (c) 2000, 2012, Oracle and/or its affiliates. All Rights Reserved.
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 the Free Software
@ -11,8 +11,8 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
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
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@ -23,9 +23,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
Innodb
*/
#ifdef USE_PRAGMA_INTERFACE
#pragma interface /* gcc class implementation */
#endif
#include "dict0stats.h"
/* Structure defines translation table between mysql index and innodb
index structures */
@ -110,7 +108,7 @@ class ha_innobase: public handler
ulint innobase_update_autoinc(ulonglong auto_inc);
void innobase_initialize_autoinc();
dict_index_t* innobase_get_index(uint keynr);
int info_low(uint flag, bool called_from_analyze);
int info_low(uint flag, dict_stats_upd_option_t stats_upd_option);
/* Init values for the class: */
public:
@ -133,7 +131,6 @@ class ha_innobase: public handler
const key_map* keys_to_use_for_scanning();
int open(const char *name, int mode, uint test_if_locked);
handler* clone(const char *name, MEM_ROOT *mem_root);
int close(void);
double scan_time();
double read_time(uint index, uint ranges, ha_rows rows);
@ -163,13 +160,18 @@ class ha_innobase: public handler
int rnd_next(uchar *buf);
int rnd_pos(uchar * buf, uchar *pos);
int ft_init();
void ft_end();
FT_INFO *ft_init_ext(uint flags, uint inx, String* key);
int ft_read(uchar* buf);
void position(const uchar *record);
int info(uint);
int analyze(THD* thd,HA_CHECK_OPT* check_opt);
int optimize(THD* thd,HA_CHECK_OPT* check_opt);
int discard_or_import_tablespace(my_bool discard);
int extra(enum ha_extra_function operation);
int reset();
int reset();
int external_lock(THD *thd, int lock_type);
int transactional_table_lock(THD *thd, int lock_type);
int start_stmt(THD *thd, thr_lock_type lock_type);
@ -203,7 +205,7 @@ class ha_innobase: public handler
int reset_auto_increment(ulonglong value);
virtual bool get_error_message(int error, String *buf);
virtual bool get_foreign_dup_key(char*, uint, char*, uint);
uint8 table_cache_type();
/*
ask handler about permission to cache table during query registration
@ -212,7 +214,7 @@ class ha_innobase: public handler
uint key_length,
qc_engine_callback *call_back,
ulonglong *engine_data);
static char *get_mysql_bin_log_name();
static const char *get_mysql_bin_log_name();
static ulonglong get_mysql_bin_log_pos();
bool primary_key_is_clustered();
int cmp_ref(const uchar *ref1, const uchar *ref2);
@ -226,6 +228,77 @@ class ha_innobase: public handler
/** @} */
bool check_if_incompatible_data(HA_CREATE_INFO *info,
uint table_changes);
private:
/** Builds a 'template' to the prebuilt struct.
The template is used in fast retrieval of just those column
values MySQL needs in its processing.
@param whole_row true if access is needed to a whole row,
false if accessing individual fields is enough */
void build_template(bool whole_row);
/** Resets a query execution 'template'.
@see build_template() */
inline void reset_template();
public:
/** @name Multi Range Read interface @{ */
/** Initialize multi range read @see DsMrr_impl::dsmrr_init
* @param seq
* @param seq_init_param
* @param n_ranges
* @param mode
* @param buf
*/
int multi_range_read_init(RANGE_SEQ_IF* seq,
void* seq_init_param,
uint n_ranges, uint mode,
HANDLER_BUFFER* buf);
/** Process next multi range read @see DsMrr_impl::dsmrr_next
* @param range_info
*/
int multi_range_read_next(range_id_t *range_info);
/** Initialize multi range read and get information.
* @see ha_myisam::multi_range_read_info_const
* @see DsMrr_impl::dsmrr_info_const
* @param keyno
* @param seq
* @param seq_init_param
* @param n_ranges
* @param bufsz
* @param flags
* @param cost
*/
ha_rows multi_range_read_info_const(uint keyno, RANGE_SEQ_IF* seq,
void* seq_init_param,
uint n_ranges, uint* bufsz,
uint* flags, Cost_estimate* cost);
/** Initialize multi range read and get information.
* @see DsMrr_impl::dsmrr_info
* @param keyno
* @param seq
* @param seq_init_param
* @param n_ranges
* @param bufsz
* @param flags
* @param cost
*/
ha_rows multi_range_read_info(uint keyno,
uint n_ranges, uint keys,
uint key_parts,
uint* bufsz, uint* mrr_mode,
Cost_estimate* cost);
/** Attempt to push down an index condition.
* @param[in] keyno MySQL key number
* @param[in] idx_cond Index condition to be checked
* @return idx_cond if pushed; NULL if not pushed
*/
class Item* idx_cond_push(uint keyno, class Item* idx_cond);
private:
/** The multi range read session object */
DsMrr_impl ds_mrr;
/* @} */
};
/* Some accessor functions which the InnoDB plugin needs, but which
@ -236,9 +309,11 @@ the definitions are bracketed with #ifdef INNODB_COMPATIBILITY_HOOKS */
#error InnoDB needs MySQL to be built with #define INNODB_COMPATIBILITY_HOOKS
#endif
LEX_STRING* thd_query_string(MYSQL_THD thd);
extern "C" {
struct charset_info_st *thd_charset(MYSQL_THD thd);
LEX_STRING *thd_query_string(MYSQL_THD thd);
/**
Check if a user thread is a replication slave thread
@ -284,7 +359,8 @@ bool thd_binlog_filter_ok(const MYSQL_THD thd);
@return 1 the query may generate row changes, 0 otherwise.
*/
bool thd_sqlcom_can_generate_row_events(const MYSQL_THD thd);
}
} /* extern "C" */
/** Get the file name and position of the MySQL binlog corresponding to the
* current commit.
@ -292,13 +368,23 @@ bool thd_sqlcom_can_generate_row_events(const MYSQL_THD thd);
extern void mysql_bin_log_commit_pos(THD *thd, ulonglong *out_pos, const char **out_file);
typedef struct trx_struct trx_t;
extern const struct _ft_vft ft_vft_result;
/* Structure Returned by ha_innobase::ft_init_ext() */
typedef struct new_ft_info
{
struct _ft_vft *please;
row_prebuilt_t* ft_prebuilt;
fts_result_t* ft_result;
} NEW_FT_INFO;
/********************************************************************//**
@file handler/ha_innodb.h
Converts an InnoDB error code to a MySQL error code and also tells to MySQL
about a possible transaction rollback inside InnoDB caused by a lock wait
timeout or a deadlock.
@return MySQL error code */
extern "C"
int
convert_error_code_to_mysql(
/*========================*/
@ -309,20 +395,17 @@ convert_error_code_to_mysql(
/*********************************************************************//**
Allocates an InnoDB transaction for a MySQL handler object.
@return InnoDB transaction handle */
extern "C"
trx_t*
innobase_trx_allocate(
/*==================*/
MYSQL_THD thd); /*!< in: user thread handle */
/*********************************************************************//**
This function checks each index name for a table against reserved
system default primary index name 'GEN_CLUST_INDEX'. If a name
matches, this function pushes an warning message to the client,
and returns true.
@return true if the index name matches the reserved name */
extern "C"
bool
innobase_index_name_is_reserved(
/*============================*/
@ -330,4 +413,79 @@ innobase_index_name_is_reserved(
const KEY* key_info, /*!< in: Indexes to be created */
ulint num_of_keys); /*!< in: Number of indexes to
be created. */
/*********************************************************************//**
Retrieve the FTS Relevance Ranking result for doc with doc_id
of prebuilt->fts_doc_id
@return the relevance ranking value */
UNIV_INTERN
float
innobase_fts_retrieve_ranking(
/*==========================*/
FT_INFO* fts_hdl); /*!< in: FTS handler */
/*********************************************************************//**
Find and Retrieve the FTS Relevance Ranking result for doc with doc_id
of prebuilt->fts_doc_id
@return the relevance ranking value */
UNIV_INTERN
float
innobase_fts_find_ranking(
/*==========================*/
FT_INFO* fts_hdl, /*!< in: FTS handler */
uchar* record, /*!< in: Unused */
uint len); /*!< in: Unused */
/*********************************************************************//**
Free the memory for the FTS handler */
UNIV_INTERN
void
innobase_fts_close_ranking(
/*==========================*/
FT_INFO* fts_hdl); /*!< in: FTS handler */
/*********************************************************************//**
Free the memory for the FTS handler */
void
innobase_fts_close_ranking(
/*==========================*/
FT_INFO* fts_hdl); /*!< in: FTS handler */
/*****************************************************************//**
Initialize the table FTS stopword list
@return TRUE is succeed */
UNIV_INTERN
ibool
innobase_fts_load_stopword(
/*=======================*/
dict_table_t* table, /*!< in: Table has the FTS */
trx_t* trx, /*!< in: transaction */
THD* thd); /*!< in: current thread */
/** Some defines for innobase_fts_check_doc_id_index() return value */
enum fts_doc_id_index_enum {
FTS_INCORRECT_DOC_ID_INDEX,
FTS_EXIST_DOC_ID_INDEX,
FTS_NOT_EXIST_DOC_ID_INDEX
};
/*******************************************************************//**
Check whether the table has a unique index with FTS_DOC_ID_INDEX_NAME
on the Doc ID column.
@return FTS_EXIST_DOC_ID_INDEX if there exists the FTS_DOC_ID index,
FTS_INCORRECT_DOC_ID_INDEX if the FTS_DOC_ID index is of wrong format */
UNIV_INTERN
enum fts_doc_id_index_enum
innobase_fts_check_doc_id_index(
/*============================*/
dict_table_t* table, /*!< in: table definition */
ulint* fts_doc_col_no);/*!< out: The column number for
Doc ID */
/*******************************************************************//**
Check whether the table has a unique index with FTS_DOC_ID_INDEX_NAME
on the Doc ID column in MySQL create index definition.
@return FTS_EXIST_DOC_ID_INDEX if there exists the FTS_DOC_ID index,
FTS_INCORRECT_DOC_ID_INDEX if the FTS_DOC_ID index is of wrong format */
UNIV_INTERN
enum fts_doc_id_index_enum
innobase_fts_check_doc_id_index_in_def(
/*===================================*/
ulint n_key, /*!< in: Number of keys */
KEY* key_info); /*!< in: Key definition */

View file

@ -26,7 +26,7 @@ Smart ALTER TABLE
#include <sql_lex.h> // SQLCOM_CREATE_INDEX
#include <innodb_priv.h>
extern "C" {
#include "dict0stats.h"
#include "log0log.h"
#include "row0merge.h"
#include "srv0srv.h"
@ -34,7 +34,8 @@ extern "C" {
#include "trx0roll.h"
#include "ha_prototypes.h"
#include "handler0alter.h"
}
#include "srv0mon.h"
#include "fts0priv.h"
#include "ha_innodb.h"
@ -128,7 +129,7 @@ innobase_col_to_mysql(
/*************************************************************//**
Copies an InnoDB record to table->record[0]. */
extern "C" UNIV_INTERN
UNIV_INTERN
void
innobase_rec_to_mysql(
/*==================*/
@ -141,7 +142,9 @@ innobase_rec_to_mysql(
uint n_fields = table->s->fields;
uint i;
ut_ad(n_fields == dict_table_get_n_user_cols(index->table));
ut_ad(n_fields == dict_table_get_n_user_cols(index->table)
|| (DICT_TF2_FLAG_IS_SET(index->table, DICT_TF2_FTS_HAS_DOC_ID)
&& n_fields + 1 == dict_table_get_n_user_cols(index->table)));
for (i = 0; i < n_fields; i++) {
Field* field = table->field[i];
@ -178,7 +181,7 @@ null_field:
/*************************************************************//**
Resets table->record[0]. */
extern "C" UNIV_INTERN
UNIV_INTERN
void
innobase_rec_reset(
/*===============*/
@ -362,7 +365,7 @@ innobase_create_index_field_def(
&& field->type() != MYSQL_TYPE_VARCHAR)
|| (field->type() == MYSQL_TYPE_VARCHAR
&& key_part->length < field->pack_length()
- ((Field_varstring*)field)->length_bytes)) {
- ((Field_varstring*) field)->length_bytes)) {
index_field->prefix_len = key_part->length;
} else {
@ -416,6 +419,10 @@ innobase_create_index_def(
index->ind_type |= DICT_UNIQUE;
}
if (key->flags & HA_FULLTEXT) {
index->ind_type |= DICT_FTS;
}
if (key_primary) {
index->ind_type |= DICT_CLUSTERED;
}
@ -485,6 +492,143 @@ innobase_copy_index_def(
DBUG_VOID_RETURN;
}
/*******************************************************************//**
Check whether the table has the FTS_DOC_ID column
@return TRUE if there exists the FTS_DOC_ID column, if TRUE but fts_doc_col_no
equal to ULINT_UNDEFINED then that means the column exists but is not
of the right type. */
static
ibool
innobase_fts_check_doc_id_col(
/*==========================*/
dict_table_t* table, /*!< in: table with FTS index */
ulint* fts_doc_col_no) /*!< out: The column number for
Doc ID */
{
*fts_doc_col_no = ULINT_UNDEFINED;
for (ulint i = 0; i + DATA_N_SYS_COLS < (ulint) table->n_cols; i++) {
const char* name = dict_table_get_col_name(table, i);
if (strcmp(name, FTS_DOC_ID_COL_NAME) == 0) {
const dict_col_t* col;
col = dict_table_get_nth_col(table, i);
if (col->mtype != DATA_INT || col->len != 8) {
fprintf(stderr,
" InnoDB: %s column in table %s"
" must be of the BIGINT datatype\n",
FTS_DOC_ID_COL_NAME, table->name);
} else if (!(col->prtype & DATA_NOT_NULL)) {
fprintf(stderr,
" InnoDB: %s column in table %s"
" must be NOT NULL\n",
FTS_DOC_ID_COL_NAME, table->name);
} else if (!(col->prtype & DATA_UNSIGNED)) {
fprintf(stderr,
" InnoDB: %s column in table %s"
" must be UNSIGNED\n",
FTS_DOC_ID_COL_NAME, table->name);
} else {
*fts_doc_col_no = i;
}
return(TRUE);
}
}
return(FALSE);
}
/*******************************************************************//**
Check whether the table has a unique index with FTS_DOC_ID_INDEX_NAME
on the Doc ID column.
@return FTS_EXIST_DOC_ID_INDEX if there exists the FTS_DOC_ID index,
FTS_INCORRECT_DOC_ID_INDEX if the FTS_DOC_ID index is of wrong format */
UNIV_INTERN
enum fts_doc_id_index_enum
innobase_fts_check_doc_id_index(
/*============================*/
dict_table_t* table, /*!< in: table definition */
ulint* fts_doc_col_no) /*!< out: The column number for
Doc ID */
{
dict_index_t* index;
dict_field_t* field;
for (index = dict_table_get_first_index(table);
index; index = dict_table_get_next_index(index)) {
/* Check if there exists a unique index with the name of
FTS_DOC_ID_INDEX_NAME */
if (innobase_strcasecmp(index->name, FTS_DOC_ID_INDEX_NAME)) {
continue;
}
if (!dict_index_is_unique(index)
|| strcmp(index->name, FTS_DOC_ID_INDEX_NAME)) {
return(FTS_INCORRECT_DOC_ID_INDEX);
}
/* Check whether the index has FTS_DOC_ID as its
first column */
field = dict_index_get_nth_field(index, 0);
/* The column would be of a BIGINT data type */
if (strcmp(field->name, FTS_DOC_ID_COL_NAME) == 0
&& field->col->mtype == DATA_INT
&& field->col->len == 8
&& field->col->prtype & DATA_NOT_NULL) {
if (fts_doc_col_no) {
*fts_doc_col_no = dict_col_get_no(field->col);
}
return(FTS_EXIST_DOC_ID_INDEX);
} else {
return(FTS_INCORRECT_DOC_ID_INDEX);
}
}
/* Not found */
return(FTS_NOT_EXIST_DOC_ID_INDEX);
}
/*******************************************************************//**
Check whether the table has a unique index with FTS_DOC_ID_INDEX_NAME
on the Doc ID column in MySQL create index definition.
@return FTS_EXIST_DOC_ID_INDEX if there exists the FTS_DOC_ID index,
FTS_INCORRECT_DOC_ID_INDEX if the FTS_DOC_ID index is of wrong format */
UNIV_INTERN
enum fts_doc_id_index_enum
innobase_fts_check_doc_id_index_in_def(
/*===================================*/
ulint n_key, /*!< in: Number of keys */
KEY * key_info) /*!< in: Key definition */
{
/* Check whether there is a "FTS_DOC_ID_INDEX" in the to be built index
list */
for (ulint j = 0; j < n_key; j++) {
KEY* key = &key_info[j];
if (innobase_strcasecmp(key->name, FTS_DOC_ID_INDEX_NAME)) {
continue;
}
/* Do a check on FTS DOC ID_INDEX, it must be unique,
named as "FTS_DOC_ID_INDEX" and on column "FTS_DOC_ID" */
if (!(key->flags & HA_NOSAME)
|| strcmp(key->name, FTS_DOC_ID_INDEX_NAME)
|| strcmp(key->key_part[0].field->field_name,
FTS_DOC_ID_COL_NAME)) {
return(FTS_INCORRECT_DOC_ID_INDEX);
}
return(FTS_EXIST_DOC_ID_INDEX);
}
return(FTS_NOT_EXIST_DOC_ID_INDEX);
}
/*******************************************************************//**
Create an index table where indexes are ordered as follows:
@ -507,12 +651,17 @@ merge_index_def_t*
innobase_create_key_def(
/*====================*/
trx_t* trx, /*!< in: trx */
const dict_table_t*table, /*!< in: table definition */
dict_table_t* table, /*!< in: table definition */
mem_heap_t* heap, /*!< in: heap where space for key
definitions are allocated */
KEY* key_info, /*!< in: Indexes to be created */
ulint& n_keys) /*!< in/out: Number of indexes to
ulint& n_keys, /*!< in/out: Number of indexes to
be created */
ulint* num_fts_index, /*!< out: Number of FTS indexes */
ibool* add_fts_doc_id, /*!< out: Whether we need to add
new DOC ID column for FTS index */
ibool* add_fts_doc_id_idx)/*!< out: Whether we need to add
new index on DOC ID column */
{
ulint i = 0;
merge_index_def_t* indexdef;
@ -525,6 +674,9 @@ innobase_create_key_def(
mem_heap_alloc(heap, sizeof *indexdef
* (n_keys + UT_LIST_GET_LEN(table->indexes)));
*add_fts_doc_id = FALSE;
*add_fts_doc_id_idx = FALSE;
/* If there is a primary key, it is always the first index
defined for the table. */
@ -552,12 +704,111 @@ innobase_create_key_def(
}
}
if (new_primary) {
/* Check whether any indexes in the create list are Full
Text Indexes*/
for (ulint j = 0; j < n_keys; j++) {
if (key_info[j].flags & HA_FULLTEXT) {
(*num_fts_index)++;
}
}
/* Check whether there is a "FTS_DOC_ID_INDEX" in the to be built index
list */
if (innobase_fts_check_doc_id_index_in_def(n_keys, key_info)
== FTS_INCORRECT_DOC_ID_INDEX) {
push_warning_printf((THD*) trx->mysql_thd,
Sql_condition::WARN_LEVEL_WARN,
ER_WRONG_NAME_FOR_INDEX,
" InnoDB: Index name %s is reserved"
" for the unique index on"
" FTS_DOC_ID column for FTS"
" document ID indexing"
" on table %s. Please check"
" the index definition to"
" make sure it is of correct"
" type\n",
FTS_DOC_ID_INDEX_NAME,
table->name);
DBUG_RETURN(NULL);
}
/* If we are to build an FTS index, check whether the table
already has a DOC ID column, if not, we will need to add a
Doc ID hidden column and rebuild the primary index */
if (*num_fts_index) {
enum fts_doc_id_index_enum ret;
ibool exists;
ulint doc_col_no;
ulint fts_doc_col_no;
exists = innobase_fts_check_doc_id_col(table, &fts_doc_col_no);
if (exists) {
if (fts_doc_col_no == ULINT_UNDEFINED) {
push_warning_printf(
(THD*) trx->mysql_thd,
Sql_condition::WARN_LEVEL_WARN,
ER_WRONG_COLUMN_NAME,
" InnoDB: There exists a column %s "
"in table %s, but it is the wrong "
"type. Create of FTS index failed.\n",
FTS_DOC_ID_COL_NAME, table->name);
DBUG_RETURN(NULL);
} else if (!table->fts) {
table->fts = fts_create(table);
}
table->fts->doc_col = fts_doc_col_no;
} else {
*add_fts_doc_id = TRUE;
*add_fts_doc_id_idx = TRUE;
ut_print_timestamp(stderr);
fprintf(stderr, " InnoDB: Rebuild table %s to add "
"DOC_ID column\n", table->name);
}
ret = innobase_fts_check_doc_id_index(table, &doc_col_no);
switch (ret) {
case FTS_NOT_EXIST_DOC_ID_INDEX:
*add_fts_doc_id_idx = TRUE;
break;
case FTS_INCORRECT_DOC_ID_INDEX:
ut_print_timestamp(stderr);
fprintf(stderr, " InnoDB: Index %s is used for FTS"
" Doc ID indexing on table %s, it is"
" now on the wrong column or of"
" wrong format. Please drop it.\n",
FTS_DOC_ID_INDEX_NAME, table->name);
DBUG_RETURN(NULL);
default:
ut_ad(ret == FTS_EXIST_DOC_ID_INDEX);
ut_ad(doc_col_no == fts_doc_col_no);
}
}
/* If DICT_TF2_FTS_ADD_DOC_ID is set, we will need to rebuild
the table to add the unique Doc ID column for FTS index. And
thus the primary index would required to be rebuilt. Copy all
the index definitions */
if (new_primary || *add_fts_doc_id) {
const dict_index_t* index;
/* Create the PRIMARY key index definition */
innobase_create_index_def(&key_info[i++], TRUE, TRUE,
indexdef++, heap);
if (new_primary) {
/* Create the PRIMARY key index definition */
innobase_create_index_def(&key_info[i++],
TRUE, TRUE,
indexdef++, heap);
}
row_mysql_lock_data_dictionary(trx);
@ -568,17 +819,32 @@ innobase_create_key_def(
index or a PRIMARY KEY. If the clustered index is a
UNIQUE INDEX, it must be converted to a secondary index. */
if (dict_index_get_nth_col(index, 0)->mtype == DATA_SYS
|| !my_strcasecmp(system_charset_info,
index->name, "PRIMARY")) {
if (new_primary
&& (dict_index_get_nth_col(index, 0)->mtype
== DATA_SYS
|| !my_strcasecmp(system_charset_info,
index->name, "PRIMARY"))) {
index = dict_table_get_next_index(index);
}
while (index) {
innobase_copy_index_def(index, indexdef++, heap);
if (new_primary && index->type & DICT_FTS) {
(*num_fts_index)++;
}
index = dict_table_get_next_index(index);
}
/* The primary index would be rebuilt if a FTS Doc ID
column is to be added, and the primary index definition
is just copied from old table and stored in indexdefs[0] */
if (*add_fts_doc_id) {
indexdefs[0].ind_type |= DICT_CLUSTERED;
DICT_TF2_FLAG_SET(table, DICT_TF2_FTS_ADD_DOC_ID);
}
row_mysql_unlock_data_dictionary(trx);
}
@ -652,6 +918,88 @@ public:
~ha_innobase_add_index() {}
};
/*******************************************************************//**
This is to create FTS_DOC_ID_INDEX definition on the newly added Doc ID for
the FTS indexes table
@return dict_index_t for the FTS_DOC_ID_INDEX */
dict_index_t*
innobase_create_fts_doc_id_idx(
/*===========================*/
dict_table_t* indexed_table, /*!< in: Table where indexes are
created */
trx_t* trx, /*!< in: Transaction */
mem_heap_t* heap) /*!< Heap for index definitions */
{
dict_index_t* index;
merge_index_def_t fts_index_def;
char* index_name;
/* Create the temp index name for FTS_DOC_ID_INDEX */
fts_index_def.name = index_name = (char*) mem_heap_alloc(
heap, FTS_DOC_ID_INDEX_NAME_LEN + 2);
*index_name++ = TEMP_INDEX_PREFIX;
memcpy(index_name, FTS_DOC_ID_INDEX_NAME,
FTS_DOC_ID_INDEX_NAME_LEN);
index_name[FTS_DOC_ID_INDEX_NAME_LEN] = 0;
/* Only the Doc ID will be indexed */
fts_index_def.n_fields = 1;
fts_index_def.ind_type = DICT_UNIQUE;
fts_index_def.fields = (merge_index_field_t*) mem_heap_alloc(
heap, sizeof *fts_index_def.fields);
fts_index_def.fields[0].prefix_len = 0;
fts_index_def.fields[0].field_name = mem_heap_strdup(
heap, FTS_DOC_ID_COL_NAME);
index = row_merge_create_index(trx, indexed_table, &fts_index_def);
return(index);
}
/*******************************************************************//**
Clean up on ha_innobase::add_index error. */
static
void
innobase_add_index_cleanup(
/*=======================*/
row_prebuilt_t* prebuilt, /*!< in/out: prebuilt */
trx_t* trx, /*!< in/out: transaction */
dict_table_t* table) /*!< in/out: table on which
the indexes were going to be
created */
{
trx_rollback_to_savepoint(trx, NULL);
ut_a(trx != prebuilt->trx);
trx_free_for_mysql(trx);
trx_commit_for_mysql(prebuilt->trx);
if (table != NULL) {
rw_lock_x_lock(&dict_operation_lock);
dict_mutex_enter_for_mysql();
/* Note: This check excludes the system tables. However, we
should be safe because users cannot add indexes to system
tables. */
if (UT_LIST_GET_LEN(table->foreign_list) == 0
&& UT_LIST_GET_LEN(table->referenced_list) == 0
&& !table->can_be_evicted) {
dict_table_move_from_non_lru_to_lru(table);
}
dict_table_close(table, TRUE);
dict_mutex_exit_for_mysql();
rw_lock_x_unlock(&dict_operation_lock);
}
}
/*******************************************************************//**
Create indexes.
@return 0 or error number */
@ -659,7 +1007,7 @@ UNIV_INTERN
int
ha_innobase::add_index(
/*===================*/
TABLE* table, /*!< in: Table where indexes
TABLE* in_table, /*!< in: Table where indexes
are created */
KEY* key_info, /*!< in: Indexes
to be created */
@ -667,16 +1015,21 @@ ha_innobase::add_index(
to be created */
handler_add_index** add) /*!< out: context */
{
dict_index_t** index; /*!< Index to be created */
dict_index_t** index = NULL; /*!< Index to be created */
dict_index_t* fts_index = NULL;/*!< FTS Index to be created */
dict_table_t* indexed_table; /*!< Table where indexes are created */
merge_index_def_t* index_defs; /*!< Index definitions */
mem_heap_t* heap; /*!< Heap for index definitions */
mem_heap_t* heap = NULL; /*!< Heap for index definitions */
trx_t* trx; /*!< Transaction */
ulint num_of_idx;
ulint num_created = 0;
ibool dict_locked = FALSE;
ulint new_primary;
ulint new_primary = 0;
int error;
ulint num_fts_index = 0;
ulint num_idx_create = 0;
ibool fts_add_doc_id = FALSE;
ibool fts_add_doc_idx = FALSE;
DBUG_ENTER("ha_innobase::add_index");
ut_a(table);
@ -700,7 +1053,7 @@ ha_innobase::add_index(
DBUG_RETURN(-1);
}
indexed_table = dict_table_get(prebuilt->table->name, FALSE);
indexed_table = dict_table_open_on_name(prebuilt->table->name, FALSE);
if (UNIV_UNLIKELY(!indexed_table)) {
DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
@ -712,16 +1065,22 @@ ha_innobase::add_index(
error = innobase_check_index_keys(key_info, num_of_keys, prebuilt->table);
if (UNIV_UNLIKELY(error)) {
dict_table_close(prebuilt->table, FALSE);
DBUG_RETURN(error);
}
/* Check each index's column length to make sure they do not
exceed limit */
for (ulint i = 0; i < num_of_keys; i++) {
if (key_info[i].flags & HA_FULLTEXT) {
continue;
}
error = innobase_check_column_length(prebuilt->table,
&key_info[i]);
if (error) {
dict_table_close(prebuilt->table, FALSE);
DBUG_RETURN(error);
}
}
@ -734,6 +1093,20 @@ ha_innobase::add_index(
trx = innobase_trx_allocate(user_thd);
trx_start_if_not_started(trx);
/* We don't want this table to be evicted from the cache while we
are building an index on it. Another issue is that while we are
building the index this table could be referred to in a foreign
key relationship. In innobase_add_index_cleanup() we check for
that condition before moving it back to the LRU list. */
row_mysql_lock_data_dictionary(trx);
if (prebuilt->table->can_be_evicted) {
dict_table_move_from_lru_to_non_lru(prebuilt->table);
}
row_mysql_unlock_data_dictionary(trx);
/* Create table containing all indexes to be built in this
alter table add index so that they are in the correct order
in the table. */
@ -741,14 +1114,34 @@ ha_innobase::add_index(
num_of_idx = num_of_keys;
index_defs = innobase_create_key_def(
trx, prebuilt->table, heap, key_info, num_of_idx);
trx, prebuilt->table, heap, key_info, num_of_idx,
&num_fts_index, &fts_add_doc_id, &fts_add_doc_idx);
if (!index_defs) {
error = DB_UNSUPPORTED;
goto error_handling;
}
/* Currently, support create one single FULLTEXT index in parallel at
a time */
if (num_fts_index > 1) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Only support create ONE Fulltext index"
" at a time\n");
error = DB_UNSUPPORTED;
goto error_handling;
}
new_primary = DICT_CLUSTERED & index_defs[0].ind_type;
/* Allocate memory for dictionary index definitions */
/* If a new FTS Doc ID column is to be added, there will be
one additional index to be built on the Doc ID column itself. */
num_idx_create = (fts_add_doc_idx) ? num_of_idx + 1 : num_of_idx;
/* Allocate memory for dictionary index definitions */
index = (dict_index_t**) mem_heap_alloc(
heap, num_of_idx * sizeof *index);
heap, num_idx_create * sizeof *index);
/* Flag this transaction as a dictionary operation, so that
the data dictionary will be locked in crash recovery. */
@ -776,8 +1169,9 @@ ha_innobase::add_index(
if (UNIV_UNLIKELY(new_primary)) {
/* This transaction should be the only one
operating on the table. */
ut_a(prebuilt->table->n_mysql_handles_opened == 1);
operating on the table. The table get above
would have incremented the ref count to 2. */
ut_a(prebuilt->table->n_ref_count == 2);
char* new_table_name = innobase_create_temporary_tablename(
heap, '1', prebuilt->table->name);
@ -806,11 +1200,12 @@ ha_innobase::add_index(
ut_d(dict_table_check_for_dup_indexes(prebuilt->table,
FALSE));
mem_heap_free(heap);
trx_general_rollback_for_mysql(trx, NULL);
row_mysql_unlock_data_dictionary(trx);
trx_free_for_mysql(trx);
trx_commit_for_mysql(prebuilt->trx);
mem_heap_free(heap);
innobase_add_index_cleanup(
prebuilt, trx, prebuilt->table);
DBUG_RETURN(error);
}
@ -828,6 +1223,40 @@ ha_innobase::add_index(
error = trx->error_state;
goto error_handling;
}
if (index[num_created]->type & DICT_FTS) {
fts_index = index[num_created];
fts_create_index_tables(trx, fts_index);
}
}
/* create FTS_DOC_ID_INDEX on the Doc ID column on the table */
if (fts_add_doc_idx) {
index[num_of_idx] = innobase_create_fts_doc_id_idx(
indexed_table, trx, heap);
/* FTS_DOC_ID_INDEX is internal defined new index */
num_of_idx++;
num_created++;
}
if (num_fts_index) {
DICT_TF2_FLAG_SET(indexed_table, DICT_TF2_FTS);
if (!indexed_table->fts
|| ib_vector_size(indexed_table->fts->indexes) == 0) {
fts_create_common_tables(trx, indexed_table,
prebuilt->table->name, TRUE);
indexed_table->fts->fts_status |= TABLE_DICT_LOCKED;
innobase_fts_load_stopword(
indexed_table, trx, ha_thd());
indexed_table->fts->fts_status &= ~TABLE_DICT_LOCKED;
}
if (new_primary && prebuilt->table->fts) {
indexed_table->fts->doc_col = prebuilt->table->fts->doc_col;
}
}
ut_ad(error == DB_SUCCESS);
@ -843,8 +1272,7 @@ ha_innobase::add_index(
row_mysql_unlock_data_dictionary(trx);
dict_locked = FALSE;
ut_a(trx->n_active_thrs == 0);
ut_a(UT_LIST_GET_LEN(trx->signals) == 0);
ut_a(trx->lock.n_active_thrs == 0);
if (UNIV_UNLIKELY(new_primary)) {
/* A primary key is to be built. Acquire an exclusive
@ -867,60 +1295,66 @@ ha_innobase::add_index(
index, num_of_idx, table);
error_handling:
/* After an error, remove all those index definitions from the
dictionary which were defined. */
if (!dict_locked) {
row_mysql_lock_data_dictionary(trx);
dict_locked = TRUE;
}
switch (error) {
case DB_SUCCESS:
ut_a(!dict_locked);
ut_d(mutex_enter(&dict_sys->mutex));
ut_d(dict_table_check_for_dup_indexes(prebuilt->table, TRUE));
ut_d(mutex_exit(&dict_sys->mutex));
*add = new ha_innobase_add_index(table, key_info, num_of_keys,
indexed_table);
*add = new ha_innobase_add_index(
table, key_info, num_of_keys, indexed_table);
dict_table_close(prebuilt->table, dict_locked);
break;
case DB_TOO_BIG_RECORD:
my_error(HA_ERR_TO_BIG_ROW, MYF(0));
goto error;
goto error_exit;
case DB_PRIMARY_KEY_IS_NULL:
my_error(ER_PRIMARY_CANT_HAVE_NULL, MYF(0));
/* fall through */
case DB_DUPLICATE_KEY:
error:
if (fts_add_doc_idx
&& prebuilt->trx->error_key_num == num_of_idx - 1) {
prebuilt->trx->error_key_num = ULINT_UNDEFINED;
}
error_exit:
prebuilt->trx->error_info = NULL;
/* fall through */
default:
dict_table_close(prebuilt->table, dict_locked);
trx->error_state = DB_SUCCESS;
if (new_primary) {
if (indexed_table != prebuilt->table) {
dict_table_close(indexed_table, dict_locked);
row_merge_drop_table(trx, indexed_table);
}
} else {
if (!dict_locked) {
row_mysql_lock_data_dictionary(trx);
dict_locked = TRUE;
}
row_merge_drop_indexes(trx, indexed_table,
index, num_created);
}
}
ut_ad(!new_primary || prebuilt->table->n_ref_count == 1);
trx_commit_for_mysql(trx);
ut_ad(dict_locked);
row_mysql_unlock_data_dictionary(trx);
trx_free_for_mysql(trx);
mem_heap_free(heap);
if (prebuilt->trx) {
trx_commit_for_mysql(prebuilt->trx);
}
if (dict_locked) {
row_mysql_unlock_data_dictionary(trx);
}
trx_free_for_mysql(trx);
mem_heap_free(heap);
/* There might be work for utility threads.*/
srv_active_wake_master_thread();
@ -982,9 +1416,12 @@ ha_innobase::final_add_index(
prebuilt->table, add->indexed_table,
tmp_name, trx);
ut_a(prebuilt->table->n_ref_count == 1);
switch (error) {
case DB_TABLESPACE_ALREADY_EXISTS:
case DB_DUPLICATE_KEY:
ut_a(add->indexed_table->n_ref_count == 0);
innobase_convert_tablename(tmp_name);
my_error(HA_ERR_TABLE_EXIST, MYF(0), tmp_name);
err = HA_ERR_TABLE_EXIST;
@ -1000,6 +1437,7 @@ ha_innobase::final_add_index(
}
if (!commit || err) {
dict_table_close(add->indexed_table, TRUE);
error = row_merge_drop_table(trx, add->indexed_table);
trx_commit_for_mysql(prebuilt->trx);
} else {
@ -1007,7 +1445,6 @@ ha_innobase::final_add_index(
trx_commit_for_mysql(prebuilt->trx);
row_prebuilt_free(prebuilt, TRUE);
error = row_merge_drop_table(trx, old_table);
add->indexed_table->n_mysql_handles_opened++;
prebuilt = row_create_prebuilt(add->indexed_table,
0 /* XXX Do we know the mysql_row_len here?
Before the addition of this parameter to
@ -1018,8 +1455,14 @@ ha_innobase::final_add_index(
err = convert_error_code_to_mysql(
error, prebuilt->table->flags, user_thd);
} else {
/* We created secondary indexes (!new_primary). */
}
if (add->indexed_table == prebuilt->table
|| DICT_TF2_FLAG_IS_SET(prebuilt->table, DICT_TF2_FTS_ADD_DOC_ID)) {
/* We created secondary indexes (!new_primary) or create full
text index and added a new Doc ID column, we will need to
rename the secondary index on the Doc ID column to its
official index name.. */
if (commit) {
err = convert_error_code_to_mysql(
@ -1043,13 +1486,66 @@ ha_innobase::final_add_index(
}
}
}
DICT_TF2_FLAG_UNSET(prebuilt->table, DICT_TF2_FTS_ADD_DOC_ID);
}
/* If index is successfully built, we will need to rebuild index
translation table. Set valid index entry count in the translation
table to zero. */
if (err == 0 && commit) {
ibool new_primary;
dict_index_t* index;
dict_index_t* next_index;
ibool new_fts = FALSE;
dict_index_t* primary;
new_primary = !my_strcasecmp(
system_charset_info, add->key_info[0].name, "PRIMARY");
primary = dict_table_get_first_index(add->indexed_table);
if (!new_primary) {
new_primary = !my_strcasecmp(
system_charset_info, add->key_info[0].name,
primary->name);
}
share->idx_trans_tbl.index_count = 0;
if (new_primary) {
for (index = primary; index; index = next_index) {
next_index = dict_table_get_next_index(index);
if (index->type & DICT_FTS) {
fts_add_index(index,
add->indexed_table);
new_fts = TRUE;
}
}
} else {
ulint i;
for (i = 0; i < add->num_of_keys; i++) {
if (add->key_info[i].flags & HA_FULLTEXT) {
dict_index_t* fts_index;
fts_index =
dict_table_get_index_on_name(
prebuilt->table,
add->key_info[i].name);
ut_ad(fts_index);
fts_add_index(fts_index,
prebuilt->table);
new_fts = TRUE;
}
}
}
if (new_fts) {
fts_optimize_add_table(prebuilt->table);
}
}
trx_commit_for_mysql(trx);
@ -1058,6 +1554,9 @@ ha_innobase::final_add_index(
}
ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE));
ut_a(fts_check_cached_index(prebuilt->table));
row_mysql_unlock_data_dictionary(trx);
trx_free_for_mysql(trx);
@ -1068,7 +1567,6 @@ ha_innobase::final_add_index(
delete add;
DBUG_RETURN(err);
}
/*******************************************************************//**
Prepare to drop some indexes of a table.
@return 0 or error number */
@ -1076,13 +1574,13 @@ UNIV_INTERN
int
ha_innobase::prepare_drop_index(
/*============================*/
TABLE* table, /*!< in: Table where indexes are dropped */
TABLE* in_table, /*!< in: Table where indexes are dropped */
uint* key_num, /*!< in: Key nums to be dropped */
uint num_of_keys) /*!< in: Number of keys to be dropped */
{
trx_t* trx;
int err = 0;
uint n_key;
uint n_key;
DBUG_ENTER("ha_innobase::prepare_drop_index");
ut_ad(table);
@ -1284,7 +1782,8 @@ UNIV_INTERN
int
ha_innobase::final_drop_index(
/*==========================*/
TABLE* table) /*!< in: Table where indexes are dropped */
TABLE* iin_table) /*!< in: Table where indexes
are dropped */
{
dict_index_t* index; /*!< Index to be dropped */
trx_t* trx; /*!< Transaction */
@ -1300,12 +1799,12 @@ ha_innobase::final_drop_index(
update_thd();
trx_search_latch_release_if_reserved(prebuilt->trx);
trx_start_if_not_started(prebuilt->trx);
trx_start_if_not_started_xa(prebuilt->trx);
/* Create a background transaction for the operations on
the data dictionary tables. */
trx = innobase_trx_allocate(user_thd);
trx_start_if_not_started(trx);
trx_start_if_not_started_xa(trx);
/* Flag this transaction as a dictionary operation, so that
the data dictionary will be locked in crash recovery. */
@ -1317,6 +1816,36 @@ ha_innobase::final_drop_index(
row_merge_lock_table(prebuilt->trx, prebuilt->table, LOCK_X),
prebuilt->table->flags, user_thd);
/* Delete corresponding rows from the stats table.
Marko advises not to edit both user tables and SYS_* tables in one
trx, thus we use prebuilt->trx instead of trx. Because of this the
drop from SYS_* and from the stats table cannot happen in one
transaction and eventually if a crash occurs below, between
trx_commit_for_mysql(trx); which drops the indexes from SYS_* and
trx_commit_for_mysql(prebuilt->trx);
then an orphaned rows will be left in the stats table. */
for (index = dict_table_get_first_index(prebuilt->table);
index != NULL;
index = dict_table_get_next_index(index)) {
if (index->to_be_dropped) {
enum db_err ret;
char errstr[1024];
ret = dict_stats_delete_index_stats(
index, prebuilt->trx,
errstr, sizeof(errstr));
if (ret != DB_SUCCESS) {
push_warning(user_thd,
Sql_condition::WARN_LEVEL_WARN,
ER_LOCK_WAIT_TIMEOUT,
errstr);
}
}
}
row_mysql_lock_data_dictionary(trx);
ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE));
@ -1344,7 +1873,6 @@ ha_innobase::final_drop_index(
next_index = dict_table_get_next_index(index);
if (index->to_be_dropped) {
row_merge_drop_index(index, prebuilt->table, trx);
}
@ -1363,6 +1891,9 @@ ha_innobase::final_drop_index(
func_exit:
ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE));
ut_a(fts_check_cached_index(prebuilt->table));
trx_commit_for_mysql(trx);
trx_commit_for_mysql(prebuilt->trx);
row_mysql_unlock_data_dictionary(trx);

File diff suppressed because it is too large Load diff

Some files were not shown because too many files have changed in this diff Show more