mirror of
https://github.com/MariaDB/server.git
synced 2025-01-19 13:32:33 +01:00
Merge bk-internal.mysql.com:/home/bk/mysql-5.0
into mysql.com:/home/my/mysql-5.0
This commit is contained in:
commit
615129206c
81 changed files with 2662 additions and 1225 deletions
|
@ -48,8 +48,8 @@ global_warnings="-Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wch
|
|||
c_warnings="$global_warnings -Wunused"
|
||||
cxx_warnings="$global_warnings -Woverloaded-virtual -Wsign-promo -Wreorder -Wctor-dtor-privacy -Wnon-virtual-dtor"
|
||||
|
||||
base_max_configs="--with-innodb --with-berkeley-db --with-ndbcluster --with-archive-storage-engine --with-raid --with-openssl --with-raid --with-vio"
|
||||
max_leave_isam_configs="--with-innodb --with-berkeley-db --with-ndbcluster --with-archive-storage-engine --with-federated-storage-engine --with-raid --with-openssl --with-raid --with-vio --with-embedded-server"
|
||||
base_max_configs="--with-innodb --with-berkeley-db --with-ndbcluster --with-archive-storage-engine --with-raid --with-openssl --with-raid"
|
||||
max_leave_isam_configs="--with-innodb --with-berkeley-db --with-ndbcluster --with-archive-storage-engine --with-federated-storage-engine --with-raid --with-openssl --with-raid --with-embedded-server"
|
||||
max_no_es_configs="$max_leave_isam_configs --without-isam"
|
||||
max_configs="$max_no_es_configs --with-embedded-server"
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ cxx_warnings="$cxx_warnings $debug_extra_warnings"
|
|||
extra_configs="$pentium_configs $debug_configs"
|
||||
|
||||
# We want to test isam when building with valgrind
|
||||
extra_configs="$extra_configs --with-berkeley-db --with-innodb --with-isam --with-embedded-server --with-openssl --with-vio --with-raid --with-ndbcluster"
|
||||
extra_configs="$extra_configs --with-berkeley-db --with-innodb --with-isam --with-embedded-server --with-openssl --with-raid --with-ndbcluster"
|
||||
|
||||
. "$path/FINISH.sh"
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ dlenev@build.mysql.com
|
|||
dlenev@jabberwock.localdomain
|
||||
dlenev@mysql.com
|
||||
ejonore@mc03.ndb.mysql.com
|
||||
gbichot@quadita2.mysql.com
|
||||
georg@beethoven.local
|
||||
georg@beethoven.site
|
||||
gerberb@ou800.zenez.com
|
||||
|
@ -71,6 +72,7 @@ hf@deer.(none)
|
|||
hf@deer.mysql.r18.ru
|
||||
hf@genie.(none)
|
||||
igor@hundin.mysql.fi
|
||||
igor@linux.local
|
||||
igor@rurik.mysql.com
|
||||
ingo@mysql.com
|
||||
jan@hundin.mysql.fi
|
||||
|
|
|
@ -594,22 +594,13 @@ AC_MSG_RESULT($ac_cv_conv_longlong_to_float)
|
|||
])
|
||||
|
||||
AC_DEFUN([MYSQL_CHECK_VIO], [
|
||||
AC_ARG_WITH([vio],
|
||||
[ --with-vio Include the Virtual IO support],
|
||||
[vio="$withval"],
|
||||
[vio=no])
|
||||
|
||||
if test "$vio" = "yes"
|
||||
then
|
||||
vio_dir="vio"
|
||||
vio_libs="../vio/libvio.la"
|
||||
AC_DEFINE(HAVE_VIO, 1)
|
||||
else
|
||||
vio_dir=""
|
||||
vio_libs=""
|
||||
fi
|
||||
AC_SUBST([vio_dir])
|
||||
AC_SUBST([vio_libs])
|
||||
dnl
|
||||
dnl we always use vio: no need for special defines
|
||||
dnl
|
||||
AC_DEFINE([HAVE_VIO_READ_BUFF], [1],
|
||||
[Define to enable buffered read. This works only if syscalls
|
||||
read/recv return as soon as there is some data in the kernel
|
||||
buffer, no matter how big the given buffer is.])
|
||||
])
|
||||
|
||||
# Local version of _AC_PROG_CXX_EXIT_DECLARATION that does not
|
||||
|
|
|
@ -89,9 +89,6 @@ AC_MSG_CHECKING(for OpenSSL)
|
|||
fi
|
||||
MYSQL_FIND_OPENSSL([$openssl_includes], [$openssl_libs])
|
||||
#force VIO use
|
||||
vio_dir="vio"
|
||||
vio_libs="../vio/libvio.la"
|
||||
AC_DEFINE([HAVE_VIO], [1], [Virtual IO])
|
||||
AC_MSG_RESULT(yes)
|
||||
openssl_libs="-L$OPENSSL_LIB -lssl -lcrypto"
|
||||
# Don't set openssl_includes to /usr/include as this gives us a lot of
|
||||
|
|
|
@ -308,7 +308,7 @@ inline double ulonglong2double(ulonglong value)
|
|||
#define HAVE_QUERY_CACHE
|
||||
#define SPRINTF_RETURNS_INT
|
||||
#define HAVE_SETFILEPOINTER
|
||||
#define HAVE_VIO
|
||||
#define HAVE_VIO_READ_BUFF
|
||||
|
||||
#ifdef NOT_USED
|
||||
#define HAVE_SNPRINTF /* Gave link error */
|
||||
|
|
|
@ -523,6 +523,9 @@ typedef SOCKET_SIZE_TYPE size_socket;
|
|||
#ifndef O_SHORT_LIVED
|
||||
#define O_SHORT_LIVED 0
|
||||
#endif
|
||||
#ifndef O_NOFOLLOW
|
||||
#define O_NOFOLLOW 0
|
||||
#endif
|
||||
|
||||
/* #define USE_RECORD_LOCK */
|
||||
|
||||
|
|
|
@ -279,6 +279,7 @@ enum loglevel {
|
|||
enum cache_type
|
||||
{
|
||||
READ_CACHE,WRITE_CACHE,
|
||||
APPEND_CACHE, /* Like WRITE_CACHE, but only append */
|
||||
SEQ_READ_APPEND /* sequential read or append */,
|
||||
READ_FIFO, READ_NET,WRITE_NET};
|
||||
|
||||
|
|
|
@ -37,7 +37,12 @@ enum enum_vio_type
|
|||
VIO_TYPE_SSL, VIO_TYPE_SHARED_MEMORY
|
||||
};
|
||||
|
||||
Vio* vio_new(my_socket sd, enum enum_vio_type type, my_bool localhost);
|
||||
|
||||
#define VIO_LOCALHOST 1 /* a localhost connection */
|
||||
#define VIO_BUFFERED_READ 2 /* use buffered read */
|
||||
#define VIO_READ_BUFFER_SIZE 16384 /* size of read buffer */
|
||||
|
||||
Vio* vio_new(my_socket sd, enum enum_vio_type type, uint flags);
|
||||
#ifdef __WIN__
|
||||
Vio* vio_new_win32pipe(HANDLE hPipe);
|
||||
Vio* vio_new_win32shared_memory(NET *net,HANDLE handle_file_map,
|
||||
|
@ -57,8 +62,9 @@ int vio_close_pipe(Vio * vio);
|
|||
void vio_delete(Vio* vio);
|
||||
int vio_close(Vio* vio);
|
||||
void vio_reset(Vio* vio, enum enum_vio_type type,
|
||||
my_socket sd, HANDLE hPipe, my_bool localhost);
|
||||
my_socket sd, HANDLE hPipe, uint flags);
|
||||
int vio_read(Vio *vio, gptr buf, int size);
|
||||
int vio_read_buff(Vio *vio, gptr buf, int size);
|
||||
int vio_write(Vio *vio, const gptr buf, int size);
|
||||
int vio_blocking(Vio *vio, my_bool onoff, my_bool *old_mode);
|
||||
my_bool vio_is_blocking(Vio *vio);
|
||||
|
@ -135,7 +141,7 @@ int vio_close_shared_memory(Vio * vio);
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_VIO) && !defined(DONT_MAP_VIO)
|
||||
#if !defined(DONT_MAP_VIO)
|
||||
#define vio_delete(vio) (vio)->viodelete(vio)
|
||||
#define vio_errno(vio) (vio)->vioerrno(vio)
|
||||
#define vio_read(vio, buf, size) (vio)->read(vio,buf,size)
|
||||
|
@ -150,7 +156,7 @@ int vio_close_shared_memory(Vio * vio);
|
|||
#define vio_peer_addr(vio, buf, prt) (vio)->peer_addr(vio, buf, prt)
|
||||
#define vio_in_addr(vio, in) (vio)->in_addr(vio, in)
|
||||
#define vio_timeout(vio, seconds) (vio)->timeout(vio, seconds)
|
||||
#endif /* defined(HAVE_VIO) && !defined(DONT_MAP_VIO) */
|
||||
#endif /* !defined(DONT_MAP_VIO) */
|
||||
|
||||
/* This enumerator is used in parser - should be always visible */
|
||||
enum SSL_type
|
||||
|
@ -175,7 +181,10 @@ struct st_vio
|
|||
struct sockaddr_in remote; /* Remote internet address */
|
||||
enum enum_vio_type type; /* Type of connection */
|
||||
char desc[30]; /* String description */
|
||||
#ifdef HAVE_VIO
|
||||
char *read_buffer; /* buffer for vio_read_buff */
|
||||
char *read_pos; /* start of unfetched data in the
|
||||
read buffer */
|
||||
char *read_end; /* end of unfetched data */
|
||||
/* function pointers. They are similar for socket/SSL/whatever */
|
||||
void (*viodelete)(Vio*);
|
||||
int (*vioerrno)(Vio*);
|
||||
|
@ -203,6 +212,5 @@ struct st_vio
|
|||
char *shared_memory_pos;
|
||||
NET *net;
|
||||
#endif /* HAVE_SMEM */
|
||||
#endif /* HAVE_VIO */
|
||||
};
|
||||
#endif /* vio_violite_h_ */
|
||||
|
|
|
@ -262,6 +262,20 @@ trx_free(
|
|||
putc('\n', stderr);
|
||||
}
|
||||
|
||||
if (trx->n_mysql_tables_in_use != 0
|
||||
|| trx->mysql_n_tables_locked != 0) {
|
||||
|
||||
ut_print_timestamp(stderr);
|
||||
fprintf(stderr,
|
||||
" InnoDB: Error: MySQL is freeing a thd\n"
|
||||
"InnoDB: though trx->n_mysql_tables_in_use is %lu\n"
|
||||
"InnoDB: and trx->mysql_n_tables_locked is %lu.\n",
|
||||
(ulong)trx->n_mysql_tables_in_use,
|
||||
(ulong)trx->mysql_n_tables_locked);
|
||||
|
||||
trx_print(stderr, trx);
|
||||
}
|
||||
|
||||
ut_a(trx->magic_n == TRX_MAGIC_N);
|
||||
|
||||
trx->magic_n = 11112222;
|
||||
|
@ -272,9 +286,6 @@ trx_free(
|
|||
|
||||
ut_a(trx->insert_undo == NULL);
|
||||
ut_a(trx->update_undo == NULL);
|
||||
|
||||
ut_a(trx->n_mysql_tables_in_use == 0);
|
||||
ut_a(trx->mysql_n_tables_locked == 0);
|
||||
|
||||
if (trx->undo_no_arr) {
|
||||
trx_undo_arr_free(trx->undo_no_arr);
|
||||
|
|
|
@ -14,6 +14,7 @@ Created 5/11/1994 Heikki Tuuri
|
|||
|
||||
#include "mem0mem.h"
|
||||
#include "os0sync.h"
|
||||
#include "os0thread.h"
|
||||
|
||||
/* This struct is placed first in every allocated memory block */
|
||||
typedef struct ut_mem_block_struct ut_mem_block_t;
|
||||
|
@ -66,6 +67,7 @@ ut_malloc_low(
|
|||
ibool assert_on_error) /* in: if TRUE, we crash mysqld if the memory
|
||||
cannot be allocated */
|
||||
{
|
||||
ulint retry_count = 0;
|
||||
void* ret;
|
||||
|
||||
ut_ad((sizeof(ut_mem_block_t) % 8) == 0); /* check alignment ok */
|
||||
|
@ -73,24 +75,26 @@ ut_malloc_low(
|
|||
if (!ut_mem_block_list_inited) {
|
||||
ut_mem_block_list_init();
|
||||
}
|
||||
|
||||
retry:
|
||||
os_fast_mutex_lock(&ut_list_mutex);
|
||||
|
||||
ret = malloc(n + sizeof(ut_mem_block_t));
|
||||
|
||||
if (ret == NULL) {
|
||||
ut_print_timestamp(stderr);
|
||||
fprintf(stderr,
|
||||
" InnoDB: Fatal error: cannot allocate %lu bytes of\n"
|
||||
if (ret == NULL && retry_count < 60) {
|
||||
if (retry_count == 0) {
|
||||
ut_print_timestamp(stderr);
|
||||
|
||||
fprintf(stderr,
|
||||
" InnoDB: Error: cannot allocate %lu bytes of\n"
|
||||
"InnoDB: memory with malloc! Total allocated memory\n"
|
||||
"InnoDB: by InnoDB %lu bytes. Operating system errno: %lu\n"
|
||||
"InnoDB: Cannot continue operation!\n"
|
||||
"InnoDB: Check if you should increase the swap file or\n"
|
||||
"InnoDB: ulimits of your operating system.\n"
|
||||
"InnoDB: On FreeBSD check you have compiled the OS with\n"
|
||||
"InnoDB: a big enough maximum process size.\n"
|
||||
"InnoDB: Note that in most 32-bit computers the process\n"
|
||||
"InnoDB: memory space is limited to 2 GB or 4 GB.\n",
|
||||
"InnoDB: memory space is limited to 2 GB or 4 GB.\n"
|
||||
"InnoDB: We keep retrying the allocation for 60 seconds...\n",
|
||||
(ulong) n, (ulong) ut_total_allocated_memory,
|
||||
#ifdef __WIN__
|
||||
(ulong) GetLastError()
|
||||
|
@ -98,7 +102,21 @@ ut_malloc_low(
|
|||
(ulong) errno
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
os_fast_mutex_unlock(&ut_list_mutex);
|
||||
|
||||
/* Sleep for a second and retry the allocation; maybe this is
|
||||
just a temporary shortage of memory */
|
||||
|
||||
os_thread_sleep(1000000);
|
||||
|
||||
retry_count++;
|
||||
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (ret == NULL) {
|
||||
/* Flush stderr to make more probable that the error
|
||||
message gets in the error file before we generate a seg
|
||||
fault */
|
||||
|
@ -113,8 +131,10 @@ ut_malloc_low(
|
|||
by graceful exit handling in ut_a(). */
|
||||
#if (!defined __NETWARE__)
|
||||
if (assert_on_error) {
|
||||
ut_print_timestamp(stderr);
|
||||
|
||||
fprintf(stderr,
|
||||
"InnoDB: We now intentionally generate a seg fault so that\n"
|
||||
" InnoDB: We now intentionally generate a seg fault so that\n"
|
||||
"InnoDB: on Linux we get a stack trace.\n");
|
||||
|
||||
if (*ut_mem_null_ptr) ut_mem_null_ptr = 0;
|
||||
|
|
|
@ -68,7 +68,7 @@ struct st_ftb_expr
|
|||
my_off_t docid[2];
|
||||
float weight;
|
||||
float cur_weight;
|
||||
byte *quot, *qend;
|
||||
LIST *phrase; /* phrase words */
|
||||
uint yesses; /* number of "yes" words matched */
|
||||
uint nos; /* number of "no" words matched */
|
||||
uint ythresh; /* number of "yes" words in expr */
|
||||
|
@ -132,20 +132,22 @@ static int FTB_WORD_cmp_list(CHARSET_INFO *cs, FTB_WORD **a, FTB_WORD **b)
|
|||
}
|
||||
|
||||
static void _ftb_parse_query(FTB *ftb, byte **start, byte *end,
|
||||
FTB_EXPR *up, uint depth)
|
||||
FTB_EXPR *up, uint depth, byte *up_quot)
|
||||
{
|
||||
byte res;
|
||||
FTB_PARAM param;
|
||||
FT_WORD w;
|
||||
FTB_WORD *ftbw;
|
||||
FTB_EXPR *ftbe;
|
||||
FT_WORD *phrase_word;
|
||||
LIST *phrase_list;
|
||||
uint extra=HA_FT_WLEN+ftb->info->s->rec_reflength; /* just a shortcut */
|
||||
|
||||
if (ftb->state != UNINITIALIZED)
|
||||
return;
|
||||
|
||||
param.prev=' ';
|
||||
param.quot=up->quot;
|
||||
param.quot= up_quot;
|
||||
while ((res=ft_get_word(ftb->charset,start,end,&w,¶m)))
|
||||
{
|
||||
int r=param.plusminus;
|
||||
|
@ -172,6 +174,14 @@ static void _ftb_parse_query(FTB *ftb, byte **start, byte *end,
|
|||
if (param.yesno > 0) up->ythresh++;
|
||||
queue_insert(& ftb->queue, (byte *)ftbw);
|
||||
ftb->with_scan|=(param.trunc & FTB_FLAG_TRUNC);
|
||||
case 4: /* not indexed word (stopword or too short/long) */
|
||||
if (! up_quot) break;
|
||||
phrase_word= (FT_WORD *)alloc_root(&ftb->mem_root, sizeof(FT_WORD));
|
||||
phrase_list= (LIST *)alloc_root(&ftb->mem_root, sizeof(LIST));
|
||||
phrase_word->pos= w.pos;
|
||||
phrase_word->len= w.len;
|
||||
phrase_list->data= (void *)phrase_word;
|
||||
up->phrase= list_add(up->phrase, phrase_list);
|
||||
break;
|
||||
case 2: /* left bracket */
|
||||
ftbe=(FTB_EXPR *)alloc_root(&ftb->mem_root, sizeof(FTB_EXPR));
|
||||
|
@ -182,13 +192,14 @@ static void _ftb_parse_query(FTB *ftb, byte **start, byte *end,
|
|||
ftbe->up=up;
|
||||
ftbe->ythresh=ftbe->yweaks=0;
|
||||
ftbe->docid[0]=ftbe->docid[1]=HA_OFFSET_ERROR;
|
||||
if ((ftbe->quot=param.quot)) ftb->with_scan|=2;
|
||||
ftbe->phrase= NULL;
|
||||
if (param.quot) ftb->with_scan|=2;
|
||||
if (param.yesno > 0) up->ythresh++;
|
||||
_ftb_parse_query(ftb, start, end, ftbe, depth+1);
|
||||
_ftb_parse_query(ftb, start, end, ftbe, depth+1, param.quot);
|
||||
param.quot=0;
|
||||
break;
|
||||
case 3: /* right bracket */
|
||||
if (up->quot) up->qend=param.quot;
|
||||
if (up_quot) up->phrase= list_reverse(up->phrase);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -410,12 +421,12 @@ FT_INFO * ft_init_boolean_search(MI_INFO *info, uint keynr, byte *query,
|
|||
ftbe->weight=1;
|
||||
ftbe->flags=FTB_FLAG_YES;
|
||||
ftbe->nos=1;
|
||||
ftbe->quot=0;
|
||||
ftbe->up=0;
|
||||
ftbe->ythresh=ftbe->yweaks=0;
|
||||
ftbe->docid[0]=ftbe->docid[1]=HA_OFFSET_ERROR;
|
||||
ftbe->phrase= NULL;
|
||||
ftb->root=ftbe;
|
||||
_ftb_parse_query(ftb, &query, query+query_len, ftbe, 0);
|
||||
_ftb_parse_query(ftb, &query, query+query_len, ftbe, 0, NULL);
|
||||
ftb->list=(FTB_WORD **)alloc_root(&ftb->mem_root,
|
||||
sizeof(FTB_WORD *)*ftb->queue.elements);
|
||||
memcpy(ftb->list, ftb->queue.root+1, sizeof(FTB_WORD *)*ftb->queue.elements);
|
||||
|
@ -431,29 +442,45 @@ err:
|
|||
}
|
||||
|
||||
|
||||
/* returns 1 if str0 ~= /\bstr1\b/ */
|
||||
static int _ftb_strstr(const byte *s0, const byte *e0,
|
||||
const byte *s1, const byte *e1,
|
||||
CHARSET_INFO *cs)
|
||||
/*
|
||||
Checks if given buffer matches phrase list.
|
||||
|
||||
SYNOPSIS
|
||||
_ftb_check_phrase()
|
||||
s0 start of buffer
|
||||
e0 end of buffer
|
||||
phrase broken into list phrase
|
||||
cs charset info
|
||||
|
||||
RETURN VALUE
|
||||
1 is returned if phrase found, 0 else.
|
||||
*/
|
||||
|
||||
static int _ftb_check_phrase(const byte *s0, const byte *e0,
|
||||
LIST *phrase, CHARSET_INFO *cs)
|
||||
{
|
||||
const byte *p0= s0;
|
||||
my_bool s_after= true_word_char(cs, s1[0]);
|
||||
my_bool e_before= true_word_char(cs, e1[-1]);
|
||||
uint p0_len;
|
||||
my_match_t m[2];
|
||||
FT_WORD h_word;
|
||||
const byte *h_start= s0;
|
||||
DBUG_ENTER("_ftb_strstr");
|
||||
DBUG_ASSERT(phrase);
|
||||
|
||||
while (p0 < e0)
|
||||
while (ft_simple_get_word(cs, (byte **)&h_start, e0, &h_word, FALSE))
|
||||
{
|
||||
if (cs->coll->instr(cs, p0, e0 - p0, s1, e1 - s1, m, 2) != 2)
|
||||
return(0);
|
||||
if ((!s_after || p0 + m[1].beg == s0 || !true_word_char(cs, p0[m[1].beg-1])) &&
|
||||
(!e_before || p0 + m[1].end == e0 || !true_word_char(cs, p0[m[1].end])))
|
||||
return(1);
|
||||
p0+= m[1].beg;
|
||||
p0+= (p0_len= my_mbcharlen(cs, *(uchar *)p0)) ? p0_len : 1;
|
||||
FT_WORD *n_word;
|
||||
LIST *phrase_element= phrase;
|
||||
const byte *h_start1= h_start;
|
||||
for (;;)
|
||||
{
|
||||
n_word= (FT_WORD *)phrase_element->data;
|
||||
if (my_strnncoll(cs, h_word.pos, h_word.len, n_word->pos, n_word->len))
|
||||
break;
|
||||
if (! (phrase_element= phrase_element->next))
|
||||
DBUG_RETURN(1);
|
||||
if (! ft_simple_get_word(cs, (byte **)&h_start1, e0, &h_word, FALSE))
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
}
|
||||
|
||||
return(0);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -484,7 +511,7 @@ static void _ftb_climb_the_tree(FTB *ftb, FTB_WORD *ftbw, FT_SEG_ITERATOR *ftsi_
|
|||
{
|
||||
yn=ftbe->flags;
|
||||
weight=ftbe->cur_weight*ftbe->weight;
|
||||
if (mode && ftbe->quot)
|
||||
if (mode && ftbe->phrase)
|
||||
{
|
||||
int not_found=1;
|
||||
|
||||
|
@ -493,8 +520,8 @@ static void _ftb_climb_the_tree(FTB *ftb, FTB_WORD *ftbw, FT_SEG_ITERATOR *ftsi_
|
|||
{
|
||||
if (!ftsi.pos)
|
||||
continue;
|
||||
not_found = ! _ftb_strstr(ftsi.pos, ftsi.pos+ftsi.len,
|
||||
ftbe->quot, ftbe->qend, ftb->charset);
|
||||
not_found = ! _ftb_check_phrase(ftsi.pos, ftsi.pos+ftsi.len,
|
||||
ftbe->phrase, ftb->charset);
|
||||
}
|
||||
if (not_found) break;
|
||||
} /* ftbe->quot */
|
||||
|
@ -642,8 +669,8 @@ float ft_boolean_find_relevance(FT_INFO *ftb, byte *record, uint length)
|
|||
continue;
|
||||
|
||||
end=ftsi.pos+ftsi.len;
|
||||
while (ft_simple_get_word(ftb->charset,
|
||||
(byte **) &ftsi.pos, (byte *) end, &word))
|
||||
while (ft_simple_get_word(ftb->charset, (byte **) &ftsi.pos,
|
||||
(byte *) end, &word, TRUE))
|
||||
{
|
||||
int a, b, c;
|
||||
for (a=0, b=ftb->queue.elements, c=(a+b)/2; b-a>1; c=(a+b)/2)
|
||||
|
|
|
@ -93,12 +93,14 @@ my_bool ft_boolean_check_syntax_string(const byte *str)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* returns:
|
||||
* 0 - eof
|
||||
* 1 - word found
|
||||
* 2 - left bracket
|
||||
* 3 - right bracket
|
||||
*/
|
||||
/*
|
||||
RETURN VALUE
|
||||
0 - eof
|
||||
1 - word found
|
||||
2 - left bracket
|
||||
3 - right bracket
|
||||
4 - stopword found
|
||||
*/
|
||||
byte ft_get_word(CHARSET_INFO *cs, byte **start, byte *end,
|
||||
FT_WORD *word, FTB_PARAM *param)
|
||||
{
|
||||
|
@ -161,6 +163,11 @@ byte ft_get_word(CHARSET_INFO *cs, byte **start, byte *end,
|
|||
*start=doc;
|
||||
return 1;
|
||||
}
|
||||
else if (length) /* make sure length > 0 (if start contains spaces only) */
|
||||
{
|
||||
*start= doc;
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
if (param->quot)
|
||||
{
|
||||
|
@ -170,18 +177,19 @@ byte ft_get_word(CHARSET_INFO *cs, byte **start, byte *end,
|
|||
return 0;
|
||||
}
|
||||
|
||||
byte ft_simple_get_word(CHARSET_INFO *cs, byte **start, byte *end,
|
||||
FT_WORD *word)
|
||||
byte ft_simple_get_word(CHARSET_INFO *cs, byte **start, const byte *end,
|
||||
FT_WORD *word, my_bool skip_stopwords)
|
||||
{
|
||||
byte *doc= *start;
|
||||
uint mwc, length, mbl;
|
||||
DBUG_ENTER("ft_simple_get_word");
|
||||
|
||||
while (doc<end)
|
||||
do
|
||||
{
|
||||
for (;doc<end;doc++)
|
||||
for (;; doc++)
|
||||
{
|
||||
if (true_word_char(cs,*doc)) break;
|
||||
if (doc >= end) DBUG_RETURN(0);
|
||||
if (true_word_char(cs, *doc)) break;
|
||||
}
|
||||
|
||||
mwc= length= 0;
|
||||
|
@ -193,13 +201,14 @@ byte ft_simple_get_word(CHARSET_INFO *cs, byte **start, byte *end,
|
|||
|
||||
word->len= (uint)(doc-word->pos) - mwc;
|
||||
|
||||
if (length >= ft_min_word_len && length < ft_max_word_len &&
|
||||
!is_stopword(word->pos, word->len))
|
||||
if (skip_stopwords == FALSE ||
|
||||
(length >= ft_min_word_len && length < ft_max_word_len &&
|
||||
!is_stopword(word->pos, word->len)))
|
||||
{
|
||||
*start= doc;
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
}
|
||||
} while (doc < end);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
@ -217,7 +226,7 @@ int ft_parse(TREE *wtree, byte *doc, int doclen, my_bool with_alloc)
|
|||
FT_WORD w;
|
||||
DBUG_ENTER("ft_parse");
|
||||
|
||||
while (ft_simple_get_word(wtree->custom_arg, &doc,end,&w))
|
||||
while (ft_simple_get_word(wtree->custom_arg, &doc, end, &w, TRUE))
|
||||
{
|
||||
if (with_alloc)
|
||||
{
|
||||
|
|
|
@ -81,7 +81,7 @@ int ft_init_stopwords()
|
|||
goto err0;
|
||||
len=my_read(fd, buffer, len, MYF(MY_WME));
|
||||
end=start+len;
|
||||
while (ft_simple_get_word(default_charset_info, &start, end, &w))
|
||||
while (ft_simple_get_word(default_charset_info, &start, end, &w, TRUE))
|
||||
{
|
||||
if (ft_add_stopword(my_strdup_with_length(w.pos, w.len, MYF(0))))
|
||||
goto err1;
|
||||
|
|
|
@ -112,7 +112,8 @@ int is_stopword(char *word, uint len);
|
|||
uint _ft_make_key(MI_INFO *, uint , byte *, FT_WORD *, my_off_t);
|
||||
|
||||
byte ft_get_word(CHARSET_INFO *, byte **, byte *, FT_WORD *, FTB_PARAM *);
|
||||
byte ft_simple_get_word(CHARSET_INFO *, byte **, byte *, FT_WORD *);
|
||||
byte ft_simple_get_word(CHARSET_INFO *, byte **, const byte *,
|
||||
FT_WORD *, my_bool);
|
||||
|
||||
typedef struct _st_ft_seg_iterator {
|
||||
uint num, len;
|
||||
|
|
|
@ -39,7 +39,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
|
|||
{
|
||||
register uint i,j;
|
||||
File dfile,file;
|
||||
int errpos,save_errno;
|
||||
int errpos,save_errno, create_mode= O_RDWR | O_TRUNC;
|
||||
myf create_flag;
|
||||
uint fields,length,max_key_length,packed,pointer,real_length_diff,
|
||||
key_length,info_length,key_segs,options,min_key_length_skip,
|
||||
|
@ -173,7 +173,10 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
|
|||
if (!(options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)))
|
||||
min_pack_length+= varchar_length;
|
||||
if (flags & HA_CREATE_TMP_TABLE)
|
||||
{
|
||||
options|= HA_OPTION_TMP_TABLE;
|
||||
create_mode|= O_EXCL | O_NOFOLLOW;
|
||||
}
|
||||
if (flags & HA_CREATE_CHECKSUM || (options & HA_OPTION_CHECKSUM))
|
||||
{
|
||||
options|= HA_OPTION_CHECKSUM;
|
||||
|
@ -573,9 +576,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
|
|||
goto err;
|
||||
}
|
||||
|
||||
if ((file= my_create_with_symlink(linkname_ptr,
|
||||
filename,
|
||||
0, O_RDWR | O_TRUNC,
|
||||
if ((file= my_create_with_symlink(linkname_ptr, filename, 0, create_mode,
|
||||
MYF(MY_WME | create_flag))) < 0)
|
||||
goto err;
|
||||
errpos=1;
|
||||
|
@ -586,7 +587,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
|
|||
if (share.base.raid_type)
|
||||
{
|
||||
(void) fn_format(filename,name,"",MI_NAME_DEXT,2+4);
|
||||
if ((dfile=my_raid_create(filename,0,O_RDWR | O_TRUNC,
|
||||
if ((dfile=my_raid_create(filename, 0, create_mode,
|
||||
share.base.raid_type,
|
||||
share.base.raid_chunks,
|
||||
share.base.raid_chunksize,
|
||||
|
@ -610,8 +611,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
|
|||
create_flag=MY_DELETE_OLD;
|
||||
}
|
||||
if ((dfile=
|
||||
my_create_with_symlink(linkname_ptr, filename,
|
||||
0,O_RDWR | O_TRUNC,
|
||||
my_create_with_symlink(linkname_ptr, filename, 0, create_mode,
|
||||
MYF(MY_WME | create_flag))) < 0)
|
||||
goto err;
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ int myrg_create(const char *name, const char **table_names,
|
|||
|
||||
errpos=0;
|
||||
if ((file = my_create(fn_format(buff,name,"",MYRG_NAME_EXT,4),0,
|
||||
O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
|
||||
O_RDWR | O_EXCL | O_NOFOLLOW,MYF(MY_WME))) < 0)
|
||||
goto err;
|
||||
errpos=1;
|
||||
if (table_names)
|
||||
|
|
|
@ -203,3 +203,9 @@ cast(@v1 as decimal(22, 2))
|
|||
select cast(-1e18 as decimal(22,2));
|
||||
cast(-1e18 as decimal(22,2))
|
||||
-1000000000000000000.00
|
||||
create table t1(s1 time);
|
||||
insert into t1 values ('11:11:11');
|
||||
select cast(s1 as decimal(7,2)) from t1;
|
||||
cast(s1 as decimal(7,2))
|
||||
111111.00
|
||||
drop table t1;
|
||||
|
|
|
@ -514,7 +514,7 @@ Variable_name Value
|
|||
character_set_client latin1
|
||||
SELECT charset('a'),collation('a'),coercibility('a'),'a'='A';
|
||||
charset('a') collation('a') coercibility('a') 'a'='A'
|
||||
latin1 latin1_swedish_ci 3 1
|
||||
latin1 latin1_swedish_ci 4 1
|
||||
explain extended SELECT charset('a'),collation('a'),coercibility('a'),'a'='A';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used
|
||||
|
@ -525,7 +525,7 @@ SHOW VARIABLES LIKE 'collation_client';
|
|||
Variable_name Value
|
||||
SELECT charset('a'),collation('a'),coercibility('a'),'a'='A';
|
||||
charset('a') collation('a') coercibility('a') 'a'='A'
|
||||
latin1 latin1_swedish_ci 3 1
|
||||
latin1 latin1_swedish_ci 4 1
|
||||
SET CHARACTER SET 'DEFAULT';
|
||||
ERROR 42000: Unknown character set: 'DEFAULT'
|
||||
DROP TABLE t1;
|
||||
|
|
|
@ -832,3 +832,52 @@ id stddev_pop(value1) var_pop(value1) stddev_samp(value1) var_samp(value1)
|
|||
1 0.816497 0.666667 1.000000 1.000000
|
||||
2 1.118034 1.250000 1.290994 1.666667
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 (col1 decimal(16,12));
|
||||
INSERT INTO t1 VALUES (-5.00000000001),(-5.00000000002),(-5.00000000003),(-5.00000000000),(-5.00000000001),(-5.00000000002);
|
||||
insert into t1 select * from t1;
|
||||
select col1,count(col1),sum(col1),avg(col1) from t1 group by col1;
|
||||
col1 count(col1) sum(col1) avg(col1)
|
||||
-5.000000000030 2 -10.000000000060 -5.0000000000300000
|
||||
-5.000000000020 4 -20.000000000080 -5.0000000000200000
|
||||
-5.000000000010 4 -20.000000000040 -5.0000000000100000
|
||||
-5.000000000000 2 -10.000000000000 -5.0000000000000000
|
||||
DROP TABLE t1;
|
||||
create table t1 (col1 decimal(16,12));
|
||||
insert into t1 values (-5.00000000001);
|
||||
insert into t1 values (-5.00000000001);
|
||||
select col1,sum(col1),max(col1),min(col1) from t1 group by col1;
|
||||
col1 sum(col1) max(col1) min(col1)
|
||||
-5.000000000010 -10.000000000020 -5.000000000010 -5.000000000010
|
||||
delete from t1;
|
||||
insert into t1 values (5.00000000001);
|
||||
insert into t1 values (5.00000000001);
|
||||
select col1,sum(col1),max(col1),min(col1) from t1 group by col1;
|
||||
col1 sum(col1) max(col1) min(col1)
|
||||
5.000000000010 10.000000000020 5.000000000010 5.000000000010
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(
|
||||
id int PRIMARY KEY,
|
||||
a int,
|
||||
b int,
|
||||
INDEX i_b_id(a,b,id),
|
||||
INDEX i_id(a,id)
|
||||
);
|
||||
INSERT INTO t1 VALUES
|
||||
(1,1,4), (2,2,1), (3,1,3), (4,2,1), (5,1,1);
|
||||
SELECT MAX(id) FROM t1 WHERE id < 3 AND a=2 AND b=6;
|
||||
MAX(id)
|
||||
NULL
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(
|
||||
id int PRIMARY KEY,
|
||||
a int,
|
||||
b int,
|
||||
INDEX i_id(a,id),
|
||||
INDEX i_b_id(a,b,id)
|
||||
);
|
||||
INSERT INTO t1 VALUES
|
||||
(1,1,4), (2,2,1), (3,1,3), (4,2,1), (5,1,1);
|
||||
SELECT MAX(id) FROM t1 WHERE id < 3 AND a=2 AND b=6;
|
||||
MAX(id)
|
||||
NULL
|
||||
DROP TABLE t1;
|
||||
|
|
|
@ -467,97 +467,97 @@ select _latin1'B' COLLATE latin1_general_ci in (_latin1'a',_latin1'b' COLLATE la
|
|||
ERROR HY000: Illegal mix of collations (latin1_general_ci,EXPLICIT), (latin1_swedish_ci,COERCIBLE), (latin1_bin,EXPLICIT) for operation ' IN '
|
||||
select collation(bin(130)), coercibility(bin(130));
|
||||
collation(bin(130)) coercibility(bin(130))
|
||||
latin1_swedish_ci 3
|
||||
latin1_swedish_ci 4
|
||||
select collation(oct(130)), coercibility(oct(130));
|
||||
collation(oct(130)) coercibility(oct(130))
|
||||
latin1_swedish_ci 3
|
||||
latin1_swedish_ci 4
|
||||
select collation(conv(130,16,10)), coercibility(conv(130,16,10));
|
||||
collation(conv(130,16,10)) coercibility(conv(130,16,10))
|
||||
latin1_swedish_ci 3
|
||||
latin1_swedish_ci 4
|
||||
select collation(hex(130)), coercibility(hex(130));
|
||||
collation(hex(130)) coercibility(hex(130))
|
||||
latin1_swedish_ci 3
|
||||
latin1_swedish_ci 4
|
||||
select collation(char(130)), coercibility(hex(130));
|
||||
collation(char(130)) coercibility(hex(130))
|
||||
latin1_swedish_ci 3
|
||||
latin1_swedish_ci 4
|
||||
select collation(format(130,10)), coercibility(format(130,10));
|
||||
collation(format(130,10)) coercibility(format(130,10))
|
||||
latin1_swedish_ci 3
|
||||
latin1_swedish_ci 4
|
||||
select collation(lcase(_latin2'a')), coercibility(lcase(_latin2'a'));
|
||||
collation(lcase(_latin2'a')) coercibility(lcase(_latin2'a'))
|
||||
latin2_general_ci 3
|
||||
latin2_general_ci 4
|
||||
select collation(ucase(_latin2'a')), coercibility(ucase(_latin2'a'));
|
||||
collation(ucase(_latin2'a')) coercibility(ucase(_latin2'a'))
|
||||
latin2_general_ci 3
|
||||
latin2_general_ci 4
|
||||
select collation(left(_latin2'a',1)), coercibility(left(_latin2'a',1));
|
||||
collation(left(_latin2'a',1)) coercibility(left(_latin2'a',1))
|
||||
latin2_general_ci 3
|
||||
latin2_general_ci 4
|
||||
select collation(right(_latin2'a',1)), coercibility(right(_latin2'a',1));
|
||||
collation(right(_latin2'a',1)) coercibility(right(_latin2'a',1))
|
||||
latin2_general_ci 3
|
||||
latin2_general_ci 4
|
||||
select collation(substring(_latin2'a',1,1)), coercibility(substring(_latin2'a',1,1));
|
||||
collation(substring(_latin2'a',1,1)) coercibility(substring(_latin2'a',1,1))
|
||||
latin2_general_ci 3
|
||||
latin2_general_ci 4
|
||||
select collation(concat(_latin2'a',_latin2'b')), coercibility(concat(_latin2'a',_latin2'b'));
|
||||
collation(concat(_latin2'a',_latin2'b')) coercibility(concat(_latin2'a',_latin2'b'))
|
||||
latin2_general_ci 3
|
||||
latin2_general_ci 4
|
||||
select collation(lpad(_latin2'a',4,_latin2'b')), coercibility(lpad(_latin2'a',4,_latin2'b'));
|
||||
collation(lpad(_latin2'a',4,_latin2'b')) coercibility(lpad(_latin2'a',4,_latin2'b'))
|
||||
latin2_general_ci 3
|
||||
latin2_general_ci 4
|
||||
select collation(rpad(_latin2'a',4,_latin2'b')), coercibility(rpad(_latin2'a',4,_latin2'b'));
|
||||
collation(rpad(_latin2'a',4,_latin2'b')) coercibility(rpad(_latin2'a',4,_latin2'b'))
|
||||
latin2_general_ci 3
|
||||
latin2_general_ci 4
|
||||
select collation(concat_ws(_latin2'a',_latin2'b')), coercibility(concat_ws(_latin2'a',_latin2'b'));
|
||||
collation(concat_ws(_latin2'a',_latin2'b')) coercibility(concat_ws(_latin2'a',_latin2'b'))
|
||||
latin2_general_ci 3
|
||||
latin2_general_ci 4
|
||||
select collation(make_set(255,_latin2'a',_latin2'b',_latin2'c')), coercibility(make_set(255,_latin2'a',_latin2'b',_latin2'c'));
|
||||
collation(make_set(255,_latin2'a',_latin2'b',_latin2'c')) coercibility(make_set(255,_latin2'a',_latin2'b',_latin2'c'))
|
||||
latin2_general_ci 3
|
||||
latin2_general_ci 4
|
||||
select collation(export_set(255,_latin2'y',_latin2'n',_latin2' ')), coercibility(export_set(255,_latin2'y',_latin2'n',_latin2' '));
|
||||
collation(export_set(255,_latin2'y',_latin2'n',_latin2' ')) coercibility(export_set(255,_latin2'y',_latin2'n',_latin2' '))
|
||||
binary 3
|
||||
binary 4
|
||||
select collation(trim(_latin2' a ')), coercibility(trim(_latin2' a '));
|
||||
collation(trim(_latin2' a ')) coercibility(trim(_latin2' a '))
|
||||
latin2_general_ci 3
|
||||
latin2_general_ci 4
|
||||
select collation(ltrim(_latin2' a ')), coercibility(ltrim(_latin2' a '));
|
||||
collation(ltrim(_latin2' a ')) coercibility(ltrim(_latin2' a '))
|
||||
latin2_general_ci 3
|
||||
latin2_general_ci 4
|
||||
select collation(rtrim(_latin2' a ')), coercibility(rtrim(_latin2' a '));
|
||||
collation(rtrim(_latin2' a ')) coercibility(rtrim(_latin2' a '))
|
||||
latin2_general_ci 3
|
||||
latin2_general_ci 4
|
||||
select collation(trim(LEADING _latin2' ' FROM _latin2'a')), coercibility(trim(LEADING _latin2'a' FROM _latin2'a'));
|
||||
collation(trim(LEADING _latin2' ' FROM _latin2'a')) coercibility(trim(LEADING _latin2'a' FROM _latin2'a'))
|
||||
latin2_general_ci 3
|
||||
latin2_general_ci 4
|
||||
select collation(trim(TRAILING _latin2' ' FROM _latin2'a')), coercibility(trim(TRAILING _latin2'a' FROM _latin2'a'));
|
||||
collation(trim(TRAILING _latin2' ' FROM _latin2'a')) coercibility(trim(TRAILING _latin2'a' FROM _latin2'a'))
|
||||
latin2_general_ci 3
|
||||
latin2_general_ci 4
|
||||
select collation(trim(BOTH _latin2' ' FROM _latin2'a')), coercibility(trim(BOTH _latin2'a' FROM _latin2'a'));
|
||||
collation(trim(BOTH _latin2' ' FROM _latin2'a')) coercibility(trim(BOTH _latin2'a' FROM _latin2'a'))
|
||||
latin2_general_ci 3
|
||||
latin2_general_ci 4
|
||||
select collation(repeat(_latin2'a',10)), coercibility(repeat(_latin2'a',10));
|
||||
collation(repeat(_latin2'a',10)) coercibility(repeat(_latin2'a',10))
|
||||
latin2_general_ci 3
|
||||
latin2_general_ci 4
|
||||
select collation(reverse(_latin2'ab')), coercibility(reverse(_latin2'ab'));
|
||||
collation(reverse(_latin2'ab')) coercibility(reverse(_latin2'ab'))
|
||||
latin2_general_ci 3
|
||||
latin2_general_ci 4
|
||||
select collation(quote(_latin2'ab')), coercibility(quote(_latin2'ab'));
|
||||
collation(quote(_latin2'ab')) coercibility(quote(_latin2'ab'))
|
||||
latin2_general_ci 3
|
||||
latin2_general_ci 4
|
||||
select collation(soundex(_latin2'ab')), coercibility(soundex(_latin2'ab'));
|
||||
collation(soundex(_latin2'ab')) coercibility(soundex(_latin2'ab'))
|
||||
latin2_general_ci 3
|
||||
latin2_general_ci 4
|
||||
select collation(substring(_latin2'ab',1)), coercibility(substring(_latin2'ab',1));
|
||||
collation(substring(_latin2'ab',1)) coercibility(substring(_latin2'ab',1))
|
||||
latin2_general_ci 3
|
||||
latin2_general_ci 4
|
||||
select collation(insert(_latin2'abcd',2,3,_latin2'ef')), coercibility(insert(_latin2'abcd',2,3,_latin2'ef'));
|
||||
collation(insert(_latin2'abcd',2,3,_latin2'ef')) coercibility(insert(_latin2'abcd',2,3,_latin2'ef'))
|
||||
latin2_general_ci 3
|
||||
latin2_general_ci 4
|
||||
select collation(replace(_latin2'abcd',_latin2'b',_latin2'B')), coercibility(replace(_latin2'abcd',_latin2'b',_latin2'B'));
|
||||
collation(replace(_latin2'abcd',_latin2'b',_latin2'B')) coercibility(replace(_latin2'abcd',_latin2'b',_latin2'B'))
|
||||
latin2_general_ci 3
|
||||
latin2_general_ci 4
|
||||
select collation(encode('abcd','ab')), coercibility(encode('abcd','ab'));
|
||||
collation(encode('abcd','ab')) coercibility(encode('abcd','ab'))
|
||||
binary 3
|
||||
binary 4
|
||||
create table t1
|
||||
select
|
||||
bin(130),
|
||||
|
|
|
@ -68,3 +68,11 @@ drop table t1;
|
|||
select TRUE,FALSE,NULL;
|
||||
TRUE FALSE NULL
|
||||
1 0 NULL
|
||||
create table t1 (a char(10)) character set latin1;
|
||||
select * from t1 where a=version();
|
||||
a
|
||||
select * from t1 where a=database();
|
||||
a
|
||||
select * from t1 where a=user();
|
||||
a
|
||||
drop table t1;
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
show variables where variable_name like "skip_show_database";
|
||||
Variable_name Value
|
||||
skip_show_database OFF
|
||||
grant all privileges on test.* to mysqltest_1@localhost;
|
||||
grant select, update, execute on test.* to mysqltest_2@localhost;
|
||||
grant select, update on test.* to mysqltest_1@localhost;
|
||||
select * from information_schema.SCHEMATA where schema_name > 'm';
|
||||
CATALOG_NAME SCHEMA_NAME DEFAULT_CHARACTER_SET_NAME SQL_PATH
|
||||
NULL mysql latin1 NULL
|
||||
|
@ -229,6 +230,44 @@ sel2 sel2
|
|||
select count(*) from information_schema.ROUTINES;
|
||||
count(*)
|
||||
2
|
||||
select ROUTINE_NAME, ROUTINE_DEFINITION from information_schema.ROUTINES;
|
||||
ROUTINE_NAME ROUTINE_DEFINITION
|
||||
show create function sub1;
|
||||
ERROR 42000: FUNCTION sub1 does not exist
|
||||
select ROUTINE_NAME, ROUTINE_DEFINITION from information_schema.ROUTINES;
|
||||
ROUTINE_NAME ROUTINE_DEFINITION
|
||||
sel2
|
||||
sub1
|
||||
grant all privileges on test.* to mysqltest_1@localhost;
|
||||
select ROUTINE_NAME, ROUTINE_DEFINITION from information_schema.ROUTINES;
|
||||
ROUTINE_NAME ROUTINE_DEFINITION
|
||||
sel2
|
||||
sub1
|
||||
create function sub2(i int) returns int
|
||||
return i+1;
|
||||
select ROUTINE_NAME, ROUTINE_DEFINITION from information_schema.ROUTINES;
|
||||
ROUTINE_NAME ROUTINE_DEFINITION
|
||||
sel2
|
||||
sub1
|
||||
sub2 return i+1
|
||||
show create procedure sel2;
|
||||
Procedure sql_mode Create Procedure
|
||||
sel2
|
||||
show create function sub1;
|
||||
Function sql_mode Create Function
|
||||
sub1
|
||||
show create function sub2;
|
||||
Function sql_mode Create Function
|
||||
sub2 CREATE FUNCTION `test`.`sub2`(i int) RETURNS int
|
||||
return i+1
|
||||
drop function sub2;
|
||||
show create procedure sel2;
|
||||
Procedure sql_mode Create Procedure
|
||||
sel2 CREATE PROCEDURE `test`.`sel2`()
|
||||
begin
|
||||
select * from t1;
|
||||
select * from t2;
|
||||
end
|
||||
create view v0 (c) as select schema_name from information_schema.schemata;
|
||||
select * from v0;
|
||||
c
|
||||
|
@ -311,8 +350,8 @@ GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME PRIVILEGE_TYPE IS_GRAN
|
|||
'mysqltest_1'@'localhost' NULL test t1 a INSERT NO
|
||||
'mysqltest_1'@'localhost' NULL test t1 a UPDATE NO
|
||||
'mysqltest_1'@'localhost' NULL test t1 a REFERENCES NO
|
||||
delete from mysql.user where user='mysqltest_1';
|
||||
delete from mysql.db where user='mysqltest_1';
|
||||
delete from mysql.user where user='mysqltest_1' or user='mysqltest_2';
|
||||
delete from mysql.db where user='mysqltest_1' or user='mysqltest_2';
|
||||
delete from mysql.tables_priv where user='mysqltest_1';
|
||||
delete from mysql.columns_priv where user='mysqltest_1';
|
||||
flush privileges;
|
||||
|
|
|
@ -42,7 +42,7 @@ check table t2;
|
|||
Table Op Msg_type Msg_text
|
||||
test.t2 check error Table 't2' was not locked with LOCK TABLES
|
||||
insert into t1 select index1,nr from t1;
|
||||
ERROR 42000: INSERT command denied to user 'root'@'localhost' for column 'index1' in table 't1'
|
||||
ERROR HY000: Table 't1' was not locked with LOCK TABLES
|
||||
unlock tables;
|
||||
lock tables t1 write, t1 as t1_alias read;
|
||||
insert into t1 select index1,nr from t1 as t1_alias;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
DROP TABLE IF EXISTS t1, `"t"1`, t1aa,t2aa;
|
||||
drop database if exists mysqldump_test_db;
|
||||
drop view if exists v1;
|
||||
CREATE TABLE t1(a int);
|
||||
INSERT INTO t1 VALUES (1), (2);
|
||||
<?xml version="1.0"?>
|
||||
|
|
|
@ -237,6 +237,13 @@ insert into t2 values ("a", 1, 1.1), ("b", 2, 1.2), ("c", 3, 1.3)|
|
|||
drop procedure if exists sub1|
|
||||
create procedure sub1(id char(16), x int)
|
||||
insert into test.t1 values (id, x)|
|
||||
drop procedure if exists sub2|
|
||||
create procedure sub2(id char(16))
|
||||
begin
|
||||
declare x int;
|
||||
set x = (select sum(t.i) from test.t2 t);
|
||||
insert into test.t1 values (id, x);
|
||||
end|
|
||||
drop procedure if exists sub3|
|
||||
create function sub3(i int) returns int
|
||||
return i+1|
|
||||
|
@ -244,16 +251,19 @@ call sub1("sub1a", (select 7))|
|
|||
call sub1("sub1b", (select max(i) from t2))|
|
||||
call sub1("sub1c", (select i,d from t2 limit 1))|
|
||||
call sub1("sub1d", (select 1 from (select 1) a))|
|
||||
call sub2("sub2");
|
||||
select * from t1|
|
||||
id data
|
||||
sub1a 7
|
||||
sub1b 3
|
||||
sub1c 1
|
||||
sub1d 1
|
||||
sub2 6
|
||||
select sub3((select max(i) from t2))|
|
||||
sub3((select max(i) from t2))
|
||||
4
|
||||
drop procedure sub1|
|
||||
drop procedure sub2|
|
||||
drop function sub3|
|
||||
delete from t2|
|
||||
drop procedure if exists a0|
|
||||
|
@ -269,6 +279,7 @@ sub1a 7
|
|||
sub1b 3
|
||||
sub1c 1
|
||||
sub1d 1
|
||||
sub2 6
|
||||
a0 2
|
||||
a0 1
|
||||
a0 0
|
||||
|
@ -1045,6 +1056,200 @@ select row_count()|
|
|||
row_count()
|
||||
-1
|
||||
drop procedure rc|
|
||||
drop function if exists f0|
|
||||
drop function if exists f1|
|
||||
drop function if exists f2|
|
||||
drop function if exists f3|
|
||||
drop function if exists f4|
|
||||
drop function if exists f5|
|
||||
drop function if exists f6|
|
||||
drop function if exists f7|
|
||||
drop function if exists f8|
|
||||
drop view if exists v0|
|
||||
drop view if exists v1|
|
||||
drop view if exists v2|
|
||||
delete from t1|
|
||||
delete from t2|
|
||||
insert into t1 values ("a", 1), ("b", 2) |
|
||||
insert into t2 values ("a", 1, 1.0), ("b", 2, 2.0), ("c", 3, 3.0) |
|
||||
create function f1() returns int
|
||||
return (select sum(data) from t1)|
|
||||
select f1()|
|
||||
f1()
|
||||
3
|
||||
select id, f1() from t1|
|
||||
id f1()
|
||||
a 3
|
||||
b 3
|
||||
create function f2() returns int
|
||||
return (select data from t1 where data <= (select sum(data) from t1) limit 1)|
|
||||
select f2()|
|
||||
f2()
|
||||
1
|
||||
select id, f2() from t1|
|
||||
id f2()
|
||||
a 1
|
||||
b 1
|
||||
create function f3() returns int
|
||||
begin
|
||||
declare n int;
|
||||
declare m int;
|
||||
set n:= (select min(data) from t1);
|
||||
set m:= (select max(data) from t1);
|
||||
return n < m;
|
||||
end|
|
||||
select f3()|
|
||||
f3()
|
||||
1
|
||||
select id, f3() from t1|
|
||||
id f3()
|
||||
a 1
|
||||
b 1
|
||||
select f1(), f3()|
|
||||
f1() f3()
|
||||
3 1
|
||||
select id, f1(), f3() from t1|
|
||||
id f1() f3()
|
||||
a 3 1
|
||||
b 3 1
|
||||
create function f4() returns double
|
||||
return (select d from t1, t2 where t1.data = t2.i and t1.id= "b")|
|
||||
select f4()|
|
||||
f4()
|
||||
2
|
||||
select s, f4() from t2|
|
||||
s f4()
|
||||
a 2
|
||||
b 2
|
||||
c 2
|
||||
create function f5(i int) returns int
|
||||
begin
|
||||
if i <= 0 then
|
||||
return 0;
|
||||
elseif i = 1 then
|
||||
return (select count(*) from t1 where data = i);
|
||||
else
|
||||
return (select count(*) + f5( i - 1) from t1 where data = i);
|
||||
end if;
|
||||
end|
|
||||
select f5(1)|
|
||||
f5(1)
|
||||
1
|
||||
select f5(2)|
|
||||
ERROR HY000: Table 't1' was not locked with LOCK TABLES
|
||||
create function f6() returns int
|
||||
begin
|
||||
declare n int;
|
||||
set n:= f1();
|
||||
return (select count(*) from t1 where data <= f7() and data <= n);
|
||||
end|
|
||||
create function f7() returns int
|
||||
return (select sum(data) from t1 where data <= f1())|
|
||||
select f6()|
|
||||
f6()
|
||||
2
|
||||
select id, f6() from t1|
|
||||
id f6()
|
||||
a 2
|
||||
b 2
|
||||
create view v1 (a) as select f1()|
|
||||
select * from v1|
|
||||
a
|
||||
3
|
||||
select id, a from t1, v1|
|
||||
id a
|
||||
a 3
|
||||
b 3
|
||||
select * from v1, v1 as v|
|
||||
a a
|
||||
3 3
|
||||
create view v2 (a) as select a*10 from v1|
|
||||
select * from v2|
|
||||
a
|
||||
30
|
||||
select id, a from t1, v2|
|
||||
id a
|
||||
a 30
|
||||
b 30
|
||||
select * from v1, v2|
|
||||
a a
|
||||
3 30
|
||||
create function f8 () returns int
|
||||
return (select count(*) from v2)|
|
||||
select *, f8() from v1|
|
||||
a f8()
|
||||
3 1
|
||||
drop function f1|
|
||||
select * from v1|
|
||||
ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s)
|
||||
create function f1() returns int
|
||||
return (select sum(data) from t1) + (select sum(data) from v1)|
|
||||
drop function f1|
|
||||
create function f1() returns int
|
||||
return (select sum(data) from t1)|
|
||||
create function f0() returns int
|
||||
return (select * from (select 100) as r)|
|
||||
select f0()|
|
||||
f0()
|
||||
100
|
||||
select *, f0() from (select 1) as t|
|
||||
1 f0()
|
||||
1 100
|
||||
create view v0 as select f0()|
|
||||
select * from v0|
|
||||
f0()
|
||||
100
|
||||
select *, f0() from v0|
|
||||
f0() f0()
|
||||
100 100
|
||||
lock tables t1 read, t1 as t11 read, mysql.proc read|
|
||||
select f3()|
|
||||
f3()
|
||||
1
|
||||
select id, f3() from t1 as t11|
|
||||
id f3()
|
||||
a 1
|
||||
b 1
|
||||
select f0()|
|
||||
f0()
|
||||
100
|
||||
select * from v0|
|
||||
f0()
|
||||
100
|
||||
select *, f0() from v0, (select 123) as d1|
|
||||
f0() 123 f0()
|
||||
100 123 100
|
||||
select id, f3() from t1|
|
||||
ERROR HY000: Table 't1' was not locked with LOCK TABLES
|
||||
select f4()|
|
||||
ERROR HY000: Table 't2' was not locked with LOCK TABLES
|
||||
unlock tables|
|
||||
lock tables v2 read, mysql.proc read|
|
||||
select * from v2|
|
||||
a
|
||||
30
|
||||
select * from v1|
|
||||
a
|
||||
3
|
||||
select * from v1, v2|
|
||||
ERROR HY000: Table 't1' was not locked with LOCK TABLES
|
||||
select f4()|
|
||||
ERROR HY000: Table 't2' was not locked with LOCK TABLES
|
||||
unlock tables|
|
||||
drop function f0|
|
||||
drop function f1|
|
||||
drop function f2|
|
||||
drop function f3|
|
||||
drop function f4|
|
||||
drop function f5|
|
||||
drop function f6|
|
||||
drop function f7|
|
||||
drop function f8|
|
||||
drop view v0|
|
||||
drop view v1|
|
||||
drop view v2|
|
||||
delete from t1 |
|
||||
delete from t2 |
|
||||
drop procedure if exists bug822|
|
||||
create procedure bug822(a_id char(16), a_data int)
|
||||
begin
|
||||
|
@ -1177,56 +1382,6 @@ select @x2|
|
|||
@x2
|
||||
2
|
||||
drop procedure bug2260|
|
||||
drop procedure if exists bug2267_1|
|
||||
create procedure bug2267_1()
|
||||
begin
|
||||
show procedure status;
|
||||
end|
|
||||
drop procedure if exists bug2267_2|
|
||||
create procedure bug2267_2()
|
||||
begin
|
||||
show function status;
|
||||
end|
|
||||
drop procedure if exists bug2267_3|
|
||||
create procedure bug2267_3()
|
||||
begin
|
||||
show create procedure bug2267_1;
|
||||
end|
|
||||
drop procedure if exists bug2267_4|
|
||||
create procedure bug2267_4()
|
||||
begin
|
||||
show create function fac;
|
||||
end|
|
||||
call bug2267_1()|
|
||||
Db Name Type Definer Modified Created Security_type Comment
|
||||
test bug2267_1 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
|
||||
test bug2267_2 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
|
||||
test bug2267_3 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
|
||||
test bug2267_4 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
|
||||
call bug2267_2()|
|
||||
Db Name Type Definer Modified Created Security_type Comment
|
||||
test fac FUNCTION root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
|
||||
call bug2267_3()|
|
||||
Procedure sql_mode Create Procedure
|
||||
bug2267_1 CREATE PROCEDURE `test`.`bug2267_1`()
|
||||
begin
|
||||
show procedure status;
|
||||
end
|
||||
call bug2267_4()|
|
||||
Function sql_mode Create Function
|
||||
fac CREATE FUNCTION `test`.`fac`(n int unsigned) RETURNS bigint unsigned
|
||||
begin
|
||||
declare f bigint unsigned default 1;
|
||||
while n > 1 do
|
||||
set f = f * n;
|
||||
set n = n - 1;
|
||||
end while;
|
||||
return f;
|
||||
end
|
||||
drop procedure bug2267_1|
|
||||
drop procedure bug2267_2|
|
||||
drop procedure bug2267_3|
|
||||
drop procedure bug2267_4|
|
||||
drop procedure if exists bug2227|
|
||||
create procedure bug2227(x int)
|
||||
begin
|
||||
|
@ -1331,7 +1486,7 @@ declare t2 int;
|
|||
declare t3 int;
|
||||
declare rc int default 0;
|
||||
declare continue handler for 1065 set rc = 1;
|
||||
drop table if exists temp_t1;
|
||||
drop temporary table if exists temp_t1;
|
||||
create temporary table temp_t1 (
|
||||
f1 int auto_increment, f2 varchar(20), primary key (f1)
|
||||
);
|
||||
|
@ -1349,6 +1504,7 @@ f1 rc t3
|
|||
2 0 NULL
|
||||
2 0 NULL
|
||||
drop procedure bug1863|
|
||||
drop temporary table temp_t1;
|
||||
drop table t3, t4|
|
||||
drop table if exists t3, t4|
|
||||
create table t3 (
|
||||
|
@ -2515,7 +2671,7 @@ delete from t1|
|
|||
insert into t1 values ("answer", 42)|
|
||||
select id, bug5240() from t1|
|
||||
id bug5240()
|
||||
42 42
|
||||
answer 42
|
||||
drop function bug5240|
|
||||
drop function if exists bug5278|
|
||||
create function bug5278 () returns char
|
||||
|
|
|
@ -509,7 +509,7 @@ charset(load_file('../../std_data/words.dat')),
|
|||
collation(load_file('../../std_data/words.dat')),
|
||||
coercibility(load_file('../../std_data/words.dat'));
|
||||
charset(load_file('../../std_data/words.dat')) collation(load_file('../../std_data/words.dat')) coercibility(load_file('../../std_data/words.dat'))
|
||||
binary binary 3
|
||||
binary binary 4
|
||||
explain extended select
|
||||
charset(load_file('../../std_data/words.dat')),
|
||||
collation(load_file('../../std_data/words.dat')),
|
||||
|
|
|
@ -733,6 +733,9 @@ abs(9999999999999999999999)
|
|||
select abs(-9999999999999999999999);
|
||||
abs(-9999999999999999999999)
|
||||
9999999999999999999999
|
||||
select ceiling(999999999999999999);
|
||||
ceiling(999999999999999999)
|
||||
999999999999999999
|
||||
select ceiling(99999999999999999999);
|
||||
ceiling(99999999999999999999)
|
||||
99999999999999999999
|
||||
|
@ -741,13 +744,16 @@ ceiling(9.9999999999999999999)
|
|||
10
|
||||
select ceiling(-9.9999999999999999999);
|
||||
ceiling(-9.9999999999999999999)
|
||||
-10
|
||||
-9
|
||||
select floor(999999999999999999);
|
||||
floor(999999999999999999)
|
||||
999999999999999999
|
||||
select floor(9999999999999999999999);
|
||||
floor(9999999999999999999999)
|
||||
9999999999999999999999
|
||||
select floor(9.999999999999999999999);
|
||||
floor(9.999999999999999999999)
|
||||
10
|
||||
9
|
||||
select floor(-9.999999999999999999999);
|
||||
floor(-9.999999999999999999999)
|
||||
-10
|
||||
|
|
|
@ -126,3 +126,8 @@ select cast(cast('1.2' as decimal(3,2)) as signed);
|
|||
set @v1=1e18;
|
||||
select cast(@v1 as decimal(22, 2));
|
||||
select cast(-1e18 as decimal(22,2));
|
||||
|
||||
create table t1(s1 time);
|
||||
insert into t1 values ('11:11:11');
|
||||
select cast(s1 as decimal(7,2)) from t1;
|
||||
drop table t1;
|
||||
|
|
|
@ -537,3 +537,57 @@ CREATE TABLE t1 (id int(11),value1 float(10,2));
|
|||
INSERT INTO t1 VALUES (1,0.00),(1,1.00), (1,2.00), (2,10.00), (2,11.00), (2,12.00), (2,13.00);
|
||||
select id, stddev_pop(value1), var_pop(value1), stddev_samp(value1), var_samp(value1) from t1 group by id;
|
||||
DROP TABLE t1;
|
||||
|
||||
#
|
||||
# BUG#8464 decimal AVG returns incorrect result
|
||||
#
|
||||
|
||||
CREATE TABLE t1 (col1 decimal(16,12));
|
||||
INSERT INTO t1 VALUES (-5.00000000001),(-5.00000000002),(-5.00000000003),(-5.00000000000),(-5.00000000001),(-5.00000000002);
|
||||
insert into t1 select * from t1;
|
||||
select col1,count(col1),sum(col1),avg(col1) from t1 group by col1;
|
||||
DROP TABLE t1;
|
||||
|
||||
#
|
||||
# BUG#8465 decimal MIN and MAX return incorrect result
|
||||
#
|
||||
|
||||
create table t1 (col1 decimal(16,12));
|
||||
insert into t1 values (-5.00000000001);
|
||||
insert into t1 values (-5.00000000001);
|
||||
select col1,sum(col1),max(col1),min(col1) from t1 group by col1;
|
||||
delete from t1;
|
||||
insert into t1 values (5.00000000001);
|
||||
insert into t1 values (5.00000000001);
|
||||
select col1,sum(col1),max(col1),min(col1) from t1 group by col1;
|
||||
DROP TABLE t1;
|
||||
|
||||
#
|
||||
# Bug 8893: wrong result for min/max optimization with 2 indexes
|
||||
#
|
||||
|
||||
CREATE TABLE t1(
|
||||
id int PRIMARY KEY,
|
||||
a int,
|
||||
b int,
|
||||
INDEX i_b_id(a,b,id),
|
||||
INDEX i_id(a,id)
|
||||
);
|
||||
INSERT INTO t1 VALUES
|
||||
(1,1,4), (2,2,1), (3,1,3), (4,2,1), (5,1,1);
|
||||
SELECT MAX(id) FROM t1 WHERE id < 3 AND a=2 AND b=6;
|
||||
DROP TABLE t1;
|
||||
|
||||
# change the order of the last two index definitions
|
||||
|
||||
CREATE TABLE t1(
|
||||
id int PRIMARY KEY,
|
||||
a int,
|
||||
b int,
|
||||
INDEX i_id(a,id),
|
||||
INDEX i_b_id(a,b,id)
|
||||
);
|
||||
INSERT INTO t1 VALUES
|
||||
(1,1,4), (2,2,1), (3,1,3), (4,2,1), (5,1,1);
|
||||
SELECT MAX(id) FROM t1 WHERE id < 3 AND a=2 AND b=6;
|
||||
DROP TABLE t1;
|
||||
|
|
|
@ -30,3 +30,12 @@ show create table t1;
|
|||
drop table t1;
|
||||
|
||||
select TRUE,FALSE,NULL;
|
||||
|
||||
#
|
||||
# Bug#8291 Illegal collation mix with USER() function
|
||||
#
|
||||
create table t1 (a char(10)) character set latin1;
|
||||
select * from t1 where a=version();
|
||||
select * from t1 where a=database();
|
||||
select * from t1 where a=user();
|
||||
drop table t1;
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
# show databases
|
||||
|
||||
show variables where variable_name like "skip_show_database";
|
||||
grant all privileges on test.* to mysqltest_1@localhost;
|
||||
grant select, update, execute on test.* to mysqltest_2@localhost;
|
||||
grant select, update on test.* to mysqltest_1@localhost;
|
||||
|
||||
select * from information_schema.SCHEMATA where schema_name > 'm';
|
||||
select schema_name from information_schema.schemata;
|
||||
|
@ -104,6 +105,30 @@ select a.ROUTINE_NAME, b.name from information_schema.ROUTINES a,
|
|||
mysql.proc b where a.ROUTINE_NAME = convert(b.name using utf8);
|
||||
select count(*) from information_schema.ROUTINES;
|
||||
|
||||
connect (user1,localhost,mysqltest_1,,);
|
||||
connect (user3,localhost,mysqltest_2,,);
|
||||
connection user1;
|
||||
select ROUTINE_NAME, ROUTINE_DEFINITION from information_schema.ROUTINES;
|
||||
--error 1305
|
||||
show create function sub1;
|
||||
connection user3;
|
||||
select ROUTINE_NAME, ROUTINE_DEFINITION from information_schema.ROUTINES;
|
||||
connection default;
|
||||
grant all privileges on test.* to mysqltest_1@localhost;
|
||||
connect (user2,localhost,mysqltest_1,,);
|
||||
connection user2;
|
||||
select ROUTINE_NAME, ROUTINE_DEFINITION from information_schema.ROUTINES;
|
||||
create function sub2(i int) returns int
|
||||
return i+1;
|
||||
select ROUTINE_NAME, ROUTINE_DEFINITION from information_schema.ROUTINES;
|
||||
show create procedure sel2;
|
||||
show create function sub1;
|
||||
show create function sub2;
|
||||
connection default;
|
||||
disconnect user1;
|
||||
drop function sub2;
|
||||
show create procedure sel2;
|
||||
|
||||
#
|
||||
# Test for views
|
||||
#
|
||||
|
@ -138,8 +163,8 @@ select * from information_schema.USER_PRIVILEGES where grantee like '%mysqltest_
|
|||
select * from information_schema.SCHEMA_PRIVILEGES where grantee like '%mysqltest_1%';
|
||||
select * from information_schema.TABLE_PRIVILEGES where grantee like '%mysqltest_1%';
|
||||
select * from information_schema.COLUMN_PRIVILEGES where grantee like '%mysqltest_1%';
|
||||
delete from mysql.user where user='mysqltest_1';
|
||||
delete from mysql.db where user='mysqltest_1';
|
||||
delete from mysql.user where user='mysqltest_1' or user='mysqltest_2';
|
||||
delete from mysql.db where user='mysqltest_1' or user='mysqltest_2';
|
||||
delete from mysql.tables_priv where user='mysqltest_1';
|
||||
delete from mysql.columns_priv where user='mysqltest_1';
|
||||
flush privileges;
|
||||
|
@ -160,13 +185,11 @@ TABLE_SCHEMA= "test";
|
|||
select * from information_schema.KEY_COLUMN_USAGE where
|
||||
TABLE_SCHEMA= "test";
|
||||
|
||||
|
||||
connect (user1,localhost,mysqltest_1,,);
|
||||
connection user1;
|
||||
connection user2;
|
||||
select table_name from information_schema.TABLES where table_schema like "test%";
|
||||
select table_name,column_name from information_schema.COLUMNS where table_schema like "test%";
|
||||
select ROUTINE_NAME from information_schema.ROUTINES;
|
||||
disconnect user1;
|
||||
disconnect user2;
|
||||
connection default;
|
||||
delete from mysql.user where user='mysqltest_1';
|
||||
drop table t1;
|
||||
|
|
|
@ -53,7 +53,7 @@ check table t1;
|
|||
# Check error message
|
||||
lock tables t1 write;
|
||||
check table t2;
|
||||
--error 1143
|
||||
--error 1100
|
||||
insert into t1 select index1,nr from t1;
|
||||
unlock tables;
|
||||
lock tables t1 write, t1 as t1_alias read;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
--disable_warnings
|
||||
DROP TABLE IF EXISTS t1, `"t"1`, t1aa,t2aa;
|
||||
drop database if exists mysqldump_test_db;
|
||||
drop view if exists v1;
|
||||
--enable_warnings
|
||||
|
||||
# XML output
|
||||
|
|
|
@ -339,16 +339,15 @@ drop procedure if exists sub1|
|
|||
create procedure sub1(id char(16), x int)
|
||||
insert into test.t1 values (id, x)|
|
||||
|
||||
# QQ This doesn't work yet
|
||||
#--disable_warnings
|
||||
#drop procedure if exists sub2|
|
||||
#--enable_warnings
|
||||
#create procedure sub2(id char(16))
|
||||
#begin
|
||||
# declare x int;
|
||||
# set x = (select sum(t.x) from test.t2 t);
|
||||
# insert into test.t1 values (id, x);
|
||||
#end|
|
||||
--disable_warnings
|
||||
drop procedure if exists sub2|
|
||||
--enable_warnings
|
||||
create procedure sub2(id char(16))
|
||||
begin
|
||||
declare x int;
|
||||
set x = (select sum(t.i) from test.t2 t);
|
||||
insert into test.t1 values (id, x);
|
||||
end|
|
||||
|
||||
--disable_warnings
|
||||
drop procedure if exists sub3|
|
||||
|
@ -360,11 +359,11 @@ call sub1("sub1a", (select 7))|
|
|||
call sub1("sub1b", (select max(i) from t2))|
|
||||
call sub1("sub1c", (select i,d from t2 limit 1))|
|
||||
call sub1("sub1d", (select 1 from (select 1) a))|
|
||||
#call sub2("sub2");
|
||||
call sub2("sub2");
|
||||
select * from t1|
|
||||
select sub3((select max(i) from t2))|
|
||||
drop procedure sub1|
|
||||
#drop procedure sub2|
|
||||
drop procedure sub2|
|
||||
drop function sub3|
|
||||
delete from t2|
|
||||
|
||||
|
@ -1278,6 +1277,202 @@ select row_count()|
|
|||
drop procedure rc|
|
||||
|
||||
|
||||
#
|
||||
# Let us test how well new locking scheme works.
|
||||
#
|
||||
|
||||
# Let us prepare playground
|
||||
--disable_warnings
|
||||
drop function if exists f0|
|
||||
drop function if exists f1|
|
||||
drop function if exists f2|
|
||||
drop function if exists f3|
|
||||
drop function if exists f4|
|
||||
drop function if exists f5|
|
||||
drop function if exists f6|
|
||||
drop function if exists f7|
|
||||
drop function if exists f8|
|
||||
drop view if exists v0|
|
||||
drop view if exists v1|
|
||||
drop view if exists v2|
|
||||
--enable_warnings
|
||||
delete from t1|
|
||||
delete from t2|
|
||||
insert into t1 values ("a", 1), ("b", 2) |
|
||||
insert into t2 values ("a", 1, 1.0), ("b", 2, 2.0), ("c", 3, 3.0) |
|
||||
|
||||
# Test the simplest function using tables
|
||||
create function f1() returns int
|
||||
return (select sum(data) from t1)|
|
||||
select f1()|
|
||||
# This should work too (and give 2 rows as result)
|
||||
select id, f1() from t1|
|
||||
|
||||
# Function which uses two instances of table simultaneously
|
||||
create function f2() returns int
|
||||
return (select data from t1 where data <= (select sum(data) from t1) limit 1)|
|
||||
select f2()|
|
||||
select id, f2() from t1|
|
||||
|
||||
# Function which uses the same table twice in different queries
|
||||
create function f3() returns int
|
||||
begin
|
||||
declare n int;
|
||||
declare m int;
|
||||
set n:= (select min(data) from t1);
|
||||
set m:= (select max(data) from t1);
|
||||
return n < m;
|
||||
end|
|
||||
select f3()|
|
||||
select id, f3() from t1|
|
||||
|
||||
# Calling two functions using same table
|
||||
select f1(), f3()|
|
||||
select id, f1(), f3() from t1|
|
||||
|
||||
# Function which uses two different tables
|
||||
create function f4() returns double
|
||||
return (select d from t1, t2 where t1.data = t2.i and t1.id= "b")|
|
||||
select f4()|
|
||||
select s, f4() from t2|
|
||||
|
||||
# Recursive functions which due to this recursion require simultaneous
|
||||
# access to several instance of the same table won't work
|
||||
create function f5(i int) returns int
|
||||
begin
|
||||
if i <= 0 then
|
||||
return 0;
|
||||
elseif i = 1 then
|
||||
return (select count(*) from t1 where data = i);
|
||||
else
|
||||
return (select count(*) + f5( i - 1) from t1 where data = i);
|
||||
end if;
|
||||
end|
|
||||
select f5(1)|
|
||||
# This should generate an error about insuficient number of tables locked
|
||||
--error 1100
|
||||
select f5(2)|
|
||||
# But now it simply miserably fails because we are trying to use the same
|
||||
# lex on the next iteration :/ It should generate some error too...
|
||||
# select f5(3)|
|
||||
|
||||
# OTOH this should work
|
||||
create function f6() returns int
|
||||
begin
|
||||
declare n int;
|
||||
set n:= f1();
|
||||
return (select count(*) from t1 where data <= f7() and data <= n);
|
||||
end|
|
||||
create function f7() returns int
|
||||
return (select sum(data) from t1 where data <= f1())|
|
||||
select f6()|
|
||||
select id, f6() from t1|
|
||||
|
||||
# TODO Test temporary table handling
|
||||
|
||||
#
|
||||
# Let us test how new locking work with views
|
||||
#
|
||||
# The most trivial view
|
||||
create view v1 (a) as select f1()|
|
||||
select * from v1|
|
||||
select id, a from t1, v1|
|
||||
select * from v1, v1 as v|
|
||||
# A bit more complex construction
|
||||
create view v2 (a) as select a*10 from v1|
|
||||
select * from v2|
|
||||
select id, a from t1, v2|
|
||||
select * from v1, v2|
|
||||
|
||||
# Nice example where the same view is used on
|
||||
# on different expression levels
|
||||
create function f8 () returns int
|
||||
return (select count(*) from v2)|
|
||||
|
||||
select *, f8() from v1|
|
||||
|
||||
# Let us test what will happen if function is missing
|
||||
drop function f1|
|
||||
--error 1356
|
||||
select * from v1|
|
||||
|
||||
# And what will happen if we have recursion which involves
|
||||
# views and functions ?
|
||||
create function f1() returns int
|
||||
return (select sum(data) from t1) + (select sum(data) from v1)|
|
||||
# FIXME All these just exceed file limit for me :)
|
||||
#select f1()|
|
||||
#select * from v1|
|
||||
#select * from v2|
|
||||
# Back to the normal cases
|
||||
drop function f1|
|
||||
create function f1() returns int
|
||||
return (select sum(data) from t1)|
|
||||
|
||||
# Let us also test some weird cases where no real tables is used
|
||||
create function f0() returns int
|
||||
return (select * from (select 100) as r)|
|
||||
select f0()|
|
||||
select *, f0() from (select 1) as t|
|
||||
create view v0 as select f0()|
|
||||
select * from v0|
|
||||
select *, f0() from v0|
|
||||
|
||||
#
|
||||
# Let us test how well prelocking works with explicit LOCK TABLES.
|
||||
#
|
||||
# Nowdays we have to lock mysql.proc to be able to read SP definitions.
|
||||
# But Monty was going to fix this.
|
||||
lock tables t1 read, t1 as t11 read, mysql.proc read|
|
||||
# These should work well
|
||||
select f3()|
|
||||
select id, f3() from t1 as t11|
|
||||
# Degenerate cases work too :)
|
||||
select f0()|
|
||||
select * from v0|
|
||||
select *, f0() from v0, (select 123) as d1|
|
||||
# But these should not !
|
||||
--error 1100
|
||||
select id, f3() from t1|
|
||||
--error 1100
|
||||
select f4()|
|
||||
unlock tables|
|
||||
|
||||
# Let us test how LOCK TABLES which implicitly depends on functions
|
||||
# works
|
||||
lock tables v2 read, mysql.proc read|
|
||||
select * from v2|
|
||||
select * from v1|
|
||||
# These should not work as we have too little instances of tables locked
|
||||
--error 1100
|
||||
select * from v1, v2|
|
||||
--error 1100
|
||||
select f4()|
|
||||
unlock tables|
|
||||
|
||||
|
||||
# TODO We also should test integration with triggers
|
||||
|
||||
|
||||
# Cleanup
|
||||
drop function f0|
|
||||
drop function f1|
|
||||
drop function f2|
|
||||
drop function f3|
|
||||
drop function f4|
|
||||
drop function f5|
|
||||
drop function f6|
|
||||
drop function f7|
|
||||
drop function f8|
|
||||
drop view v0|
|
||||
drop view v1|
|
||||
drop view v2|
|
||||
delete from t1 |
|
||||
delete from t2 |
|
||||
|
||||
# End of non-bug tests
|
||||
|
||||
|
||||
#
|
||||
# Test cases for old bugs
|
||||
#
|
||||
|
@ -1453,49 +1648,56 @@ drop procedure bug2260|
|
|||
#
|
||||
# BUG#2267
|
||||
#
|
||||
--disable_warnings
|
||||
drop procedure if exists bug2267_1|
|
||||
--enable_warnings
|
||||
create procedure bug2267_1()
|
||||
begin
|
||||
show procedure status;
|
||||
end|
|
||||
|
||||
--disable_warnings
|
||||
drop procedure if exists bug2267_2|
|
||||
--enable_warnings
|
||||
create procedure bug2267_2()
|
||||
begin
|
||||
show function status;
|
||||
end|
|
||||
|
||||
--disable_warnings
|
||||
drop procedure if exists bug2267_3|
|
||||
--enable_warnings
|
||||
create procedure bug2267_3()
|
||||
begin
|
||||
show create procedure bug2267_1;
|
||||
end|
|
||||
|
||||
--disable_warnings
|
||||
drop procedure if exists bug2267_4|
|
||||
--enable_warnings
|
||||
create procedure bug2267_4()
|
||||
begin
|
||||
show create function fac;
|
||||
end|
|
||||
|
||||
--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
|
||||
call bug2267_1()|
|
||||
--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
|
||||
call bug2267_2()|
|
||||
call bug2267_3()|
|
||||
call bug2267_4()|
|
||||
|
||||
drop procedure bug2267_1|
|
||||
drop procedure bug2267_2|
|
||||
drop procedure bug2267_3|
|
||||
drop procedure bug2267_4|
|
||||
# NOTE: This test case will be fixed as soon as Monty
|
||||
# will allow to open mysql.proc table under LOCK TABLES
|
||||
# without mentioning in lock list.
|
||||
#
|
||||
# FIXME: Other solution would be to use preopened proc table
|
||||
# instead of opening it anew.
|
||||
#
|
||||
#--disable_warnings
|
||||
#drop procedure if exists bug2267_1|
|
||||
#--enable_warnings
|
||||
#create procedure bug2267_1()
|
||||
#begin
|
||||
# show procedure status;
|
||||
#end|
|
||||
#
|
||||
#--disable_warnings
|
||||
#drop procedure if exists bug2267_2|
|
||||
#--enable_warnings
|
||||
#create procedure bug2267_2()
|
||||
#begin
|
||||
# show function status;
|
||||
#end|
|
||||
#
|
||||
#--disable_warnings
|
||||
#drop procedure if exists bug2267_3|
|
||||
#--enable_warnings
|
||||
#create procedure bug2267_3()
|
||||
#begin
|
||||
# show create procedure bug2267_1;
|
||||
#end|
|
||||
#
|
||||
#--disable_warnings
|
||||
#drop procedure if exists bug2267_4|
|
||||
#--enable_warnings
|
||||
#create procedure bug2267_4()
|
||||
#begin
|
||||
# show create function fac;
|
||||
#end|
|
||||
#
|
||||
#--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
|
||||
#call bug2267_1()|
|
||||
#--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
|
||||
#call bug2267_2()|
|
||||
#call bug2267_3()|
|
||||
#call bug2267_4()|
|
||||
#
|
||||
#drop procedure bug2267_1|
|
||||
#drop procedure bug2267_2|
|
||||
#drop procedure bug2267_3|
|
||||
#drop procedure bug2267_4|
|
||||
|
||||
#
|
||||
# BUG#2227
|
||||
|
@ -1529,7 +1731,7 @@ drop procedure bug2227|
|
|||
#--enable_warnings
|
||||
#create procedure bug2614()
|
||||
#begin
|
||||
# drop table if exists t3;
|
||||
# drop temporary table if exists t3;
|
||||
# create temporary table t3 (id int default '0' not null);
|
||||
# insert into t3 select 12;
|
||||
# insert into t3 select * from t3;
|
||||
|
@ -1539,7 +1741,7 @@ drop procedure bug2227|
|
|||
#call bug2614()|
|
||||
#--enable_warnings
|
||||
#call bug2614()|
|
||||
#drop table t3|
|
||||
#drop temporary table t3|
|
||||
#drop procedure bug2614|
|
||||
|
||||
#
|
||||
|
@ -1680,7 +1882,7 @@ begin
|
|||
declare rc int default 0;
|
||||
declare continue handler for 1065 set rc = 1;
|
||||
|
||||
drop table if exists temp_t1;
|
||||
drop temporary table if exists temp_t1;
|
||||
create temporary table temp_t1 (
|
||||
f1 int auto_increment, f2 varchar(20), primary key (f1)
|
||||
);
|
||||
|
@ -1702,6 +1904,7 @@ call bug1863(10)|
|
|||
select * from t4|
|
||||
|
||||
drop procedure bug1863|
|
||||
drop temporary table temp_t1;
|
||||
drop table t3, t4|
|
||||
|
||||
#
|
||||
|
@ -3005,15 +3208,6 @@ select * from t3|
|
|||
drop table t3|
|
||||
drop function getcount|
|
||||
|
||||
#
|
||||
# Former BUG#1654
|
||||
# QQ Currently crashes
|
||||
#
|
||||
#create function bug1654() returns int
|
||||
# return (select sum(t1.data) from test.t1 t)|
|
||||
#
|
||||
#select bug1654()|
|
||||
|
||||
#
|
||||
# BUG#5240: Stored procedure crash if function has cursor declaration
|
||||
#
|
||||
|
@ -3039,7 +3233,6 @@ end|
|
|||
|
||||
delete from t1|
|
||||
insert into t1 values ("answer", 42)|
|
||||
# QQ BUG: This returns the wrong result, id=42 instead of "answer".
|
||||
select id, bug5240() from t1|
|
||||
drop function bug5240|
|
||||
|
||||
|
|
|
@ -601,6 +601,7 @@ select abs(9999999999999999999999);
|
|||
select abs(-9999999999999999999999);
|
||||
#-- should return 9999999999999999999999
|
||||
#
|
||||
select ceiling(999999999999999999);
|
||||
select ceiling(99999999999999999999);
|
||||
#-- should return 99999999999999999999
|
||||
#
|
||||
|
@ -610,6 +611,7 @@ select ceiling(9.9999999999999999999);
|
|||
select ceiling(-9.9999999999999999999);
|
||||
#-- should return 9
|
||||
#
|
||||
select floor(999999999999999999);
|
||||
select floor(9999999999999999999999);
|
||||
#-- should return 9999999999999999999999
|
||||
#
|
||||
|
|
|
@ -87,7 +87,7 @@ static void my_aiowait(my_aio_result *result);
|
|||
void setup_io_cache(IO_CACHE* info)
|
||||
{
|
||||
/* Ensure that my_b_tell() and my_b_bytes_in_cache works */
|
||||
if (info->type == WRITE_CACHE)
|
||||
if (info->type == WRITE_CACHE || info->type == APPEND_CACHE)
|
||||
{
|
||||
info->current_pos= &info->write_pos;
|
||||
info->current_end= &info->write_end;
|
||||
|
@ -247,7 +247,7 @@ int init_io_cache(IO_CACHE *info, File file, uint cachesize,
|
|||
}
|
||||
#endif
|
||||
|
||||
if (type == WRITE_CACHE)
|
||||
if (type == WRITE_CACHE || type == APPEND_CACHE)
|
||||
info->write_end=
|
||||
info->buffer+info->buffer_length- (seek_offset & (IO_SIZE-1));
|
||||
else
|
||||
|
@ -318,6 +318,7 @@ my_bool reinit_io_cache(IO_CACHE *info, enum cache_type type,
|
|||
/* One can't do reinit with the following types */
|
||||
DBUG_ASSERT(type != READ_NET && info->type != READ_NET &&
|
||||
type != WRITE_NET && info->type != WRITE_NET &&
|
||||
type != APPEND_CACHE && info->type != APPEND_CACHE &&
|
||||
type != SEQ_READ_APPEND && info->type != SEQ_READ_APPEND);
|
||||
|
||||
/* If the whole file is in memory, avoid flushing to disk */
|
||||
|
@ -1123,7 +1124,8 @@ int my_b_flush_io_cache(IO_CACHE *info, int need_append_buffer_lock)
|
|||
my_off_t pos_in_file;
|
||||
DBUG_ENTER("my_b_flush_io_cache");
|
||||
|
||||
if (!(append_cache = (info->type == SEQ_READ_APPEND)))
|
||||
if (!(append_cache = (info->type == SEQ_READ_APPEND ||
|
||||
info->type == APPEND_CACHE)))
|
||||
need_append_buffer_lock=0;
|
||||
|
||||
if (info->type == WRITE_CACHE || append_cache)
|
||||
|
@ -1170,7 +1172,13 @@ int my_b_flush_io_cache(IO_CACHE *info, int need_append_buffer_lock)
|
|||
else
|
||||
{
|
||||
info->end_of_file+=(info->write_pos-info->append_read_pos);
|
||||
DBUG_ASSERT(info->end_of_file == my_tell(info->file,MYF(0)));
|
||||
/*
|
||||
We only need to worry that info->end_of_file is really accurate
|
||||
for SEQ_READ_APPEND. For APPEND_CACHE, it is possible that the
|
||||
file is non-seekable, like a FIFO.
|
||||
*/
|
||||
DBUG_ASSERT(info->type != SEQ_READ_APPEND ||
|
||||
info->end_of_file == my_tell(info->file,MYF(0)));
|
||||
}
|
||||
|
||||
info->append_read_pos=info->write_pos=info->write_buffer;
|
||||
|
|
|
@ -70,7 +70,7 @@ File create_temp_file(char *to, const char *dir, const char *prefix,
|
|||
{
|
||||
strmake(to,res,FN_REFLEN-1);
|
||||
(*free)(res);
|
||||
file=my_create(to,0, mode, MyFlags);
|
||||
file=my_create(to,0, mode | O_EXCL | O_NOFOLLOW, MyFlags);
|
||||
}
|
||||
environ=old_env;
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ File create_temp_file(char *to, const char *dir, const char *prefix,
|
|||
{
|
||||
strmake(to,res,FN_REFLEN-1);
|
||||
(*free)(res);
|
||||
file=my_create(to, 0, mode, MyFlags);
|
||||
file=my_create(to, 0, mode | O_EXCL | O_NOFOLLOW, MyFlags);
|
||||
}
|
||||
#elif defined(HAVE_MKSTEMP) && !defined(__NETWARE__)
|
||||
{
|
||||
|
@ -143,7 +143,7 @@ File create_temp_file(char *to, const char *dir, const char *prefix,
|
|||
strmake(to,res,FN_REFLEN-1);
|
||||
(*free)(res);
|
||||
file=my_create(to,0,
|
||||
(int) (O_RDWR | O_BINARY | O_TRUNC |
|
||||
(int) (O_RDWR | O_BINARY | O_TRUNC | O_EXCL | O_NOFOLLOW |
|
||||
O_TEMPORARY | O_SHORT_LIVED),
|
||||
MYF(MY_WME));
|
||||
|
||||
|
@ -186,7 +186,7 @@ File create_temp_file(char *to, const char *dir, const char *prefix,
|
|||
}
|
||||
(void) strmov(end_pos,TMP_EXT);
|
||||
file=my_create(to,0,
|
||||
(int) (O_RDWR | O_BINARY | O_TRUNC |
|
||||
(int) (O_RDWR | O_BINARY | O_TRUNC | O_EXCL | O_NOFOLLOW |
|
||||
O_TEMPORARY | O_SHORT_LIVED),
|
||||
MYF(MY_WME));
|
||||
}
|
||||
|
|
|
@ -1681,7 +1681,8 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
|
|||
ER(net->last_errno),socket_errno);
|
||||
goto error;
|
||||
}
|
||||
net->vio = vio_new(sock, VIO_TYPE_SOCKET, TRUE);
|
||||
net->vio= vio_new(sock, VIO_TYPE_SOCKET,
|
||||
VIO_LOCALHOST | VIO_BUFFERED_READ);
|
||||
bzero((char*) &UNIXaddr,sizeof(UNIXaddr));
|
||||
UNIXaddr.sun_family = AF_UNIX;
|
||||
strmake(UNIXaddr.sun_path, unix_socket, sizeof(UNIXaddr.sun_path)-1);
|
||||
|
@ -1756,7 +1757,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
|
|||
ER(net->last_errno),socket_errno);
|
||||
goto error;
|
||||
}
|
||||
net->vio = vio_new(sock,VIO_TYPE_TCPIP,FALSE);
|
||||
net->vio= vio_new(sock, VIO_TYPE_TCPIP, VIO_BUFFERED_READ);
|
||||
bzero((char*) &sock_addr,sizeof(sock_addr));
|
||||
sock_addr.sin_family = AF_INET;
|
||||
|
||||
|
|
|
@ -626,7 +626,6 @@ int Field_str::store_decimal(const my_decimal *d)
|
|||
|
||||
my_decimal *Field_str::val_decimal(my_decimal *decimal_value)
|
||||
{
|
||||
DBUG_ASSERT(result_type() == INT_RESULT);
|
||||
longlong nr= val_int();
|
||||
int2my_decimal(E_DEC_FATAL_ERROR, nr, 0, decimal_value);
|
||||
return decimal_value;
|
||||
|
|
0
sql/ha_federated.h
Executable file → Normal file
0
sql/ha_federated.h
Executable file → Normal file
|
@ -2632,6 +2632,7 @@ ha_innobase::write_row(
|
|||
table->timestamp_field->set_time();
|
||||
|
||||
if ((user_thd->lex->sql_command == SQLCOM_ALTER_TABLE
|
||||
|| user_thd->lex->sql_command == SQLCOM_OPTIMIZE
|
||||
|| user_thd->lex->sql_command == SQLCOM_CREATE_INDEX
|
||||
|| user_thd->lex->sql_command == SQLCOM_DROP_INDEX)
|
||||
&& num_write_row >= 10000) {
|
||||
|
|
|
@ -1350,7 +1350,7 @@ int ha_myisam::create(const char *name, register TABLE *table_arg,
|
|||
HA_CREATE_INFO *info)
|
||||
{
|
||||
int error;
|
||||
uint i,j,recpos,minpos,fieldpos,temp_length,length;
|
||||
uint i,j,recpos,minpos,fieldpos,temp_length,length, create_flags= 0;
|
||||
bool found_real_auto_increment=0;
|
||||
enum ha_base_keytype type;
|
||||
char buff[FN_REFLEN];
|
||||
|
@ -1538,17 +1538,21 @@ int ha_myisam::create(const char *name, register TABLE *table_arg,
|
|||
create_info.data_file_name= info->data_file_name;
|
||||
create_info.index_file_name= info->index_file_name;
|
||||
|
||||
if (info->options & HA_LEX_CREATE_TMP_TABLE)
|
||||
create_flags|= HA_CREATE_TMP_TABLE;
|
||||
if (options & HA_OPTION_PACK_RECORD)
|
||||
create_flags|= HA_PACK_RECORD;
|
||||
if (options & HA_OPTION_CHECKSUM)
|
||||
create_flags|= HA_CREATE_CHECKSUM;
|
||||
if (options & HA_OPTION_DELAY_KEY_WRITE)
|
||||
create_flags|= HA_CREATE_DELAY_KEY_WRITE;
|
||||
|
||||
/* TODO: Check that the following fn_format is really needed */
|
||||
error=mi_create(fn_format(buff,name,"","",2+4),
|
||||
share->keys,keydef,
|
||||
(uint) (recinfo_pos-recinfo), recinfo,
|
||||
0, (MI_UNIQUEDEF*) 0,
|
||||
&create_info,
|
||||
(((options & HA_OPTION_PACK_RECORD) ? HA_PACK_RECORD : 0) |
|
||||
((options & HA_OPTION_CHECKSUM) ? HA_CREATE_CHECKSUM : 0) |
|
||||
((options & HA_OPTION_DELAY_KEY_WRITE) ?
|
||||
HA_CREATE_DELAY_KEY_WRITE : 0)));
|
||||
|
||||
&create_info, create_flags);
|
||||
|
||||
my_free((gptr) recinfo,MYF(0));
|
||||
DBUG_RETURN(error);
|
||||
|
|
10
sql/item.cc
10
sql/item.cc
|
@ -724,7 +724,6 @@ void Item::split_sum_func2(THD *thd, Item **ref_pointer_array,
|
|||
*/
|
||||
bool DTCollation::aggregate(DTCollation &dt, uint flags)
|
||||
{
|
||||
nagg++;
|
||||
if (!my_charset_same(collation, dt.collation))
|
||||
{
|
||||
/*
|
||||
|
@ -740,7 +739,6 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags)
|
|||
else
|
||||
{
|
||||
set(dt);
|
||||
strong= nagg;
|
||||
}
|
||||
}
|
||||
else if (dt.collation == &my_charset_bin)
|
||||
|
@ -748,7 +746,6 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags)
|
|||
if (dt.derivation <= derivation)
|
||||
{
|
||||
set(dt);
|
||||
strong= nagg;
|
||||
}
|
||||
else
|
||||
; // Do nothing
|
||||
|
@ -764,20 +761,18 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags)
|
|||
dt.collation->state & MY_CS_UNICODE)
|
||||
{
|
||||
set(dt);
|
||||
strong= nagg;
|
||||
}
|
||||
else if ((flags & MY_COLL_ALLOW_COERCIBLE_CONV) &&
|
||||
derivation < dt.derivation &&
|
||||
dt.derivation >= DERIVATION_COERCIBLE)
|
||||
dt.derivation >= DERIVATION_SYSCONST)
|
||||
{
|
||||
// Do nothing;
|
||||
}
|
||||
else if ((flags & MY_COLL_ALLOW_COERCIBLE_CONV) &&
|
||||
dt.derivation < derivation &&
|
||||
derivation >= DERIVATION_COERCIBLE)
|
||||
derivation >= DERIVATION_SYSCONST)
|
||||
{
|
||||
set(dt);
|
||||
strong= nagg;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -793,7 +788,6 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags)
|
|||
else if (dt.derivation < derivation)
|
||||
{
|
||||
set(dt);
|
||||
strong= nagg;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
12
sql/item.h
12
sql/item.h
|
@ -32,8 +32,9 @@ class Item_field;
|
|||
|
||||
enum Derivation
|
||||
{
|
||||
DERIVATION_IGNORABLE= 4,
|
||||
DERIVATION_COERCIBLE= 3,
|
||||
DERIVATION_IGNORABLE= 5,
|
||||
DERIVATION_COERCIBLE= 4,
|
||||
DERIVATION_SYSCONST= 3,
|
||||
DERIVATION_IMPLICIT= 2,
|
||||
DERIVATION_NONE= 1,
|
||||
DERIVATION_EXPLICIT= 0
|
||||
|
@ -62,22 +63,16 @@ class DTCollation {
|
|||
public:
|
||||
CHARSET_INFO *collation;
|
||||
enum Derivation derivation;
|
||||
uint nagg; // Total number of aggregated collations.
|
||||
uint strong; // Number of the strongest collation.
|
||||
|
||||
DTCollation()
|
||||
{
|
||||
collation= &my_charset_bin;
|
||||
derivation= DERIVATION_NONE;
|
||||
nagg= 0;
|
||||
strong= 0;
|
||||
}
|
||||
DTCollation(CHARSET_INFO *collation_arg, Derivation derivation_arg)
|
||||
{
|
||||
collation= collation_arg;
|
||||
derivation= derivation_arg;
|
||||
nagg= 0;
|
||||
strong= 0;
|
||||
}
|
||||
void set(DTCollation &dt)
|
||||
{
|
||||
|
@ -103,6 +98,7 @@ public:
|
|||
case DERIVATION_IGNORABLE: return "IGNORABLE";
|
||||
case DERIVATION_COERCIBLE: return "COERCIBLE";
|
||||
case DERIVATION_IMPLICIT: return "IMPLICIT";
|
||||
case DERIVATION_SYSCONST: return "SYSCONST";
|
||||
case DERIVATION_EXPLICIT: return "EXPLICIT";
|
||||
case DERIVATION_NONE: return "NONE";
|
||||
default: return "UNKNOWN";
|
||||
|
|
|
@ -434,7 +434,7 @@ Item *create_func_version(void)
|
|||
{
|
||||
return new Item_static_string_func("version()", server_version,
|
||||
(uint) strlen(server_version),
|
||||
system_charset_info, DERIVATION_IMPLICIT);
|
||||
system_charset_info, DERIVATION_SYSCONST);
|
||||
}
|
||||
|
||||
Item *create_func_weekday(Item* a)
|
||||
|
|
|
@ -82,8 +82,6 @@ bool Item_func::agg_arg_collations(DTCollation &c, Item **av, uint count,
|
|||
uint flags)
|
||||
{
|
||||
uint i;
|
||||
c.nagg= 0;
|
||||
c.strong= 0;
|
||||
c.set(av[0]->collation);
|
||||
for (i= 1; i < count; i++)
|
||||
{
|
||||
|
@ -1629,13 +1627,25 @@ void Item_func_int_val::find_num_type()
|
|||
|
||||
longlong Item_func_ceiling::int_op()
|
||||
{
|
||||
/*
|
||||
the volatile's for BUG #3051 to calm optimizer down (because of gcc's
|
||||
bug)
|
||||
*/
|
||||
volatile double value= args[0]->val_real();
|
||||
null_value= args[0]->null_value;
|
||||
return (longlong) ceil(value);
|
||||
longlong result;
|
||||
switch (args[0]->result_type()) {
|
||||
case INT_RESULT:
|
||||
result= args[0]->val_int();
|
||||
null_value= args[0]->null_value;
|
||||
break;
|
||||
case DECIMAL_RESULT:
|
||||
{
|
||||
my_decimal dec_buf, *dec;
|
||||
if ((dec= Item_func_ceiling::decimal_op(&dec_buf)))
|
||||
my_decimal2int(E_DEC_FATAL_ERROR, dec, unsigned_flag, &result);
|
||||
else
|
||||
result= 0;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
result= (longlong)Item_func_ceiling::real_op();
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1664,13 +1674,25 @@ my_decimal *Item_func_ceiling::decimal_op(my_decimal *decimal_value)
|
|||
|
||||
longlong Item_func_floor::int_op()
|
||||
{
|
||||
/*
|
||||
the volatile's for BUG #3051 to calm optimizer down (because of gcc's
|
||||
bug)
|
||||
*/
|
||||
volatile double value= args[0]->val_real();
|
||||
null_value= args[0]->null_value;
|
||||
return (longlong) floor(value);
|
||||
longlong result;
|
||||
switch (args[0]->result_type()) {
|
||||
case INT_RESULT:
|
||||
result= args[0]->val_int();
|
||||
null_value= args[0]->null_value;
|
||||
break;
|
||||
case DECIMAL_RESULT:
|
||||
{
|
||||
my_decimal dec_buf, *dec;
|
||||
if ((dec= Item_func_floor::decimal_op(&dec_buf)))
|
||||
my_decimal2int(E_DEC_FATAL_ERROR, dec, unsigned_flag, &result);
|
||||
else
|
||||
result= 0;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
result= (longlong)Item_func_floor::real_op();
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
@ -4414,11 +4436,6 @@ Item_func_sp::execute(Item **itp)
|
|||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
We don't need to suppress sending of OK packet here (by setting
|
||||
thd->net.no_send_ok to true), because we are not allowing statements
|
||||
in functions now.
|
||||
*/
|
||||
res= m_sp->execute_function(thd, args, arg_count, itp);
|
||||
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
|
|
|
@ -1515,6 +1515,23 @@ String *Item_func_decode::val_str(String *str)
|
|||
}
|
||||
|
||||
|
||||
Item *Item_func_sysconst::safe_charset_converter(CHARSET_INFO *tocs)
|
||||
{
|
||||
Item_string *conv;
|
||||
uint conv_errors;
|
||||
String tmp, cstr, *ostr= val_str(&tmp);
|
||||
cstr.copy(ostr->ptr(), ostr->length(), ostr->charset(), tocs, &conv_errors);
|
||||
if (conv_errors || !(conv= new Item_string(cstr.ptr(), cstr.length(),
|
||||
cstr.charset(),
|
||||
collation.derivation)))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
conv->str_value.copy();
|
||||
return conv;
|
||||
}
|
||||
|
||||
|
||||
String *Item_func_database::val_str(String *str)
|
||||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
|
|
|
@ -337,10 +337,18 @@ public:
|
|||
};
|
||||
|
||||
|
||||
class Item_func_database :public Item_str_func
|
||||
class Item_func_sysconst :public Item_str_func
|
||||
{
|
||||
public:
|
||||
Item_func_database() { collation.set(system_charset_info,DERIVATION_IMPLICIT); }
|
||||
Item_func_sysconst()
|
||||
{ collation.set(system_charset_info,DERIVATION_SYSCONST); }
|
||||
Item *safe_charset_converter(CHARSET_INFO *tocs);
|
||||
};
|
||||
|
||||
class Item_func_database :public Item_func_sysconst
|
||||
{
|
||||
public:
|
||||
Item_func_database() :Item_func_sysconst() {}
|
||||
String *val_str(String *);
|
||||
void fix_length_and_dec()
|
||||
{
|
||||
|
@ -350,10 +358,10 @@ public:
|
|||
const char *func_name() const { return "database"; }
|
||||
};
|
||||
|
||||
class Item_func_user :public Item_str_func
|
||||
class Item_func_user :public Item_func_sysconst
|
||||
{
|
||||
public:
|
||||
Item_func_user() { collation.set(system_charset_info, DERIVATION_IMPLICIT); }
|
||||
Item_func_user() :Item_func_sysconst() {}
|
||||
String *val_str(String *);
|
||||
void fix_length_and_dec()
|
||||
{
|
||||
|
|
|
@ -453,6 +453,7 @@ bool check_procedure_access(THD *thd,ulong want_access,char *db,char *name,
|
|||
bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table);
|
||||
bool check_merge_table_access(THD *thd, char *db,
|
||||
TABLE_LIST *table_list);
|
||||
bool check_some_routine_access(THD *thd, char *db, char *name);
|
||||
bool multi_update_precheck(THD *thd, TABLE_LIST *tables);
|
||||
bool multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count);
|
||||
bool mysql_multi_update_prepare(THD *thd);
|
||||
|
@ -870,7 +871,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
|
|||
int setup_ftfuncs(SELECT_LEX* select);
|
||||
int init_ftfuncs(THD *thd, SELECT_LEX* select, bool no_order);
|
||||
void wait_for_refresh(THD *thd);
|
||||
int open_tables(THD *thd, TABLE_LIST *tables, uint *counter);
|
||||
int open_tables(THD *thd, TABLE_LIST **tables, uint *counter);
|
||||
int simple_open_n_lock_tables(THD *thd,TABLE_LIST *tables);
|
||||
bool open_and_lock_tables(THD *thd,TABLE_LIST *tables);
|
||||
bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables);
|
||||
|
@ -1064,7 +1065,7 @@ extern my_bool opt_sql_bin_update, opt_safe_user_create, opt_no_mix_types;
|
|||
extern my_bool opt_safe_show_db, opt_local_infile;
|
||||
extern my_bool opt_slave_compressed_protocol, use_temp_pool;
|
||||
extern my_bool opt_readonly, lower_case_file_system;
|
||||
extern my_bool opt_enable_named_pipe, opt_sync_frm;
|
||||
extern my_bool opt_enable_named_pipe, opt_sync_frm, opt_allow_suspicious_udfs;
|
||||
extern my_bool opt_secure_auth;
|
||||
extern my_bool sp_automatic_privileges;
|
||||
extern my_bool opt_old_style_user_limits;
|
||||
|
|
|
@ -305,7 +305,7 @@ const char *opt_ndb_mgmd;
|
|||
ulong opt_ndb_nodeid;
|
||||
#endif
|
||||
my_bool opt_readonly, use_temp_pool, relay_log_purge;
|
||||
my_bool opt_sync_bdb_logs, opt_sync_frm;
|
||||
my_bool opt_sync_bdb_logs, opt_sync_frm, opt_allow_suspicious_udfs;
|
||||
my_bool opt_secure_auth= 0;
|
||||
my_bool opt_short_log_format= 0;
|
||||
my_bool opt_log_queries_not_using_indexes= 0;
|
||||
|
@ -3745,7 +3745,7 @@ extern "C" pthread_handler_decl(handle_connections_sockets,
|
|||
if (!(vio_tmp=vio_new(new_sock,
|
||||
sock == unix_sock ? VIO_TYPE_SOCKET :
|
||||
VIO_TYPE_TCPIP,
|
||||
sock == unix_sock)) ||
|
||||
sock == unix_sock ? VIO_LOCALHOST: 0)) ||
|
||||
my_net_init(&thd->net,vio_tmp))
|
||||
{
|
||||
if (vio_tmp)
|
||||
|
@ -4220,7 +4220,7 @@ enum options_mysqld
|
|||
OPT_BDB_MAX_LOCK,
|
||||
OPT_ERROR_LOG_FILE,
|
||||
OPT_DEFAULT_WEEK_FORMAT,
|
||||
OPT_RANGE_ALLOC_BLOCK_SIZE,
|
||||
OPT_RANGE_ALLOC_BLOCK_SIZE, OPT_ALLOW_SUSPICIOUS_UDFS,
|
||||
OPT_QUERY_ALLOC_BLOCK_SIZE, OPT_QUERY_PREALLOC_SIZE,
|
||||
OPT_TRANS_ALLOC_BLOCK_SIZE, OPT_TRANS_PREALLOC_SIZE,
|
||||
OPT_SYNC_FRM, OPT_SYNC_BINLOG,
|
||||
|
@ -4268,6 +4268,13 @@ struct my_option my_long_options[] =
|
|||
#endif /* HAVE_REPLICATION */
|
||||
{"ansi", 'a', "Use ANSI SQL syntax instead of MySQL syntax. This mode will also set transaction isolation level 'serializable'.", 0, 0, 0,
|
||||
GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"allow-suspicious-udfs", OPT_ALLOW_SUSPICIOUS_UDFS,
|
||||
"Allows use of UDFs consisting of only one symbol xxx() "
|
||||
"without corresponding xxx_init() or xxx_deinit(). That also means "
|
||||
"that one can load any function from any library, for example exit() "
|
||||
"from libc.so",
|
||||
(gptr*) &opt_allow_suspicious_udfs, (gptr*) &opt_allow_suspicious_udfs,
|
||||
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"auto-increment-increment", OPT_AUTO_INCREMENT,
|
||||
"Auto-increment columns are incremented by this",
|
||||
(gptr*) &global_system_variables.auto_increment_increment,
|
||||
|
@ -5411,7 +5418,7 @@ The minimum value for this variable is 4096.",
|
|||
"it failed with a deadlock or elapsed lock wait timeout, "
|
||||
"before giving up and stopping.",
|
||||
(gptr*) &slave_trans_retries, (gptr*) &slave_trans_retries, 0,
|
||||
GET_ULONG, REQUIRED_ARG, 0L, 0L, (longlong) ULONG_MAX, 0, 1, 0},
|
||||
GET_ULONG, REQUIRED_ARG, 10L, 0L, (longlong) ULONG_MAX, 0, 1, 0},
|
||||
#endif /* HAVE_REPLICATION */
|
||||
{"slow_launch_time", OPT_SLOW_LAUNCH_TIME,
|
||||
"If creating the thread takes longer than this value (in seconds), the Slow_launch_threads counter will be incremented.",
|
||||
|
|
|
@ -638,7 +638,6 @@ static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref,
|
|||
{
|
||||
if (!(field->flags & PART_KEY_FLAG))
|
||||
return 0; // Not key field
|
||||
*prefix_len= 0;
|
||||
|
||||
TABLE *table= field->table;
|
||||
uint idx= 0;
|
||||
|
@ -651,6 +650,7 @@ static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref,
|
|||
KEY_PART_INFO *part,*part_end;
|
||||
key_part_map key_part_to_use= 0;
|
||||
uint jdx= 0;
|
||||
*prefix_len= 0;
|
||||
for (part= keyinfo->key_part, part_end= part+keyinfo->key_parts ;
|
||||
part != part_end ;
|
||||
part++, jdx++, key_part_to_use= (key_part_to_use << 1) | 1)
|
||||
|
|
189
sql/sp.cc
189
sql/sp.cc
|
@ -307,8 +307,6 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
|
|||
goto done;
|
||||
if (sp)
|
||||
{
|
||||
if (oldlex != newlex)
|
||||
sp->restore_lex(thd);
|
||||
delete sp;
|
||||
newlex->sphead= NULL;
|
||||
}
|
||||
|
@ -720,8 +718,29 @@ sp_drop_db_routines(THD *thd, char *db)
|
|||
PROCEDURE
|
||||
******************************************************************************/
|
||||
|
||||
/*
|
||||
Obtain object representing stored procedure by its name from
|
||||
stored procedures cache and looking into mysql.proc if needed.
|
||||
|
||||
SYNOPSIS
|
||||
sp_find_procedure()
|
||||
thd - thread context
|
||||
name - name of procedure
|
||||
cache_only - if true perform cache-only lookup
|
||||
(Don't look in mysql.proc).
|
||||
|
||||
TODO
|
||||
We should consider merging of sp_find_procedure() and
|
||||
sp_find_function() into one sp_find_routine() function
|
||||
(the same applies to other similarly paired functions).
|
||||
|
||||
RETURN VALUE
|
||||
Non-0 pointer to sp_head object for the procedure, or
|
||||
0 - in case of error.
|
||||
*/
|
||||
|
||||
sp_head *
|
||||
sp_find_procedure(THD *thd, sp_name *name)
|
||||
sp_find_procedure(THD *thd, sp_name *name, bool cache_only)
|
||||
{
|
||||
sp_head *sp;
|
||||
DBUG_ENTER("sp_find_procedure");
|
||||
|
@ -729,7 +748,7 @@ sp_find_procedure(THD *thd, sp_name *name)
|
|||
name->m_db.length, name->m_db.str,
|
||||
name->m_name.length, name->m_name.str));
|
||||
|
||||
if (!(sp= sp_cache_lookup(&thd->sp_proc_cache, name)))
|
||||
if (!(sp= sp_cache_lookup(&thd->sp_proc_cache, name)) && !cache_only)
|
||||
{
|
||||
if (db_find_routine(thd, TYPE_ENUM_PROCEDURE, name, &sp) == SP_OK)
|
||||
sp_cache_insert(&thd->sp_proc_cache, sp);
|
||||
|
@ -855,6 +874,25 @@ sp_show_status_procedure(THD *thd, const char *wild)
|
|||
FUNCTION
|
||||
******************************************************************************/
|
||||
|
||||
/*
|
||||
Obtain object representing stored function by its name from
|
||||
stored functions cache and looking into mysql.proc if needed.
|
||||
|
||||
SYNOPSIS
|
||||
sp_find_function()
|
||||
thd - thread context
|
||||
name - name of function
|
||||
cache_only - if true perform cache-only lookup
|
||||
(Don't look in mysql.proc).
|
||||
|
||||
NOTE
|
||||
See TODO section for sp_find_procedure().
|
||||
|
||||
RETURN VALUE
|
||||
Non-0 pointer to sp_head object for the function, or
|
||||
0 - in case of error.
|
||||
*/
|
||||
|
||||
sp_head *
|
||||
sp_find_function(THD *thd, sp_name *name, bool cache_only)
|
||||
{
|
||||
|
@ -988,79 +1026,120 @@ sp_add_to_hash(HASH *h, sp_name *fun)
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
/*
|
||||
Merge contents of two hashes containing LEX_STRING's
|
||||
|
||||
SYNOPSIS
|
||||
sp_merge_hash()
|
||||
dst - hash to which elements should be added
|
||||
src - hash from which elements merged
|
||||
|
||||
RETURN VALUE
|
||||
TRUE - if we have added some new elements to destination hash.
|
||||
FALSE - there were no new elements in src.
|
||||
*/
|
||||
|
||||
bool
|
||||
sp_merge_hash(HASH *dst, HASH *src)
|
||||
{
|
||||
bool res= FALSE;
|
||||
for (uint i=0 ; i < src->records ; i++)
|
||||
{
|
||||
LEX_STRING *ls= (LEX_STRING *)hash_element(src, i);
|
||||
|
||||
if (! hash_search(dst, (byte *)ls->str, ls->length))
|
||||
{
|
||||
my_hash_insert(dst, (byte *)ls);
|
||||
res= TRUE;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
sp_cache_routines(THD *thd, LEX *lex, int type)
|
||||
/*
|
||||
Cache all routines implicitly or explicitly used by query
|
||||
(or whatever object is represented by LEX).
|
||||
|
||||
SYNOPSIS
|
||||
sp_cache_routines()
|
||||
thd - thread context
|
||||
lex - LEX representing query
|
||||
|
||||
NOTE
|
||||
If some function is missing this won't be reported here.
|
||||
Instead this fact will be discovered during query execution.
|
||||
|
||||
TODO
|
||||
Currently if after passing through routine hashes we discover
|
||||
that we have added something to them, we do one more pass to
|
||||
process all routines which were missed on previous pass because
|
||||
of these additions. We can avoid this if along with hashes
|
||||
we use lists holding routine names and iterate other these
|
||||
lists instead of hashes (since addition to the end of list
|
||||
does not reorder elements in it).
|
||||
*/
|
||||
|
||||
void
|
||||
sp_cache_routines(THD *thd, LEX *lex)
|
||||
{
|
||||
HASH *h= (type == TYPE_ENUM_FUNCTION ? &lex->spfuns : &lex->spprocs);
|
||||
int ret= 0;
|
||||
bool routines_added= TRUE;
|
||||
|
||||
for (uint i=0 ; i < h->records ; i++)
|
||||
DBUG_ENTER("sp_cache_routines");
|
||||
|
||||
while (routines_added)
|
||||
{
|
||||
LEX_STRING *ls= (LEX_STRING *)hash_element(h, i);
|
||||
sp_name name(*ls);
|
||||
routines_added= FALSE;
|
||||
|
||||
name.m_qname= *ls;
|
||||
if (! sp_cache_lookup((type == TYPE_ENUM_FUNCTION ?
|
||||
&thd->sp_func_cache : &thd->sp_proc_cache),
|
||||
&name))
|
||||
for (int type= TYPE_ENUM_FUNCTION; type < TYPE_ENUM_TRIGGER; type++)
|
||||
{
|
||||
sp_head *sp;
|
||||
LEX *oldlex= thd->lex;
|
||||
LEX *newlex= new st_lex;
|
||||
HASH *h= (type == TYPE_ENUM_FUNCTION ? &lex->spfuns : &lex->spprocs);
|
||||
|
||||
thd->lex= newlex;
|
||||
newlex->proc_table= oldlex->proc_table; // hint if mysql.oper is opened
|
||||
newlex->current_select= NULL;
|
||||
name.m_name.str= strchr(name.m_qname.str, '.');
|
||||
name.m_db.length= name.m_name.str - name.m_qname.str;
|
||||
name.m_db.str= strmake_root(thd->mem_root,
|
||||
name.m_qname.str, name.m_db.length);
|
||||
name.m_name.str+= 1;
|
||||
name.m_name.length= name.m_qname.length - name.m_db.length - 1;
|
||||
for (uint i=0 ; i < h->records ; i++)
|
||||
{
|
||||
LEX_STRING *ls= (LEX_STRING *)hash_element(h, i);
|
||||
sp_name name(*ls);
|
||||
sp_head *sp;
|
||||
|
||||
if (db_find_routine(thd, type, &name, &sp) == SP_OK)
|
||||
{
|
||||
if (type == TYPE_ENUM_FUNCTION)
|
||||
sp_cache_insert(&thd->sp_func_cache, sp);
|
||||
else
|
||||
sp_cache_insert(&thd->sp_proc_cache, sp);
|
||||
ret= sp_cache_routines(thd, newlex, TYPE_ENUM_FUNCTION);
|
||||
if (!ret)
|
||||
{
|
||||
sp_merge_hash(&lex->spfuns, &newlex->spfuns);
|
||||
ret= sp_cache_routines(thd, newlex, TYPE_ENUM_PROCEDURE);
|
||||
}
|
||||
if (!ret)
|
||||
{
|
||||
sp_merge_hash(&lex->spprocs, &newlex->spprocs);
|
||||
sp_merge_table_hash(&lex->sptabs, &sp->m_sptabs);
|
||||
}
|
||||
delete newlex;
|
||||
thd->lex= oldlex;
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete newlex;
|
||||
thd->lex= oldlex;
|
||||
name.m_qname= *ls;
|
||||
if (!(sp= sp_cache_lookup((type == TYPE_ENUM_FUNCTION ?
|
||||
&thd->sp_func_cache : &thd->sp_proc_cache),
|
||||
&name)))
|
||||
{
|
||||
LEX *oldlex= thd->lex;
|
||||
LEX *newlex= new st_lex;
|
||||
|
||||
thd->lex= newlex;
|
||||
/* Pass hint pointer to mysql.proc table */
|
||||
newlex->proc_table= oldlex->proc_table;
|
||||
newlex->current_select= NULL;
|
||||
name.m_name.str= strchr(name.m_qname.str, '.');
|
||||
name.m_db.length= name.m_name.str - name.m_qname.str;
|
||||
name.m_db.str= strmake_root(thd->mem_root, name.m_qname.str,
|
||||
name.m_db.length);
|
||||
name.m_name.str+= 1;
|
||||
name.m_name.length= name.m_qname.length - name.m_db.length - 1;
|
||||
|
||||
if (db_find_routine(thd, type, &name, &sp) == SP_OK)
|
||||
{
|
||||
if (type == TYPE_ENUM_FUNCTION)
|
||||
sp_cache_insert(&thd->sp_func_cache, sp);
|
||||
else
|
||||
sp_cache_insert(&thd->sp_proc_cache, sp);
|
||||
}
|
||||
delete newlex;
|
||||
thd->lex= oldlex;
|
||||
}
|
||||
|
||||
if (sp)
|
||||
{
|
||||
routines_added|= sp_merge_hash(&lex->spfuns, &sp->m_spfuns);
|
||||
routines_added|= sp_merge_hash(&lex->spprocs, &sp->m_spprocs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
8
sql/sp.h
8
sql/sp.h
|
@ -34,7 +34,7 @@ int
|
|||
sp_drop_db_routines(THD *thd, char *db);
|
||||
|
||||
sp_head *
|
||||
sp_find_procedure(THD *thd, sp_name *name);
|
||||
sp_find_procedure(THD *thd, sp_name *name, bool cache_only = 0);
|
||||
|
||||
int
|
||||
sp_exists_routine(THD *thd, TABLE_LIST *procs, bool any, bool no_error);
|
||||
|
@ -82,10 +82,10 @@ sp_function_exists(THD *thd, sp_name *name);
|
|||
*/
|
||||
void
|
||||
sp_add_to_hash(HASH *h, sp_name *fun);
|
||||
void
|
||||
bool
|
||||
sp_merge_hash(HASH *dst, HASH *src);
|
||||
int
|
||||
sp_cache_routines(THD *thd, LEX *lex, int type);
|
||||
void
|
||||
sp_cache_routines(THD *thd, LEX *lex);
|
||||
|
||||
|
||||
//
|
||||
|
|
736
sql/sp_head.cc
736
sql/sp_head.cc
File diff suppressed because it is too large
Load diff
221
sql/sp_head.h
221
sql/sp_head.h
|
@ -103,7 +103,14 @@ public:
|
|||
LEX_STRING m_definer_host;
|
||||
longlong m_created;
|
||||
longlong m_modified;
|
||||
HASH m_sptabs; /* Merged table lists */
|
||||
/*
|
||||
Sets containing names of SP and SF used by this routine.
|
||||
|
||||
TODO Probably we should combine these two hashes in one. It will
|
||||
decrease memory overhead ans simplify algorithms using them. The
|
||||
same applies to similar hashes in LEX.
|
||||
*/
|
||||
HASH m_spfuns, m_spprocs;
|
||||
// Pointers set during parsing
|
||||
uchar *m_param_begin, *m_param_end, *m_returns_begin, *m_returns_end,
|
||||
*m_body_begin;
|
||||
|
@ -225,6 +232,10 @@ public:
|
|||
return ip;
|
||||
}
|
||||
|
||||
/* Add tables used by routine to the table list. */
|
||||
bool add_used_tables_to_table_list(THD *thd,
|
||||
TABLE_LIST ***query_tables_last_ptr);
|
||||
|
||||
private:
|
||||
|
||||
MEM_ROOT *m_thd_root; // Temp. store for thd's mem_root
|
||||
|
@ -240,10 +251,20 @@ private:
|
|||
sp_instr *instr;
|
||||
} bp_t;
|
||||
List<bp_t> m_backpatch; // Instructions needing backpatching
|
||||
/*
|
||||
Multi-set representing optimized list of tables to be locked by this
|
||||
routine. Does not include tables which are used by invoked routines.
|
||||
*/
|
||||
HASH m_sptabs;
|
||||
|
||||
int
|
||||
execute(THD *thd);
|
||||
|
||||
/*
|
||||
Merge the list of tables used by query into the multi-set of tables used
|
||||
by routine.
|
||||
*/
|
||||
bool merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check);
|
||||
}; // class sp_head : public Sql_alloc
|
||||
|
||||
|
||||
|
@ -277,6 +298,17 @@ public:
|
|||
// Returns 0 on success, non-zero if some error occured.
|
||||
virtual int execute(THD *thd, uint *nextp) = 0;
|
||||
|
||||
/*
|
||||
Execute core function of instruction after all preparations (e.g.
|
||||
setting of proper LEX, saving part of the thread context have been
|
||||
done).
|
||||
|
||||
Should be implemented for instructions using expressions or whole
|
||||
statements (thus having to have own LEX). Used in concert with
|
||||
sp_lex_keeper class and its descendants.
|
||||
*/
|
||||
virtual int exec_core(THD *thd, uint *nextp);
|
||||
|
||||
virtual void print(String *str) = 0;
|
||||
|
||||
virtual void backpatch(uint dest, sp_pcontext *dst_ctx)
|
||||
|
@ -301,6 +333,60 @@ public:
|
|||
}; // class sp_instr : public Sql_alloc
|
||||
|
||||
|
||||
/*
|
||||
Auxilary class to which instructions delegate responsibility
|
||||
for handling LEX and preparations before executing statement
|
||||
or calculating complex expression.
|
||||
|
||||
Exist mainly to avoid having double hierarchy between instruction
|
||||
classes.
|
||||
|
||||
TODO: Add ability to not store LEX and do any preparations if
|
||||
expression used is simple.
|
||||
*/
|
||||
|
||||
class sp_lex_keeper
|
||||
{
|
||||
/* Prevent use of these */
|
||||
sp_lex_keeper(const sp_lex_keeper &);
|
||||
void operator=(sp_lex_keeper &);
|
||||
public:
|
||||
|
||||
sp_lex_keeper(LEX *lex, bool lex_resp)
|
||||
: m_lex(lex), m_lex_resp(lex_resp)
|
||||
{
|
||||
lex->sp_lex_in_use= TRUE;
|
||||
}
|
||||
virtual ~sp_lex_keeper()
|
||||
{
|
||||
if (m_lex_resp)
|
||||
delete m_lex;
|
||||
}
|
||||
|
||||
/*
|
||||
Prepare execution of instruction using LEX, if requested check whenever
|
||||
we have read access to tables used and open/lock them, call instruction's
|
||||
exec_core() method, perform cleanup afterwards.
|
||||
*/
|
||||
int reset_lex_and_exec_core(THD *thd, uint *nextp, bool open_tables,
|
||||
sp_instr* instr);
|
||||
|
||||
inline uint sql_command() const
|
||||
{
|
||||
return (uint)m_lex->sql_command;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
LEX *m_lex;
|
||||
/*
|
||||
Indicates whenever this sp_lex_keeper instance responsible
|
||||
for LEX deletion.
|
||||
*/
|
||||
bool m_lex_resp;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Call out to some prepared SQL statement.
|
||||
//
|
||||
|
@ -313,38 +399,25 @@ public:
|
|||
|
||||
LEX_STRING m_query; // For thd->query
|
||||
|
||||
sp_instr_stmt(uint ip, sp_pcontext *ctx)
|
||||
: sp_instr(ip, ctx), m_lex(NULL)
|
||||
sp_instr_stmt(uint ip, sp_pcontext *ctx, LEX *lex)
|
||||
: sp_instr(ip, ctx), m_lex_keeper(lex, TRUE)
|
||||
{
|
||||
m_query.str= 0;
|
||||
m_query.length= 0;
|
||||
}
|
||||
|
||||
virtual ~sp_instr_stmt();
|
||||
virtual ~sp_instr_stmt()
|
||||
{};
|
||||
|
||||
virtual int execute(THD *thd, uint *nextp);
|
||||
|
||||
virtual int exec_core(THD *thd, uint *nextp);
|
||||
|
||||
virtual void print(String *str);
|
||||
|
||||
inline void
|
||||
set_lex(LEX *lex)
|
||||
{
|
||||
m_lex= lex;
|
||||
}
|
||||
|
||||
inline LEX *
|
||||
get_lex()
|
||||
{
|
||||
return m_lex;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
int exec_stmt(THD *thd, LEX *lex); // Execute a statement
|
||||
|
||||
private:
|
||||
|
||||
LEX *m_lex; // My own lex
|
||||
sp_lex_keeper m_lex_keeper;
|
||||
|
||||
}; // class sp_instr_stmt : public sp_instr
|
||||
|
||||
|
@ -356,12 +429,11 @@ class sp_instr_set : public sp_instr
|
|||
|
||||
public:
|
||||
|
||||
TABLE_LIST *tables;
|
||||
|
||||
sp_instr_set(uint ip, sp_pcontext *ctx,
|
||||
uint offset, Item *val, enum enum_field_types type)
|
||||
: sp_instr(ip, ctx),
|
||||
tables(NULL), m_offset(offset), m_value(val), m_type(type)
|
||||
uint offset, Item *val, enum enum_field_types type,
|
||||
LEX *lex, bool lex_resp)
|
||||
: sp_instr(ip, ctx), m_offset(offset), m_value(val), m_type(type),
|
||||
m_lex_keeper(lex, lex_resp)
|
||||
{}
|
||||
|
||||
virtual ~sp_instr_set()
|
||||
|
@ -369,6 +441,8 @@ public:
|
|||
|
||||
virtual int execute(THD *thd, uint *nextp);
|
||||
|
||||
virtual int exec_core(THD *thd, uint *nextp);
|
||||
|
||||
virtual void print(String *str);
|
||||
|
||||
private:
|
||||
|
@ -376,41 +450,11 @@ private:
|
|||
uint m_offset; // Frame offset
|
||||
Item *m_value;
|
||||
enum enum_field_types m_type; // The declared type
|
||||
sp_lex_keeper m_lex_keeper;
|
||||
|
||||
}; // class sp_instr_set : public sp_instr
|
||||
|
||||
|
||||
/*
|
||||
Set user variable instruction.
|
||||
Used in functions and triggers to set user variables because we don't
|
||||
want use sp_instr_stmt + "SET @a:=..." statement in this case since
|
||||
latter will close all tables and thus will ruin execution of statement
|
||||
calling/invoking this function/trigger.
|
||||
*/
|
||||
class sp_instr_set_user_var : public sp_instr
|
||||
{
|
||||
sp_instr_set_user_var(const sp_instr_set_user_var &);
|
||||
void operator=(sp_instr_set_user_var &);
|
||||
|
||||
public:
|
||||
|
||||
sp_instr_set_user_var(uint ip, sp_pcontext *ctx, LEX_STRING var, Item *val)
|
||||
: sp_instr(ip, ctx), m_set_var_item(var, val)
|
||||
{}
|
||||
|
||||
virtual ~sp_instr_set_user_var()
|
||||
{}
|
||||
|
||||
virtual int execute(THD *thd, uint *nextp);
|
||||
|
||||
virtual void print(String *str);
|
||||
|
||||
private:
|
||||
|
||||
Item_func_set_user_var m_set_var_item;
|
||||
}; // class sp_instr_set_user_var : public sp_instr
|
||||
|
||||
|
||||
/*
|
||||
Set NEW/OLD row field value instruction. Used in triggers.
|
||||
*/
|
||||
|
@ -492,14 +536,12 @@ class sp_instr_jump_if : public sp_instr_jump
|
|||
|
||||
public:
|
||||
|
||||
TABLE_LIST *tables;
|
||||
|
||||
sp_instr_jump_if(uint ip, sp_pcontext *ctx, Item *i)
|
||||
: sp_instr_jump(ip, ctx), tables(NULL), m_expr(i)
|
||||
sp_instr_jump_if(uint ip, sp_pcontext *ctx, Item *i, LEX *lex)
|
||||
: sp_instr_jump(ip, ctx), m_expr(i), m_lex_keeper(lex, TRUE)
|
||||
{}
|
||||
|
||||
sp_instr_jump_if(uint ip, sp_pcontext *ctx, Item *i, uint dest)
|
||||
: sp_instr_jump(ip, ctx, dest), tables(NULL), m_expr(i)
|
||||
sp_instr_jump_if(uint ip, sp_pcontext *ctx, Item *i, uint dest, LEX *lex)
|
||||
: sp_instr_jump(ip, ctx, dest), m_expr(i), m_lex_keeper(lex, TRUE)
|
||||
{}
|
||||
|
||||
virtual ~sp_instr_jump_if()
|
||||
|
@ -507,6 +549,8 @@ public:
|
|||
|
||||
virtual int execute(THD *thd, uint *nextp);
|
||||
|
||||
virtual int exec_core(THD *thd, uint *nextp);
|
||||
|
||||
virtual void print(String *str);
|
||||
|
||||
virtual uint opt_mark(sp_head *sp);
|
||||
|
@ -519,6 +563,7 @@ public:
|
|||
private:
|
||||
|
||||
Item *m_expr; // The condition
|
||||
sp_lex_keeper m_lex_keeper;
|
||||
|
||||
}; // class sp_instr_jump_if : public sp_instr_jump
|
||||
|
||||
|
@ -530,14 +575,12 @@ class sp_instr_jump_if_not : public sp_instr_jump
|
|||
|
||||
public:
|
||||
|
||||
TABLE_LIST *tables;
|
||||
|
||||
sp_instr_jump_if_not(uint ip, sp_pcontext *ctx, Item *i)
|
||||
: sp_instr_jump(ip, ctx), tables(NULL), m_expr(i)
|
||||
sp_instr_jump_if_not(uint ip, sp_pcontext *ctx, Item *i, LEX *lex)
|
||||
: sp_instr_jump(ip, ctx), m_expr(i), m_lex_keeper(lex, TRUE)
|
||||
{}
|
||||
|
||||
sp_instr_jump_if_not(uint ip, sp_pcontext *ctx, Item *i, uint dest)
|
||||
: sp_instr_jump(ip, ctx, dest), tables(NULL), m_expr(i)
|
||||
sp_instr_jump_if_not(uint ip, sp_pcontext *ctx, Item *i, uint dest, LEX *lex)
|
||||
: sp_instr_jump(ip, ctx, dest), m_expr(i), m_lex_keeper(lex, TRUE)
|
||||
{}
|
||||
|
||||
virtual ~sp_instr_jump_if_not()
|
||||
|
@ -545,6 +588,8 @@ public:
|
|||
|
||||
virtual int execute(THD *thd, uint *nextp);
|
||||
|
||||
virtual int exec_core(THD *thd, uint *nextp);
|
||||
|
||||
virtual void print(String *str);
|
||||
|
||||
virtual uint opt_mark(sp_head *sp);
|
||||
|
@ -557,6 +602,7 @@ public:
|
|||
private:
|
||||
|
||||
Item *m_expr; // The condition
|
||||
sp_lex_keeper m_lex_keeper;
|
||||
|
||||
}; // class sp_instr_jump_if_not : public sp_instr_jump
|
||||
|
||||
|
@ -568,11 +614,9 @@ class sp_instr_freturn : public sp_instr
|
|||
|
||||
public:
|
||||
|
||||
TABLE_LIST *tables;
|
||||
|
||||
sp_instr_freturn(uint ip, sp_pcontext *ctx,
|
||||
Item *val, enum enum_field_types type)
|
||||
: sp_instr(ip, ctx), tables(NULL), m_value(val), m_type(type)
|
||||
Item *val, enum enum_field_types type, LEX *lex)
|
||||
: sp_instr(ip, ctx), m_value(val), m_type(type), m_lex_keeper(lex, TRUE)
|
||||
{}
|
||||
|
||||
virtual ~sp_instr_freturn()
|
||||
|
@ -580,6 +624,8 @@ public:
|
|||
|
||||
virtual int execute(THD *thd, uint *nextp);
|
||||
|
||||
virtual int exec_core(THD *thd, uint *nextp);
|
||||
|
||||
virtual void print(String *str);
|
||||
|
||||
virtual uint opt_mark(sp_head *sp)
|
||||
|
@ -592,6 +638,7 @@ protected:
|
|||
|
||||
Item *m_value;
|
||||
enum enum_field_types m_type;
|
||||
sp_lex_keeper m_lex_keeper;
|
||||
|
||||
}; // class sp_instr_freturn : public sp_instr
|
||||
|
||||
|
@ -710,10 +757,11 @@ class sp_instr_cpush : public sp_instr
|
|||
public:
|
||||
|
||||
sp_instr_cpush(uint ip, sp_pcontext *ctx, LEX *lex)
|
||||
: sp_instr(ip, ctx), m_lex(lex)
|
||||
: sp_instr(ip, ctx), m_lex_keeper(lex, TRUE)
|
||||
{}
|
||||
|
||||
virtual ~sp_instr_cpush();
|
||||
virtual ~sp_instr_cpush()
|
||||
{}
|
||||
|
||||
virtual int execute(THD *thd, uint *nextp);
|
||||
|
||||
|
@ -721,7 +769,7 @@ public:
|
|||
|
||||
private:
|
||||
|
||||
LEX *m_lex;
|
||||
sp_lex_keeper m_lex_keeper;
|
||||
|
||||
}; // class sp_instr_cpush : public sp_instr
|
||||
|
||||
|
@ -760,7 +808,7 @@ private:
|
|||
}; // class sp_instr_cpop : public sp_instr
|
||||
|
||||
|
||||
class sp_instr_copen : public sp_instr_stmt
|
||||
class sp_instr_copen : public sp_instr
|
||||
{
|
||||
sp_instr_copen(const sp_instr_copen &); /* Prevent use of these */
|
||||
void operator=(sp_instr_copen &);
|
||||
|
@ -768,7 +816,7 @@ class sp_instr_copen : public sp_instr_stmt
|
|||
public:
|
||||
|
||||
sp_instr_copen(uint ip, sp_pcontext *ctx, uint c)
|
||||
: sp_instr_stmt(ip, ctx), m_cursor(c)
|
||||
: sp_instr(ip, ctx), m_cursor(c)
|
||||
{}
|
||||
|
||||
virtual ~sp_instr_copen()
|
||||
|
@ -776,6 +824,8 @@ public:
|
|||
|
||||
virtual int execute(THD *thd, uint *nextp);
|
||||
|
||||
virtual int exec_core(THD *thd, uint *nextp);
|
||||
|
||||
virtual void print(String *str);
|
||||
|
||||
private:
|
||||
|
@ -893,22 +943,11 @@ void
|
|||
sp_restore_security_context(THD *thd, sp_head *sp,st_sp_security_context *ctxp);
|
||||
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
|
||||
|
||||
bool
|
||||
sp_merge_table_list(THD *thd, HASH *h, TABLE_LIST *table,
|
||||
LEX *lex_for_tmp_check = 0);
|
||||
void
|
||||
sp_merge_routine_tables(THD *thd, LEX *lex);
|
||||
void
|
||||
sp_merge_table_hash(HASH *hdst, HASH *hsrc);
|
||||
TABLE_LIST *
|
||||
sp_hash_to_table_list(THD *thd, HASH *h);
|
||||
bool
|
||||
sp_open_and_lock_tables(THD *thd, TABLE_LIST *tables);
|
||||
void
|
||||
sp_unlock_tables(THD *thd);
|
||||
TABLE_LIST *
|
||||
sp_add_to_query_tables(THD *thd, LEX *lex,
|
||||
const char *db, const char *name,
|
||||
thr_lock_type locktype);
|
||||
bool
|
||||
sp_add_sp_tables_to_table_list(THD *thd, LEX *lex, LEX *func_lex);
|
||||
|
||||
#endif /* _SP_HEAD_H_ */
|
||||
|
|
|
@ -125,9 +125,9 @@ sp_rcontext::restore_variables(uint fp)
|
|||
}
|
||||
|
||||
void
|
||||
sp_rcontext::push_cursor(LEX *lex)
|
||||
sp_rcontext::push_cursor(sp_lex_keeper *lex_keeper)
|
||||
{
|
||||
m_cstack[m_ccount++]= new sp_cursor(lex);
|
||||
m_cstack[m_ccount++]= new sp_cursor(lex_keeper);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -148,7 +148,7 @@ sp_rcontext::pop_cursors(uint count)
|
|||
|
||||
// We have split this in two to make it easy for sp_instr_copen
|
||||
// to reuse the sp_instr::exec_stmt() code.
|
||||
LEX *
|
||||
sp_lex_keeper*
|
||||
sp_cursor::pre_open(THD *thd)
|
||||
{
|
||||
if (m_isopen)
|
||||
|
@ -168,7 +168,7 @@ sp_cursor::pre_open(THD *thd)
|
|||
|
||||
m_nseof= thd->net.no_send_eof;
|
||||
thd->net.no_send_eof= TRUE;
|
||||
return m_lex;
|
||||
return m_lex_keeper;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
struct sp_cond_type;
|
||||
class sp_cursor;
|
||||
struct sp_pvar;
|
||||
class sp_lex_keeper;
|
||||
|
||||
#define SP_HANDLER_NONE 0
|
||||
#define SP_HANDLER_EXIT 1
|
||||
|
@ -164,7 +165,7 @@ class sp_rcontext : public Sql_alloc
|
|||
restore_variables(uint fp);
|
||||
|
||||
void
|
||||
push_cursor(LEX *lex);
|
||||
push_cursor(sp_lex_keeper *lex_keeper);
|
||||
|
||||
void
|
||||
pop_cursors(uint count);
|
||||
|
@ -207,8 +208,8 @@ class sp_cursor : public Sql_alloc
|
|||
{
|
||||
public:
|
||||
|
||||
sp_cursor(LEX *lex)
|
||||
: m_lex(lex), m_prot(NULL), m_isopen(0), m_current_row(NULL)
|
||||
sp_cursor(sp_lex_keeper *lex_keeper)
|
||||
: m_lex_keeper(lex_keeper), m_prot(NULL), m_isopen(0), m_current_row(NULL)
|
||||
{
|
||||
/* Empty */
|
||||
}
|
||||
|
@ -220,7 +221,7 @@ public:
|
|||
|
||||
// We have split this in two to make it easy for sp_instr_copen
|
||||
// to reuse the sp_instr::exec_stmt() code.
|
||||
LEX *
|
||||
sp_lex_keeper *
|
||||
pre_open(THD *thd);
|
||||
void
|
||||
post_open(THD *thd, my_bool was_opened);
|
||||
|
@ -240,7 +241,7 @@ public:
|
|||
private:
|
||||
|
||||
MEM_ROOT m_mem_root; // My own mem_root
|
||||
LEX *m_lex;
|
||||
sp_lex_keeper *m_lex_keeper;
|
||||
Protocol_cursor *m_prot;
|
||||
my_bool m_isopen;
|
||||
my_bool m_nseof; // Original no_send_eof
|
||||
|
|
|
@ -138,7 +138,6 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
|
|||
TABLE_LIST tables[3];
|
||||
TABLE *table;
|
||||
READ_RECORD read_record_info;
|
||||
MYSQL_LOCK *lock;
|
||||
my_bool return_val=1;
|
||||
bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE;
|
||||
char tmp_name[NAME_LEN+1];
|
||||
|
@ -176,20 +175,9 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
|
|||
tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_READ;
|
||||
tables[0].db=tables[1].db=tables[2].db=thd->db;
|
||||
|
||||
uint counter;
|
||||
if (open_tables(thd, tables, &counter))
|
||||
if (simple_open_n_lock_tables(thd, tables))
|
||||
{
|
||||
sql_print_error("Fatal error: Can't open privilege tables: %s",
|
||||
thd->net.last_error);
|
||||
goto end;
|
||||
}
|
||||
TABLE *ptr[3]; // Lock tables for quick update
|
||||
ptr[0]= tables[0].table;
|
||||
ptr[1]= tables[1].table;
|
||||
ptr[2]= tables[2].table;
|
||||
if (!(lock=mysql_lock_tables(thd,ptr,3)))
|
||||
{
|
||||
sql_print_error("Fatal error: Can't lock privilege tables: %s",
|
||||
sql_print_error("Fatal error: Can't open and lock privilege tables: %s",
|
||||
thd->net.last_error);
|
||||
goto end;
|
||||
}
|
||||
|
@ -459,7 +447,6 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
|
|||
freeze_size(&acl_dbs);
|
||||
init_check_host();
|
||||
|
||||
mysql_unlock_tables(thd, lock);
|
||||
initialized=1;
|
||||
thd->version--; // Force close to free memory
|
||||
return_val=0;
|
||||
|
@ -3112,7 +3099,6 @@ my_bool grant_init(THD *org_thd)
|
|||
{
|
||||
THD *thd;
|
||||
TABLE_LIST tables[3];
|
||||
MYSQL_LOCK *lock;
|
||||
MEM_ROOT *memex_ptr;
|
||||
my_bool return_val= 1;
|
||||
TABLE *t_table, *c_table, *p_table;
|
||||
|
@ -3146,15 +3132,7 @@ my_bool grant_init(THD *org_thd)
|
|||
tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_READ;
|
||||
tables[0].db=tables[1].db=tables[2].db=thd->db;
|
||||
|
||||
uint counter;
|
||||
if (open_tables(thd, tables, &counter))
|
||||
goto end;
|
||||
|
||||
TABLE *ptr[3]; // Lock tables for quick update
|
||||
ptr[0]= tables[0].table;
|
||||
ptr[1]= tables[1].table;
|
||||
ptr[2]= tables[2].table;
|
||||
if (!(lock=mysql_lock_tables(thd,ptr,3)))
|
||||
if (simple_open_n_lock_tables(thd, tables))
|
||||
goto end;
|
||||
|
||||
t_table = tables[0].table; c_table = tables[1].table;
|
||||
|
@ -3244,7 +3222,6 @@ my_bool grant_init(THD *org_thd)
|
|||
end_unlock:
|
||||
t_table->file->ha_index_end();
|
||||
p_table->file->ha_index_end();
|
||||
mysql_unlock_tables(thd, lock);
|
||||
thd->version--; // Force close to free memory
|
||||
|
||||
end:
|
||||
|
@ -3606,6 +3583,37 @@ err:
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
Check if routine has any of the
|
||||
procedure level grants
|
||||
|
||||
SYNPOSIS
|
||||
bool check_routine_level_acl()
|
||||
thd Thread handler
|
||||
db Database name
|
||||
name Routine name
|
||||
|
||||
RETURN
|
||||
1 error
|
||||
0 Ok
|
||||
*/
|
||||
|
||||
bool check_routine_level_acl(THD *thd, char *db, char *name)
|
||||
{
|
||||
bool no_routine_acl= 1;
|
||||
if (grant_option)
|
||||
{
|
||||
GRANT_NAME *grant_proc;
|
||||
rw_rdlock(&LOCK_grant);
|
||||
if ((grant_proc= proc_hash_search(thd->priv_host, thd->ip, db,
|
||||
thd->priv_user, name, 0)))
|
||||
no_routine_acl= !(grant_proc->privs & SHOW_PROC_ACLS);
|
||||
rw_unlock(&LOCK_grant);
|
||||
}
|
||||
return no_routine_acl;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
Functions to retrieve the grant for a table/column (for SHOW functions)
|
||||
*****************************************************************************/
|
||||
|
|
|
@ -63,6 +63,9 @@
|
|||
#define PROC_ACLS \
|
||||
(ALTER_PROC_ACL | EXECUTE_ACL | GRANT_ACL)
|
||||
|
||||
#define SHOW_PROC_ACLS \
|
||||
(ALTER_PROC_ACL | EXECUTE_ACL | CREATE_PROC_ACL)
|
||||
|
||||
#define GLOBAL_ACLS \
|
||||
(SELECT_ACL | INSERT_ACL | UPDATE_ACL | DELETE_ACL | CREATE_ACL | DROP_ACL | \
|
||||
RELOAD_ACL | SHUTDOWN_ACL | PROCESS_ACL | FILE_ACL | GRANT_ACL | \
|
||||
|
@ -216,6 +219,7 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
|
|||
const char *db, const char *table);
|
||||
bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name);
|
||||
bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name);
|
||||
bool check_routine_level_acl(THD *thd, char *db, char *name);
|
||||
|
||||
#ifdef NO_EMBEDDED_ACCESS_CHECKS
|
||||
#define check_grant(A,B,C,D,E,F) 0
|
||||
|
|
373
sql/sql_base.cc
373
sql/sql_base.cc
|
@ -20,6 +20,7 @@
|
|||
#include "mysql_priv.h"
|
||||
#include "sql_select.h"
|
||||
#include "sp_head.h"
|
||||
#include "sp.h"
|
||||
#include "sql_trigger.h"
|
||||
#include <m_ctype.h>
|
||||
#include <my_dir.h>
|
||||
|
@ -359,7 +360,30 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
|
|||
|
||||
|
||||
/*
|
||||
Close all tables used by thread
|
||||
Mark all tables in the list which were used by current substatement
|
||||
as free for reuse.
|
||||
|
||||
SYNOPSIS
|
||||
mark_used_tables_as_free_for_reuse()
|
||||
thd - thread context
|
||||
table - head of the list of tables
|
||||
|
||||
DESCRIPTION
|
||||
Marks all tables in the list which were used by current substatement
|
||||
(they are marked by its query_id) as free for reuse.
|
||||
*/
|
||||
|
||||
static void mark_used_tables_as_free_for_reuse(THD *thd, TABLE *table)
|
||||
{
|
||||
for (; table ; table= table->next)
|
||||
if (table->query_id == thd->query_id)
|
||||
table->query_id= 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Close all tables used by the current substatement, or all tables
|
||||
used by this thread if we are on the upper level.
|
||||
|
||||
SYNOPSIS
|
||||
close_thread_tables()
|
||||
|
@ -372,14 +396,31 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
|
|||
IMPLEMENTATION
|
||||
Unlocks tables and frees derived tables.
|
||||
Put all normal tables used by thread in free list.
|
||||
|
||||
When in prelocked mode it will only close/mark as free for reuse
|
||||
tables opened by this substatement, it will also check if we are
|
||||
closing tables after execution of complete query (i.e. we are on
|
||||
upper level) and will leave prelocked mode if needed.
|
||||
*/
|
||||
|
||||
void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived,
|
||||
TABLE *stopper)
|
||||
{
|
||||
bool found_old_table;
|
||||
prelocked_mode_type prelocked_mode= thd->prelocked_mode;
|
||||
DBUG_ENTER("close_thread_tables");
|
||||
|
||||
/*
|
||||
We are assuming here that thd->derived_tables contains ONLY derived
|
||||
tables for this substatement. i.e. instead of approach which uses
|
||||
query_id matching for determining which of the derived tables belong
|
||||
to this substatement we rely on the ability of substatements to
|
||||
save/restore thd->derived_tables during their execution.
|
||||
|
||||
TODO: Probably even better approach is to simply associate list of
|
||||
derived tables with (sub-)statement instead of thread and destroy
|
||||
them at the end of its execution.
|
||||
*/
|
||||
if (thd->derived_tables && !skip_derived)
|
||||
{
|
||||
TABLE *table, *next;
|
||||
|
@ -394,10 +435,50 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived,
|
|||
}
|
||||
thd->derived_tables= 0;
|
||||
}
|
||||
if (thd->locked_tables)
|
||||
|
||||
if (prelocked_mode)
|
||||
{
|
||||
ha_commit_stmt(thd); // If select statement
|
||||
DBUG_VOID_RETURN; // LOCK TABLES in use
|
||||
/*
|
||||
Mark all temporary tables used by this substatement as free for reuse.
|
||||
*/
|
||||
mark_used_tables_as_free_for_reuse(thd, thd->temporary_tables);
|
||||
}
|
||||
|
||||
if (thd->locked_tables || prelocked_mode)
|
||||
{
|
||||
/*
|
||||
TODO: It is not 100% clear whenever we should do ha_commit_stmt() for
|
||||
sub-statements. This issue needs additional investigation.
|
||||
*/
|
||||
ha_commit_stmt(thd);
|
||||
|
||||
/* We are under simple LOCK TABLES so should not do anything else. */
|
||||
if (!prelocked_mode)
|
||||
DBUG_VOID_RETURN;
|
||||
|
||||
if (!thd->lex->requires_prelocking())
|
||||
{
|
||||
/*
|
||||
If we are executing one of substatements we have to mark
|
||||
all tables which it used as free for reuse.
|
||||
*/
|
||||
mark_used_tables_as_free_for_reuse(thd, thd->open_tables);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
DBUG_ASSERT(prelocked_mode);
|
||||
/*
|
||||
We are in prelocked mode, so we have to leave it now with doing
|
||||
implicit UNLOCK TABLES if need.
|
||||
*/
|
||||
thd->prelocked_mode= NON_PRELOCKED;
|
||||
|
||||
if (prelocked_mode == PRELOCKED_UNDER_LOCK_TABLES)
|
||||
DBUG_VOID_RETURN;
|
||||
|
||||
thd->lock= thd->locked_tables;
|
||||
thd->locked_tables= 0;
|
||||
/* Fallthrough */
|
||||
}
|
||||
|
||||
if (thd->lock)
|
||||
|
@ -441,6 +522,17 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived,
|
|||
if (!lock_in_use)
|
||||
VOID(pthread_mutex_unlock(&LOCK_open));
|
||||
/* VOID(pthread_sigmask(SIG_SETMASK,&thd->signals,NULL)); */
|
||||
|
||||
if (prelocked_mode == PRELOCKED)
|
||||
{
|
||||
/*
|
||||
If we are here then we are leaving normal prelocked mode, so it is
|
||||
good idea to turn off OPTION_TABLE_LOCK flag.
|
||||
*/
|
||||
DBUG_ASSERT(thd->lex->requires_prelocking());
|
||||
thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
|
||||
}
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
@ -910,7 +1002,8 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
|||
!memcmp(table->s->table_cache_key, key,
|
||||
key_length + TMP_TABLE_KEY_EXTRA))
|
||||
{
|
||||
if (table->query_id == thd->query_id)
|
||||
if (table->query_id == thd->query_id ||
|
||||
thd->prelocked_mode && table->query_id)
|
||||
{
|
||||
my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias);
|
||||
DBUG_RETURN(0);
|
||||
|
@ -924,16 +1017,17 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
|||
}
|
||||
}
|
||||
|
||||
if (thd->locked_tables)
|
||||
if (thd->locked_tables || thd->prelocked_mode)
|
||||
{ // Using table locks
|
||||
for (table=thd->open_tables; table ; table=table->next)
|
||||
{
|
||||
if (table->s->key_length == key_length &&
|
||||
!memcmp(table->s->table_cache_key,key,key_length) &&
|
||||
!my_strcasecmp(system_charset_info, table->alias, alias))
|
||||
!memcmp(table->s->table_cache_key, key, key_length) &&
|
||||
!my_strcasecmp(system_charset_info, table->alias, alias) &&
|
||||
table->query_id != thd->query_id && /* skip tables already used by this query */
|
||||
!(thd->prelocked_mode && table->query_id))
|
||||
{
|
||||
if (table->query_id != thd->query_id)
|
||||
table->query_id=thd->query_id;
|
||||
table->query_id= thd->query_id;
|
||||
DBUG_PRINT("info",("Using locked table"));
|
||||
goto reset;
|
||||
}
|
||||
|
@ -1625,21 +1719,34 @@ err:
|
|||
SYNOPSIS
|
||||
open_tables()
|
||||
thd - thread handler
|
||||
start - list of tables
|
||||
start - list of tables in/out
|
||||
counter - number of opened tables will be return using this parameter
|
||||
|
||||
NOTE
|
||||
Unless we are already in prelocked mode, this function will also precache
|
||||
all SP/SFs explicitly or implicitly (via views and triggers) used by the
|
||||
query and add tables needed for their execution to table list. If resulting
|
||||
tables list will be non empty it will mark query as requiring precaching.
|
||||
Prelocked mode will be enabled for such query during lock_tables() call.
|
||||
|
||||
If query for which we are opening tables is already marked as requiring
|
||||
prelocking it won't do such precaching and will simply reuse table list
|
||||
which is already built.
|
||||
|
||||
RETURN
|
||||
0 - OK
|
||||
-1 - error
|
||||
*/
|
||||
|
||||
int open_tables(THD *thd, TABLE_LIST *start, uint *counter)
|
||||
int open_tables(THD *thd, TABLE_LIST **start, uint *counter)
|
||||
{
|
||||
TABLE_LIST *tables;
|
||||
bool refresh;
|
||||
int result=0;
|
||||
DBUG_ENTER("open_tables");
|
||||
MEM_ROOT new_frm_mem;
|
||||
/* Also used for indicating that prelocking is need */
|
||||
TABLE_LIST **query_tables_last_own;
|
||||
DBUG_ENTER("open_tables");
|
||||
/*
|
||||
temporary mem_root for new .frm parsing.
|
||||
TODO: variables for size
|
||||
|
@ -1649,8 +1756,51 @@ int open_tables(THD *thd, TABLE_LIST *start, uint *counter)
|
|||
thd->current_tablenr= 0;
|
||||
restart:
|
||||
*counter= 0;
|
||||
query_tables_last_own= 0;
|
||||
thd->proc_info="Opening tables";
|
||||
for (tables= start; tables ;tables= tables->next_global)
|
||||
|
||||
/*
|
||||
If we are not already executing prelocked statement and don't have
|
||||
statement for which table list for prelocking is already built, let
|
||||
us cache routines and try to build such table list.
|
||||
|
||||
NOTE: If we want queries with functions to work under explicit
|
||||
LOCK TABLES we have to additionaly lock mysql.proc table in it.
|
||||
At least until Monty will fix SP loading :)
|
||||
|
||||
NOTE: We can't delay prelocking until we will met some sub-statement
|
||||
which really uses tables, since this will imply that we have to restore
|
||||
its table list to be able execute it in some other context.
|
||||
And current views implementation assumes that view tables are added to
|
||||
global table list only once during PS preparing/first SP execution.
|
||||
Also locking at earlier stage is probably faster altough may decrease
|
||||
concurrency a bit.
|
||||
|
||||
NOTE: We will mark statement as requiring prelocking only if we will
|
||||
have non empty table list. But this does not guarantee that in prelocked
|
||||
mode we will have some locked tables, because queries which use only
|
||||
derived/information schema tables and views possible. Thus "counter"
|
||||
may be still zero for prelocked statement...
|
||||
*/
|
||||
if (!thd->prelocked_mode && !thd->lex->requires_prelocking() &&
|
||||
(thd->lex->spfuns.records || thd->lex->spprocs.records))
|
||||
{
|
||||
TABLE_LIST **save_query_tables_last;
|
||||
|
||||
sp_cache_routines(thd, thd->lex);
|
||||
save_query_tables_last= thd->lex->query_tables_last;
|
||||
|
||||
DBUG_ASSERT(thd->lex->query_tables == *start);
|
||||
|
||||
if (sp_add_sp_tables_to_table_list(thd, thd->lex, thd->lex) ||
|
||||
*start)
|
||||
{
|
||||
query_tables_last_own= save_query_tables_last;
|
||||
*start= thd->lex->query_tables;
|
||||
}
|
||||
}
|
||||
|
||||
for (tables= *start; tables ;tables= tables->next_global)
|
||||
{
|
||||
/*
|
||||
Ignore placeholders for derived tables. After derived tables
|
||||
|
@ -1671,8 +1821,27 @@ int open_tables(THD *thd, TABLE_LIST *start, uint *counter)
|
|||
free_root(&new_frm_mem, MYF(MY_KEEP_PREALLOC));
|
||||
if (tables->view)
|
||||
{
|
||||
/* VIEW placeholder */
|
||||
(*counter)--;
|
||||
continue; //VIEW placeholder
|
||||
/*
|
||||
Again if needed we have to get cache all routines used by this view
|
||||
and add tables used by them to table list.
|
||||
*/
|
||||
if (!thd->prelocked_mode && !thd->lex->requires_prelocking() &&
|
||||
(tables->view->spfuns.records || tables->view->spprocs.records))
|
||||
{
|
||||
// FIXME We should catch recursion for both views and funcs here
|
||||
sp_cache_routines(thd, tables->view);
|
||||
|
||||
/* We have at least one table in TL here */
|
||||
if (!query_tables_last_own)
|
||||
query_tables_last_own= thd->lex->query_tables_last;
|
||||
sp_add_sp_tables_to_table_list(thd, thd->lex, tables->view);
|
||||
}
|
||||
/* Cleanup hashes because destructo for this LEX is never called */
|
||||
hash_free(&tables->view->spfuns);
|
||||
hash_free(&tables->view->spprocs);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (refresh) // Refresh in progress
|
||||
|
@ -1684,7 +1853,12 @@ int open_tables(THD *thd, TABLE_LIST *start, uint *counter)
|
|||
thd->version=refresh_version;
|
||||
TABLE **prev_table= &thd->open_tables;
|
||||
bool found=0;
|
||||
for (TABLE_LIST *tmp= start; tmp; tmp= tmp->next_global)
|
||||
/*
|
||||
QQ: What we should do if we have started building of table list
|
||||
for prelocking ??? Probably throw it away ? But before we should
|
||||
mark all temporary tables as free? How about locked ?
|
||||
*/
|
||||
for (TABLE_LIST *tmp= *start; tmp; tmp= tmp->next_global)
|
||||
{
|
||||
/* Close normal (not temporary) changed tables */
|
||||
if (tmp->table && ! tmp->table->s->tmp_table)
|
||||
|
@ -1713,7 +1887,27 @@ int open_tables(THD *thd, TABLE_LIST *start, uint *counter)
|
|||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
If we are not already in prelocked mode and extended table list is not
|
||||
yet built and we have trigger for table being opened then we should
|
||||
cache all routines used by its triggers and add their tables to
|
||||
prelocking list.
|
||||
If we lock table for reading we won't update it so there is no need to
|
||||
process its triggers since they never will be activated.
|
||||
|
||||
FIXME Now we are simply turning on prelocking. Proper integration
|
||||
and testing is to be done later.
|
||||
*/
|
||||
if (!thd->prelocked_mode && !thd->lex->requires_prelocking() &&
|
||||
tables->table->triggers &&
|
||||
tables->lock_type >= TL_WRITE_ALLOW_WRITE)
|
||||
{
|
||||
if (!query_tables_last_own)
|
||||
query_tables_last_own= thd->lex->query_tables_last;
|
||||
}
|
||||
free_root(&new_frm_mem, MYF(MY_KEEP_PREALLOC));
|
||||
}
|
||||
|
||||
if (tables->lock_type != TL_UNLOCK && ! thd->locked_tables)
|
||||
tables->table->reginfo.lock_type=tables->lock_type;
|
||||
|
@ -1721,6 +1915,10 @@ int open_tables(THD *thd, TABLE_LIST *start, uint *counter)
|
|||
}
|
||||
thd->proc_info=0;
|
||||
free_root(&new_frm_mem, MYF(0)); // Free pre-alloced block
|
||||
|
||||
if (query_tables_last_own)
|
||||
thd->lex->mark_as_requiring_prelocking(query_tables_last_own);
|
||||
|
||||
DBUG_RETURN(result);
|
||||
}
|
||||
|
||||
|
@ -1769,6 +1967,11 @@ static bool check_lock_and_start_stmt(THD *thd, TABLE *table,
|
|||
table_list Table to open is first table in this list
|
||||
lock_type Lock to use for open
|
||||
|
||||
NOTE
|
||||
This function don't do anything like SP/SF/views/triggers analysis done
|
||||
in open_tables(). It is intended for opening of only one concrete table.
|
||||
And used only in special contexts.
|
||||
|
||||
RETURN VALUES
|
||||
table Opened table
|
||||
0 Error
|
||||
|
@ -1843,7 +2046,7 @@ int simple_open_n_lock_tables(THD *thd, TABLE_LIST *tables)
|
|||
{
|
||||
DBUG_ENTER("simple_open_n_lock_tables");
|
||||
uint counter;
|
||||
if (open_tables(thd, tables, &counter) || lock_tables(thd, tables, counter))
|
||||
if (open_tables(thd, &tables, &counter) || lock_tables(thd, tables, counter))
|
||||
DBUG_RETURN(-1); /* purecov: inspected */
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
@ -1870,7 +2073,7 @@ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables)
|
|||
{
|
||||
uint counter;
|
||||
DBUG_ENTER("open_and_lock_tables");
|
||||
if (open_tables(thd, tables, &counter) ||
|
||||
if (open_tables(thd, &tables, &counter) ||
|
||||
lock_tables(thd, tables, counter) ||
|
||||
mysql_handle_derived(thd->lex, &mysql_derived_prepare) ||
|
||||
(thd->fill_derived_tables() &&
|
||||
|
@ -1903,7 +2106,7 @@ bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables)
|
|||
uint counter;
|
||||
DBUG_ENTER("open_normal_and_derived_tables");
|
||||
DBUG_ASSERT(!thd->fill_derived_tables());
|
||||
if (open_tables(thd, tables, &counter) ||
|
||||
if (open_tables(thd, &tables, &counter) ||
|
||||
mysql_handle_derived(thd->lex, &mysql_derived_prepare))
|
||||
DBUG_RETURN(TRUE); /* purecov: inspected */
|
||||
relink_tables_for_multidelete(thd); // Not really needed, but
|
||||
|
@ -1936,6 +2139,27 @@ static void relink_tables_for_multidelete(THD *thd)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
Mark all real tables in the list as free for reuse.
|
||||
|
||||
SYNOPSIS
|
||||
mark_real_tables_as_free_for_reuse()
|
||||
thd - thread context
|
||||
table - head of the list of tables
|
||||
|
||||
DESCRIPTION
|
||||
Marks all real tables in the list (i.e. not views, derived
|
||||
or schema tables) as free for reuse.
|
||||
*/
|
||||
|
||||
static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table)
|
||||
{
|
||||
for (; table; table= table->next_global)
|
||||
if (!table->placeholder() && !table->schema_table)
|
||||
table->table->query_id= 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Lock all tables in list
|
||||
|
||||
|
@ -1950,6 +2174,10 @@ static void relink_tables_for_multidelete(THD *thd)
|
|||
handling thr_lock gives us. You most always get all needed locks at
|
||||
once.
|
||||
|
||||
If query for which we are calling this function marked as requring
|
||||
prelocking, this function will do implicit LOCK TABLES and change
|
||||
thd::prelocked_mode accordingly.
|
||||
|
||||
RETURN VALUES
|
||||
0 ok
|
||||
-1 Error
|
||||
|
@ -1958,36 +2186,125 @@ static void relink_tables_for_multidelete(THD *thd)
|
|||
int lock_tables(THD *thd, TABLE_LIST *tables, uint count)
|
||||
{
|
||||
TABLE_LIST *table;
|
||||
if (!tables)
|
||||
return 0;
|
||||
|
||||
if (!thd->locked_tables)
|
||||
DBUG_ENTER("lock_tables");
|
||||
/*
|
||||
We can't meet statement requiring prelocking if we already
|
||||
in prelocked mode.
|
||||
*/
|
||||
DBUG_ASSERT(!thd->prelocked_mode || !thd->lex->requires_prelocking());
|
||||
/*
|
||||
If statement requires prelocking then it has non-empty table list.
|
||||
So it is safe to shortcut.
|
||||
*/
|
||||
DBUG_ASSERT(!thd->lex->requires_prelocking() || tables);
|
||||
|
||||
if (!tables)
|
||||
DBUG_RETURN(0);
|
||||
|
||||
/*
|
||||
We need this extra check for thd->prelocked_mode because we want to avoid
|
||||
attempts to lock tables in substatements. Checking for thd->locked_tables
|
||||
is not enough in some situations. For example for SP containing
|
||||
"drop table t3; create temporary t3 ..; insert into t3 ...;"
|
||||
thd->locked_tables may be 0 after drop tables, and without this extra
|
||||
check insert will try to lock temporary table t3, that will lead
|
||||
to memory leak...
|
||||
*/
|
||||
if (!thd->locked_tables && !thd->prelocked_mode)
|
||||
{
|
||||
DBUG_ASSERT(thd->lock == 0); // You must lock everything at once
|
||||
TABLE **start,**ptr;
|
||||
|
||||
if (!(ptr=start=(TABLE**) thd->alloc(sizeof(TABLE*)*count)))
|
||||
return -1;
|
||||
DBUG_RETURN(-1);
|
||||
for (table= tables; table; table= table->next_global)
|
||||
{
|
||||
if (!table->placeholder() && !table->schema_table)
|
||||
*(ptr++)= table->table;
|
||||
}
|
||||
|
||||
/* We have to emulate LOCK TABLES if we are statement needs prelocking. */
|
||||
if (thd->lex->requires_prelocking())
|
||||
{
|
||||
thd->in_lock_tables=1;
|
||||
thd->options|= OPTION_TABLE_LOCK;
|
||||
}
|
||||
|
||||
if (!(thd->lock=mysql_lock_tables(thd,start, (uint) (ptr - start))))
|
||||
return -1; /* purecov: inspected */
|
||||
{
|
||||
if (thd->lex->requires_prelocking())
|
||||
{
|
||||
thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
|
||||
thd->in_lock_tables=0;
|
||||
}
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
if (thd->lex->requires_prelocking() &&
|
||||
thd->lex->sql_command != SQLCOM_LOCK_TABLES)
|
||||
{
|
||||
TABLE_LIST *first_not_own= thd->lex->first_not_own_table();
|
||||
/*
|
||||
We just have done implicit LOCK TABLES, and now we have
|
||||
to emulate first open_and_lock_tables() after it.
|
||||
|
||||
Note that "LOCK TABLES" can also be marked as requiring prelocking
|
||||
(e.g. if one locks view which uses functions). We should not emulate
|
||||
such open_and_lock_tables() in this case. We also should not set
|
||||
THD::prelocked_mode or first close_thread_tables() call will do
|
||||
"UNLOCK TABLES".
|
||||
*/
|
||||
thd->locked_tables= thd->lock;
|
||||
thd->lock= 0;
|
||||
thd->in_lock_tables=0;
|
||||
|
||||
for (table= tables; table != first_not_own; table= table->next_global)
|
||||
{
|
||||
if (!table->placeholder() && !table->schema_table)
|
||||
{
|
||||
table->table->query_id= thd->query_id;
|
||||
if (check_lock_and_start_stmt(thd, table->table, table->lock_type))
|
||||
{
|
||||
ha_rollback_stmt(thd);
|
||||
mysql_unlock_tables(thd, thd->locked_tables);
|
||||
thd->locked_tables= 0;
|
||||
thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
Let us mark all tables which don't belong to the statement itself,
|
||||
and was marked as occupied during open_tables() as free for reuse.
|
||||
*/
|
||||
mark_real_tables_as_free_for_reuse(first_not_own);
|
||||
thd->prelocked_mode= PRELOCKED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (table= tables; table; table= table->next_global)
|
||||
TABLE_LIST *first_not_own= thd->lex->first_not_own_table();
|
||||
for (table= tables; table != first_not_own; table= table->next_global)
|
||||
{
|
||||
if (!table->placeholder() &&
|
||||
if (!table->placeholder() && !table->schema_table &&
|
||||
check_lock_and_start_stmt(thd, table->table, table->lock_type))
|
||||
{
|
||||
ha_rollback_stmt(thd);
|
||||
return -1;
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
}
|
||||
/*
|
||||
If we are under explicit LOCK TABLES and our statement requires
|
||||
prelocking, we should mark all "additional" tables as free for use
|
||||
and enter prelocked mode.
|
||||
*/
|
||||
if (thd->lex->requires_prelocking())
|
||||
{
|
||||
mark_real_tables_as_free_for_reuse(first_not_own);
|
||||
thd->prelocked_mode= PRELOCKED_UNDER_LOCK_TABLES;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -251,8 +251,9 @@ THD::THD()
|
|||
protocol_prep.init(this);
|
||||
|
||||
tablespace_op=FALSE;
|
||||
ulong tmp=sql_rnd_with_mutex();
|
||||
randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::query_id);
|
||||
ulong tmp=sql_rnd_with_mutex();
|
||||
randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::query_id);
|
||||
prelocked_mode= NON_PRELOCKED;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -293,13 +293,13 @@ public:
|
|||
{
|
||||
char buf[FN_REFLEN];
|
||||
return open(generate_name(log_name, ".log", 0, buf),
|
||||
LOG_NORMAL, 0, WRITE_CACHE, 0, 0, 0);
|
||||
LOG_NORMAL, 0, APPEND_CACHE, 0, 0, 0);
|
||||
}
|
||||
bool open_slow_log(const char *log_name)
|
||||
{
|
||||
char buf[FN_REFLEN];
|
||||
return open(generate_name(log_name, "-slow.log", 0, buf),
|
||||
LOG_NORMAL, 0, WRITE_CACHE, 0, 0, 0);
|
||||
LOG_NORMAL, 0, APPEND_CACHE, 0, 0, 0);
|
||||
}
|
||||
bool open_index_file(const char *index_file_name_arg,
|
||||
const char *log_name);
|
||||
|
@ -925,6 +925,15 @@ struct Item_change_record;
|
|||
typedef I_List<Item_change_record> Item_change_list;
|
||||
|
||||
|
||||
/*
|
||||
Type of prelocked mode.
|
||||
See comment for THD::prelocked_mode for complete description.
|
||||
*/
|
||||
|
||||
enum prelocked_mode_type {NON_PRELOCKED= 0, PRELOCKED= 1,
|
||||
PRELOCKED_UNDER_LOCK_TABLES= 2};
|
||||
|
||||
|
||||
/*
|
||||
For each client connection we create a separate thread with THD serving as
|
||||
a thread/connection descriptor
|
||||
|
@ -1025,7 +1034,13 @@ public:
|
|||
See also lock_tables() for details.
|
||||
*/
|
||||
MYSQL_LOCK *lock; /* Current locks */
|
||||
MYSQL_LOCK *locked_tables; /* Tables locked with LOCK */
|
||||
/*
|
||||
Tables that were locked with explicit or implicit LOCK TABLES.
|
||||
(Implicit LOCK TABLES happens when we are prelocking tables for
|
||||
execution of statement which uses stored routines. See description
|
||||
THD::prelocked_mode for more info.)
|
||||
*/
|
||||
MYSQL_LOCK *locked_tables;
|
||||
HASH handler_tables_hash;
|
||||
/*
|
||||
One thread can hold up to one named user-level lock. This variable
|
||||
|
@ -1192,8 +1207,6 @@ public:
|
|||
sp_rcontext *spcont; // SP runtime context
|
||||
sp_cache *sp_proc_cache;
|
||||
sp_cache *sp_func_cache;
|
||||
bool shortcut_make_view; /* Don't do full mysql_make_view()
|
||||
during pre-opening of tables. */
|
||||
|
||||
/*
|
||||
If we do a purge of binary logs, log index info of the threads
|
||||
|
@ -1209,6 +1222,31 @@ public:
|
|||
long long_value;
|
||||
} sys_var_tmp;
|
||||
|
||||
/*
|
||||
prelocked_mode_type enum and prelocked_mode member are used for
|
||||
indicating whenever "prelocked mode" is on, and what type of
|
||||
"prelocked mode" is it.
|
||||
|
||||
Prelocked mode is used for execution of queries which explicitly
|
||||
or implicitly (via views or triggers) use functions, thus may need
|
||||
some additional tables (mentioned in query table list) for their
|
||||
execution.
|
||||
|
||||
First open_tables() call for such query will analyse all functions
|
||||
used by it and add all additional tables to table its list. It will
|
||||
also mark this query as requiring prelocking. After that lock_tables()
|
||||
will issue implicit LOCK TABLES for the whole table list and change
|
||||
thd::prelocked_mode to non-0. All queries called in functions invoked
|
||||
by the main query will use prelocked tables. Non-0 prelocked_mode
|
||||
will also surpress mentioned analysys in those queries thus saving
|
||||
cycles. Prelocked mode will be turned off once close_thread_tables()
|
||||
for the main query will be called.
|
||||
|
||||
Note: Since not all "tables" present in table list are really locked
|
||||
thd::relocked_mode does not imply thd::locked_tables.
|
||||
*/
|
||||
prelocked_mode_type prelocked_mode;
|
||||
|
||||
THD();
|
||||
~THD();
|
||||
|
||||
|
|
|
@ -187,7 +187,7 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
|
|||
|
||||
/* for now HANDLER can be used only for real TABLES */
|
||||
tables->required_type= FRMTYPE_TABLE;
|
||||
error= open_tables(thd, tables, &counter);
|
||||
error= open_tables(thd, &tables, &counter);
|
||||
|
||||
HANDLER_TABLES_HACK(thd);
|
||||
if (error)
|
||||
|
|
|
@ -169,13 +169,12 @@ void lex_start(THD *thd, uchar *buf,uint length)
|
|||
lex->sphead= NULL;
|
||||
lex->spcont= NULL;
|
||||
lex->proc_list.first= 0;
|
||||
lex->query_tables_own_last= 0;
|
||||
|
||||
if (lex->spfuns.records)
|
||||
my_hash_reset(&lex->spfuns);
|
||||
if (lex->spprocs.records)
|
||||
my_hash_reset(&lex->spprocs);
|
||||
if (lex->sptabs.records)
|
||||
my_hash_reset(&lex->sptabs);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
@ -1868,6 +1867,8 @@ TABLE_LIST *st_lex::unlink_first_table(bool *link_to_local)
|
|||
*/
|
||||
if ((query_tables= query_tables->next_global))
|
||||
query_tables->prev_global= &query_tables;
|
||||
else
|
||||
query_tables_last= &query_tables;
|
||||
first->next_global= 0;
|
||||
|
||||
/*
|
||||
|
@ -1973,6 +1974,8 @@ void st_lex::link_first_table_back(TABLE_LIST *first,
|
|||
{
|
||||
if ((first->next_global= query_tables))
|
||||
query_tables->prev_global= &first->next_global;
|
||||
else
|
||||
query_tables_last= &first->next_global;
|
||||
query_tables= first;
|
||||
|
||||
if (link_to_local)
|
||||
|
|
|
@ -784,7 +784,6 @@ typedef struct st_lex
|
|||
sp_pcontext *spcont;
|
||||
HASH spfuns; /* Called functions */
|
||||
HASH spprocs; /* Called procedures */
|
||||
HASH sptabs; /* Merged table lists */
|
||||
st_sp_chistics sp_chistics;
|
||||
bool only_view; /* used for SHOW CREATE TABLE/VIEW */
|
||||
/*
|
||||
|
@ -803,23 +802,25 @@ typedef struct st_lex
|
|||
*/
|
||||
SQL_LIST trg_table_fields;
|
||||
|
||||
st_lex() :result(0), sql_command(SQLCOM_END)
|
||||
/*
|
||||
If non-0 then indicates that query requires prelocking and points to
|
||||
next_global member of last own element in query table list (i.e. last
|
||||
table which was not added to it as part of preparation to prelocking).
|
||||
0 - indicates that this query does not need prelocking.
|
||||
*/
|
||||
TABLE_LIST **query_tables_own_last;
|
||||
|
||||
st_lex() :result(0), sql_command(SQLCOM_END), query_tables_own_last(0)
|
||||
{
|
||||
extern byte *sp_lex_sp_key(const byte *ptr, uint *plen, my_bool first);
|
||||
extern byte *sp_table_key(const byte *ptr, uint *plen, my_bool first);
|
||||
hash_init(&spfuns, system_charset_info, 0, 0, 0, sp_lex_sp_key, 0, 0);
|
||||
hash_init(&spprocs, system_charset_info, 0, 0, 0, sp_lex_sp_key, 0, 0);
|
||||
hash_init(&sptabs, system_charset_info, 0, 0, 0, sp_table_key, 0, 0);
|
||||
}
|
||||
|
||||
~st_lex()
|
||||
|
||||
virtual ~st_lex()
|
||||
{
|
||||
if (spfuns.array.buffer)
|
||||
hash_free(&spfuns);
|
||||
if (spprocs.array.buffer)
|
||||
hash_free(&spprocs);
|
||||
if (sptabs.array.buffer)
|
||||
hash_free(&sptabs);
|
||||
hash_free(&spfuns);
|
||||
hash_free(&spprocs);
|
||||
}
|
||||
|
||||
inline void uncacheable(uint8 cause)
|
||||
|
@ -856,6 +857,21 @@ typedef struct st_lex
|
|||
bool can_not_use_merged();
|
||||
bool only_view_structure();
|
||||
bool need_correct_ident();
|
||||
|
||||
inline bool requires_prelocking()
|
||||
{
|
||||
return query_tables_own_last;
|
||||
}
|
||||
inline void mark_as_requiring_prelocking(TABLE_LIST **tables_own_last)
|
||||
{
|
||||
query_tables_own_last= tables_own_last;
|
||||
}
|
||||
/* Return pointer to first not-own table in query-tables or 0 */
|
||||
TABLE_LIST* first_not_own_table()
|
||||
{
|
||||
return ( query_tables_own_last ? *query_tables_own_last : 0);
|
||||
}
|
||||
|
||||
} LEX;
|
||||
|
||||
struct st_lex_local: public st_lex
|
||||
|
|
204
sql/sql_parse.cc
204
sql/sql_parse.cc
|
@ -1453,105 +1453,6 @@ bool do_command(THD *thd)
|
|||
}
|
||||
#endif /* EMBEDDED_LIBRARY */
|
||||
|
||||
static void release_local_lock(THD *thd, TABLE_LIST *locked_tables,
|
||||
bool old_innodb_table_locks)
|
||||
{
|
||||
if (locked_tables)
|
||||
{
|
||||
#ifdef HAVE_INNOBASE_DB
|
||||
thd->variables.innodb_table_locks= old_innodb_table_locks;
|
||||
#endif
|
||||
if (thd->locked_tables)
|
||||
sp_unlock_tables(thd);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static bool process_nested_sp(THD *thd, LEX *lex, TABLE_LIST** locked_tables)
|
||||
{
|
||||
DBUG_ENTER("process_nested_sp");
|
||||
while (1)
|
||||
{
|
||||
if (sp_cache_routines(thd, lex, TYPE_ENUM_FUNCTION))
|
||||
DBUG_RETURN(TRUE);
|
||||
if (sp_cache_routines(thd, lex, TYPE_ENUM_PROCEDURE))
|
||||
DBUG_RETURN(TRUE);
|
||||
if (!thd->locked_tables &&
|
||||
lex->sql_command != SQLCOM_CREATE_TABLE &&
|
||||
lex->sql_command != SQLCOM_CREATE_VIEW)
|
||||
{
|
||||
MEM_ROOT *thdmemroot= NULL;
|
||||
|
||||
sp_merge_routine_tables(thd, lex);
|
||||
// QQ Preopen tables to find views and triggers.
|
||||
// This means we open, close and open again, which sucks, but
|
||||
// right now it's the easiest way to get it to work. A better
|
||||
// solution will hopefully be found soon...
|
||||
if (lex->sptabs.records || lex->query_tables)
|
||||
{
|
||||
uint procs, funs, tabs;
|
||||
|
||||
if (thd->mem_root != thd->current_arena->mem_root)
|
||||
{
|
||||
thdmemroot= thd->mem_root;
|
||||
thd->mem_root= thd->current_arena->mem_root;
|
||||
}
|
||||
if (!sp_merge_table_list(thd, &lex->sptabs, lex->query_tables))
|
||||
DBUG_RETURN(TRUE);
|
||||
procs= lex->spprocs.records;
|
||||
funs= lex->spfuns.records;
|
||||
tabs= lex->sptabs.records;
|
||||
|
||||
if (((*locked_tables)= sp_hash_to_table_list(thd, &lex->sptabs)))
|
||||
{
|
||||
// We don't want these updated now
|
||||
uint ctmpdtabs= thd->status_var.created_tmp_disk_tables;
|
||||
uint ctmptabs= thd->status_var.created_tmp_tables;
|
||||
uint count;
|
||||
|
||||
thd->shortcut_make_view= TRUE;
|
||||
open_tables(thd, *locked_tables, &count);
|
||||
thd->shortcut_make_view= FALSE;
|
||||
close_thread_tables(thd);
|
||||
thd->status_var.created_tmp_disk_tables= ctmpdtabs;
|
||||
thd->status_var.created_tmp_tables= ctmptabs;
|
||||
thd->clear_error();
|
||||
mysql_reset_errors(thd);
|
||||
(*locked_tables)= NULL;
|
||||
}
|
||||
// A kludge: Decrease all temp. table's query ids to allow a
|
||||
// second opening.
|
||||
for (TABLE *table= thd->temporary_tables; table ; table=table->next)
|
||||
table->query_id-= 1;
|
||||
if (procs < lex->spprocs.records ||
|
||||
funs < lex->spfuns.records ||
|
||||
tabs < lex->sptabs.records)
|
||||
{
|
||||
if (thdmemroot)
|
||||
thd->mem_root= thdmemroot;
|
||||
continue; // Found more SPs or tabs, try again
|
||||
}
|
||||
}
|
||||
if (lex->sptabs.records &&
|
||||
(lex->spfuns.records || lex->spprocs.records) &&
|
||||
sp_merge_table_list(thd, &lex->sptabs, lex->query_tables))
|
||||
{
|
||||
if (((*locked_tables)= sp_hash_to_table_list(thd, &lex->sptabs)))
|
||||
{
|
||||
#ifdef HAVE_INNOBASE_DB
|
||||
thd->variables.innodb_table_locks= FALSE;
|
||||
#endif
|
||||
sp_open_and_lock_tables(thd, *locked_tables);
|
||||
}
|
||||
}
|
||||
if (thdmemroot)
|
||||
thd->mem_root= thdmemroot;
|
||||
}
|
||||
break;
|
||||
} // while (1)
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Perform one connection-level (COM_XXXX) command.
|
||||
|
@ -1752,7 +1653,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
|||
in embedded server - just store them to be executed later
|
||||
*/
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
if (thd->lock || thd->open_tables || thd->derived_tables)
|
||||
if (thd->lock || thd->open_tables || thd->derived_tables ||
|
||||
thd->prelocked_mode)
|
||||
close_thread_tables(thd);
|
||||
#endif
|
||||
ulong length= (ulong)(packet_end-packet);
|
||||
|
@ -1855,19 +1757,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
|||
select_lex.table_list.link_in_list((byte*) &table_list,
|
||||
(byte**) &table_list.next_local);
|
||||
thd->lex->query_tables= &table_list;
|
||||
thd->shortcut_make_view= 0;
|
||||
process_nested_sp(thd, thd->lex, &locked_tables);
|
||||
|
||||
/* switch on VIEW optimisation: do not fill temporary tables */
|
||||
thd->lex->sql_command= SQLCOM_SHOW_FIELDS;
|
||||
mysqld_list_fields(thd,&table_list,fields);
|
||||
thd->lex->unit.cleanup();
|
||||
thd->cleanup_after_query();
|
||||
#ifdef HAVE_INNOBASE_DB
|
||||
release_local_lock(thd, locked_tables, old_innodb_table_locks);
|
||||
#else
|
||||
release_local_lock(thd, locked_tables, false);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
@ -2089,7 +1984,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
|||
my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
|
||||
break;
|
||||
}
|
||||
if (thd->lock || thd->open_tables || thd->derived_tables)
|
||||
if (thd->lock || thd->open_tables || thd->derived_tables ||
|
||||
thd->prelocked_mode)
|
||||
{
|
||||
thd->proc_info="closing tables";
|
||||
close_thread_tables(thd); /* Free tables */
|
||||
|
@ -2334,11 +2230,7 @@ mysql_execute_command(THD *thd)
|
|||
TABLE_LIST *all_tables;
|
||||
/* most outer SELECT_LEX_UNIT of query */
|
||||
SELECT_LEX_UNIT *unit= &lex->unit;
|
||||
/* Locked closure of all tables */
|
||||
TABLE_LIST *locked_tables= NULL;
|
||||
/* Saved variable value */
|
||||
my_bool old_innodb_table_locks=
|
||||
IF_INNOBASE_DB(thd->variables.innodb_table_locks, FALSE);
|
||||
DBUG_ENTER("mysql_execute_command");
|
||||
thd->net.no_send_error= 0;
|
||||
|
||||
|
@ -2361,26 +2253,14 @@ mysql_execute_command(THD *thd)
|
|||
/* should be assigned after making first tables same */
|
||||
all_tables= lex->query_tables;
|
||||
|
||||
thd->shortcut_make_view= 0;
|
||||
if (lex->sql_command != SQLCOM_CREATE_PROCEDURE &&
|
||||
lex->sql_command != SQLCOM_CREATE_SPFUNCTION &&
|
||||
lex->sql_command != SQLCOM_LOCK_TABLES &&
|
||||
lex->sql_command != SQLCOM_UNLOCK_TABLES)
|
||||
{
|
||||
thd->no_warnings_for_error= 1;
|
||||
res= process_nested_sp(thd, lex, &locked_tables);
|
||||
thd->no_warnings_for_error= 0;
|
||||
if (res)
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
Reset warning count for each query that uses tables
|
||||
A better approach would be to reset this for any commands
|
||||
that is not a SHOW command or a select that only access local
|
||||
variables, but for now this is probably good enough.
|
||||
*/
|
||||
if (all_tables || &lex->select_lex != lex->all_selects_list)
|
||||
if (all_tables || &lex->select_lex != lex->all_selects_list ||
|
||||
lex->spfuns.records || lex->spprocs.records)
|
||||
mysql_reset_errors(thd);
|
||||
|
||||
#ifdef HAVE_REPLICATION
|
||||
|
@ -2614,9 +2494,8 @@ mysql_execute_command(THD *thd)
|
|||
break;
|
||||
}
|
||||
case SQLCOM_DO:
|
||||
if (all_tables &&
|
||||
(check_table_access(thd, SELECT_ACL, all_tables, 0) ||
|
||||
open_and_lock_tables(thd, all_tables)))
|
||||
if (check_table_access(thd, SELECT_ACL, all_tables, 0) ||
|
||||
open_and_lock_tables(thd, all_tables))
|
||||
goto error;
|
||||
|
||||
res= mysql_do(thd, *lex->insert_list);
|
||||
|
@ -3485,8 +3364,7 @@ unsent_create_error:
|
|||
case SQLCOM_SET_OPTION:
|
||||
{
|
||||
List<set_var_base> *lex_var_list= &lex->var_list;
|
||||
if (all_tables &&
|
||||
(check_table_access(thd, SELECT_ACL, all_tables, 0) ||
|
||||
if ((check_table_access(thd, SELECT_ACL, all_tables, 0) ||
|
||||
open_and_lock_tables(thd, all_tables)))
|
||||
goto error;
|
||||
if (lex->one_shot_set && not_all_support_one_shot(lex_var_list))
|
||||
|
@ -3532,7 +3410,7 @@ unsent_create_error:
|
|||
thd->in_lock_tables=1;
|
||||
thd->options|= OPTION_TABLE_LOCK;
|
||||
|
||||
if (!(res= open_and_lock_tables(thd, all_tables)))
|
||||
if (!(res= simple_open_n_lock_tables(thd, all_tables)))
|
||||
{
|
||||
#ifdef HAVE_QUERY_CACHE
|
||||
if (thd->variables.query_cache_wlock_invalidate)
|
||||
|
@ -4115,7 +3993,20 @@ unsent_create_error:
|
|||
{
|
||||
sp_head *sp;
|
||||
|
||||
if (!(sp= sp_find_procedure(thd, lex->spname)))
|
||||
/*
|
||||
This will cache all SP and SF and open and lock all tables
|
||||
required for execution.
|
||||
*/
|
||||
if (check_table_access(thd, SELECT_ACL, all_tables, 0) ||
|
||||
open_and_lock_tables(thd, all_tables))
|
||||
goto error;
|
||||
|
||||
/*
|
||||
By this moment all needed SPs should be in cache so no need
|
||||
to look into DB. Moreover we may be unable to do it becuase
|
||||
we may don't have read lock on mysql.proc
|
||||
*/
|
||||
if (!(sp= sp_find_procedure(thd, lex->spname, TRUE)))
|
||||
{
|
||||
my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PROCEDURE",
|
||||
lex->spname->m_qname.str);
|
||||
|
@ -4130,12 +4021,6 @@ unsent_create_error:
|
|||
/* bits that should be cleared in thd->server_status */
|
||||
uint bits_to_be_cleared= 0;
|
||||
|
||||
/* In case the arguments are subselects... */
|
||||
if (all_tables &&
|
||||
(check_table_access(thd, SELECT_ACL, all_tables, 0) ||
|
||||
open_and_lock_tables(thd, all_tables)))
|
||||
goto error;
|
||||
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
my_bool nsok= thd->net.no_send_ok;
|
||||
thd->net.no_send_ok= TRUE;
|
||||
|
@ -4606,11 +4491,6 @@ cleanup:
|
|||
if (thd->lock == thd->locked_tables)
|
||||
thd->lock= 0;
|
||||
}
|
||||
#ifdef HAVE_INNOBASE_DB
|
||||
release_local_lock(thd, locked_tables, old_innodb_table_locks);
|
||||
#else
|
||||
release_local_lock(thd, locked_tables, false);
|
||||
#endif
|
||||
DBUG_RETURN(res || thd->net.report_error);
|
||||
}
|
||||
|
||||
|
@ -4865,6 +4745,38 @@ check_procedure_access(THD *thd, ulong want_access,char *db, char *name,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Check if the routine has any of the routine privileges
|
||||
|
||||
SYNOPSIS
|
||||
check_some_routine_access()
|
||||
thd Thread handler
|
||||
db Database name
|
||||
name Routine name
|
||||
|
||||
RETURN
|
||||
0 ok
|
||||
1 error
|
||||
*/
|
||||
|
||||
bool check_some_routine_access(THD *thd, char *db, char *name)
|
||||
{
|
||||
ulong save_priv;
|
||||
if (thd->master_access & SHOW_PROC_ACLS)
|
||||
return FALSE;
|
||||
if (!check_access(thd, SHOW_PROC_ACLS, db, &save_priv, 0, 1) ||
|
||||
(save_priv & SHOW_PROC_ACLS))
|
||||
return FALSE;
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
if (grant_option)
|
||||
return check_routine_level_acl(thd, db, name);
|
||||
#endif
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Check if the given table has any of the asked privileges
|
||||
|
||||
|
@ -5203,8 +5115,6 @@ void mysql_parse(THD *thd, char *inBuf, uint length)
|
|||
{
|
||||
if (thd->lex->sphead)
|
||||
{
|
||||
if (lex != thd->lex)
|
||||
thd->lex->sphead->restore_lex(thd);
|
||||
delete thd->lex->sphead;
|
||||
thd->lex->sphead= NULL;
|
||||
}
|
||||
|
@ -5240,8 +5150,6 @@ void mysql_parse(THD *thd, char *inBuf, uint length)
|
|||
if (thd->lex->sphead)
|
||||
{
|
||||
/* Clean up after failed stored procedure/function */
|
||||
if (lex != thd->lex)
|
||||
thd->lex->sphead->restore_lex(thd);
|
||||
delete thd->lex->sphead;
|
||||
thd->lex->sphead= NULL;
|
||||
}
|
||||
|
|
|
@ -1004,7 +1004,7 @@ static int mysql_test_update(Prepared_statement *stmt,
|
|||
if (update_precheck(thd, table_list))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
if (!open_tables(thd, table_list, &table_count))
|
||||
if (!open_tables(thd, &table_list, &table_count))
|
||||
{
|
||||
if (table_list->ancestor && table_list->ancestor->next_local)
|
||||
{
|
||||
|
@ -1545,22 +1545,6 @@ static int check_prepared_statement(Prepared_statement *stmt,
|
|||
lex->first_lists_tables_same();
|
||||
tables= lex->query_tables;
|
||||
|
||||
/*
|
||||
Preopen 'proc' system table and cache all functions used in this
|
||||
statement. We must do that before we open ordinary tables to avoid
|
||||
deadlocks. We can't open and lock any table once query tables were
|
||||
opened.
|
||||
*/
|
||||
if (lex->sql_command != SQLCOM_CREATE_PROCEDURE &&
|
||||
lex->sql_command != SQLCOM_CREATE_SPFUNCTION)
|
||||
{
|
||||
/* The error is printed inside */
|
||||
if (sp_cache_routines(thd, lex, TYPE_ENUM_FUNCTION))
|
||||
DBUG_RETURN(-1);
|
||||
if (sp_cache_routines(thd, lex, TYPE_ENUM_PROCEDURE))
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
switch (sql_command) {
|
||||
case SQLCOM_REPLACE:
|
||||
case SQLCOM_INSERT:
|
||||
|
@ -1787,15 +1771,13 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
|
|||
my_pthread_setprio(pthread_self(),WAIT_PRIOR);
|
||||
if (error && thd->lex->sphead)
|
||||
{
|
||||
if (lex != thd->lex)
|
||||
thd->lex->sphead->restore_lex(thd);
|
||||
delete thd->lex->sphead;
|
||||
thd->lex->sphead= NULL;
|
||||
}
|
||||
lex_end(lex);
|
||||
close_thread_tables(thd);
|
||||
thd->restore_backup_statement(stmt, &thd->stmt_backup);
|
||||
cleanup_items(stmt->free_list);
|
||||
close_thread_tables(thd);
|
||||
thd->rollback_item_tree_changes();
|
||||
thd->cleanup_after_query();
|
||||
thd->current_arena= thd;
|
||||
|
@ -1885,6 +1867,11 @@ void reset_stmt_for_execute(THD *thd, LEX *lex)
|
|||
to indicate the table is altered, and re-do the setup_*
|
||||
and open the tables back.
|
||||
*/
|
||||
/*
|
||||
NOTE: We should reset whole table list here including all tables added
|
||||
by prelocking algorithm (it is not a problem for substatements since
|
||||
they have their own table list).
|
||||
*/
|
||||
for (TABLE_LIST *tables= lex->query_tables;
|
||||
tables;
|
||||
tables= tables->next_global)
|
||||
|
|
|
@ -2468,32 +2468,41 @@ int fill_schema_coll_charset_app(THD *thd, TABLE_LIST *tables, COND *cond)
|
|||
}
|
||||
|
||||
|
||||
void store_schema_proc(THD *thd, TABLE *table,
|
||||
TABLE *proc_table,
|
||||
const char *wild)
|
||||
void store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table,
|
||||
const char *wild, bool full_access, const char *sp_user)
|
||||
{
|
||||
String tmp_string;
|
||||
TIME time;
|
||||
LEX *lex= thd->lex;
|
||||
CHARSET_INFO *cs= system_charset_info;
|
||||
restore_record(table, s->default_values);
|
||||
const char *sp_db, *sp_name, *definer;
|
||||
sp_db= get_field(thd->mem_root, proc_table->field[0]);
|
||||
sp_name= get_field(thd->mem_root, proc_table->field[1]);
|
||||
definer= get_field(thd->mem_root, proc_table->field[11]);
|
||||
if (!full_access)
|
||||
full_access= !strcmp(sp_user, definer);
|
||||
if (!full_access)
|
||||
{
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
if (check_some_routine_access(thd, (char * )sp_db, (char * )sp_name))
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (lex->orig_sql_command == SQLCOM_SHOW_STATUS_PROC &&
|
||||
proc_table->field[2]->val_int() == TYPE_ENUM_PROCEDURE ||
|
||||
lex->orig_sql_command == SQLCOM_SHOW_STATUS_FUNC &&
|
||||
proc_table->field[2]->val_int() == TYPE_ENUM_FUNCTION ||
|
||||
lex->orig_sql_command == SQLCOM_END)
|
||||
{
|
||||
tmp_string.length(0);
|
||||
get_field(thd->mem_root, proc_table->field[1], &tmp_string);
|
||||
if (!wild || !wild[0] || !wild_compare(tmp_string.ptr(), wild, 0))
|
||||
restore_record(table, s->default_values);
|
||||
if (!wild || !wild[0] || !wild_compare(sp_name, wild, 0))
|
||||
{
|
||||
table->field[3]->store(tmp_string.ptr(), tmp_string.length(), cs);
|
||||
table->field[3]->store(sp_name, strlen(sp_name), cs);
|
||||
tmp_string.length(0);
|
||||
get_field(thd->mem_root, proc_table->field[3], &tmp_string);
|
||||
table->field[0]->store(tmp_string.ptr(), tmp_string.length(), cs);
|
||||
tmp_string.length(0);
|
||||
get_field(thd->mem_root, proc_table->field[0], &tmp_string);
|
||||
table->field[2]->store(tmp_string.ptr(), tmp_string.length(), cs);
|
||||
table->field[2]->store(sp_db, strlen(sp_db), cs);
|
||||
tmp_string.length(0);
|
||||
get_field(thd->mem_root, proc_table->field[2], &tmp_string);
|
||||
table->field[4]->store(tmp_string.ptr(), tmp_string.length(), cs);
|
||||
|
@ -2504,10 +2513,13 @@ void store_schema_proc(THD *thd, TABLE *table,
|
|||
table->field[5]->store(tmp_string.ptr(), tmp_string.length(), cs);
|
||||
table->field[5]->set_notnull();
|
||||
}
|
||||
if (full_access)
|
||||
{
|
||||
tmp_string.length(0);
|
||||
get_field(thd->mem_root, proc_table->field[10], &tmp_string);
|
||||
table->field[7]->store(tmp_string.ptr(), tmp_string.length(), cs);
|
||||
}
|
||||
table->field[6]->store("SQL", 3, cs);
|
||||
tmp_string.length(0);
|
||||
get_field(thd->mem_root, proc_table->field[10], &tmp_string);
|
||||
table->field[7]->store(tmp_string.ptr(), tmp_string.length(), cs);
|
||||
table->field[10]->store("SQL", 3, cs);
|
||||
tmp_string.length(0);
|
||||
get_field(thd->mem_root, proc_table->field[6], &tmp_string);
|
||||
|
@ -2531,9 +2543,7 @@ void store_schema_proc(THD *thd, TABLE *table,
|
|||
tmp_string.length(0);
|
||||
get_field(thd->mem_root, proc_table->field[15], &tmp_string);
|
||||
table->field[18]->store(tmp_string.ptr(), tmp_string.length(), cs);
|
||||
tmp_string.length(0);
|
||||
get_field(thd->mem_root, proc_table->field[11], &tmp_string);
|
||||
table->field[19]->store(tmp_string.ptr(), tmp_string.length(), cs);
|
||||
table->field[19]->store(definer, strlen(definer), cs);
|
||||
table->file->write_row(table->record[0]);
|
||||
}
|
||||
}
|
||||
|
@ -2547,14 +2557,18 @@ int fill_schema_proc(THD *thd, TABLE_LIST *tables, COND *cond)
|
|||
const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
|
||||
int res= 0;
|
||||
TABLE *table= tables->table, *old_open_tables= thd->open_tables;
|
||||
bool full_access;
|
||||
char definer[HOSTNAME_LENGTH+USERNAME_LENGTH+2];
|
||||
DBUG_ENTER("fill_schema_proc");
|
||||
|
||||
strxmov(definer, thd->priv_user, "@", thd->priv_host, NullS);
|
||||
bzero((char*) &proc_tables,sizeof(proc_tables));
|
||||
proc_tables.db= (char*) "mysql";
|
||||
proc_tables.db_length= 5;
|
||||
proc_tables.table_name= proc_tables.alias= (char*) "proc";
|
||||
proc_tables.table_name_length= 4;
|
||||
proc_tables.lock_type= TL_READ;
|
||||
full_access= !check_table_access(thd, SELECT_ACL, &proc_tables, 1);
|
||||
if (!(proc_table= open_ltable(thd, &proc_tables, TL_READ)))
|
||||
{
|
||||
DBUG_RETURN(1);
|
||||
|
@ -2565,9 +2579,9 @@ int fill_schema_proc(THD *thd, TABLE_LIST *tables, COND *cond)
|
|||
res= (res == HA_ERR_END_OF_FILE) ? 0 : 1;
|
||||
goto err;
|
||||
}
|
||||
store_schema_proc(thd, table, proc_table, wild);
|
||||
store_schema_proc(thd, table, proc_table, wild, full_access, definer);
|
||||
while (!proc_table->file->index_next(proc_table->record[0]))
|
||||
store_schema_proc(thd, table, proc_table, wild);
|
||||
store_schema_proc(thd, table, proc_table, wild, full_access, definer);
|
||||
|
||||
err:
|
||||
proc_table->file->ha_index_end();
|
||||
|
|
|
@ -415,9 +415,8 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
|
|||
*/
|
||||
if (lex.sphead)
|
||||
{
|
||||
if (&lex != thd->lex)
|
||||
thd->lex->sphead->restore_lex(thd);
|
||||
delete lex.sphead;
|
||||
lex.sphead= 0;
|
||||
}
|
||||
goto err_with_lex_cleanup;
|
||||
}
|
||||
|
|
|
@ -42,14 +42,21 @@ public:
|
|||
|
||||
if (bodies[event][time_type])
|
||||
{
|
||||
/*
|
||||
Similar to function invocation we don't need to surpress sending of
|
||||
ok packets here because don't allow execute statements from trigger.
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
/* Surpress OK packets in case if we will execute statements */
|
||||
my_bool nsok= thd->net.no_send_ok;
|
||||
thd->net.no_send_ok= TRUE;
|
||||
#endif
|
||||
|
||||
/*
|
||||
FIXME: We should juggle with security context here (because trigger
|
||||
should be invoked with creator rights).
|
||||
*/
|
||||
res= bodies[event][time_type]->execute_function(thd, 0, 0, 0);
|
||||
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
thd->net.no_send_ok= nsok;
|
||||
#endif
|
||||
}
|
||||
|
||||
return res;
|
||||
|
|
123
sql/sql_udf.cc
123
sql/sql_udf.cc
|
@ -17,15 +17,15 @@
|
|||
/* This implements 'user defined functions' */
|
||||
|
||||
/*
|
||||
** Known bugs:
|
||||
**
|
||||
** Memory for functions are never freed!
|
||||
** Shared libraries are not closed before mysqld exists;
|
||||
** - This is because we can't be sure if some threads is using
|
||||
** a functions.
|
||||
**
|
||||
** The buggs only affects applications that creates and frees a lot of
|
||||
** dynamic functions, so this shouldn't be a real problem.
|
||||
Known bugs:
|
||||
|
||||
Memory for functions is never freed!
|
||||
Shared libraries are not closed before mysqld exits;
|
||||
- This is because we can't be sure if some threads are using
|
||||
a function.
|
||||
|
||||
The bugs only affect applications that create and free a lot of
|
||||
dynamic functions, so this shouldn't be a real problem.
|
||||
*/
|
||||
|
||||
#ifdef __GNUC__
|
||||
|
@ -74,32 +74,49 @@ static HASH udf_hash;
|
|||
static rw_lock_t THR_LOCK_udf;
|
||||
|
||||
|
||||
static udf_func *add_udf(LEX_STRING *name, Item_result ret, char *dl,
|
||||
Item_udftype typ);
|
||||
static udf_func *add_udf(LEX_STRING *name, Item_result ret,
|
||||
char *dl, Item_udftype typ);
|
||||
static void del_udf(udf_func *udf);
|
||||
static void *find_udf_dl(const char *dl);
|
||||
|
||||
|
||||
static void init_syms(udf_func *tmp)
|
||||
static char *init_syms(udf_func *tmp, char *nm)
|
||||
{
|
||||
char nm[MAX_FIELD_NAME+16],*end;
|
||||
char *end;
|
||||
|
||||
if (!((tmp->func= dlsym(tmp->dlhandle, tmp->name.str))))
|
||||
return tmp->name.str;
|
||||
|
||||
tmp->func = dlsym(tmp->dlhandle, tmp->name.str);
|
||||
end=strmov(nm,tmp->name.str);
|
||||
(void) strmov(end,"_init");
|
||||
tmp->func_init = dlsym(tmp->dlhandle, nm);
|
||||
(void) strmov(end,"_deinit");
|
||||
tmp->func_deinit = dlsym(tmp->dlhandle, nm);
|
||||
|
||||
if (tmp->type == UDFTYPE_AGGREGATE)
|
||||
{
|
||||
(void)strmov( end, "_clear" );
|
||||
tmp->func_clear = dlsym( tmp->dlhandle, nm );
|
||||
(void)strmov( end, "_add" );
|
||||
tmp->func_add = dlsym( tmp->dlhandle, nm );
|
||||
/* Give error if _clear and _add doesn't exists */
|
||||
if (!tmp->func_clear || ! tmp->func_add)
|
||||
tmp->func= 0;
|
||||
(void)strmov(end, "_clear");
|
||||
if (!((tmp->func_clear= dlsym(tmp->dlhandle, nm))))
|
||||
return nm;
|
||||
(void)strmov(end, "_add");
|
||||
if (!((tmp->func_add= dlsym(tmp->dlhandle, nm))))
|
||||
return nm;
|
||||
}
|
||||
|
||||
(void) strmov(end,"_deinit");
|
||||
tmp->func_deinit= dlsym(tmp->dlhandle, nm);
|
||||
|
||||
(void) strmov(end,"_init");
|
||||
tmp->func_init= dlsym(tmp->dlhandle, nm);
|
||||
|
||||
/*
|
||||
to prefent loading "udf" from, e.g. libc.so
|
||||
let's ensure that at least one auxiliary symbol is defined
|
||||
*/
|
||||
if (!tmp->func_init && !tmp->func_deinit && tmp->type != UDFTYPE_AGGREGATE)
|
||||
{
|
||||
if (opt_allow_suspicious_udfs)
|
||||
sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), nm);
|
||||
else
|
||||
return nm;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" byte* get_hash_key(const byte *buff,uint *length,
|
||||
|
@ -111,7 +128,7 @@ extern "C" byte* get_hash_key(const byte *buff,uint *length,
|
|||
}
|
||||
|
||||
/*
|
||||
** Read all predeclared functions from func@mysql and accept all that
|
||||
** Read all predeclared functions from mysql.func and accept all that
|
||||
** can be used.
|
||||
*/
|
||||
|
||||
|
@ -153,7 +170,7 @@ void udf_init()
|
|||
if (simple_open_n_lock_tables(new_thd, &tables))
|
||||
{
|
||||
DBUG_PRINT("error",("Can't open udf table"));
|
||||
sql_print_error("Can't open the mysql/func table. Please run the mysql_install_db script to create it.");
|
||||
sql_print_error("Can't open the mysql.func table. Please run the mysql_install_db script to create it.");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -171,10 +188,23 @@ void udf_init()
|
|||
if (table->s->fields >= 4) // New func table
|
||||
udftype=(Item_udftype) table->field[3]->val_int();
|
||||
|
||||
if (!(tmp = add_udf(&name,(Item_result) table->field[1]->val_int(),
|
||||
dl_name, udftype)))
|
||||
/*
|
||||
Ensure that the .dll doesn't have a path
|
||||
This is done to ensure that only approved dll from the system
|
||||
directories are used (to make this even remotely secure).
|
||||
*/
|
||||
if (strchr(dl_name, '/') || name.length > NAME_LEN)
|
||||
{
|
||||
sql_print_error("Can't alloc memory for udf function: name");
|
||||
sql_print_error("Invalid row in mysql.func table for function '%.64s'",
|
||||
name.str);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (!(tmp= add_udf(&name,(Item_result) table->field[1]->val_int(),
|
||||
dl_name, udftype)))
|
||||
{
|
||||
sql_print_error("Can't alloc memory for udf function: '%.64s'", name.str);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -191,13 +221,15 @@ void udf_init()
|
|||
new_dl=1;
|
||||
}
|
||||
tmp->dlhandle = dl;
|
||||
init_syms(tmp);
|
||||
if (!tmp->func)
|
||||
{
|
||||
sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), name);
|
||||
del_udf(tmp);
|
||||
if (new_dl)
|
||||
dlclose(dl);
|
||||
char buf[MAX_FIELD_NAME+16], *missing;
|
||||
if ((missing= init_syms(tmp, buf)))
|
||||
{
|
||||
sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), missing);
|
||||
del_udf(tmp);
|
||||
if (new_dl)
|
||||
dlclose(dl);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (error > 0)
|
||||
|
@ -239,7 +271,7 @@ void udf_free()
|
|||
{
|
||||
initialized= 0;
|
||||
rwlock_destroy(&THR_LOCK_udf);
|
||||
}
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
@ -407,12 +439,13 @@ int mysql_create_function(THD *thd,udf_func *udf)
|
|||
new_dl=1;
|
||||
}
|
||||
udf->dlhandle=dl;
|
||||
init_syms(udf);
|
||||
|
||||
if (udf->func == NULL)
|
||||
{
|
||||
my_error(ER_CANT_FIND_DL_ENTRY, MYF(0), udf->name);
|
||||
goto err;
|
||||
char buf[MAX_FIELD_NAME+16], *missing;
|
||||
if ((missing= init_syms(udf, buf)))
|
||||
{
|
||||
my_error(ER_CANT_FIND_DL_ENTRY, MYF(0), missing);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
udf->name.str=strdup_root(&mem,udf->name.str);
|
||||
udf->dl=strdup_root(&mem,udf->dl);
|
||||
|
@ -425,7 +458,7 @@ int mysql_create_function(THD *thd,udf_func *udf)
|
|||
u_d->func_clear=udf->func_clear;
|
||||
u_d->func_add=udf->func_add;
|
||||
|
||||
/* create entry in mysql/func table */
|
||||
/* create entry in mysql.func table */
|
||||
|
||||
bzero((char*) &tables,sizeof(tables));
|
||||
tables.db= (char*) "mysql";
|
||||
|
@ -445,7 +478,7 @@ int mysql_create_function(THD *thd,udf_func *udf)
|
|||
close_thread_tables(thd);
|
||||
if (error)
|
||||
{
|
||||
my_error(ER_ERROR_ON_WRITE, MYF(0), "func@mysql", error);
|
||||
my_error(ER_ERROR_ON_WRITE, MYF(0), "mysql.func", error);
|
||||
del_udf(u_d);
|
||||
goto err;
|
||||
}
|
||||
|
|
|
@ -136,7 +136,7 @@ int mysql_update(THD *thd,
|
|||
|
||||
LINT_INIT(timestamp_query_id);
|
||||
|
||||
if (open_tables(thd, table_list, &table_count))
|
||||
if (open_tables(thd, &table_list, &table_count))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
if (table_list->ancestor && table_list->ancestor->next_local)
|
||||
|
@ -635,7 +635,7 @@ bool mysql_multi_update_prepare(THD *thd)
|
|||
thd->lex->sql_command= SQLCOM_UPDATE_MULTI;
|
||||
|
||||
/* open tables and create derived ones, but do not lock and fill them */
|
||||
if ((original_multiupdate && open_tables(thd, table_list, & table_count)) ||
|
||||
if ((original_multiupdate && open_tables(thd, &table_list, & table_count)) ||
|
||||
mysql_handle_derived(lex, &mysql_derived_prepare))
|
||||
DBUG_RETURN(TRUE);
|
||||
/*
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "sql_select.h"
|
||||
#include "parse_file.h"
|
||||
#include "sp.h"
|
||||
#include "sp_head.h"
|
||||
|
||||
#define MD5_BUFF_LENGTH 33
|
||||
|
||||
|
@ -615,10 +616,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
|||
table->view= lex= thd->lex= (LEX*) new(thd->mem_root) st_lex_local;
|
||||
lex_start(thd, (uchar*)table->query.str, table->query.length);
|
||||
view_select= &lex->select_lex;
|
||||
/* Only if we're not in the pre-open phase */
|
||||
if (!thd->shortcut_make_view)
|
||||
view_select->select_number= ++thd->select_number;
|
||||
old_lex->derived_tables|= DERIVED_VIEW;
|
||||
view_select->select_number= ++thd->select_number;
|
||||
{
|
||||
ulong options= thd->options;
|
||||
/* switch off modes which can prevent normal parsing of VIEW
|
||||
|
@ -662,35 +660,13 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
|||
TABLE_LIST *view_tables_tail= 0;
|
||||
TABLE_LIST *tbl;
|
||||
|
||||
/* move SP to main LEX */
|
||||
if (lex->spfuns.records)
|
||||
sp_merge_hash(&old_lex->spfuns, &lex->spfuns);
|
||||
|
||||
/* cleanup LEX */
|
||||
if (lex->spfuns.array.buffer)
|
||||
hash_free(&lex->spfuns);
|
||||
if (lex->spprocs.array.buffer)
|
||||
hash_free(&lex->spprocs);
|
||||
if (lex->sptabs.array.buffer)
|
||||
hash_free(&lex->sptabs);
|
||||
|
||||
/* If we're pre-opening tables to find SPs and tables we need
|
||||
not go any further; doing so will cause an infinite loop. */
|
||||
if (thd->shortcut_make_view)
|
||||
{
|
||||
extern bool
|
||||
sp_merge_table_list(THD *thd, HASH *h, TABLE_LIST *table,
|
||||
LEX *lex_for_tmp_check = 0);
|
||||
|
||||
sp_merge_table_list(thd, &old_lex->sptabs, view_tables);
|
||||
goto ok;
|
||||
}
|
||||
|
||||
/*
|
||||
check rights to run commands (EXPLAIN SELECT & SHOW CREATE) which show
|
||||
underlying tables
|
||||
Check rights to run commands (EXPLAIN SELECT & SHOW CREATE) which show
|
||||
underlying tables.
|
||||
Skip this step if we are opening view for prelocking only.
|
||||
*/
|
||||
if ((old_lex->sql_command == SQLCOM_SELECT && old_lex->describe))
|
||||
if (!table->prelocking_placeholder &&
|
||||
(old_lex->sql_command == SQLCOM_SELECT && old_lex->describe))
|
||||
{
|
||||
if (check_table_access(thd, SELECT_ACL, view_tables, 1) &&
|
||||
check_table_access(thd, SHOW_VIEW_ACL, table, 1))
|
||||
|
@ -699,7 +675,8 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
|||
goto err;
|
||||
}
|
||||
}
|
||||
else if (old_lex->sql_command == SQLCOM_SHOW_CREATE)
|
||||
else if (!table->prelocking_placeholder &&
|
||||
old_lex->sql_command == SQLCOM_SHOW_CREATE)
|
||||
{
|
||||
if (check_table_access(thd, SHOW_VIEW_ACL, table, 0))
|
||||
goto err;
|
||||
|
@ -717,13 +694,6 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
|||
tbl->belong_to_view= top_view;
|
||||
}
|
||||
|
||||
/* move SQL_NO_CACHE & Co to whole query */
|
||||
old_lex->safe_to_cache_query= (old_lex->safe_to_cache_query &&
|
||||
lex->safe_to_cache_query);
|
||||
/* move SQL_CACHE to whole query */
|
||||
if (view_select->options & OPTION_TO_QUERY_CACHE)
|
||||
old_lex->select_lex.options|= OPTION_TO_QUERY_CACHE;
|
||||
|
||||
/*
|
||||
Put tables of VIEW after VIEW TABLE_LIST
|
||||
|
||||
|
@ -740,12 +710,29 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
|||
}
|
||||
else
|
||||
{
|
||||
lex->query_tables_last= &view_tables_tail->next_global;
|
||||
old_lex->query_tables_last= &view_tables_tail->next_global;
|
||||
}
|
||||
view_tables->prev_global= &table->next_global;
|
||||
table->next_global= view_tables;
|
||||
}
|
||||
|
||||
/*
|
||||
If we are opening this view as part of implicit LOCK TABLES, then
|
||||
this view serves as simple placeholder and we should not continue
|
||||
further processing.
|
||||
*/
|
||||
if (table->prelocking_placeholder)
|
||||
goto ok2;
|
||||
|
||||
old_lex->derived_tables|= DERIVED_VIEW;
|
||||
|
||||
/* move SQL_NO_CACHE & Co to whole query */
|
||||
old_lex->safe_to_cache_query= (old_lex->safe_to_cache_query &&
|
||||
lex->safe_to_cache_query);
|
||||
/* move SQL_CACHE to whole query */
|
||||
if (view_select->options & OPTION_TO_QUERY_CACHE)
|
||||
old_lex->select_lex.options|= OPTION_TO_QUERY_CACHE;
|
||||
|
||||
/*
|
||||
check MERGE algorithm ability
|
||||
- algorithm is not explicit TEMPORARY TABLE
|
||||
|
@ -850,8 +837,6 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
|||
goto err;
|
||||
|
||||
ok:
|
||||
if (arena)
|
||||
thd->restore_backup_item_arena(arena, &backup);
|
||||
/* global SELECT list linking */
|
||||
end= view_select; // primary SELECT_LEX is always last
|
||||
end->link_next= old_lex->all_selects_list;
|
||||
|
@ -860,12 +845,16 @@ ok:
|
|||
lex->all_selects_list->link_prev=
|
||||
(st_select_lex_node**)&old_lex->all_selects_list;
|
||||
|
||||
ok2:
|
||||
if (arena)
|
||||
thd->restore_backup_item_arena(arena, &backup);
|
||||
thd->lex= old_lex;
|
||||
DBUG_RETURN(0);
|
||||
|
||||
err:
|
||||
if (arena)
|
||||
thd->restore_backup_item_arena(arena, &backup);
|
||||
delete table->view;
|
||||
table->view= 0; // now it is not VIEW placeholder
|
||||
thd->lex= old_lex;
|
||||
DBUG_RETURN(1);
|
||||
|
|
228
sql/sql_yacc.yy
228
sql/sql_yacc.yy
|
@ -1548,12 +1548,12 @@ sp_opt_inout:
|
|||
|
||||
sp_proc_stmts:
|
||||
/* Empty */ {}
|
||||
| sp_proc_stmts { Lex->query_tables= 0; } sp_proc_stmt ';'
|
||||
| sp_proc_stmts sp_proc_stmt ';'
|
||||
;
|
||||
|
||||
sp_proc_stmts1:
|
||||
sp_proc_stmt ';' {}
|
||||
| sp_proc_stmts1 { Lex->query_tables= 0; } sp_proc_stmt ';'
|
||||
| sp_proc_stmts1 sp_proc_stmt ';'
|
||||
;
|
||||
|
||||
sp_decls:
|
||||
|
@ -1587,13 +1587,15 @@ sp_decls:
|
|||
;
|
||||
|
||||
sp_decl:
|
||||
DECLARE_SYM sp_decl_idents type sp_opt_default
|
||||
DECLARE_SYM sp_decl_idents type
|
||||
{ Lex->sphead->reset_lex(YYTHD); }
|
||||
sp_opt_default
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
sp_pcontext *ctx= lex->spcont;
|
||||
uint max= ctx->context_pvars();
|
||||
enum enum_field_types type= (enum enum_field_types)$3;
|
||||
Item *it= $4;
|
||||
Item *it= $5;
|
||||
|
||||
for (uint i = max-$2 ; i < max ; i++)
|
||||
{
|
||||
|
@ -1605,15 +1607,19 @@ sp_decl:
|
|||
sp_instr_set *in= new sp_instr_set(lex->sphead->instructions(),
|
||||
ctx,
|
||||
ctx->pvar_context2index(i),
|
||||
it, type);
|
||||
it, type, lex,
|
||||
(i == max - 1));
|
||||
|
||||
in->tables= lex->query_tables;
|
||||
lex->query_tables= 0;
|
||||
/*
|
||||
The last instruction is assigned to be responsible for
|
||||
freeing LEX.
|
||||
*/
|
||||
lex->sphead->add_instr(in);
|
||||
ctx->set_isset(i, TRUE);
|
||||
ctx->set_default(i, it);
|
||||
}
|
||||
}
|
||||
lex->sphead->restore_lex(YYTHD);
|
||||
$$.vars= $2;
|
||||
$$.conds= $$.hndlrs= $$.curs= 0;
|
||||
}
|
||||
|
@ -1865,36 +1871,39 @@ sp_proc_stmt:
|
|||
my_message(ER_SP_NO_USE, ER(ER_SP_NO_USE), MYF(0));
|
||||
YYABORT;
|
||||
}
|
||||
/* Don't add an instruction for empty SET statements.
|
||||
** (This happens if the SET only contained local variables,
|
||||
** which get their set instructions generated separately.)
|
||||
/*
|
||||
Don't add an instruction for SET statements, since all
|
||||
instructions for them were already added during processing
|
||||
of "set" rule.
|
||||
*/
|
||||
if (lex->sql_command != SQLCOM_SET_OPTION ||
|
||||
! lex->var_list.is_empty())
|
||||
DBUG_ASSERT(lex->sql_command != SQLCOM_SET_OPTION ||
|
||||
lex->var_list.is_empty());
|
||||
if (lex->sql_command != SQLCOM_SET_OPTION)
|
||||
{
|
||||
sp_instr_stmt *i=new sp_instr_stmt(sp->instructions(),
|
||||
lex->spcont);
|
||||
sp_instr_stmt *i=new sp_instr_stmt(sp->instructions(),
|
||||
lex->spcont, lex);
|
||||
|
||||
/* Extract the query statement from the tokenizer:
|
||||
The end is either lex->tok_end or tok->ptr. */
|
||||
if (lex->ptr - lex->tok_end > 1)
|
||||
i->m_query.length= lex->ptr - sp->m_tmp_query;
|
||||
else
|
||||
i->m_query.length= lex->tok_end - sp->m_tmp_query;
|
||||
i->m_query.str= strmake_root(YYTHD->mem_root,
|
||||
(char *)sp->m_tmp_query,
|
||||
i->m_query.length);
|
||||
i->set_lex(lex);
|
||||
sp->add_instr(i);
|
||||
lex->sp_lex_in_use= TRUE;
|
||||
}
|
||||
/* Extract the query statement from the tokenizer:
|
||||
The end is either lex->tok_end or tok->ptr. */
|
||||
if (lex->ptr - lex->tok_end > 1)
|
||||
i->m_query.length= lex->ptr - sp->m_tmp_query;
|
||||
else
|
||||
i->m_query.length= lex->tok_end - sp->m_tmp_query;
|
||||
i->m_query.str= strmake_root(YYTHD->mem_root,
|
||||
(char *)sp->m_tmp_query,
|
||||
i->m_query.length);
|
||||
sp->add_instr(i);
|
||||
}
|
||||
sp->restore_lex(YYTHD);
|
||||
}
|
||||
| RETURN_SYM expr
|
||||
| RETURN_SYM
|
||||
{ Lex->sphead->reset_lex(YYTHD); }
|
||||
expr
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
sp_head *sp= lex->sphead;
|
||||
|
||||
if (lex->sphead->m_type == TYPE_ENUM_PROCEDURE)
|
||||
if (sp->m_type == TYPE_ENUM_PROCEDURE)
|
||||
{
|
||||
my_message(ER_SP_BADRETURN, ER(ER_SP_BADRETURN), MYF(0));
|
||||
YYABORT;
|
||||
|
@ -1903,12 +1912,12 @@ sp_proc_stmt:
|
|||
{
|
||||
sp_instr_freturn *i;
|
||||
|
||||
i= new sp_instr_freturn(lex->sphead->instructions(),
|
||||
lex->spcont,
|
||||
$2, lex->sphead->m_returns);
|
||||
lex->sphead->add_instr(i);
|
||||
lex->sphead->m_has_return= TRUE;
|
||||
i= new sp_instr_freturn(sp->instructions(), lex->spcont,
|
||||
$3, sp->m_returns, lex);
|
||||
sp->add_instr(i);
|
||||
sp->m_has_return= TRUE;
|
||||
}
|
||||
sp->restore_lex(YYTHD);
|
||||
}
|
||||
| IF sp_if END IF {}
|
||||
| CASE_SYM WHEN_SYM
|
||||
|
@ -1916,7 +1925,9 @@ sp_proc_stmt:
|
|||
Lex->sphead->m_simple_case= FALSE;
|
||||
}
|
||||
sp_case END CASE_SYM {}
|
||||
| CASE_SYM expr WHEN_SYM
|
||||
| CASE_SYM
|
||||
{ Lex->sphead->reset_lex(YYTHD); }
|
||||
expr WHEN_SYM
|
||||
{
|
||||
/* We "fake" this by using an anonymous variable which we
|
||||
set to the expression. Note that all WHENs are evaluate
|
||||
|
@ -1925,15 +1936,14 @@ sp_proc_stmt:
|
|||
LEX *lex= Lex;
|
||||
uint offset= lex->spcont->current_pvars();
|
||||
sp_instr_set *i = new sp_instr_set(lex->sphead->instructions(),
|
||||
lex->spcont,
|
||||
offset, $2, MYSQL_TYPE_STRING);
|
||||
lex->spcont, offset, $3,
|
||||
MYSQL_TYPE_STRING, lex, TRUE);
|
||||
LEX_STRING dummy={(char*)"", 0};
|
||||
|
||||
lex->spcont->push_pvar(&dummy, MYSQL_TYPE_STRING, sp_param_in);
|
||||
i->tables= lex->query_tables;
|
||||
lex->query_tables= 0;
|
||||
lex->sphead->add_instr(i);
|
||||
lex->sphead->m_simple_case= TRUE;
|
||||
lex->sphead->restore_lex(YYTHD);
|
||||
}
|
||||
sp_case END CASE_SYM
|
||||
{
|
||||
|
@ -2187,18 +2197,19 @@ sp_fetch_list:
|
|||
;
|
||||
|
||||
sp_if:
|
||||
expr THEN_SYM
|
||||
{ Lex->sphead->reset_lex(YYTHD); }
|
||||
expr THEN_SYM
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
sp_head *sp= lex->sphead;
|
||||
sp_pcontext *ctx= lex->spcont;
|
||||
uint ip= sp->instructions();
|
||||
sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, ctx, $1);
|
||||
sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, ctx,
|
||||
$2, lex);
|
||||
|
||||
i->tables= lex->query_tables;
|
||||
lex->query_tables= 0;
|
||||
sp->push_backpatch(i, ctx->push_label((char *)"", 0));
|
||||
sp->add_instr(i);
|
||||
sp->restore_lex(YYTHD);
|
||||
}
|
||||
sp_proc_stmts1
|
||||
{
|
||||
|
@ -2226,7 +2237,8 @@ sp_elseifs:
|
|||
;
|
||||
|
||||
sp_case:
|
||||
expr THEN_SYM
|
||||
{ Lex->sphead->reset_lex(YYTHD); }
|
||||
expr THEN_SYM
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
sp_head *sp= lex->sphead;
|
||||
|
@ -2235,7 +2247,7 @@ sp_case:
|
|||
sp_instr_jump_if_not *i;
|
||||
|
||||
if (! sp->m_simple_case)
|
||||
i= new sp_instr_jump_if_not(ip, ctx, $1);
|
||||
i= new sp_instr_jump_if_not(ip, ctx, $2, lex);
|
||||
else
|
||||
{ /* Simple case: <caseval> = <whenval> */
|
||||
LEX_STRING ivar;
|
||||
|
@ -2244,15 +2256,14 @@ sp_case:
|
|||
ivar.length= 5;
|
||||
Item *var= (Item*) new Item_splocal(ivar,
|
||||
ctx->current_pvars()-1);
|
||||
Item *expr= new Item_func_eq(var, $1);
|
||||
Item *expr= new Item_func_eq(var, $2);
|
||||
|
||||
i= new sp_instr_jump_if_not(ip, ctx, expr);
|
||||
i= new sp_instr_jump_if_not(ip, ctx, expr, lex);
|
||||
lex->variables_used= 1;
|
||||
}
|
||||
sp->push_backpatch(i, ctx->push_label((char *)"", 0));
|
||||
i->tables= lex->query_tables;
|
||||
lex->query_tables= 0;
|
||||
sp->add_instr(i);
|
||||
sp->restore_lex(YYTHD);
|
||||
}
|
||||
sp_proc_stmts1
|
||||
{
|
||||
|
@ -2368,19 +2379,20 @@ sp_unlabeled_control:
|
|||
|
||||
lex->sphead->add_instr(i);
|
||||
}
|
||||
| WHILE_SYM expr DO_SYM
|
||||
| WHILE_SYM
|
||||
{ Lex->sphead->reset_lex(YYTHD); }
|
||||
expr DO_SYM
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
sp_head *sp= lex->sphead;
|
||||
uint ip= sp->instructions();
|
||||
sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, lex->spcont,
|
||||
$2);
|
||||
$3, lex);
|
||||
|
||||
/* Jumping forward */
|
||||
sp->push_backpatch(i, lex->spcont->last_label());
|
||||
i->tables= lex->query_tables;
|
||||
lex->query_tables= 0;
|
||||
sp->add_instr(i);
|
||||
sp->restore_lex(YYTHD);
|
||||
}
|
||||
sp_proc_stmts1 END WHILE_SYM
|
||||
{
|
||||
|
@ -2391,17 +2403,18 @@ sp_unlabeled_control:
|
|||
|
||||
lex->sphead->add_instr(i);
|
||||
}
|
||||
| REPEAT_SYM sp_proc_stmts1 UNTIL_SYM expr END REPEAT_SYM
|
||||
| REPEAT_SYM sp_proc_stmts1 UNTIL_SYM
|
||||
{ Lex->sphead->reset_lex(YYTHD); }
|
||||
expr END REPEAT_SYM
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
uint ip= lex->sphead->instructions();
|
||||
sp_label_t *lab= lex->spcont->last_label(); /* Jumping back */
|
||||
sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, lex->spcont,
|
||||
$4, lab->ip);
|
||||
|
||||
i->tables= lex->query_tables;
|
||||
lex->query_tables= 0;
|
||||
$5, lab->ip,
|
||||
lex);
|
||||
lex->sphead->add_instr(i);
|
||||
lex->sphead->restore_lex(YYTHD);
|
||||
}
|
||||
;
|
||||
|
||||
|
@ -7168,8 +7181,75 @@ opt_option:
|
|||
| OPTION {};
|
||||
|
||||
option_value_list:
|
||||
option_type_value
|
||||
| option_value_list ',' option_type_value;
|
||||
|
||||
option_type_value:
|
||||
{
|
||||
if (Lex->sphead)
|
||||
{
|
||||
/*
|
||||
If we are in SP we want have own LEX for each assignment.
|
||||
This is mostly because it is hard for several sp_instr_set
|
||||
and sp_instr_set_trigger instructions share one LEX.
|
||||
(Well, it is theoretically possible but adds some extra
|
||||
overhead on preparation for execution stage and IMO less
|
||||
robust).
|
||||
|
||||
QQ: May be we should simply prohibit group assignments in SP?
|
||||
*/
|
||||
LEX *lex;
|
||||
Lex->sphead->reset_lex(YYTHD);
|
||||
lex= Lex;
|
||||
|
||||
/* Set new LEX as if we at start of set rule. */
|
||||
lex->sql_command= SQLCOM_SET_OPTION;
|
||||
mysql_init_select(lex);
|
||||
lex->option_type=OPT_SESSION;
|
||||
lex->var_list.empty();
|
||||
lex->one_shot_set= 0;
|
||||
lex->sphead->m_tmp_query= lex->tok_start;
|
||||
}
|
||||
}
|
||||
option_type option_value
|
||||
| option_value_list ',' option_type option_value;
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
|
||||
if (lex->sphead)
|
||||
{
|
||||
sp_head *sp= lex->sphead;
|
||||
|
||||
if (!lex->var_list.is_empty())
|
||||
{
|
||||
/*
|
||||
We have assignment to user or system variable or
|
||||
option setting, so we should construct sp_instr_stmt
|
||||
for it.
|
||||
*/
|
||||
LEX_STRING qbuff;
|
||||
sp_instr_stmt *i;
|
||||
|
||||
if (!(i= new sp_instr_stmt(sp->instructions(), lex->spcont,
|
||||
lex)))
|
||||
YYABORT;
|
||||
|
||||
if (lex->ptr - lex->tok_end > 1)
|
||||
qbuff.length= lex->ptr - sp->m_tmp_query;
|
||||
else
|
||||
qbuff.length= lex->tok_end - sp->m_tmp_query;
|
||||
|
||||
if (!(qbuff.str= alloc_root(YYTHD->mem_root, qbuff.length + 5)))
|
||||
YYABORT;
|
||||
|
||||
strmake(strmake(qbuff.str, "SET ", 4), (char *)sp->m_tmp_query,
|
||||
qbuff.length);
|
||||
qbuff.length+= 4;
|
||||
i->m_query= qbuff;
|
||||
sp->add_instr(i);
|
||||
}
|
||||
lex->sphead->restore_lex(YYTHD);
|
||||
}
|
||||
};
|
||||
|
||||
option_type:
|
||||
/* empty */ {}
|
||||
|
@ -7196,31 +7276,7 @@ opt_var_ident_type:
|
|||
option_value:
|
||||
'@' ident_or_text equal expr
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
|
||||
if (lex->sphead && lex->sphead->m_type != TYPE_ENUM_PROCEDURE)
|
||||
{
|
||||
/*
|
||||
We have to use special instruction in functions and triggers
|
||||
because sp_instr_stmt will close all tables and thus ruin
|
||||
execution of statement invoking function or trigger.
|
||||
|
||||
We also do not want to allow expression with subselects in
|
||||
this case.
|
||||
*/
|
||||
if (lex->query_tables)
|
||||
{
|
||||
my_message(ER_SP_SUBSELECT_NYI, ER(ER_SP_SUBSELECT_NYI),
|
||||
MYF(0));
|
||||
YYABORT;
|
||||
}
|
||||
sp_instr_set_user_var *i=
|
||||
new sp_instr_set_user_var(lex->sphead->instructions(),
|
||||
lex->spcont, $2, $4);
|
||||
lex->sphead->add_instr(i);
|
||||
}
|
||||
else
|
||||
lex->var_list.push_back(new set_var_user(new Item_func_set_user_var($2,$4)));
|
||||
Lex->var_list.push_back(new set_var_user(new Item_func_set_user_var($2,$4)));
|
||||
}
|
||||
| internal_variable_name equal set_expr_or_default
|
||||
{
|
||||
|
@ -7281,9 +7337,7 @@ option_value:
|
|||
else
|
||||
it= new Item_null();
|
||||
i= new sp_instr_set(lex->sphead->instructions(), ctx,
|
||||
spv->offset, it, spv->type);
|
||||
i->tables= lex->query_tables;
|
||||
lex->query_tables= 0;
|
||||
spv->offset, it, spv->type, lex, TRUE);
|
||||
lex->sphead->add_instr(i);
|
||||
spv->isset= TRUE;
|
||||
}
|
||||
|
|
|
@ -1276,6 +1276,10 @@ File create_frm(register my_string name, uint reclength, uchar *fileinfo,
|
|||
uint key_length;
|
||||
ulong length;
|
||||
char fill[IO_SIZE];
|
||||
int create_flags= O_RDWR | O_TRUNC;
|
||||
|
||||
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
|
||||
create_flags|= O_EXCL | O_NOFOLLOW;
|
||||
|
||||
#if SIZEOF_OFF_T > 4
|
||||
/* Fix this when we have new .frm files; Current limit is 4G rows (QQ) */
|
||||
|
@ -1290,7 +1294,7 @@ File create_frm(register my_string name, uint reclength, uchar *fileinfo,
|
|||
*/
|
||||
set_if_smaller(create_info->raid_chunks, 255);
|
||||
|
||||
if ((file=my_create(name,CREATE_MODE,O_RDWR | O_TRUNC,MYF(MY_WME))) >= 0)
|
||||
if ((file= my_create(name, CREATE_MODE, create_flags, MYF(MY_WME))) >= 0)
|
||||
{
|
||||
bzero((char*) fileinfo,64);
|
||||
/* header */
|
||||
|
|
|
@ -429,6 +429,11 @@ typedef struct st_table_list
|
|||
/* FRMTYPE_ERROR if any type is acceptable */
|
||||
enum frm_type_enum required_type;
|
||||
char timestamp_buffer[20]; /* buffer for timestamp (19+1) */
|
||||
/*
|
||||
This TABLE_LIST object is just placeholder for prelocking, it will be
|
||||
used for implicit LOCK TABLES only and won't be used in real statement.
|
||||
*/
|
||||
bool prelocking_placeholder;
|
||||
|
||||
void calc_md5(char *buffer);
|
||||
void set_ancestor();
|
||||
|
|
|
@ -1524,7 +1524,6 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
|
|||
TZ_NAMES_ENTRY *tmp_tzname;
|
||||
my_bool return_val= 1;
|
||||
int res;
|
||||
uint counter;
|
||||
DBUG_ENTER("my_tz_init");
|
||||
|
||||
/*
|
||||
|
@ -1593,8 +1592,7 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
|
|||
last_global_next_ptr= &(tables_buff[0].next_global);
|
||||
tz_init_table_list(tables_buff + 1, &last_global_next_ptr);
|
||||
|
||||
if (open_tables(thd, tables_buff, &counter) ||
|
||||
lock_tables(thd, tables_buff, counter))
|
||||
if (simple_open_n_lock_tables(thd, tables_buff))
|
||||
{
|
||||
sql_print_warning("Can't open and lock time zone table: %s "
|
||||
"trying to live without them", thd->net.last_error);
|
||||
|
|
|
@ -1199,7 +1199,10 @@ int decimal2bin(decimal *from, char *to, int precision, int frac)
|
|||
else if (fsize0 > fsize1 && frac1x)
|
||||
{
|
||||
if (frac0 == frac1)
|
||||
{
|
||||
frac1x=frac0x;
|
||||
fsize0= fsize1;
|
||||
}
|
||||
else
|
||||
{
|
||||
frac1++;
|
||||
|
|
45
vio/vio.c
45
vio/vio.c
|
@ -27,20 +27,23 @@
|
|||
* Helper to fill most of the Vio* with defaults.
|
||||
*/
|
||||
|
||||
void vio_reset(Vio* vio, enum enum_vio_type type,
|
||||
my_socket sd, HANDLE hPipe,
|
||||
my_bool localhost)
|
||||
static void vio_init(Vio* vio, enum enum_vio_type type,
|
||||
my_socket sd, HANDLE hPipe, uint flags)
|
||||
{
|
||||
DBUG_ENTER("vio_reset");
|
||||
DBUG_PRINT("enter", ("type: %d sd: %d localhost: %d", type, sd,
|
||||
localhost));
|
||||
DBUG_ENTER("vio_init");
|
||||
DBUG_PRINT("enter", ("type: %d sd: %d flags: %d", type, sd, flags));
|
||||
|
||||
#ifndef HAVE_VIO_READ_BUFF
|
||||
flags&= ~VIO_BUFFERED_READ;
|
||||
#endif
|
||||
bzero((char*) vio, sizeof(*vio));
|
||||
vio->type = type;
|
||||
vio->sd = sd;
|
||||
vio->hPipe = hPipe;
|
||||
vio->localhost= localhost;
|
||||
#ifdef HAVE_VIO
|
||||
vio->localhost= flags & VIO_LOCALHOST;
|
||||
if ((flags & VIO_BUFFERED_READ) &&
|
||||
!(vio->read_buffer= (char*)my_malloc(VIO_READ_BUFFER_SIZE, MYF(MY_WME))))
|
||||
flags&= ~VIO_BUFFERED_READ;
|
||||
#ifdef __WIN__
|
||||
if (type == VIO_TYPE_NAMEDPIPE)
|
||||
{
|
||||
|
@ -101,7 +104,7 @@ void vio_reset(Vio* vio, enum enum_vio_type type,
|
|||
{
|
||||
vio->viodelete =vio_delete;
|
||||
vio->vioerrno =vio_errno;
|
||||
vio->read =vio_read;
|
||||
vio->read= (flags & VIO_BUFFERED_READ) ? vio_read_buff : vio_read;
|
||||
vio->write =vio_write;
|
||||
vio->fastsend =vio_fastsend;
|
||||
vio->viokeepalive =vio_keepalive;
|
||||
|
@ -113,21 +116,30 @@ void vio_reset(Vio* vio, enum enum_vio_type type,
|
|||
vio->is_blocking =vio_is_blocking;
|
||||
vio->timeout =vio_timeout;
|
||||
}
|
||||
#endif /* HAVE_VIO */
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/* Reset initialized VIO to use with another transport type */
|
||||
|
||||
void vio_reset(Vio* vio, enum enum_vio_type type,
|
||||
my_socket sd, HANDLE hPipe, uint flags)
|
||||
{
|
||||
my_free(vio->read_buffer, MYF(MY_ALLOW_ZERO_PTR));
|
||||
vio_init(vio, type, sd, hPipe, flags);
|
||||
}
|
||||
|
||||
|
||||
/* Open the socket or TCP/IP connection and read the fnctl() status */
|
||||
|
||||
Vio *vio_new(my_socket sd, enum enum_vio_type type, my_bool localhost)
|
||||
Vio *vio_new(my_socket sd, enum enum_vio_type type, uint flags)
|
||||
{
|
||||
Vio *vio;
|
||||
DBUG_ENTER("vio_new");
|
||||
DBUG_PRINT("enter", ("sd: %d", sd));
|
||||
if ((vio = (Vio*) my_malloc(sizeof(*vio),MYF(MY_WME))))
|
||||
{
|
||||
vio_reset(vio, type, sd, 0, localhost);
|
||||
vio_init(vio, type, sd, 0, flags);
|
||||
sprintf(vio->desc,
|
||||
(vio->type == VIO_TYPE_SOCKET ? "socket (%d)" : "TCP/IP (%d)"),
|
||||
vio->sd);
|
||||
|
@ -163,7 +175,7 @@ Vio *vio_new_win32pipe(HANDLE hPipe)
|
|||
DBUG_ENTER("vio_new_handle");
|
||||
if ((vio = (Vio*) my_malloc(sizeof(Vio),MYF(MY_WME))))
|
||||
{
|
||||
vio_reset(vio, VIO_TYPE_NAMEDPIPE, 0, hPipe, TRUE);
|
||||
vio_init(vio, VIO_TYPE_NAMEDPIPE, 0, hPipe, VIO_LOCALHOST);
|
||||
strmov(vio->desc, "named pipe");
|
||||
}
|
||||
DBUG_RETURN(vio);
|
||||
|
@ -179,7 +191,7 @@ Vio *vio_new_win32shared_memory(NET *net,HANDLE handle_file_map, HANDLE handle_m
|
|||
DBUG_ENTER("vio_new_win32shared_memory");
|
||||
if ((vio = (Vio*) my_malloc(sizeof(Vio),MYF(MY_WME))))
|
||||
{
|
||||
vio_reset(vio, VIO_TYPE_SHARED_MEMORY, 0, 0, TRUE);
|
||||
vio_init(vio, VIO_TYPE_SHARED_MEMORY, 0, 0, VIO_LOCALHOST);
|
||||
vio->handle_file_map= handle_file_map;
|
||||
vio->handle_map= handle_map;
|
||||
vio->event_server_wrote= event_server_wrote;
|
||||
|
@ -204,11 +216,8 @@ void vio_delete(Vio* vio)
|
|||
if (vio)
|
||||
{
|
||||
if (vio->type != VIO_CLOSED)
|
||||
#ifdef HAVE_VIO /*WAX*/
|
||||
vio->vioclose(vio);
|
||||
#else
|
||||
vio_close(vio);
|
||||
#endif
|
||||
my_free((gptr) vio->read_buffer, MYF(MY_ALLOW_ZERO_PTR));
|
||||
my_free((gptr) vio,MYF(0));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,8 @@ int vio_read(Vio * vio, gptr buf, int size)
|
|||
DBUG_ENTER("vio_read");
|
||||
DBUG_PRINT("enter", ("sd: %d, buf: 0x%p, size: %d", vio->sd, buf, size));
|
||||
|
||||
/* Ensure nobody uses vio_read_buff and vio_read simultaneously */
|
||||
DBUG_ASSERT(vio->read_end == vio->read_pos);
|
||||
#ifdef __WIN__
|
||||
r = recv(vio->sd, buf, size,0);
|
||||
#else
|
||||
|
@ -52,6 +54,50 @@ int vio_read(Vio * vio, gptr buf, int size)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
Buffered read: if average read size is small it may
|
||||
reduce number of syscalls.
|
||||
*/
|
||||
|
||||
int vio_read_buff(Vio *vio, gptr buf, int size)
|
||||
{
|
||||
int rc;
|
||||
#define VIO_UNBUFFERED_READ_MIN_SIZE 2048
|
||||
DBUG_ENTER("vio_read_buff");
|
||||
DBUG_PRINT("enter", ("sd: %d, buf: 0x%p, size: %d", vio->sd, buf, size));
|
||||
|
||||
if (vio->read_pos < vio->read_end)
|
||||
{
|
||||
rc= min(vio->read_end - vio->read_pos, size);
|
||||
memcpy(buf, vio->read_pos, rc);
|
||||
vio->read_pos+= rc;
|
||||
/*
|
||||
Do not try to read from the socket now even if rc < size:
|
||||
vio_read can return -1 due to an error or non-blocking mode, and
|
||||
the safest way to handle it is to move to a separate branch.
|
||||
*/
|
||||
}
|
||||
else if (size < VIO_UNBUFFERED_READ_MIN_SIZE)
|
||||
{
|
||||
rc= vio_read(vio, vio->read_buffer, VIO_READ_BUFFER_SIZE);
|
||||
if (rc > 0)
|
||||
{
|
||||
if (rc > size)
|
||||
{
|
||||
vio->read_pos= vio->read_buffer + size;
|
||||
vio->read_end= vio->read_buffer + rc;
|
||||
rc= size;
|
||||
}
|
||||
memcpy(buf, vio->read_buffer, rc);
|
||||
}
|
||||
}
|
||||
else
|
||||
rc= vio_read(vio, buf, size);
|
||||
DBUG_RETURN(rc);
|
||||
#undef VIO_UNBUFFERED_READ_MIN_SIZE
|
||||
}
|
||||
|
||||
|
||||
int vio_write(Vio * vio, const gptr buf, int size)
|
||||
{
|
||||
int r;
|
||||
|
|
Loading…
Reference in a new issue