[Pkg-mysql-commits] r968 - in branches/etch-5.0/debian: . patches
Christian Hammers
ch at alioth.debian.org
Tue Nov 6 21:06:04 UTC 2007
Author: ch
Date: 2007-11-06 21:06:03 +0000 (Tue, 06 Nov 2007)
New Revision: 968
Added:
branches/etch-5.0/debian/patches/92_SECURITY_CVE-2007-2692_thd_privs.dpatch
branches/etch-5.0/debian/patches/93_SECURITY_CVE-2007-3780.dpatch
branches/etch-5.0/debian/patches/93_SECURITY_CVE-2007-3782.dpatch
Removed:
branches/etch-5.0/debian/patches/91_CVE-2007-3780.dpatch
branches/etch-5.0/debian/patches/91_CVE-2007-3782.dpatch
branches/etch-5.0/debian/patches/92_SECURITY_CVE-2007-2691_thd_privs.dpatch
Modified:
branches/etch-5.0/debian/changelog
branches/etch-5.0/debian/patches/00list
Log:
Preparing new security release.
* Added new CVE-2007-3780/2 patches.
* Renamed misnamed CVE-2007-2692 dpatch file.
Modified: branches/etch-5.0/debian/changelog
===================================================================
--- branches/etch-5.0/debian/changelog 2007-11-06 20:51:20 UTC (rev 967)
+++ branches/etch-5.0/debian/changelog 2007-11-06 21:06:03 UTC (rev 968)
@@ -1,26 +1,20 @@
-mysql-dfsg-5.0 (5.0.32-7etch4) stable-security; urgency=high
+mysql-dfsg-5.0 (5.0.32-7etch2) stable-security; urgency=high
* Security release prepared for the security team by the Debian MySQL
- maintainers. The patches were taken from the Ubuntu project.
- * It was discovered that MySQL could be made to overflow a signed char
- during authentication. Remote attackers could use crafted authentication
- requests to cause a denial of service. (CVE-2007-3780)
- * Phil Anderton discovered that MySQL did not properly verify access
- privileges when accessing external tables. As a result, authenticated
- users could exploit this to obtain UPDATE privileges to external
- tables. (CVE-2007-3782)
+ maintainers. The patches were mostly taken from the Ubuntu project.
+ * CVE-2007-2583: null dereference in item_cmpfunc.cc
+ * CVE-2007-2691: DROP/RENAME TABLE statements (ref: #424778).
+ * CVE-2007-2692: THD::db_access privileges (ref: #424830).
+ * CVE-2007-3780: It was discovered that MySQL could be made to overflow
+ a signed char during authentication. Remote attackers could use crafted
+ authentication requests to cause a denial of service.
+ * CVE-2007-3782: Phil Anderton discovered that MySQL did not properly
+ verify access privileges when accessing external tables. As a result,
+ authenticated users could exploit this to obtain UPDATE privileges to
+ external tables.
- -- Christian Hammers <ch at debian.org> Sat, 20 Oct 2007 16:39:32 +0200
+ -- Christian Hammers <ch at debian.org> Tue, 6 Dec 2007 21:54:01 +0100
-mysql-dfsg-5.0 (5.0.32-7etch3) stable-security; urgency=high
-
- * Upload prepared for the security team by the debian mysql maintainers
- * Fix for CVE-2007-2691: DROP/RENAME TABLE statements (ref: #424778).
- * Fix for CVE-2007-2692: THD::db_access privileges (ref: #424830).
- * Fix for CVE-2007-2583: null dereference in item_cmpfunc.cc
-
- -- sean finney <seanius at debian.org> Mon, 28 May 2007 19:34:34 +0200
-
mysql-dfsg-5.0 (5.0.32-7etch1) testing-proposed-updates; urgency=high
* SECURITY:
Modified: branches/etch-5.0/debian/patches/00list
===================================================================
--- branches/etch-5.0/debian/patches/00list 2007-11-06 20:51:20 UTC (rev 967)
+++ branches/etch-5.0/debian/patches/00list 2007-11-06 21:06:03 UTC (rev 968)
@@ -17,9 +17,9 @@
86_PATH_MAX.dpatch
88_mctype_attrib.dpatch
89_ndb__staticlib.dpatch
+90_SECURITY_CVE-2007-2583_item_cmpfunc.dpatch
90_tmp__limit_comma_bug.dpatch
-90_SECURITY_CVE-2007-2583_item_cmpfunc.dpatch
91_SECURITY_CVE-2007-2691_alter-drop.dpatch
-91_CVE-2007-3780.dpatch
-91_CVE-2007-3782.dpatch
-92_SECURITY_CVE-2007-2691_thd_privs.dpatch
+92_SECURITY_CVE-2007-2692_thd_privs.dpatch
+93_SECURITY_CVE-2007-3780.dpatch
+93_SECURITY_CVE-2007-3782.dpatch
Deleted: branches/etch-5.0/debian/patches/91_CVE-2007-3780.dpatch
===================================================================
--- branches/etch-5.0/debian/patches/91_CVE-2007-3780.dpatch 2007-11-06 20:51:20 UTC (rev 967)
+++ branches/etch-5.0/debian/patches/91_CVE-2007-3780.dpatch 2007-11-06 21:06:03 UTC (rev 968)
@@ -1,20 +0,0 @@
-#! /bin/sh /usr/share/dpatch/dpatch-run
-## 91_CVE-2007-3780.dpatch by Jamie Strandboge <jamie at ubuntu.com>
-##
-## All lines beginning with `## DP:' are a description of the patch.
-## DP: fix for CVE-2007-3780
-
- at DPATCH@
-
-diff -Nru mysql-dfsg-5.0-5.0.38.orig/sql/sql_parse.cc mysql-dfsg-5.0-5.0.38/sql/sql_parse.cc
---- mysql-dfsg-5.0-5.0.38.orig/sql/sql_parse.cc 2007-10-02 10:27:41.000000000 -0400
-+++ mysql-dfsg-5.0-5.0.38/sql/sql_parse.cc 2007-10-02 10:30:39.000000000 -0400
-@@ -1008,7 +1008,7 @@
- password both send '\0'.
- */
- uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
-- *passwd++ : strlen(passwd);
-+ (uchar) (*passwd++) : strlen(passwd);
- db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ?
- db + passwd_len + 1 : 0;
- uint db_len= db ? strlen(db) : 0;
Deleted: branches/etch-5.0/debian/patches/91_CVE-2007-3782.dpatch
===================================================================
--- branches/etch-5.0/debian/patches/91_CVE-2007-3782.dpatch 2007-11-06 20:51:20 UTC (rev 967)
+++ branches/etch-5.0/debian/patches/91_CVE-2007-3782.dpatch 2007-11-06 21:06:03 UTC (rev 968)
@@ -1,39 +0,0 @@
-#! /bin/sh /usr/share/dpatch/dpatch-run
-## 91_CVE-2007-3782.dpatch by Jamie Strandboge <jamie at ubuntu.com>
-##
-## All lines beginning with `## DP:' are a description of the patch.
-## DP: fix for CVE-2007-3782
-## DP: (patches to mysql-test/ removed as they didn't apply cleanly --ch)
-
- at DPATCH@
-
-diff -Nru mysql-dfsg-5.0-5.0.38.orig/sql/sql_prepare.cc mysql-dfsg-5.0-5.0.38/sql/sql_prepare.cc
---- mysql-dfsg-5.0-5.0.38.orig/sql/sql_prepare.cc 2007-03-20 15:12:48.000000000 -0400
-+++ mysql-dfsg-5.0-5.0.38/sql/sql_prepare.cc 2007-10-02 11:02:20.000000000 -0400
-@@ -1164,8 +1164,9 @@
- goto error;
-
- #ifndef NO_EMBEDDED_ACCESS_CHECKS
-- /* TABLE_LIST contain right privilages request */
-- want_privilege= table_list->grant.want_privilege;
-+ /* Force privilege re-checking for views after they are being opened. */
-+ want_privilege= (table_list->view ? UPDATE_ACL :
-+ table_list->grant.want_privilege);
- #endif
-
- if (mysql_prepare_update(thd, table_list, &select->where,
-diff -Nru mysql-dfsg-5.0-5.0.38.orig/sql/sql_update.cc mysql-dfsg-5.0-5.0.38/sql/sql_update.cc
---- mysql-dfsg-5.0-5.0.38.orig/sql/sql_update.cc 2007-03-20 15:12:18.000000000 -0400
-+++ mysql-dfsg-5.0-5.0.38/sql/sql_update.cc 2007-10-02 11:02:20.000000000 -0400
-@@ -173,8 +173,9 @@
- table->quick_keys.clear_all();
-
- #ifndef NO_EMBEDDED_ACCESS_CHECKS
-- /* TABLE_LIST contain right privilages request */
-- want_privilege= table_list->grant.want_privilege;
-+ /* Force privilege re-checking for views after they are being opened. */
-+ want_privilege= (table_list->view ? UPDATE_ACL :
-+ table_list->grant.want_privilege);
- #endif
- if (mysql_prepare_update(thd, table_list, &conds, order_num, order))
- DBUG_RETURN(1);
Deleted: branches/etch-5.0/debian/patches/92_SECURITY_CVE-2007-2691_thd_privs.dpatch
===================================================================
--- branches/etch-5.0/debian/patches/92_SECURITY_CVE-2007-2691_thd_privs.dpatch 2007-11-06 20:51:20 UTC (rev 967)
+++ branches/etch-5.0/debian/patches/92_SECURITY_CVE-2007-2691_thd_privs.dpatch 2007-11-06 21:06:03 UTC (rev 968)
@@ -1,13877 +0,0 @@
-#! /bin/sh /usr/share/dpatch/dpatch-run
-## 92_SECURITY_CVE-2007-2691_thd_privs.dpatch by <seanius at debian.org>
-##
-## DP: taken from http://lists.mysql.com/commits/23293
-
- at DPATCH@
-diff -urNad mysql-5.0-etch~/sql/mysql_priv.h mysql-5.0-etch/sql/mysql_priv.h
---- mysql-5.0-etch~/sql/mysql_priv.h 2007-05-28 18:56:15.000000000 +0200
-+++ mysql-5.0-etch/sql/mysql_priv.h 2007-05-28 19:12:52.000000000 +0200
-@@ -930,6 +930,8 @@
- int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
- bool get_schema_tables_result(JOIN *join,
- enum enum_schema_table_state executed_place);
-+enum enum_schema_tables get_schema_table_idx(ST_SCHEMA_TABLE *schema_table);
-+
- #define is_schema_db(X) \
- !my_strcasecmp(system_charset_info, information_schema_name.str, (X))
-
-diff -urNad mysql-5.0-etch~/sql/mysql_priv.h.orig mysql-5.0-etch/sql/mysql_priv.h.orig
---- mysql-5.0-etch~/sql/mysql_priv.h.orig 1970-01-01 01:00:00.000000000 +0100
-+++ mysql-5.0-etch/sql/mysql_priv.h.orig 2007-05-28 18:56:15.000000000 +0200
-@@ -0,0 +1,1685 @@
-+/* Copyright (C) 2000-2003 MySQL AB
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License as published by
-+ the Free Software Foundation; either version 2 of the License, or
-+ (at your option) any later version.
-+
-+ This program is distributed in the hope that it will be useful,
-+ but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ GNU General Public License for more details.
-+
-+ You should have received a copy of the GNU General Public License
-+ along with this program; if not, write to the Free Software
-+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-+
-+/*
-+ Mostly this file is used in the server. But a little part of it is used in
-+ mysqlbinlog too (definition of SELECT_DISTINCT and others).
-+ The consequence is that 90% of the file is wrapped in #ifndef MYSQL_CLIENT,
-+ except the part which must be in the server and in the client.
-+*/
-+
-+#ifndef MYSQL_CLIENT
-+
-+#include <my_global.h>
-+#include <mysql_version.h>
-+#include <mysql_embed.h>
-+#include <my_sys.h>
-+#include <my_time.h>
-+#include <m_string.h>
-+#include <hash.h>
-+#include <signal.h>
-+#include <thr_lock.h>
-+#include <my_base.h> /* Needed by field.h */
-+#include "sql_bitmap.h"
-+#include "sql_array.h"
-+
-+#ifdef __EMX__
-+#undef write /* remove pthread.h macro definition for EMX */
-+#endif
-+
-+/* TODO convert all these three maps to Bitmap classes */
-+typedef ulonglong table_map; /* Used for table bits in join */
-+#if MAX_INDEXES <= 64
-+typedef Bitmap<64> key_map; /* Used for finding keys */
-+#else
-+typedef Bitmap<((MAX_INDEXES+7)/8*8)> key_map; /* Used for finding keys */
-+#endif
-+typedef ulong key_part_map; /* Used for finding key parts */
-+typedef ulong nesting_map; /* Used for flags of nesting constructs */
-+/*
-+ Used to identify NESTED_JOIN structures within a join (applicable only to
-+ structures that have not been simplified away and embed more the one
-+ element)
-+*/
-+typedef ulonglong nested_join_map;
-+
-+/* query_id */
-+typedef ulonglong query_id_t;
-+extern query_id_t query_id;
-+
-+/* increment query_id and return it. */
-+inline query_id_t next_query_id() { return query_id++; }
-+
-+/* useful constants */
-+extern const key_map key_map_empty;
-+extern key_map key_map_full; /* Should be threaded as const */
-+extern const char *primary_key_name;
-+
-+#include "mysql_com.h"
-+#include <violite.h>
-+#include "unireg.h"
-+
-+void init_sql_alloc(MEM_ROOT *root, uint block_size, uint pre_alloc_size);
-+gptr sql_alloc(unsigned size);
-+gptr sql_calloc(unsigned size);
-+char *sql_strdup(const char *str);
-+char *sql_strmake(const char *str,uint len);
-+gptr sql_memdup(const void * ptr,unsigned size);
-+void sql_element_free(void *ptr);
-+char *sql_strmake_with_convert(const char *str, uint32 arg_length,
-+ CHARSET_INFO *from_cs,
-+ uint32 max_res_length,
-+ CHARSET_INFO *to_cs, uint32 *result_length);
-+void kill_one_thread(THD *thd, ulong id, bool only_kill_query);
-+bool net_request_file(NET* net, const char* fname);
-+char* query_table_status(THD *thd,const char *db,const char *table_name);
-+
-+#define x_free(A) { my_free((gptr) (A),MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR)); }
-+#define safeFree(x) { if(x) { my_free((gptr) x,MYF(0)); x = NULL; } }
-+#define PREV_BITS(type,A) ((type) (((type) 1 << (A)) -1))
-+#define all_bits_set(A,B) ((A) & (B) != (B))
-+
-+extern CHARSET_INFO *system_charset_info, *files_charset_info ;
-+extern CHARSET_INFO *national_charset_info, *table_alias_charset;
-+
-+
-+enum Derivation
-+{
-+ DERIVATION_IGNORABLE= 5,
-+ DERIVATION_COERCIBLE= 4,
-+ DERIVATION_SYSCONST= 3,
-+ DERIVATION_IMPLICIT= 2,
-+ DERIVATION_NONE= 1,
-+ DERIVATION_EXPLICIT= 0
-+};
-+
-+
-+typedef struct my_locale_st
-+{
-+ const char *name;
-+ const char *description;
-+ const bool is_ascii;
-+ TYPELIB *month_names;
-+ TYPELIB *ab_month_names;
-+ TYPELIB *day_names;
-+ TYPELIB *ab_day_names;
-+#ifdef __cplusplus
-+ my_locale_st(const char *name_par, const char *descr_par, bool is_ascii_par,
-+ TYPELIB *month_names_par, TYPELIB *ab_month_names_par,
-+ TYPELIB *day_names_par, TYPELIB *ab_day_names_par) :
-+ name(name_par), description(descr_par), is_ascii(is_ascii_par),
-+ month_names(month_names_par), ab_month_names(ab_month_names_par),
-+ day_names(day_names_par), ab_day_names(ab_day_names_par)
-+ {}
-+#endif
-+} MY_LOCALE;
-+
-+extern MY_LOCALE my_locale_en_US;
-+extern MY_LOCALE *my_locales[];
-+
-+MY_LOCALE *my_locale_by_name(const char *name);
-+
-+/***************************************************************************
-+ Configuration parameters
-+****************************************************************************/
-+
-+#define ACL_CACHE_SIZE 256
-+#define MAX_PASSWORD_LENGTH 32
-+#define HOST_CACHE_SIZE 128
-+#define MAX_ACCEPT_RETRY 10 // Test accept this many times
-+#define MAX_FIELDS_BEFORE_HASH 32
-+#define USER_VARS_HASH_SIZE 16
-+#define TABLE_OPEN_CACHE_MIN 64
-+#define TABLE_OPEN_CACHE_DEFAULT 64
-+
-+/*
-+ Value of 9236 discovered through binary search 2006-09-26 on Ubuntu Dapper
-+ Drake, libc6 2.3.6-0ubuntu2, Linux kernel 2.6.15-27-686, on x86. (Added
-+ 100 bytes as reasonable buffer against growth and other environments'
-+ requirements.)
-+
-+ Feel free to raise this by the smallest amount you can to get the
-+ "execution_constants" test to pass.
-+ */
-+#define STACK_MIN_SIZE 10788 // Abort if less stack during eval.
-+
-+#define STACK_MIN_SIZE_FOR_OPEN 1024*80
-+#define STACK_BUFF_ALLOC 256 // For stack overrun checks
-+#ifndef MYSQLD_NET_RETRY_COUNT
-+#define MYSQLD_NET_RETRY_COUNT 10 // Abort read after this many int.
-+#endif
-+#define TEMP_POOL_SIZE 128
-+
-+#define QUERY_ALLOC_BLOCK_SIZE 8192
-+#define QUERY_ALLOC_PREALLOC_SIZE 8192
-+#define TRANS_ALLOC_BLOCK_SIZE 4096
-+#define TRANS_ALLOC_PREALLOC_SIZE 4096
-+#define RANGE_ALLOC_BLOCK_SIZE 2048
-+#define ACL_ALLOC_BLOCK_SIZE 1024
-+#define UDF_ALLOC_BLOCK_SIZE 1024
-+#define TABLE_ALLOC_BLOCK_SIZE 1024
-+#define BDB_LOG_ALLOC_BLOCK_SIZE 1024
-+#define WARN_ALLOC_BLOCK_SIZE 2048
-+#define WARN_ALLOC_PREALLOC_SIZE 1024
-+
-+/*
-+ The following parameters is to decide when to use an extra cache to
-+ optimise seeks when reading a big table in sorted order
-+*/
-+#define MIN_FILE_LENGTH_TO_USE_ROW_CACHE (10L*1024*1024)
-+#define MIN_ROWS_TO_USE_TABLE_CACHE 100
-+#define MIN_ROWS_TO_USE_BULK_INSERT 100
-+
-+/*
-+ The following is used to decide if MySQL should use table scanning
-+ instead of reading with keys. The number says how many evaluation of the
-+ WHERE clause is comparable to reading one extra row from a table.
-+*/
-+#define TIME_FOR_COMPARE 5 // 5 compares == one read
-+
-+/*
-+ Number of comparisons of table rowids equivalent to reading one row from a
-+ table.
-+*/
-+#define TIME_FOR_COMPARE_ROWID (TIME_FOR_COMPARE*2)
-+
-+/*
-+ For sequential disk seeks the cost formula is:
-+ DISK_SEEK_BASE_COST + DISK_SEEK_PROP_COST * #blocks_to_skip
-+
-+ The cost of average seek
-+ DISK_SEEK_BASE_COST + DISK_SEEK_PROP_COST*BLOCKS_IN_AVG_SEEK =1.0.
-+*/
-+#define DISK_SEEK_BASE_COST ((double)0.5)
-+
-+#define BLOCKS_IN_AVG_SEEK 128
-+
-+#define DISK_SEEK_PROP_COST ((double)0.5/BLOCKS_IN_AVG_SEEK)
-+
-+
-+/*
-+ Number of rows in a reference table when refereed through a not unique key.
-+ This value is only used when we don't know anything about the key
-+ distribution.
-+*/
-+#define MATCHING_ROWS_IN_OTHER_TABLE 10
-+
-+/* Don't pack string keys shorter than this (if PACK_KEYS=1 isn't used) */
-+#define KEY_DEFAULT_PACK_LENGTH 8
-+
-+/* Characters shown for the command in 'show processlist' */
-+#define PROCESS_LIST_WIDTH 100
-+
-+#define PRECISION_FOR_DOUBLE 53
-+#define PRECISION_FOR_FLOAT 24
-+
-+/* The following can also be changed from the command line */
-+#define CONNECT_TIMEOUT 5 // Do not wait long for connect
-+#define DEFAULT_CONCURRENCY 10
-+#define DELAYED_LIMIT 100 /* pause after xxx inserts */
-+#define DELAYED_QUEUE_SIZE 1000
-+#define DELAYED_WAIT_TIMEOUT 5*60 /* Wait for delayed insert */
-+#define FLUSH_TIME 0 /* Don't flush tables */
-+#define MAX_CONNECT_ERRORS 10 // errors before disabling host
-+
-+#ifdef HAVE_INNOBASE_DB
-+#define IF_INNOBASE_DB(A, B) (A)
-+#else
-+#define IF_INNOBASE_DB(A, B) (B)
-+#endif
-+#ifdef __NETWARE__
-+#define IF_NETWARE(A,B) (A)
-+#else
-+#define IF_NETWARE(A,B) (B)
-+#endif
-+
-+#if defined(__WIN__) || defined(OS2)
-+#define IF_WIN(A,B) (A)
-+#undef FLUSH_TIME
-+#define FLUSH_TIME 1800 /* Flush every half hour */
-+
-+#define INTERRUPT_PRIOR -2
-+#define CONNECT_PRIOR -1
-+#define WAIT_PRIOR 0
-+#define QUERY_PRIOR 2
-+#else
-+#define IF_WIN(A,B) (B)
-+#define INTERRUPT_PRIOR 10
-+#define CONNECT_PRIOR 9
-+#define WAIT_PRIOR 8
-+#define QUERY_PRIOR 6
-+#endif /* __WIN92__ */
-+
-+ /* Bits from testflag */
-+#define TEST_PRINT_CACHED_TABLES 1
-+#define TEST_NO_KEY_GROUP 2
-+#define TEST_MIT_THREAD 4
-+#define TEST_BLOCKING 8
-+#define TEST_KEEP_TMP_TABLES 16
-+#define TEST_NO_THREADS 32 /* For debugging under Linux */
-+#define TEST_READCHECK 64 /* Force use of readcheck */
-+#define TEST_NO_EXTRA 128
-+#define TEST_CORE_ON_SIGNAL 256 /* Give core if signal */
-+#define TEST_NO_STACKTRACE 512
-+#define TEST_SIGINT 1024 /* Allow sigint on threads */
-+#define TEST_SYNCHRONIZATION 2048 /* get server to do sleep in
-+ some places */
-+#endif
-+
-+/*
-+ This is included in the server and in the client.
-+ Options for select set by the yacc parser (stored in lex->options).
-+
-+ XXX:
-+ log_event.h defines OPTIONS_WRITTEN_TO_BIN_LOG to specify what THD
-+ options list are written into binlog. These options can NOT change their
-+ values, or it will break replication between version.
-+
-+ context is encoded as following:
-+ SELECT - SELECT_LEX_NODE::options
-+ THD - THD::options
-+ intern - neither. used only as
-+ func(..., select_node->options | thd->options | OPTION_XXX, ...)
-+
-+ TODO: separate three contexts above, move them to separate bitfields.
-+*/
-+
-+#define SELECT_DISTINCT (1L << 0) // SELECT, user
-+#define SELECT_STRAIGHT_JOIN (1L << 1) // SELECT, user
-+#define SELECT_DESCRIBE (1L << 2) // SELECT, user
-+#define SELECT_SMALL_RESULT (1L << 3) // SELECT, user
-+#define SELECT_BIG_RESULT (1L << 4) // SELECT, user
-+#define OPTION_FOUND_ROWS (1L << 5) // SELECT, user
-+#define OPTION_TO_QUERY_CACHE (1L << 6) // SELECT, user
-+#define SELECT_NO_JOIN_CACHE (1L << 7) // intern
-+#define OPTION_BIG_TABLES (1L << 8) // THD, user
-+#define OPTION_BIG_SELECTS (1L << 9) // THD, user
-+#define OPTION_LOG_OFF (1L << 10) // THD, user
-+#define OPTION_UPDATE_LOG (1L << 11) // THD, user, unused
-+#define TMP_TABLE_ALL_COLUMNS (1L << 12) // SELECT, intern
-+#define OPTION_WARNINGS (1L << 13) // THD, user
-+#define OPTION_AUTO_IS_NULL (1L << 14) // THD, user, binlog
-+#define OPTION_FOUND_COMMENT (1L << 15) // SELECT, intern, parser
-+#define OPTION_SAFE_UPDATES (1L << 16) // THD, user
-+#define OPTION_BUFFER_RESULT (1L << 17) // SELECT, user
-+#define OPTION_BIN_LOG (1L << 18) // THD, user
-+#define OPTION_NOT_AUTOCOMMIT (1L << 19) // THD, user
-+#define OPTION_BEGIN (1L << 20) // THD, intern
-+#define OPTION_TABLE_LOCK (1L << 21) // THD, intern
-+#define OPTION_QUICK (1L << 22) // SELECT (for DELETE)
-+#define OPTION_QUOTE_SHOW_CREATE (1L << 23) // THD, user
-+
-+/* Thr following is used to detect a conflict with DISTINCT
-+ in the user query has requested */
-+#define SELECT_ALL (1L << 24) // SELECT, user, parser
-+
-+/* Set if we are updating a non-transaction safe table */
-+#define OPTION_STATUS_NO_TRANS_UPDATE (1L << 25) // THD, intern
-+
-+/* The following can be set when importing tables in a 'wrong order'
-+ to suppress foreign key checks */
-+#define OPTION_NO_FOREIGN_KEY_CHECKS (1L << 26) // THD, user, binlog
-+/* The following speeds up inserts to InnoDB tables by suppressing unique
-+ key checks in some cases */
-+#define OPTION_RELAXED_UNIQUE_CHECKS (1L << 27) // THD, user, binlog
-+#define SELECT_NO_UNLOCK (1L << 28) // SELECT, intern
-+#define OPTION_SCHEMA_TABLE (1L << 29) // SELECT, intern
-+/* Flag set if setup_tables already done */
-+#define OPTION_SETUP_TABLES_DONE (1L << 30) // intern
-+/* If not set then the thread will ignore all warnings with level notes. */
-+#define OPTION_SQL_NOTES (1UL << 31) // THD, user
-+/*
-+ Force the used temporary table to be a MyISAM table (because we will use
-+ fulltext functions when reading from it.
-+*/
-+#define TMP_TABLE_FORCE_MYISAM (LL(1) << 32)
-+
-+/*
-+ Maximum length of time zone name that we support
-+ (Time zone name is char(64) in db). mysqlbinlog needs it.
-+*/
-+#define MAX_TIME_ZONE_NAME_LENGTH 72
-+
-+/* The rest of the file is included in the server only */
-+#ifndef MYSQL_CLIENT
-+
-+/* Bits for different SQL modes modes (including ANSI mode) */
-+#define MODE_REAL_AS_FLOAT 1
-+#define MODE_PIPES_AS_CONCAT 2
-+#define MODE_ANSI_QUOTES 4
-+#define MODE_IGNORE_SPACE 8
-+#define MODE_NOT_USED 16
-+#define MODE_ONLY_FULL_GROUP_BY 32
-+#define MODE_NO_UNSIGNED_SUBTRACTION 64
-+#define MODE_NO_DIR_IN_CREATE 128
-+#define MODE_POSTGRESQL 256
-+#define MODE_ORACLE 512
-+#define MODE_MSSQL 1024
-+#define MODE_DB2 2048
-+#define MODE_MAXDB 4096
-+#define MODE_NO_KEY_OPTIONS 8192
-+#define MODE_NO_TABLE_OPTIONS 16384
-+#define MODE_NO_FIELD_OPTIONS 32768
-+#define MODE_MYSQL323 65536
-+#define MODE_MYSQL40 (MODE_MYSQL323*2)
-+#define MODE_ANSI (MODE_MYSQL40*2)
-+#define MODE_NO_AUTO_VALUE_ON_ZERO (MODE_ANSI*2)
-+#define MODE_NO_BACKSLASH_ESCAPES (MODE_NO_AUTO_VALUE_ON_ZERO*2)
-+#define MODE_STRICT_TRANS_TABLES (MODE_NO_BACKSLASH_ESCAPES*2)
-+#define MODE_STRICT_ALL_TABLES (MODE_STRICT_TRANS_TABLES*2)
-+#define MODE_NO_ZERO_IN_DATE (MODE_STRICT_ALL_TABLES*2)
-+#define MODE_NO_ZERO_DATE (MODE_NO_ZERO_IN_DATE*2)
-+#define MODE_INVALID_DATES (MODE_NO_ZERO_DATE*2)
-+#define MODE_ERROR_FOR_DIVISION_BY_ZERO (MODE_INVALID_DATES*2)
-+#define MODE_TRADITIONAL (MODE_ERROR_FOR_DIVISION_BY_ZERO*2)
-+#define MODE_NO_AUTO_CREATE_USER (MODE_TRADITIONAL*2)
-+#define MODE_HIGH_NOT_PRECEDENCE (MODE_NO_AUTO_CREATE_USER*2)
-+#define MODE_NO_ENGINE_SUBSTITUTION (MODE_HIGH_NOT_PRECEDENCE*2)
-+/*
-+ Replication uses 8 bytes to store SQL_MODE in the binary log. The day you
-+ use strictly more than 64 bits by adding one more define above, you should
-+ contact the replication team because the replication code should then be
-+ updated (to store more bytes on disk).
-+
-+ NOTE: When adding new SQL_MODE types, make sure to also add them to
-+ ../scripts/mysql_create_system_tables.sh and
-+ ../scripts/mysql_fix_privilege_tables.sql
-+*/
-+
-+#define RAID_BLOCK_SIZE 1024
-+
-+#define MY_CHARSET_BIN_MB_MAXLEN 1
-+
-+// uncachable cause
-+#define UNCACHEABLE_DEPENDENT 1
-+#define UNCACHEABLE_RAND 2
-+#define UNCACHEABLE_SIDEEFFECT 4
-+// forcing to save JOIN for explain
-+#define UNCACHEABLE_EXPLAIN 8
-+/* Don't evaluate subqueries in prepare even if they're not correlated */
-+#define UNCACHEABLE_PREPARE 16
-+
-+#ifdef EXTRA_DEBUG
-+/*
-+ Sync points allow us to force the server to reach a certain line of code
-+ and block there until the client tells the server it is ok to go on.
-+ The client tells the server to block with SELECT GET_LOCK()
-+ and unblocks it with SELECT RELEASE_LOCK(). Used for debugging difficult
-+ concurrency problems
-+*/
-+#define DBUG_SYNC_POINT(lock_name,lock_timeout) \
-+ debug_sync_point(lock_name,lock_timeout)
-+void debug_sync_point(const char* lock_name, uint lock_timeout);
-+#else
-+#define DBUG_SYNC_POINT(lock_name,lock_timeout)
-+#endif /* EXTRA_DEBUG */
-+
-+/* BINLOG_DUMP options */
-+
-+#define BINLOG_DUMP_NON_BLOCK 1
-+
-+/* sql_show.cc:show_log_files() */
-+#define SHOW_LOG_STATUS_FREE "FREE"
-+#define SHOW_LOG_STATUS_INUSE "IN USE"
-+
-+struct st_table_list;
-+class String;
-+void view_store_options(THD *thd, st_table_list *table, String *buff);
-+
-+/* Options to add_table_to_list() */
-+#define TL_OPTION_UPDATING 1
-+#define TL_OPTION_FORCE_INDEX 2
-+#define TL_OPTION_IGNORE_LEAVES 4
-+#define TL_OPTION_ALIAS 8
-+
-+/* Some portable defines */
-+
-+#define portable_sizeof_char_ptr 8
-+
-+#define tmp_file_prefix "#sql" /* Prefix for tmp tables */
-+#define tmp_file_prefix_length 4
-+
-+/* Flags for calc_week() function. */
-+#define WEEK_MONDAY_FIRST 1
-+#define WEEK_YEAR 2
-+#define WEEK_FIRST_WEEKDAY 4
-+
-+#define STRING_BUFFER_USUAL_SIZE 80
-+
-+enum enum_parsing_place
-+{
-+ NO_MATTER,
-+ IN_HAVING,
-+ SELECT_LIST,
-+ IN_WHERE,
-+ IN_ON
-+};
-+
-+struct st_table;
-+class THD;
-+
-+/* Struct to handle simple linked lists */
-+
-+typedef struct st_sql_list {
-+ uint elements;
-+ byte *first;
-+ byte **next;
-+
-+ st_sql_list() {} /* Remove gcc warning */
-+ inline void empty()
-+ {
-+ elements=0;
-+ first=0;
-+ next= &first;
-+ }
-+ inline void link_in_list(byte *element,byte **next_ptr)
-+ {
-+ elements++;
-+ (*next)=element;
-+ next= next_ptr;
-+ *next=0;
-+ }
-+ inline void save_and_clear(struct st_sql_list *save)
-+ {
-+ *save= *this;
-+ empty();
-+ }
-+ inline void push_front(struct st_sql_list *save)
-+ {
-+ *save->next= first; /* link current list last */
-+ first= save->first;
-+ elements+= save->elements;
-+ }
-+ inline void push_back(struct st_sql_list *save)
-+ {
-+ if (save->first)
-+ {
-+ *next= save->first;
-+ next= save->next;
-+ elements+= save->elements;
-+ }
-+ }
-+} SQL_LIST;
-+
-+
-+extern pthread_key(THD*, THR_THD);
-+inline THD *_current_thd(void)
-+{
-+ return my_pthread_getspecific_ptr(THD*,THR_THD);
-+}
-+#define current_thd _current_thd()
-+
-+/*
-+ External variables
-+*/
-+extern ulong server_id, concurrency;
-+
-+
-+typedef my_bool (*qc_engine_callback)(THD *thd, char *table_key,
-+ uint key_length,
-+ ulonglong *engine_data);
-+#include "sql_string.h"
-+#include "sql_list.h"
-+#include "sql_map.h"
-+#include "my_decimal.h"
-+#include "handler.h"
-+#include "parse_file.h"
-+#include "table.h"
-+#include "sql_error.h"
-+#include "field.h" /* Field definitions */
-+#include "protocol.h"
-+#include "sql_udf.h"
-+class user_var_entry;
-+class Security_context;
-+enum enum_var_type
-+{
-+ OPT_DEFAULT= 0, OPT_SESSION, OPT_GLOBAL
-+};
-+class sys_var;
-+class Comp_creator;
-+typedef Comp_creator* (*chooser_compare_func_creator)(bool invert);
-+#include "item.h"
-+extern my_decimal decimal_zero;
-+
-+/* sql_parse.cc */
-+void free_items(Item *item);
-+void cleanup_items(Item *item);
-+class THD;
-+void close_thread_tables(THD *thd, bool locked=0, bool skip_derived=0);
-+bool check_one_table_access(THD *thd, ulong privilege,
-+ TABLE_LIST *tables);
-+bool check_single_table_access(THD *thd, ulong privilege,
-+ TABLE_LIST *tables);
-+bool check_routine_access(THD *thd,ulong want_access,char *db,char *name,
-+ bool is_proc, bool no_errors);
-+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, const char *db, const char *name, bool is_proc);
-+bool multi_update_precheck(THD *thd, TABLE_LIST *tables);
-+bool multi_delete_precheck(THD *thd, TABLE_LIST *tables);
-+bool mysql_multi_update_prepare(THD *thd);
-+bool mysql_multi_delete_prepare(THD *thd);
-+bool mysql_insert_select_prepare(THD *thd);
-+bool update_precheck(THD *thd, TABLE_LIST *tables);
-+bool delete_precheck(THD *thd, TABLE_LIST *tables);
-+bool insert_precheck(THD *thd, TABLE_LIST *tables);
-+bool create_table_precheck(THD *thd, TABLE_LIST *tables,
-+ TABLE_LIST *create_table);
-+int append_query_string(CHARSET_INFO *csinfo,
-+ String const *from, String *to);
-+
-+void get_default_definer(THD *thd, LEX_USER *definer);
-+LEX_USER *create_default_definer(THD *thd);
-+LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name);
-+LEX_USER *get_current_user(THD *thd, LEX_USER *user);
-+bool check_string_length(LEX_STRING *str,
-+ const char *err_msg, uint max_length);
-+
-+enum enum_mysql_completiontype {
-+ ROLLBACK_RELEASE=-2, ROLLBACK=1, ROLLBACK_AND_CHAIN=7,
-+ COMMIT_RELEASE=-1, COMMIT=0, COMMIT_AND_CHAIN=6
-+};
-+
-+int end_trans(THD *thd, enum enum_mysql_completiontype completion);
-+
-+Item *negate_expression(THD *thd, Item *expr);
-+#include "sql_class.h"
-+#include "sql_acl.h"
-+#include "tztime.h"
-+#include "opt_range.h"
-+
-+#ifdef HAVE_QUERY_CACHE
-+struct Query_cache_query_flags
-+{
-+ unsigned int client_long_flag:1;
-+ unsigned int client_protocol_41:1;
-+ unsigned int more_results_exists:1;
-+ unsigned int pkt_nr;
-+ uint character_set_client_num;
-+ uint character_set_results_num;
-+ uint collation_connection_num;
-+ ha_rows limit;
-+ Time_zone *time_zone;
-+ ulong sql_mode;
-+ ulong max_sort_length;
-+ ulong group_concat_max_len;
-+ MY_LOCALE *lc_time_names;
-+};
-+#define QUERY_CACHE_FLAGS_SIZE sizeof(Query_cache_query_flags)
-+#include "sql_cache.h"
-+#define query_cache_store_query(A, B) query_cache.store_query(A, B)
-+#define query_cache_destroy() query_cache.destroy()
-+#define query_cache_result_size_limit(A) query_cache.result_size_limit(A)
-+#define query_cache_init() query_cache.init()
-+#define query_cache_resize(A) query_cache.resize(A)
-+#define query_cache_set_min_res_unit(A) query_cache.set_min_res_unit(A)
-+#define query_cache_invalidate3(A, B, C) query_cache.invalidate(A, B, C)
-+#define query_cache_invalidate1(A) query_cache.invalidate(A)
-+#define query_cache_send_result_to_client(A, B, C) \
-+ query_cache.send_result_to_client(A, B, C)
-+#define query_cache_invalidate_by_MyISAM_filename_ref \
-+ &query_cache_invalidate_by_MyISAM_filename
-+#else
-+#define QUERY_CACHE_FLAGS_SIZE 0
-+#define query_cache_store_query(A, B)
-+#define query_cache_destroy()
-+#define query_cache_result_size_limit(A)
-+#define query_cache_init()
-+#define query_cache_resize(A)
-+#define query_cache_set_min_res_unit(A)
-+#define query_cache_invalidate3(A, B, C)
-+#define query_cache_invalidate1(A)
-+#define query_cache_send_result_to_client(A, B, C) 0
-+#define query_cache_invalidate_by_MyISAM_filename_ref NULL
-+
-+#define query_cache_abort(A)
-+#define query_cache_end_of_result(A)
-+#define query_cache_invalidate_by_MyISAM_filename_ref NULL
-+#endif /*HAVE_QUERY_CACHE*/
-+
-+bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create, bool silent);
-+bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create);
-+bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent);
-+void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, ushort flags);
-+bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
-+ my_bool drop_temporary);
-+int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
-+ bool drop_temporary, bool drop_view, bool log_query);
-+int mysql_rm_table_part2_with_lock(THD *thd, TABLE_LIST *tables,
-+ bool if_exists, bool drop_temporary,
-+ bool log_query);
-+int quick_rm_table(enum db_type base,const char *db,
-+ const char *table_name);
-+void close_cached_table(THD *thd, TABLE *table);
-+bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list);
-+bool do_rename(THD *thd, TABLE_LIST *ren_table, char *new_db,
-+ char *new_table_name, char *new_table_alias,
-+ bool skip_error);
-+bool mysql_change_db(THD *thd,const char *name,bool no_access_check);
-+void mysql_parse(THD *thd,char *inBuf,uint length);
-+bool mysql_test_parse_for_slave(THD *thd,char *inBuf,uint length);
-+bool is_update_query(enum enum_sql_command command);
-+bool alloc_query(THD *thd, const char *packet, uint packet_length);
-+void mysql_init_select(LEX *lex);
-+void mysql_reset_thd_for_next_command(THD *thd);
-+void mysql_init_query(THD *thd, uchar *buf, uint length);
-+bool mysql_new_select(LEX *lex, bool move_down);
-+void create_select_for_variable(const char *var_name);
-+void mysql_init_multi_delete(LEX *lex);
-+bool multi_delete_set_locks_and_link_aux_tables(LEX *lex);
-+void init_max_user_conn(void);
-+void init_update_queries(void);
-+void free_max_user_conn(void);
-+pthread_handler_t handle_one_connection(void *arg);
-+pthread_handler_t handle_bootstrap(void *arg);
-+void end_thread(THD *thd,bool put_in_cache);
-+void flush_thread_cache();
-+bool mysql_execute_command(THD *thd);
-+bool do_command(THD *thd);
-+bool dispatch_command(enum enum_server_command command, THD *thd,
-+ char* packet, uint packet_length);
-+void log_slow_statement(THD *thd);
-+bool check_dup(const char *db, const char *name, TABLE_LIST *tables);
-+
-+bool table_cache_init(void);
-+void table_cache_free(void);
-+uint cached_tables(void);
-+void kill_mysql(void);
-+void close_connection(THD *thd, uint errcode, bool lock);
-+bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
-+ bool *write_to_binlog);
-+bool check_access(THD *thd, ulong access, const char *db, ulong *save_priv,
-+ bool no_grant, bool no_errors, bool schema_db);
-+bool check_table_access(THD *thd, ulong want_access, TABLE_LIST *tables,
-+ bool no_errors);
-+bool check_global_access(THD *thd, ulong want_access);
-+
-+bool mysql_backup_table(THD* thd, TABLE_LIST* table_list);
-+bool mysql_restore_table(THD* thd, TABLE_LIST* table_list);
-+
-+bool mysql_checksum_table(THD* thd, TABLE_LIST* table_list,
-+ HA_CHECK_OPT* check_opt);
-+bool mysql_check_table(THD* thd, TABLE_LIST* table_list,
-+ HA_CHECK_OPT* check_opt);
-+bool mysql_repair_table(THD* thd, TABLE_LIST* table_list,
-+ HA_CHECK_OPT* check_opt);
-+bool mysql_analyze_table(THD* thd, TABLE_LIST* table_list,
-+ HA_CHECK_OPT* check_opt);
-+bool mysql_optimize_table(THD* thd, TABLE_LIST* table_list,
-+ HA_CHECK_OPT* check_opt);
-+bool mysql_assign_to_keycache(THD* thd, TABLE_LIST* table_list,
-+ LEX_STRING *key_cache_name);
-+bool mysql_preload_keys(THD* thd, TABLE_LIST* table_list);
-+int reassign_keycache_tables(THD* thd, KEY_CACHE *src_cache,
-+ KEY_CACHE *dst_cache);
-+TABLE *create_virtual_tmp_table(THD *thd, List<create_field> &field_list);
-+
-+bool mysql_xa_recover(THD *thd);
-+
-+bool check_simple_select();
-+
-+SORT_FIELD * make_unireg_sortorder(ORDER *order, uint *length,
-+ SORT_FIELD *sortorder);
-+int setup_order(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
-+ List<Item> &fields, List <Item> &all_fields, ORDER *order);
-+int setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
-+ List<Item> &fields, List<Item> &all_fields, ORDER *order,
-+ bool *hidden_group_fields);
-+
-+bool handle_select(THD *thd, LEX *lex, select_result *result,
-+ ulong setup_tables_done_option);
-+bool mysql_select(THD *thd, Item ***rref_pointer_array,
-+ TABLE_LIST *tables, uint wild_num, List<Item> &list,
-+ COND *conds, uint og_num, ORDER *order, ORDER *group,
-+ Item *having, ORDER *proc_param, ulonglong select_type,
-+ select_result *result, SELECT_LEX_UNIT *unit,
-+ SELECT_LEX *select_lex);
-+void free_underlaid_joins(THD *thd, SELECT_LEX *select);
-+bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit,
-+ select_result *result);
-+int mysql_explain_select(THD *thd, SELECT_LEX *sl, char const *type,
-+ select_result *result);
-+bool mysql_union(THD *thd, LEX *lex, select_result *result,
-+ SELECT_LEX_UNIT *unit, ulong setup_tables_done_option);
-+bool mysql_handle_derived(LEX *lex, bool (*processor)(THD *thd,
-+ LEX *lex,
-+ TABLE_LIST *table));
-+bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *t);
-+bool mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *t);
-+Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
-+ Item ***copy_func, Field **from_field,
-+ Field **def_field,
-+ bool group, bool modify_item,
-+ bool table_cant_handle_bit_fields,
-+ bool make_copy_field,
-+ uint convert_blob_length);
-+void sp_prepare_create_field(THD *thd, create_field *sql_field);
-+int prepare_create_field(create_field *sql_field,
-+ uint *blob_columns,
-+ int *timestamps, int *timestamps_with_niladic,
-+ uint table_flags);
-+bool mysql_create_table(THD *thd,const char *db, const char *table_name,
-+ HA_CREATE_INFO *create_info,
-+ List<create_field> &fields, List<Key> &keys,
-+ bool tmp_table, uint select_field_count);
-+
-+bool mysql_alter_table(THD *thd, char *new_db, char *new_name,
-+ HA_CREATE_INFO *create_info,
-+ TABLE_LIST *table_list,
-+ List<create_field> &fields,
-+ List<Key> &keys,
-+ uint order_num, ORDER *order, bool ignore,
-+ ALTER_INFO *alter_info, bool do_send_ok);
-+bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list, bool do_send_ok);
-+bool mysql_create_like_table(THD *thd, TABLE_LIST *table,
-+ HA_CREATE_INFO *create_info,
-+ Table_ident *src_table);
-+bool mysql_rename_table(enum db_type base,
-+ const char *old_db,
-+ const char * old_name,
-+ const char *new_db,
-+ const char * new_name);
-+bool mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys);
-+bool mysql_drop_index(THD *thd, TABLE_LIST *table_list,
-+ ALTER_INFO *alter_info);
-+bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
-+ Item **conds, uint order_num, ORDER *order);
-+int mysql_update(THD *thd,TABLE_LIST *tables,List<Item> &fields,
-+ List<Item> &values,COND *conds,
-+ uint order_num, ORDER *order, ha_rows limit,
-+ enum enum_duplicates handle_duplicates, bool ignore);
-+bool mysql_multi_update(THD *thd, TABLE_LIST *table_list,
-+ List<Item> *fields, List<Item> *values,
-+ COND *conds, ulonglong options,
-+ enum enum_duplicates handle_duplicates, bool ignore,
-+ SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex);
-+bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
-+ List<Item> &fields, List_item *values,
-+ List<Item> &update_fields,
-+ List<Item> &update_values, enum_duplicates duplic,
-+ COND **where, bool select_insert);
-+bool mysql_insert(THD *thd,TABLE_LIST *table,List<Item> &fields,
-+ List<List_item> &values, List<Item> &update_fields,
-+ List<Item> &update_values, enum_duplicates flag,
-+ bool ignore);
-+int check_that_all_fields_are_given_values(THD *thd, TABLE *entry,
-+ TABLE_LIST *table_list);
-+void mark_fields_used_by_triggers_for_insert_stmt(THD *thd, TABLE *table,
-+ enum_duplicates duplic);
-+bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds);
-+bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
-+ SQL_LIST *order, ha_rows rows, ulonglong options,
-+ bool reset_auto_increment);
-+bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok);
-+bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create);
-+TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update);
-+TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT* mem,
-+ bool *refresh, uint flags);
-+bool reopen_name_locked_table(THD* thd, TABLE_LIST* table);
-+TABLE *find_locked_table(THD *thd, const char *db,const char *table_name);
-+bool reopen_table(TABLE *table,bool locked);
-+bool reopen_tables(THD *thd,bool get_locks,bool in_refresh);
-+void close_old_data_files(THD *thd, TABLE *table, bool abort_locks,
-+ bool send_refresh);
-+bool close_data_tables(THD *thd,const char *db, const char *table_name);
-+bool wait_for_tables(THD *thd);
-+bool table_is_used(TABLE *table, bool wait_for_name_lock);
-+bool drop_locked_tables(THD *thd,const char *db, const char *table_name);
-+void abort_locked_tables(THD *thd,const char *db, const char *table_name);
-+void execute_init_command(THD *thd, sys_var_str *init_command_var,
-+ rw_lock_t *var_mutex);
-+extern Field *not_found_field;
-+extern Field *view_ref_found;
-+
-+enum find_item_error_report_type {REPORT_ALL_ERRORS, REPORT_EXCEPT_NOT_FOUND,
-+ IGNORE_ERRORS, REPORT_EXCEPT_NON_UNIQUE,
-+ IGNORE_EXCEPT_NON_UNIQUE};
-+Field *
-+find_field_in_tables(THD *thd, Item_ident *item,
-+ TABLE_LIST *first_table, TABLE_LIST *last_table,
-+ Item **ref, find_item_error_report_type report_error,
-+ bool check_privileges, bool register_tree_change);
-+Field *
-+find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
-+ const char *name, uint length,
-+ const char *item_name, const char *db_name,
-+ const char *table_name, Item **ref,
-+ bool check_privileges, bool allow_rowid,
-+ uint *cached_field_index_ptr,
-+ bool register_tree_change, TABLE_LIST **actual_table);
-+Field *
-+find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
-+ bool allow_rowid, uint *cached_field_index_ptr);
-+
-+#ifdef HAVE_OPENSSL
-+#include <openssl/des.h>
-+struct st_des_keyblock
-+{
-+ DES_cblock key1, key2, key3;
-+};
-+struct st_des_keyschedule
-+{
-+ DES_key_schedule ks1, ks2, ks3;
-+};
-+extern char *des_key_file;
-+extern struct st_des_keyschedule des_keyschedule[10];
-+extern uint des_default_key;
-+extern pthread_mutex_t LOCK_des_key_file;
-+bool load_des_key_file(const char *file_name);
-+#endif /* HAVE_OPENSSL */
-+
-+/* sql_do.cc */
-+bool mysql_do(THD *thd, List<Item> &values);
-+
-+/* sql_analyse.h */
-+bool append_escaped(String *to_str, String *from_str);
-+
-+/* sql_show.cc */
-+bool mysqld_show_open_tables(THD *thd,const char *wild);
-+bool mysqld_show_logs(THD *thd);
-+void append_identifier(THD *thd, String *packet, const char *name,
-+ uint length);
-+int get_quote_char_for_identifier(THD *thd, const char *name, uint length);
-+void mysqld_list_fields(THD *thd,TABLE_LIST *table, const char *wild);
-+int mysqld_dump_create_info(THD *thd, TABLE_LIST *table_list, int fd);
-+bool mysqld_show_create(THD *thd, TABLE_LIST *table_list);
-+bool mysqld_show_create_db(THD *thd, char *dbname, HA_CREATE_INFO *create);
-+
-+void mysqld_list_processes(THD *thd,const char *user,bool verbose);
-+int mysqld_show_status(THD *thd);
-+int mysqld_show_variables(THD *thd,const char *wild);
-+bool mysqld_show_storage_engines(THD *thd);
-+bool mysqld_show_privileges(THD *thd);
-+bool mysqld_show_column_types(THD *thd);
-+bool mysqld_help (THD *thd, const char *text);
-+void calc_sum_of_all_status(STATUS_VAR *to);
-+
-+void append_definer(THD *thd, String *buffer, const LEX_STRING *definer_user,
-+ const LEX_STRING *definer_host);
-+
-+
-+/* information schema */
-+extern LEX_STRING information_schema_name;
-+LEX_STRING *make_lex_string(THD *thd, LEX_STRING *lex_str,
-+ const char* str, uint length,
-+ bool allocate_lex_string);
-+ST_SCHEMA_TABLE *find_schema_table(THD *thd, const char* table_name);
-+ST_SCHEMA_TABLE *get_schema_table(enum enum_schema_tables schema_table_idx);
-+int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
-+ enum enum_schema_tables schema_table_idx);
-+int make_schema_select(THD *thd, SELECT_LEX *sel,
-+ enum enum_schema_tables schema_table_idx);
-+int mysql_schema_table(THD *thd, LEX *lex, TABLE_LIST *table_list);
-+int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
-+int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
-+int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
-+int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
-+bool get_schema_tables_result(JOIN *join,
-+ enum enum_schema_table_state executed_place);
-+#define is_schema_db(X) \
-+ !my_strcasecmp(system_charset_info, information_schema_name.str, (X))
-+
-+/* sql_prepare.cc */
-+
-+void mysql_stmt_prepare(THD *thd, const char *packet, uint packet_length);
-+void mysql_stmt_execute(THD *thd, char *packet, uint packet_length);
-+void mysql_stmt_close(THD *thd, char *packet);
-+void mysql_sql_stmt_prepare(THD *thd);
-+void mysql_sql_stmt_execute(THD *thd);
-+void mysql_sql_stmt_close(THD *thd);
-+void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length);
-+void mysql_stmt_reset(THD *thd, char *packet);
-+void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length);
-+void reinit_stmt_before_use(THD *thd, LEX *lex);
-+
-+/* sql_handler.cc */
-+bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen);
-+bool mysql_ha_close(THD *thd, TABLE_LIST *tables);
-+bool mysql_ha_read(THD *, TABLE_LIST *,enum enum_ha_read_modes,char *,
-+ List<Item> *,enum ha_rkey_function,Item *,ha_rows,ha_rows);
-+int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags,
-+ bool is_locked);
-+void mysql_ha_mark_tables_for_reopen(THD *thd, TABLE *table);
-+/* mysql_ha_flush mode_flags bits */
-+#define MYSQL_HA_CLOSE_FINAL 0x00
-+#define MYSQL_HA_REOPEN_ON_USAGE 0x01
-+#define MYSQL_HA_FLUSH_ALL 0x02
-+
-+/* sql_base.cc */
-+#define TMP_TABLE_KEY_EXTRA 8
-+void set_item_name(Item *item,char *pos,uint length);
-+bool add_field_to_list(THD *thd, char *field_name, enum enum_field_types type,
-+ char *length, char *decimal,
-+ uint type_modifier,
-+ Item *default_value, Item *on_update_value,
-+ LEX_STRING *comment,
-+ char *change, List<String> *interval_list,
-+ CHARSET_INFO *cs,
-+ uint uint_geom_type);
-+create_field * new_create_field(THD *thd, char *field_name, enum_field_types type,
-+ char *length, char *decimals,
-+ uint type_modifier,
-+ Item *default_value, Item *on_update_value,
-+ LEX_STRING *comment, char *change,
-+ List<String> *interval_list, CHARSET_INFO *cs,
-+ uint uint_geom_type);
-+void store_position_for_column(const char *name);
-+bool add_to_list(THD *thd, SQL_LIST &list,Item *group,bool asc);
-+bool push_new_name_resolution_context(THD *thd,
-+ TABLE_LIST *left_op,
-+ TABLE_LIST *right_op);
-+void add_join_on(TABLE_LIST *b,Item *expr);
-+void add_join_natural(TABLE_LIST *a,TABLE_LIST *b,List<String> *using_fields);
-+bool add_proc_to_list(THD *thd, Item *item);
-+TABLE *unlink_open_table(THD *thd,TABLE *list,TABLE *find);
-+void update_non_unique_table_error(TABLE_LIST *update,
-+ const char *operation,
-+ TABLE_LIST *duplicate);
-+
-+SQL_SELECT *make_select(TABLE *head, table_map const_tables,
-+ table_map read_tables, COND *conds,
-+ bool allow_null_cond, int *error);
-+extern Item **not_found_item;
-+Item ** find_item_in_list(Item *item, List<Item> &items, uint *counter,
-+ find_item_error_report_type report_error,
-+ bool *unaliased);
-+bool get_key_map_from_key_list(key_map *map, TABLE *table,
-+ List<String> *index_list);
-+bool insert_fields(THD *thd, Name_resolution_context *context,
-+ const char *db_name, const char *table_name,
-+ List_iterator<Item> *it, bool any_privileges);
-+bool setup_tables(THD *thd, Name_resolution_context *context,
-+ List<TABLE_LIST> *from_clause, TABLE_LIST *tables,
-+ Item **conds, TABLE_LIST **leaves, bool select_insert);
-+bool setup_tables_and_check_access (THD *thd,
-+ Name_resolution_context *context,
-+ List<TABLE_LIST> *from_clause,
-+ TABLE_LIST *tables, Item **conds,
-+ TABLE_LIST **leaves,
-+ bool select_insert,
-+ ulong want_access_first,
-+ ulong want_access);
-+int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
-+ List<Item> *sum_func_list, uint wild_num);
-+bool setup_fields(THD *thd, Item** ref_pointer_array,
-+ List<Item> &item, bool set_query_id,
-+ List<Item> *sum_func_list, bool allow_sum_func);
-+inline bool setup_fields_with_no_wrap(THD *thd, Item **ref_pointer_array,
-+ List<Item> &item, bool set_query_id,
-+ List<Item> *sum_func_list,
-+ bool allow_sum_func)
-+{
-+ bool res;
-+ thd->lex->select_lex.no_wrap_view_item= TRUE;
-+ res= setup_fields(thd, ref_pointer_array, item, set_query_id, sum_func_list,
-+ allow_sum_func);
-+ thd->lex->select_lex.no_wrap_view_item= FALSE;
-+ return res;
-+}
-+int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
-+ COND **conds);
-+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, uint flags);
-+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, uint flags);
-+int lock_tables(THD *thd, TABLE_LIST *tables, uint counter, bool *need_reopen);
-+TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
-+ const char *table_name, bool link_in_list);
-+bool rm_temporary_table(enum db_type base, char *path);
-+void free_io_cache(TABLE *entry);
-+void intern_close_table(TABLE *entry);
-+bool close_thread_table(THD *thd, TABLE **table_ptr);
-+void close_temporary_tables(THD *thd);
-+void close_tables_for_reopen(THD *thd, TABLE_LIST **tables);
-+TABLE_LIST *find_table_in_list(TABLE_LIST *table,
-+ st_table_list *TABLE_LIST::*link,
-+ const char *db_name,
-+ const char *table_name);
-+TABLE_LIST *unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list);
-+TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name);
-+bool close_temporary_table(THD *thd, const char *db, const char *table_name);
-+void close_temporary(TABLE *table, bool delete_table);
-+bool rename_temporary_table(THD* thd, TABLE *table, const char *new_db,
-+ const char *table_name);
-+void remove_db_from_cache(const char *db);
-+void flush_tables();
-+bool is_equal(const LEX_STRING *a, const LEX_STRING *b);
-+
-+/* bits for last argument to remove_table_from_cache() */
-+#define RTFC_NO_FLAG 0x0000
-+#define RTFC_OWNED_BY_THD_FLAG 0x0001
-+#define RTFC_WAIT_OTHER_THREAD_FLAG 0x0002
-+#define RTFC_CHECK_KILLED_FLAG 0x0004
-+bool remove_table_from_cache(THD *thd, const char *db, const char *table,
-+ uint flags);
-+
-+bool close_cached_tables(THD *thd, bool wait_for_refresh, TABLE_LIST *tables);
-+void copy_field_from_tmp_record(Field *field,int offset);
-+bool fill_record(THD *thd, Field **field, List<Item> &values,
-+ bool ignore_errors);
-+bool fill_record_n_invoke_before_triggers(THD *thd, List<Item> &fields,
-+ List<Item> &values,
-+ bool ignore_errors,
-+ Table_triggers_list *triggers,
-+ enum trg_event_type event);
-+bool fill_record_n_invoke_before_triggers(THD *thd, Field **field,
-+ List<Item> &values,
-+ bool ignore_errors,
-+ Table_triggers_list *triggers,
-+ enum trg_event_type event);
-+OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *db, const char *wild);
-+
-+inline TABLE_LIST *find_table_in_global_list(TABLE_LIST *table,
-+ const char *db_name,
-+ const char *table_name)
-+{
-+ return find_table_in_list(table, &TABLE_LIST::next_global,
-+ db_name, table_name);
-+}
-+
-+inline TABLE_LIST *find_table_in_local_list(TABLE_LIST *table,
-+ const char *db_name,
-+ const char *table_name)
-+{
-+ return find_table_in_list(table, &TABLE_LIST::next_local,
-+ db_name, table_name);
-+}
-+
-+
-+/* sql_calc.cc */
-+bool eval_const_cond(COND *cond);
-+
-+/* sql_load.cc */
-+bool mysql_load(THD *thd, sql_exchange *ex, TABLE_LIST *table_list,
-+ List<Item> &fields_vars, List<Item> &set_fields,
-+ List<Item> &set_values_list,
-+ enum enum_duplicates handle_duplicates, bool ignore,
-+ bool local_file);
-+int write_record(THD *thd, TABLE *table, COPY_INFO *info);
-+
-+/* sql_manager.cc */
-+/* bits set in manager_status */
-+#define MANAGER_BERKELEY_LOG_CLEANUP (1L << 0)
-+extern ulong volatile manager_status;
-+extern bool volatile manager_thread_in_use, mqh_used;
-+extern pthread_t manager_thread;
-+pthread_handler_t handle_manager(void *arg);
-+
-+/* sql_test.cc */
-+#ifndef DBUG_OFF
-+void print_where(COND *cond,const char *info);
-+void print_cached_tables(void);
-+void TEST_filesort(SORT_FIELD *sortorder,uint s_length);
-+void print_plan(JOIN* join,uint idx, double record_count, double read_time,
-+ double current_read_time, const char *info);
-+#endif
-+void mysql_print_status();
-+/* key.cc */
-+int find_ref_key(TABLE *form,Field *field, uint *offset);
-+void key_copy(byte *to_key, byte *from_record, KEY *key_info, uint key_length);
-+void key_restore(byte *to_record, byte *from_key, KEY *key_info,
-+ uint key_length);
-+bool key_cmp_if_same(TABLE *form,const byte *key,uint index,uint key_length);
-+void key_unpack(String *to,TABLE *form,uint index);
-+bool is_key_used(TABLE *table, uint idx, List<Item> &fields);
-+int key_cmp(KEY_PART_INFO *key_part, const byte *key, uint key_length);
-+
-+bool init_errmessage(void);
-+void sql_perror(const char *message);
-+
-+void vprint_msg_to_log(enum loglevel level, const char *format, va_list args);
-+void sql_print_error(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2);
-+void sql_print_warning(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2);
-+void sql_print_information(const char *format, ...)
-+ ATTRIBUTE_FORMAT(printf, 1, 2);
-+
-+
-+bool fn_format_relative_to_data_home(my_string to, const char *name,
-+ const char *dir, const char *extension);
-+File open_binlog(IO_CACHE *log, const char *log_file_name,
-+ const char **errmsg);
-+
-+/* mysqld.cc */
-+extern void MYSQLerror(const char*);
-+void refresh_status(THD *thd);
-+
-+/* item_func.cc */
-+extern bool check_reserved_words(LEX_STRING *name);
-+
-+/* strfunc.cc */
-+ulonglong find_set(TYPELIB *lib, const char *x, uint length, CHARSET_INFO *cs,
-+ char **err_pos, uint *err_len, bool *set_warning);
-+uint find_type(TYPELIB *lib, const char *find, uint length, bool part_match);
-+uint find_type2(TYPELIB *lib, const char *find, uint length, CHARSET_INFO *cs);
-+void unhex_type2(TYPELIB *lib);
-+uint check_word(TYPELIB *lib, const char *val, const char *end,
-+ const char **end_of_word);
-+
-+
-+bool is_keyword(const char *name, uint len);
-+
-+#define MY_DB_OPT_FILE "db.opt"
-+bool check_db_dir_existence(const char *db_name);
-+bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create);
-+bool load_db_opt_by_name(THD *thd, const char *db_name,
-+ HA_CREATE_INFO *db_create_info);
-+bool my_dbopt_init(void);
-+void my_dbopt_cleanup(void);
-+void my_dbopt_free(void);
-+
-+/*
-+ External variables
-+*/
-+
-+extern time_t start_time;
-+extern char *mysql_data_home,server_version[SERVER_VERSION_LENGTH],
-+ mysql_real_data_home[], *opt_mysql_tmpdir, mysql_charsets_dir[],
-+ def_ft_boolean_syntax[sizeof(ft_boolean_syntax)];
-+#define mysql_tmpdir (my_tmpdir(&mysql_tmpdir_list))
-+extern MY_TMPDIR mysql_tmpdir_list;
-+extern const char *command_name[];
-+extern const char *first_keyword, *my_localhost, *delayed_user, *binary_keyword;
-+extern const char **errmesg; /* Error messages */
-+extern const char *myisam_recover_options_str;
-+extern const char *in_left_expr_name, *in_additional_cond;
-+extern const char * const triggers_file_ext;
-+extern const char * const trigname_file_ext;
-+extern Eq_creator eq_creator;
-+extern Ne_creator ne_creator;
-+extern Gt_creator gt_creator;
-+extern Lt_creator lt_creator;
-+extern Ge_creator ge_creator;
-+extern Le_creator le_creator;
-+extern char language[FN_REFLEN], reg_ext[FN_EXTLEN];
-+extern char glob_hostname[FN_REFLEN], mysql_home[FN_REFLEN];
-+extern char pidfile_name[FN_REFLEN], system_time_zone[30], *opt_init_file;
-+extern char log_error_file[FN_REFLEN], *opt_tc_log_file;
-+extern double log_10[32];
-+extern ulonglong log_10_int[20];
-+extern ulonglong keybuff_size;
-+extern ulonglong thd_startup_options;
-+extern ulong refresh_version,flush_version, thread_id;
-+extern ulong binlog_cache_use, binlog_cache_disk_use;
-+extern ulong aborted_threads,aborted_connects;
-+extern ulong delayed_insert_timeout;
-+extern ulong delayed_insert_limit, delayed_queue_size;
-+extern ulong delayed_insert_threads, delayed_insert_writes;
-+extern ulong delayed_rows_in_use,delayed_insert_errors;
-+extern ulong slave_open_temp_tables;
-+extern ulong query_cache_size, query_cache_min_res_unit;
-+extern ulong slow_launch_threads, slow_launch_time;
-+extern ulong table_cache_size;
-+extern ulong max_connections,max_connect_errors, connect_timeout;
-+extern ulong slave_net_timeout, slave_trans_retries;
-+extern uint max_user_connections;
-+extern ulong what_to_log,flush_time;
-+extern ulong query_buff_size, thread_stack;
-+extern ulong max_prepared_stmt_count, prepared_stmt_count;
-+extern ulong binlog_cache_size, max_binlog_cache_size, open_files_limit;
-+extern ulong max_binlog_size, max_relay_log_size;
-+extern ulong rpl_recovery_rank, thread_cache_size;
-+extern ulong back_log;
-+extern ulong specialflag, current_pid;
-+extern ulong expire_logs_days, sync_binlog_period, sync_binlog_counter;
-+extern ulong opt_tc_log_size, tc_log_max_pages_used, tc_log_page_size;
-+extern ulong tc_log_page_waits;
-+extern my_bool relay_log_purge, opt_innodb_safe_binlog, opt_innodb;
-+extern uint test_flags,select_errors,ha_open_options;
-+extern uint protocol_version, mysqld_port, dropping_tables;
-+extern uint delay_key_write_options, lower_case_table_names;
-+extern bool opt_endinfo, using_udf_functions;
-+extern my_bool locked_in_memory;
-+extern bool opt_using_transactions, mysqld_embedded;
-+extern bool using_update_log, opt_large_files, server_id_supplied;
-+extern bool opt_log, opt_update_log, opt_bin_log, opt_slow_log, opt_error_log;
-+extern my_bool opt_log_queries_not_using_indexes;
-+extern bool opt_disable_networking, opt_skip_show_db;
-+extern my_bool opt_character_set_client_handshake;
-+extern bool volatile abort_loop, shutdown_in_progress, grant_option;
-+extern uint volatile thread_count, thread_running, global_read_lock;
-+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, opt_allow_suspicious_udfs;
-+extern my_bool opt_secure_auth;
-+extern my_bool opt_log_slow_admin_statements;
-+extern my_bool sp_automatic_privileges, opt_noacl;
-+extern my_bool opt_old_style_user_limits, trust_function_creators;
-+extern uint opt_crash_binlog_innodb;
-+extern char *shared_memory_base_name, *mysqld_unix_port;
-+extern my_bool opt_enable_shared_memory;
-+extern char *default_tz_name;
-+extern my_bool opt_large_pages;
-+extern uint opt_large_page_size;
-+
-+extern MYSQL_LOG mysql_log,mysql_slow_log,mysql_bin_log;
-+extern FILE *bootstrap_file;
-+extern int bootstrap_error;
-+extern FILE *stderror_file;
-+extern pthread_key(MEM_ROOT**,THR_MALLOC);
-+extern pthread_mutex_t LOCK_mysql_create_db,LOCK_Acl,LOCK_open,
-+ LOCK_thread_count,LOCK_mapped_file,LOCK_user_locks, LOCK_status,
-+ LOCK_error_log, LOCK_delayed_insert, LOCK_uuid_generator,
-+ LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_timezone,
-+ LOCK_slave_list, LOCK_active_mi, LOCK_manager, LOCK_global_read_lock,
-+ LOCK_global_system_variables, LOCK_user_conn,
-+ LOCK_prepared_stmt_count,
-+ LOCK_bytes_sent, LOCK_bytes_received;
-+#ifdef HAVE_OPENSSL
-+extern pthread_mutex_t LOCK_des_key_file;
-+#endif
-+extern rw_lock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave;
-+extern pthread_cond_t COND_refresh, COND_thread_count, COND_manager;
-+extern pthread_cond_t COND_global_read_lock;
-+extern pthread_attr_t connection_attrib;
-+extern I_List<THD> threads;
-+extern I_List<NAMED_LIST> key_caches;
-+extern MY_BITMAP temp_pool;
-+extern String my_empty_string;
-+extern const String my_null_string;
-+extern SHOW_VAR init_vars[],status_vars[], internal_vars[];
-+extern struct system_variables global_system_variables;
-+extern struct system_variables max_system_variables;
-+extern struct system_status_var global_status_var;
-+extern struct rand_struct sql_rand;
-+
-+extern const char *opt_date_time_formats[];
-+extern KNOWN_DATE_TIME_FORMAT known_date_time_formats[];
-+
-+extern String null_string;
-+extern HASH open_cache;
-+extern TABLE *unused_tables;
-+extern I_List<i_string> binlog_do_db, binlog_ignore_db;
-+extern const char* any_db;
-+extern struct my_option my_long_options[];
-+extern const LEX_STRING view_type;
-+
-+/* optional things, have_* variables */
-+
-+#ifdef HAVE_INNOBASE_DB
-+extern handlerton innobase_hton;
-+#define have_innodb innobase_hton.state
-+#else
-+extern SHOW_COMP_OPTION have_innodb;
-+#endif
-+#ifdef HAVE_BERKELEY_DB
-+extern handlerton berkeley_hton;
-+#define have_berkeley_db berkeley_hton.state
-+#else
-+extern SHOW_COMP_OPTION have_berkeley_db;
-+#endif
-+#ifdef HAVE_EXAMPLE_DB
-+extern handlerton example_hton;
-+#define have_example_db example_hton.state
-+#else
-+extern SHOW_COMP_OPTION have_example_db;
-+#endif
-+#ifdef HAVE_ARCHIVE_DB
-+extern handlerton archive_hton;
-+#define have_archive_db archive_hton.state
-+#else
-+extern SHOW_COMP_OPTION have_archive_db;
-+#endif
-+#ifdef HAVE_CSV_DB
-+extern handlerton tina_hton;
-+#define have_csv_db tina_hton.state
-+#else
-+extern SHOW_COMP_OPTION have_csv_db;
-+#endif
-+#ifdef HAVE_FEDERATED_DB
-+extern handlerton federated_hton;
-+#define have_federated_db federated_hton.state
-+#else
-+extern SHOW_COMP_OPTION have_federated_db;
-+#endif
-+#ifdef HAVE_BLACKHOLE_DB
-+extern handlerton blackhole_hton;
-+#define have_blackhole_db blackhole_hton.state
-+#else
-+extern SHOW_COMP_OPTION have_blackhole_db;
-+#endif
-+#ifdef HAVE_NDBCLUSTER_DB
-+extern handlerton ndbcluster_hton;
-+#define have_ndbcluster ndbcluster_hton.state
-+#else
-+extern SHOW_COMP_OPTION have_ndbcluster;
-+#endif
-+
-+/* MRG_MYISAM handler is always built, but may be skipped */
-+extern handlerton myisammrg_hton;
-+#define have_merge_db myisammrg_hton.state
-+
-+extern SHOW_COMP_OPTION have_isam;
-+extern SHOW_COMP_OPTION have_raid, have_openssl, have_symlink, have_dlopen;
-+extern SHOW_COMP_OPTION have_query_cache;
-+extern SHOW_COMP_OPTION have_geometry, have_rtree_keys;
-+extern SHOW_COMP_OPTION have_crypt;
-+extern SHOW_COMP_OPTION have_compress;
-+
-+#ifndef __WIN__
-+extern pthread_t signal_thread;
-+#endif
-+
-+#ifdef HAVE_OPENSSL
-+extern struct st_VioSSLFd * ssl_acceptor_fd;
-+#endif /* HAVE_OPENSSL */
-+
-+MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **table, uint count,
-+ uint flags, bool *need_reopen);
-+/* mysql_lock_tables() and open_table() flags bits */
-+#define MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK 0x0001
-+#define MYSQL_LOCK_IGNORE_FLUSH 0x0002
-+#define MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN 0x0004
-+#define MYSQL_OPEN_IGNORE_LOCKED_TABLES 0x0008
-+
-+void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock);
-+void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock);
-+void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count);
-+void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table);
-+void mysql_lock_abort(THD *thd, TABLE *table);
-+bool mysql_lock_abort_for_thread(THD *thd, TABLE *table);
-+MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b);
-+TABLE_LIST *mysql_lock_have_duplicate(THD *thd, TABLE_LIST *needle,
-+ TABLE_LIST *haystack);
-+bool lock_global_read_lock(THD *thd);
-+void unlock_global_read_lock(THD *thd);
-+bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh,
-+ bool is_not_commit);
-+void start_waiting_global_read_lock(THD *thd);
-+bool make_global_read_lock_block_commit(THD *thd);
-+bool set_protect_against_global_read_lock(void);
-+void unset_protect_against_global_read_lock(void);
-+void broadcast_refresh(void);
-+
-+/* Lock based on name */
-+int lock_and_wait_for_table_name(THD *thd, TABLE_LIST *table_list);
-+int lock_table_name(THD *thd, TABLE_LIST *table_list);
-+void unlock_table_name(THD *thd, TABLE_LIST *table_list);
-+bool wait_for_locked_table_names(THD *thd, TABLE_LIST *table_list);
-+bool lock_table_names(THD *thd, TABLE_LIST *table_list);
-+void unlock_table_names(THD *thd, TABLE_LIST *table_list,
-+ TABLE_LIST *last_table);
-+
-+
-+/* old unireg functions */
-+
-+void unireg_init(ulong options);
-+void unireg_end(void);
-+bool mysql_create_frm(THD *thd, my_string file_name,
-+ const char *db, const char *table,
-+ HA_CREATE_INFO *create_info,
-+ List<create_field> &create_field,
-+ uint key_count,KEY *key_info,handler *db_type);
-+int rea_create_table(THD *thd, my_string file_name,
-+ const char *db, const char *table,
-+ HA_CREATE_INFO *create_info,
-+ List<create_field> &create_field,
-+ uint key_count,KEY *key_info);
-+int format_number(uint inputflag,uint max_length,my_string pos,uint length,
-+ my_string *errpos);
-+int openfrm(THD *thd, const char *name,const char *alias,uint filestat,
-+ uint prgflag, uint ha_open_flags, TABLE *outparam);
-+int readfrm(const char *name, const void** data, uint* length);
-+int writefrm(const char* name, const void* data, uint len);
-+int closefrm(TABLE *table);
-+int read_string(File file, gptr *to, uint length);
-+void free_blobs(TABLE *table);
-+int set_zone(int nr,int min_zone,int max_zone);
-+ulong convert_period_to_month(ulong period);
-+ulong convert_month_to_period(ulong month);
-+void get_date_from_daynr(long daynr,uint *year, uint *month,
-+ uint *day);
-+my_time_t TIME_to_timestamp(THD *thd, const TIME *t, my_bool *not_exist);
-+bool str_to_time_with_warn(const char *str,uint length,TIME *l_time);
-+timestamp_type str_to_datetime_with_warn(const char *str, uint length,
-+ TIME *l_time, uint flags);
-+void localtime_to_TIME(TIME *to, struct tm *from);
-+void calc_time_from_sec(TIME *to, long seconds, long microseconds);
-+
-+void make_truncated_value_warning(THD *thd, const char *str_val,
-+ uint str_length, timestamp_type time_type,
-+ const char *field_name);
-+extern DATE_TIME_FORMAT *date_time_format_make(timestamp_type format_type,
-+ const char *format_str,
-+ uint format_length);
-+extern DATE_TIME_FORMAT *date_time_format_copy(THD *thd,
-+ DATE_TIME_FORMAT *format);
-+const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format,
-+ timestamp_type type);
-+extern bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time,
-+ timestamp_type type, String *str);
-+void make_datetime(const DATE_TIME_FORMAT *format, const TIME *l_time,
-+ String *str);
-+void make_date(const DATE_TIME_FORMAT *format, const TIME *l_time,
-+ String *str);
-+void make_time(const DATE_TIME_FORMAT *format, const TIME *l_time,
-+ String *str);
-+
-+int test_if_number(char *str,int *res,bool allow_wildcards);
-+void change_byte(byte *,uint,char,char);
-+void init_read_record(READ_RECORD *info, THD *thd, TABLE *reg_form,
-+ SQL_SELECT *select,
-+ int use_record_cache, bool print_errors);
-+void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table,
-+ bool print_error, uint idx);
-+void end_read_record(READ_RECORD *info);
-+ha_rows filesort(THD *thd, TABLE *form,struct st_sort_field *sortorder,
-+ uint s_length, SQL_SELECT *select,
-+ ha_rows max_rows, ha_rows *examined_rows);
-+void filesort_free_buffers(TABLE *table, bool full);
-+void change_double_for_sort(double nr,byte *to);
-+double my_double_round(double value, int dec, bool truncate);
-+int get_quick_record(SQL_SELECT *select);
-+int calc_weekday(long daynr,bool sunday_first_day_of_week);
-+uint calc_week(TIME *l_time, uint week_behaviour, uint *year);
-+void find_date(char *pos,uint *vek,uint flag);
-+TYPELIB *convert_strings_to_array_type(my_string *typelibs, my_string *end);
-+TYPELIB *typelib(MEM_ROOT *mem_root, List<String> &strings);
-+ulong get_form_pos(File file, uchar *head, TYPELIB *save_names);
-+ulong make_new_entry(File file,uchar *fileinfo,TYPELIB *formnames,
-+ const char *newname);
-+ulong next_io_size(ulong pos);
-+void append_unescaped(String *res, const char *pos, uint length);
-+int create_frm(THD *thd, char *name, const char *db, const char *table,
-+ uint reclength,uchar *fileinfo,
-+ HA_CREATE_INFO *create_info, uint keys);
-+void update_create_info_from_table(HA_CREATE_INFO *info, TABLE *form);
-+int rename_file_ext(const char * from,const char * to,const char * ext);
-+bool check_db_name(char *db);
-+bool check_column_name(const char *name);
-+bool check_table_name(const char *name, uint length);
-+char *get_field(MEM_ROOT *mem, Field *field);
-+bool get_field(MEM_ROOT *mem, Field *field, class String *res);
-+int wild_case_compare(CHARSET_INFO *cs, const char *str,const char *wildstr);
-+
-+/* from hostname.cc */
-+struct in_addr;
-+my_string ip_to_hostname(struct in_addr *in,uint *errors);
-+void inc_host_errors(struct in_addr *in);
-+void reset_host_errors(struct in_addr *in);
-+bool hostname_cache_init();
-+void hostname_cache_free();
-+void hostname_cache_refresh(void);
-+
-+/* sql_cache.cc */
-+extern bool sql_cache_init();
-+extern void sql_cache_free();
-+extern int sql_cache_hit(THD *thd, char *inBuf, uint length);
-+
-+/* item_func.cc */
-+Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name,
-+ LEX_STRING component);
-+int get_var_with_binlog(THD *thd, enum_sql_command sql_command,
-+ LEX_STRING &name, user_var_entry **out_entry);
-+/* log.cc */
-+bool flush_error_log(void);
-+
-+/* sql_list.cc */
-+void free_list(I_List <i_string_pair> *list);
-+void free_list(I_List <i_string> *list);
-+
-+/* sql_yacc.cc */
-+extern int MYSQLparse(void *thd);
-+#ifndef DBUG_OFF
-+extern void turn_parser_debug_on();
-+#endif
-+
-+/* frm_crypt.cc */
-+#ifdef HAVE_CRYPTED_FRM
-+SQL_CRYPT *get_crypt_for_frm(void);
-+#endif
-+
-+#include "sql_view.h"
-+
-+/* Some inline functions for more speed */
-+
-+inline bool add_item_to_list(THD *thd, Item *item)
-+{
-+ return thd->lex->current_select->add_item_to_list(thd, item);
-+}
-+
-+inline bool add_value_to_list(THD *thd, Item *value)
-+{
-+ return thd->lex->value_list.push_back(value);
-+}
-+
-+inline bool add_order_to_list(THD *thd, Item *item, bool asc)
-+{
-+ return thd->lex->current_select->add_order_to_list(thd, item, asc);
-+}
-+
-+inline bool add_group_to_list(THD *thd, Item *item, bool asc)
-+{
-+ return thd->lex->current_select->add_group_to_list(thd, item, asc);
-+}
-+
-+inline void mark_as_null_row(TABLE *table)
-+{
-+ table->null_row=1;
-+ table->status|=STATUS_NULL_ROW;
-+ bfill(table->null_flags,table->s->null_bytes,255);
-+}
-+
-+inline void table_case_convert(char * name, uint length)
-+{
-+ if (lower_case_table_names)
-+ files_charset_info->cset->casedn(files_charset_info,
-+ name, length, name, length);
-+}
-+
-+inline const char *table_case_name(HA_CREATE_INFO *info, const char *name)
-+{
-+ return ((lower_case_table_names == 2 && info->alias) ? info->alias : name);
-+}
-+
-+inline ulong sql_rnd_with_mutex()
-+{
-+ pthread_mutex_lock(&LOCK_thread_count);
-+ ulong tmp=(ulong) (my_rnd(&sql_rand) * 0xffffffff); /* make all bits random */
-+ pthread_mutex_unlock(&LOCK_thread_count);
-+ return tmp;
-+}
-+
-+Comp_creator *comp_eq_creator(bool invert);
-+Comp_creator *comp_ge_creator(bool invert);
-+Comp_creator *comp_gt_creator(bool invert);
-+Comp_creator *comp_le_creator(bool invert);
-+Comp_creator *comp_lt_creator(bool invert);
-+Comp_creator *comp_ne_creator(bool invert);
-+
-+Item * all_any_subquery_creator(Item *left_expr,
-+ chooser_compare_func_creator cmp,
-+ bool all,
-+ SELECT_LEX *select_lex);
-+
-+/*
-+ clean/setup table fields and map
-+
-+ SYNOPSYS
-+ setup_table_map()
-+ table - TABLE structure pointer (which should be setup)
-+ table_list TABLE_LIST structure pointer (owner of TABLE)
-+ tablenr - table number
-+*/
-+
-+inline void setup_table_map(TABLE *table, TABLE_LIST *table_list, uint tablenr)
-+{
-+ table->used_fields= 0;
-+ table->const_table= 0;
-+ table->null_row= 0;
-+ table->status= STATUS_NO_RECORD;
-+ table->keys_in_use_for_query= table->s->keys_in_use;
-+ table->maybe_null= table_list->outer_join;
-+ TABLE_LIST *embedding= table_list->embedding;
-+ while (!table->maybe_null && embedding)
-+ {
-+ table->maybe_null= embedding->outer_join;
-+ embedding= embedding->embedding;
-+ }
-+ table->tablenr= tablenr;
-+ table->map= (table_map) 1 << tablenr;
-+ table->force_index= table_list->force_index;
-+}
-+
-+
-+/*
-+ SYNOPSYS
-+ hexchar_to_int()
-+ convert a hex digit into number
-+*/
-+
-+inline int hexchar_to_int(char c)
-+{
-+ if (c <= '9' && c >= '0')
-+ return c-'0';
-+ c|=32;
-+ if (c <= 'f' && c >= 'a')
-+ return c-'a'+10;
-+ return -1;
-+}
-+
-+/*
-+ is_user_table()
-+ return true if the table was created explicitly
-+*/
-+
-+inline bool is_user_table(TABLE * table)
-+{
-+ const char *name= table->s->table_name;
-+ return strncmp(name, tmp_file_prefix, tmp_file_prefix_length);
-+}
-+
-+/*
-+ Some functions that are different in the embedded library and the normal
-+ server
-+*/
-+
-+#ifndef EMBEDDED_LIBRARY
-+extern "C" void unireg_abort(int exit_code);
-+void kill_delayed_threads(void);
-+bool check_stack_overrun(THD *thd, long margin, char *dummy);
-+#else
-+#define unireg_abort(exit_code) DBUG_RETURN(exit_code)
-+inline void kill_delayed_threads(void) {}
-+#define check_stack_overrun(A, B, C) 0
-+#endif
-+
-+#endif /* MYSQL_CLIENT */
-diff -urNad mysql-5.0-etch~/sql/sql_parse.cc mysql-5.0-etch/sql/sql_parse.cc
---- mysql-5.0-etch~/sql/sql_parse.cc 2007-05-28 18:56:15.000000000 +0200
-+++ mysql-5.0-etch/sql/sql_parse.cc 2007-05-28 19:12:52.000000000 +0200
-@@ -2213,7 +2213,8 @@
- enum enum_schema_tables schema_table_idx)
- {
- DBUG_ENTER("prepare_schema_table");
-- SELECT_LEX *sel= 0;
-+ SELECT_LEX *schema_select_lex= NULL;
-+
- switch (schema_table_idx) {
- case SCH_SCHEMATA:
- #if defined(DONT_ALLOW_SHOW_COMMANDS)
-@@ -2221,11 +2222,9 @@
- ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
- DBUG_RETURN(1);
- #else
-- if ((specialflag & SPECIAL_SKIP_SHOW_DB) &&
-- check_global_access(thd, SHOW_DB_ACL))
-- DBUG_RETURN(1);
- break;
- #endif
-+
- case SCH_TABLE_NAMES:
- case SCH_TABLES:
- case SCH_VIEWS:
-@@ -2235,32 +2234,25 @@
- ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
- DBUG_RETURN(1);
- #else
-+ if (lex->select_lex.db == NULL &&
-+ thd->copy_db_to(&lex->select_lex.db, NULL))
- {
-- char *db;
-- if (lex->select_lex.db == NULL &&
-- thd->copy_db_to(&lex->select_lex.db, 0))
-- {
-- DBUG_RETURN(1);
-- }
-- db= lex->select_lex.db;
-- remove_escape(db); // Fix escaped '_'
-- if (check_db_name(db))
-- {
-- my_error(ER_WRONG_DB_NAME, MYF(0), db);
-- DBUG_RETURN(1);
-- }
-- if (check_access(thd, SELECT_ACL, db, &thd->col_access, 0, 0,
-- is_schema_db(db)))
-- DBUG_RETURN(1); /* purecov: inspected */
-- if (!thd->col_access && check_grant_db(thd,db))
-- {
-- my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
-- thd->security_ctx->priv_user, thd->security_ctx->priv_host,
-- db);
-- DBUG_RETURN(1);
-- }
-- break;
-+ DBUG_RETURN(1);
-+ }
-+
-+ schema_select_lex= new SELECT_LEX();
-+ schema_select_lex->db= lex->select_lex.db;
-+ schema_select_lex->table_list.first= NULL;
-+ remove_escape(schema_select_lex->db); // Fix escaped '_'
-+
-+ if (check_db_name(schema_select_lex->db))
-+ {
-+ my_error(ER_WRONG_DB_NAME, MYF(0), schema_select_lex->db);
-+ DBUG_RETURN(1);
- }
-+
-+
-+ break;
- #endif
- case SCH_COLUMNS:
- case SCH_STATISTICS:
-@@ -2269,28 +2261,23 @@
- ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
- DBUG_RETURN(1);
- #else
-- if (table_ident)
- {
-+ DBUG_ASSERT(table_ident);
-+
- TABLE_LIST **query_tables_last= lex->query_tables_last;
-- sel= new SELECT_LEX();
-+ schema_select_lex= new SELECT_LEX();
- /* 'parent_lex' is used in init_query() so it must be before it. */
-- sel->parent_lex= lex;
-- sel->init_query();
-- if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ,
-- (List<String> *) 0, (List<String> *) 0))
-+ schema_select_lex->parent_lex= lex;
-+ schema_select_lex->init_query();
-+ if (!schema_select_lex->add_table_to_list(thd, table_ident, 0, 0, TL_READ,
-+ (List<String> *) 0, (List<String> *) 0))
- DBUG_RETURN(1);
- lex->query_tables_last= query_tables_last;
-- TABLE_LIST *table_list= (TABLE_LIST*) sel->table_list.first;
-- char *db= table_list->db;
-- remove_escape(db); // Fix escaped '_'
-- remove_escape(table_list->table_name);
-- if (check_access(thd,SELECT_ACL | EXTRA_ACL,db,
-- &table_list->grant.privilege, 0, 0,
-- test(table_list->schema_table)))
-- DBUG_RETURN(1); /* purecov: inspected */
-- if (grant_option && check_grant(thd, SELECT_ACL, table_list, 2,
-- UINT_MAX, 0))
-- DBUG_RETURN(1);
-+
-+ TABLE_LIST *dst_table= (TABLE_LIST*) schema_select_lex->table_list.first;
-+ remove_escape(dst_table->db); // Fix escaped '_'
-+ remove_escape(dst_table->table_name);
-+
- break;
- }
- #endif
-@@ -2317,7 +2304,7 @@
- DBUG_RETURN(1);
- }
- TABLE_LIST *table_list= (TABLE_LIST*) select_lex->table_list.first;
-- table_list->schema_select_lex= sel;
-+ table_list->schema_select_lex= schema_select_lex;
- table_list->schema_table_reformed= 1;
- statistic_increment(thd->status_var.com_stat[lex->orig_sql_command],
- &LOCK_status);
-@@ -5272,6 +5259,83 @@
- }
-
-
-+static bool check_show_access(THD *thd, TABLE_LIST *table)
-+{
-+ switch (get_schema_table_idx(table->schema_table))
-+ {
-+ case SCH_SCHEMATA:
-+ return (specialflag & SPECIAL_SKIP_SHOW_DB) &&
-+ check_global_access(thd, SHOW_DB_ACL);
-+
-+ case SCH_TABLE_NAMES:
-+ case SCH_TABLES:
-+ case SCH_VIEWS:
-+ case SCH_TRIGGERS:
-+ {
-+ const char *dst_db_name= table->schema_select_lex->db;
-+
-+ DBUG_ASSERT(dst_db_name);
-+
-+ if (check_access(thd, SELECT_ACL, dst_db_name,
-+ &thd->col_access, FALSE, FALSE,
-+ is_schema_db(dst_db_name)))
-+ {
-+ return TRUE;
-+ }
-+
-+ if (!thd->col_access && check_grant_db(thd, dst_db_name))
-+ {
-+ my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
-+ thd->security_ctx->priv_user,
-+ thd->security_ctx->priv_host,
-+ dst_db_name);
-+ return TRUE;
-+ }
-+
-+ return FALSE;
-+ }
-+
-+ case SCH_COLUMNS:
-+ case SCH_STATISTICS:
-+ {
-+ TABLE_LIST *dst_table=
-+ (TABLE_LIST *) table->schema_select_lex->table_list.first;
-+
-+ DBUG_ASSERT(dst_table);
-+
-+ if (check_access(thd, SELECT_ACL | EXTRA_ACL,
-+ dst_table->db,
-+ &dst_table->grant.privilege,
-+ FALSE, FALSE,
-+ test(dst_table->schema_table)))
-+ {
-+ return FALSE;
-+ }
-+
-+ return grant_option &&
-+ check_grant(thd, SELECT_ACL, dst_table, 2, UINT_MAX, FALSE);
-+ }
-+
-+ case SCH_OPEN_TABLES:
-+ case SCH_VARIABLES:
-+ case SCH_STATUS:
-+ case SCH_PROCEDURES:
-+ case SCH_CHARSETS:
-+ case SCH_COLLATIONS:
-+ case SCH_COLLATION_CHARACTER_SET_APPLICABILITY:
-+ case SCH_USER_PRIVILEGES:
-+ case SCH_SCHEMA_PRIVILEGES:
-+ case SCH_TABLE_PRIVILEGES:
-+ case SCH_COLUMN_PRIVILEGES:
-+ case SCH_TABLE_CONSTRAINTS:
-+ case SCH_KEY_COLUMN_USAGE:
-+ break;
-+ }
-+
-+ return FALSE;
-+}
-+
-+
- /*
- Check the privilege for all used tables.
-
-@@ -5330,7 +5394,16 @@
- Remove SHOW_VIEW_ACL, because it will be checked during making view
- */
- tables->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL);
-- if (tables->derived || tables->schema_table ||
-+
-+ if (tables->schema_table_reformed)
-+ {
-+ if (check_show_access(thd, tables))
-+ goto deny;
-+
-+ continue;
-+ }
-+
-+ if (tables->derived ||
- (tables->table && (int)tables->table->s->tmp_table) ||
- my_tz_check_n_skip_implicit_tables(&tables,
- thd->lex->time_zone_tables_used))
-diff -urNad mysql-5.0-etch~/sql/sql_parse.cc.orig mysql-5.0-etch/sql/sql_parse.cc.orig
---- mysql-5.0-etch~/sql/sql_parse.cc.orig 1970-01-01 01:00:00.000000000 +0100
-+++ mysql-5.0-etch/sql/sql_parse.cc.orig 2007-05-28 18:56:15.000000000 +0200
-@@ -0,0 +1,7572 @@
-+/* Copyright (C) 2000-2003 MySQL AB
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License as published by
-+ the Free Software Foundation; either version 2 of the License, or
-+ (at your option) any later version.
-+
-+ This program is distributed in the hope that it will be useful,
-+ but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ GNU General Public License for more details.
-+
-+ You should have received a copy of the GNU General Public License
-+ along with this program; if not, write to the Free Software
-+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-+
-+#define MYSQL_LEX 1
-+#include "mysql_priv.h"
-+#include "sql_repl.h"
-+#include "repl_failsafe.h"
-+#include <m_ctype.h>
-+#include <myisam.h>
-+#include <my_dir.h>
-+
-+#ifdef HAVE_INNOBASE_DB
-+#include "ha_innodb.h"
-+#endif
-+
-+#ifdef HAVE_NDBCLUSTER_DB
-+#include "ha_ndbcluster.h"
-+#endif
-+
-+#include "sp_head.h"
-+#include "sp.h"
-+#include "sp_cache.h"
-+
-+#ifdef HAVE_OPENSSL
-+/*
-+ Without SSL the handshake consists of one packet. This packet
-+ has both client capabilites and scrambled password.
-+ With SSL the handshake might consist of two packets. If the first
-+ packet (client capabilities) has CLIENT_SSL flag set, we have to
-+ switch to SSL and read the second packet. The scrambled password
-+ is in the second packet and client_capabilites field will be ignored.
-+ Maybe it is better to accept flags other than CLIENT_SSL from the
-+ second packet?
-+*/
-+#define SSL_HANDSHAKE_SIZE 2
-+#define NORMAL_HANDSHAKE_SIZE 6
-+#define MIN_HANDSHAKE_SIZE 2
-+#else
-+#define MIN_HANDSHAKE_SIZE 6
-+#endif /* HAVE_OPENSSL */
-+
-+/* Used in error handling only */
-+#define SP_TYPE_STRING(LP) \
-+ ((LP)->sphead->m_type == TYPE_ENUM_FUNCTION ? "FUNCTION" : "PROCEDURE")
-+#define SP_COM_STRING(LP) \
-+ ((LP)->sql_command == SQLCOM_CREATE_SPFUNCTION || \
-+ (LP)->sql_command == SQLCOM_ALTER_FUNCTION || \
-+ (LP)->sql_command == SQLCOM_SHOW_CREATE_FUNC || \
-+ (LP)->sql_command == SQLCOM_DROP_FUNCTION ? \
-+ "FUNCTION" : "PROCEDURE")
-+
-+#ifdef SOLARIS
-+extern "C" int gethostname(char *name, int namelen);
-+#endif
-+
-+static void time_out_user_resource_limits(THD *thd, USER_CONN *uc);
-+#ifndef NO_EMBEDDED_ACCESS_CHECKS
-+static int check_for_max_user_connections(THD *thd, USER_CONN *uc);
-+static void decrease_user_connections(USER_CONN *uc);
-+#endif /* NO_EMBEDDED_ACCESS_CHECKS */
-+static bool check_db_used(THD *thd,TABLE_LIST *tables);
-+static bool check_multi_update_lock(THD *thd);
-+static void remove_escape(char *name);
-+static bool append_file_to_dir(THD *thd, const char **filename_ptr,
-+ const char *table_name);
-+
-+const char *any_db="*any*"; // Special symbol for check_access
-+
-+const char *command_name[]={
-+ "Sleep", "Quit", "Init DB", "Query", "Field List", "Create DB",
-+ "Drop DB", "Refresh", "Shutdown", "Statistics", "Processlist",
-+ "Connect","Kill","Debug","Ping","Time","Delayed insert","Change user",
-+ "Binlog Dump","Table Dump", "Connect Out", "Register Slave",
-+ "Prepare", "Execute", "Long Data", "Close stmt",
-+ "Reset stmt", "Set option", "Fetch",
-+ "Error" // Last command number
-+};
-+
-+const char *xa_state_names[]={
-+ "NON-EXISTING", "ACTIVE", "IDLE", "PREPARED"
-+};
-+
-+#ifdef __WIN__
-+static void test_signal(int sig_ptr)
-+{
-+#if !defined( DBUG_OFF)
-+ MessageBox(NULL,"Test signal","DBUG",MB_OK);
-+#endif
-+#if defined(OS2)
-+ fprintf(stderr, "Test signal %d\n", sig_ptr);
-+ fflush(stderr);
-+#endif
-+}
-+static void init_signals(void)
-+{
-+ int signals[7] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGBREAK,SIGABRT } ;
-+ for (int i=0 ; i < 7 ; i++)
-+ signal( signals[i], test_signal) ;
-+}
-+#endif
-+
-+static void unlock_locked_tables(THD *thd)
-+{
-+ if (thd->locked_tables)
-+ {
-+ thd->lock=thd->locked_tables;
-+ thd->locked_tables=0; // Will be automatically closed
-+ close_thread_tables(thd); // Free tables
-+ }
-+}
-+
-+
-+static bool end_active_trans(THD *thd)
-+{
-+ int error=0;
-+ DBUG_ENTER("end_active_trans");
-+ if (unlikely(thd->in_sub_stmt))
-+ {
-+ my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
-+ DBUG_RETURN(1);
-+ }
-+ if (thd->transaction.xid_state.xa_state != XA_NOTR)
-+ {
-+ my_error(ER_XAER_RMFAIL, MYF(0),
-+ xa_state_names[thd->transaction.xid_state.xa_state]);
-+ DBUG_RETURN(1);
-+ }
-+ if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN |
-+ OPTION_TABLE_LOCK))
-+ {
-+ DBUG_PRINT("info",("options: 0x%lx", (ulong) thd->options));
-+ /* Safety if one did "drop table" on locked tables */
-+ if (!thd->locked_tables)
-+ thd->options&= ~OPTION_TABLE_LOCK;
-+ thd->server_status&= ~SERVER_STATUS_IN_TRANS;
-+ if (ha_commit(thd))
-+ error=1;
-+ thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
-+ }
-+ DBUG_RETURN(error);
-+}
-+
-+static bool begin_trans(THD *thd)
-+{
-+ int error=0;
-+ if (unlikely(thd->in_sub_stmt))
-+ {
-+ my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
-+ return 1;
-+ }
-+ if (thd->locked_tables)
-+ {
-+ thd->lock=thd->locked_tables;
-+ thd->locked_tables=0; // Will be automatically closed
-+ close_thread_tables(thd); // Free tables
-+ }
-+ if (end_active_trans(thd))
-+ error= -1;
-+ else
-+ {
-+ LEX *lex= thd->lex;
-+ thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) |
-+ OPTION_BEGIN);
-+ thd->server_status|= SERVER_STATUS_IN_TRANS;
-+ if (lex->start_transaction_opt & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT)
-+ error= ha_start_consistent_snapshot(thd);
-+ }
-+ return error;
-+}
-+
-+#ifdef HAVE_REPLICATION
-+/*
-+ Returns true if all tables should be ignored
-+*/
-+inline bool all_tables_not_ok(THD *thd, TABLE_LIST *tables)
-+{
-+ return table_rules_on && tables && !tables_ok(thd,tables);
-+}
-+#endif
-+
-+
-+static bool some_non_temp_table_to_be_updated(THD *thd, TABLE_LIST *tables)
-+{
-+ for (TABLE_LIST *table= tables; table; table= table->next_global)
-+ {
-+ DBUG_ASSERT(table->db && table->table_name);
-+ if (table->updating &&
-+ !find_temporary_table(thd, table->db, table->table_name))
-+ return 1;
-+ }
-+ return 0;
-+}
-+
-+#ifndef NO_EMBEDDED_ACCESS_CHECKS
-+static HASH hash_user_connections;
-+
-+static int get_or_create_user_conn(THD *thd, const char *user,
-+ const char *host,
-+ USER_RESOURCES *mqh)
-+{
-+ int return_val= 0;
-+ uint temp_len, user_len;
-+ char temp_user[USER_HOST_BUFF_SIZE];
-+ struct user_conn *uc;
-+
-+ DBUG_ASSERT(user != 0);
-+ DBUG_ASSERT(host != 0);
-+
-+ user_len= strlen(user);
-+ temp_len= (strmov(strmov(temp_user, user)+1, host) - temp_user)+1;
-+ (void) pthread_mutex_lock(&LOCK_user_conn);
-+ if (!(uc = (struct user_conn *) hash_search(&hash_user_connections,
-+ (byte*) temp_user, temp_len)))
-+ {
-+ /* First connection for user; Create a user connection object */
-+ if (!(uc= ((struct user_conn*)
-+ my_malloc(sizeof(struct user_conn) + temp_len+1,
-+ MYF(MY_WME)))))
-+ {
-+ net_send_error(thd, 0, NullS); // Out of memory
-+ return_val= 1;
-+ goto end;
-+ }
-+ uc->user=(char*) (uc+1);
-+ memcpy(uc->user,temp_user,temp_len+1);
-+ uc->host= uc->user + user_len + 1;
-+ uc->len= temp_len;
-+ uc->connections= uc->questions= uc->updates= uc->conn_per_hour= 0;
-+ uc->user_resources= *mqh;
-+ uc->intime= thd->thr_create_time;
-+ if (my_hash_insert(&hash_user_connections, (byte*) uc))
-+ {
-+ my_free((char*) uc,0);
-+ net_send_error(thd, 0, NullS); // Out of memory
-+ return_val= 1;
-+ goto end;
-+ }
-+ }
-+ thd->user_connect=uc;
-+ uc->connections++;
-+end:
-+ (void) pthread_mutex_unlock(&LOCK_user_conn);
-+ return return_val;
-+
-+}
-+#endif /* !NO_EMBEDDED_ACCESS_CHECKS */
-+
-+
-+/*
-+ Check if user exist and password supplied is correct.
-+
-+ SYNOPSIS
-+ check_user()
-+ thd thread handle, thd->security_ctx->{host,user,ip} are used
-+ command originator of the check: now check_user is called
-+ during connect and change user procedures; used for
-+ logging.
-+ passwd scrambled password received from client
-+ passwd_len length of scrambled password
-+ db database name to connect to, may be NULL
-+ check_count dont know exactly
-+
-+ Note, that host, user and passwd may point to communication buffer.
-+ Current implementation does not depend on that, but future changes
-+ should be done with this in mind; 'thd' is INOUT, all other params
-+ are 'IN'.
-+
-+ RETURN VALUE
-+ 0 OK; thd->security_ctx->user/master_access/priv_user/db_access and
-+ thd->db are updated; OK is sent to client;
-+ -1 access denied or handshake error; error is sent to client;
-+ >0 error, not sent to client
-+*/
-+
-+int check_user(THD *thd, enum enum_server_command command,
-+ const char *passwd, uint passwd_len, const char *db,
-+ bool check_count)
-+{
-+ DBUG_ENTER("check_user");
-+
-+#ifdef NO_EMBEDDED_ACCESS_CHECKS
-+ thd->main_security_ctx.master_access= GLOBAL_ACLS; // Full rights
-+ /* Change database if necessary */
-+ if (db && db[0])
-+ {
-+ /*
-+ thd->db is saved in caller and needs to be freed by caller if this
-+ function returns 0
-+ */
-+ thd->reset_db(NULL, 0);
-+ if (mysql_change_db(thd, db, FALSE))
-+ {
-+ /* Send the error to the client */
-+ net_send_error(thd);
-+ DBUG_RETURN(-1);
-+ }
-+ }
-+ send_ok(thd);
-+ DBUG_RETURN(0);
-+#else
-+
-+ my_bool opt_secure_auth_local;
-+ pthread_mutex_lock(&LOCK_global_system_variables);
-+ opt_secure_auth_local= opt_secure_auth;
-+ pthread_mutex_unlock(&LOCK_global_system_variables);
-+
-+ /*
-+ If the server is running in secure auth mode, short scrambles are
-+ forbidden.
-+ */
-+ if (opt_secure_auth_local && passwd_len == SCRAMBLE_LENGTH_323)
-+ {
-+ net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE);
-+ mysql_log.write(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
-+ DBUG_RETURN(-1);
-+ }
-+ if (passwd_len != 0 &&
-+ passwd_len != SCRAMBLE_LENGTH &&
-+ passwd_len != SCRAMBLE_LENGTH_323)
-+ DBUG_RETURN(ER_HANDSHAKE_ERROR);
-+
-+ /*
-+ Clear thd->db as it points to something, that will be freed when
-+ connection is closed. We don't want to accidentally free a wrong pointer
-+ if connect failed. Also in case of 'CHANGE USER' failure, current
-+ database will be switched to 'no database selected'.
-+ */
-+ thd->reset_db(NULL, 0);
-+
-+ USER_RESOURCES ur;
-+ int res= acl_getroot(thd, &ur, passwd, passwd_len);
-+#ifndef EMBEDDED_LIBRARY
-+ if (res == -1)
-+ {
-+ /*
-+ This happens when client (new) sends password scrambled with
-+ scramble(), but database holds old value (scrambled with
-+ scramble_323()). Here we please client to send scrambled_password
-+ in old format.
-+ */
-+ NET *net= &thd->net;
-+ if (opt_secure_auth_local)
-+ {
-+ net_printf_error(thd, ER_SERVER_IS_IN_SECURE_AUTH_MODE,
-+ thd->main_security_ctx.user,
-+ thd->main_security_ctx.host_or_ip);
-+ mysql_log.write(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE),
-+ thd->main_security_ctx.user,
-+ thd->main_security_ctx.host_or_ip);
-+ DBUG_RETURN(-1);
-+ }
-+ /* We have to read very specific packet size */
-+ if (send_old_password_request(thd) ||
-+ my_net_read(net) != SCRAMBLE_LENGTH_323 + 1)
-+ {
-+ inc_host_errors(&thd->remote.sin_addr);
-+ DBUG_RETURN(ER_HANDSHAKE_ERROR);
-+ }
-+ /* Final attempt to check the user based on reply */
-+ /* So as passwd is short, errcode is always >= 0 */
-+ res= acl_getroot(thd, &ur, (char *) net->read_pos, SCRAMBLE_LENGTH_323);
-+ }
-+#endif /*EMBEDDED_LIBRARY*/
-+ /* here res is always >= 0 */
-+ if (res == 0)
-+ {
-+ if (!(thd->main_security_ctx.master_access &
-+ NO_ACCESS)) // authentication is OK
-+ {
-+ DBUG_PRINT("info",
-+ ("Capabilities: %lu packet_length: %ld Host: '%s' "
-+ "Login user: '%s' Priv_user: '%s' Using password: %s "
-+ "Access: %lu db: '%s'",
-+ thd->client_capabilities,
-+ thd->max_client_packet_length,
-+ thd->main_security_ctx.host_or_ip,
-+ thd->main_security_ctx.user,
-+ thd->main_security_ctx.priv_user,
-+ passwd_len ? "yes": "no",
-+ thd->main_security_ctx.master_access,
-+ (thd->db ? thd->db : "*none*")));
-+
-+ if (check_count)
-+ {
-+ VOID(pthread_mutex_lock(&LOCK_thread_count));
-+ bool count_ok= thread_count <= max_connections + delayed_insert_threads
-+ || (thd->main_security_ctx.master_access & SUPER_ACL);
-+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
-+ if (!count_ok)
-+ { // too many connections
-+ net_send_error(thd, ER_CON_COUNT_ERROR);
-+ DBUG_RETURN(-1);
-+ }
-+ }
-+
-+ /* Why logging is performed before all checks've passed? */
-+ mysql_log.write(thd, command,
-+ (thd->main_security_ctx.priv_user ==
-+ thd->main_security_ctx.user ?
-+ (char*) "%s@%s on %s" :
-+ (char*) "%s@%s as anonymous on %s"),
-+ thd->main_security_ctx.user,
-+ thd->main_security_ctx.host_or_ip,
-+ db ? db : (char*) "");
-+
-+ /*
-+ This is the default access rights for the current database. It's
-+ set to 0 here because we don't have an active database yet (and we
-+ may not have an active database to set.
-+ */
-+ thd->main_security_ctx.db_access=0;
-+
-+ /* Don't allow user to connect if he has done too many queries */
-+ if ((ur.questions || ur.updates || ur.conn_per_hour || ur.user_conn ||
-+ max_user_connections) &&
-+ get_or_create_user_conn(thd,
-+ (opt_old_style_user_limits ? thd->main_security_ctx.user :
-+ thd->main_security_ctx.priv_user),
-+ (opt_old_style_user_limits ? thd->main_security_ctx.host_or_ip :
-+ thd->main_security_ctx.priv_host),
-+ &ur))
-+ DBUG_RETURN(-1);
-+ if (thd->user_connect &&
-+ (thd->user_connect->user_resources.conn_per_hour ||
-+ thd->user_connect->user_resources.user_conn ||
-+ max_user_connections) &&
-+ check_for_max_user_connections(thd, thd->user_connect))
-+ DBUG_RETURN(-1);
-+
-+ /* Change database if necessary */
-+ if (db && db[0])
-+ {
-+ if (mysql_change_db(thd, db, FALSE))
-+ {
-+ /* Send error to the client */
-+ net_send_error(thd);
-+ if (thd->user_connect)
-+ decrease_user_connections(thd->user_connect);
-+ DBUG_RETURN(-1);
-+ }
-+ }
-+ send_ok(thd);
-+ thd->password= test(passwd_len); // remember for error messages
-+ /* Ready to handle queries */
-+ DBUG_RETURN(0);
-+ }
-+ }
-+ else if (res == 2) // client gave short hash, server has long hash
-+ {
-+ net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE);
-+ mysql_log.write(thd,COM_CONNECT,ER(ER_NOT_SUPPORTED_AUTH_MODE));
-+ DBUG_RETURN(-1);
-+ }
-+ net_printf_error(thd, ER_ACCESS_DENIED_ERROR,
-+ thd->main_security_ctx.user,
-+ thd->main_security_ctx.host_or_ip,
-+ passwd_len ? ER(ER_YES) : ER(ER_NO));
-+ mysql_log.write(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR),
-+ thd->main_security_ctx.user,
-+ thd->main_security_ctx.host_or_ip,
-+ passwd_len ? ER(ER_YES) : ER(ER_NO));
-+ DBUG_RETURN(-1);
-+#endif /* NO_EMBEDDED_ACCESS_CHECKS */
-+}
-+
-+/*
-+ Check for maximum allowable user connections, if the mysqld server is
-+ started with corresponding variable that is greater then 0.
-+*/
-+
-+extern "C" byte *get_key_conn(user_conn *buff, uint *length,
-+ my_bool not_used __attribute__((unused)))
-+{
-+ *length=buff->len;
-+ return (byte*) buff->user;
-+}
-+
-+extern "C" void free_user(struct user_conn *uc)
-+{
-+ my_free((char*) uc,MYF(0));
-+}
-+
-+void init_max_user_conn(void)
-+{
-+#ifndef NO_EMBEDDED_ACCESS_CHECKS
-+ (void) hash_init(&hash_user_connections,system_charset_info,max_connections,
-+ 0,0,
-+ (hash_get_key) get_key_conn, (hash_free_key) free_user,
-+ 0);
-+#endif
-+}
-+
-+
-+/*
-+ check if user has already too many connections
-+
-+ SYNOPSIS
-+ check_for_max_user_connections()
-+ thd Thread handle
-+ uc User connect object
-+
-+ NOTES
-+ If check fails, we decrease user connection count, which means one
-+ shouldn't call decrease_user_connections() after this function.
-+
-+ RETURN
-+ 0 ok
-+ 1 error
-+*/
-+
-+#ifndef NO_EMBEDDED_ACCESS_CHECKS
-+
-+static int check_for_max_user_connections(THD *thd, USER_CONN *uc)
-+{
-+ int error=0;
-+ DBUG_ENTER("check_for_max_user_connections");
-+
-+ (void) pthread_mutex_lock(&LOCK_user_conn);
-+ if (max_user_connections && !uc->user_resources.user_conn &&
-+ max_user_connections < (uint) uc->connections)
-+ {
-+ net_printf_error(thd, ER_TOO_MANY_USER_CONNECTIONS, uc->user);
-+ error=1;
-+ goto end;
-+ }
-+ time_out_user_resource_limits(thd, uc);
-+ if (uc->user_resources.user_conn &&
-+ uc->user_resources.user_conn < uc->connections)
-+ {
-+ net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user,
-+ "max_user_connections",
-+ (long) uc->user_resources.user_conn);
-+ error= 1;
-+ goto end;
-+ }
-+ if (uc->user_resources.conn_per_hour &&
-+ uc->user_resources.conn_per_hour <= uc->conn_per_hour)
-+ {
-+ net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user,
-+ "max_connections_per_hour",
-+ (long) uc->user_resources.conn_per_hour);
-+ error=1;
-+ goto end;
-+ }
-+ uc->conn_per_hour++;
-+
-+ end:
-+ if (error)
-+ uc->connections--; // no need for decrease_user_connections() here
-+ (void) pthread_mutex_unlock(&LOCK_user_conn);
-+ DBUG_RETURN(error);
-+}
-+
-+/*
-+ Decrease user connection count
-+
-+ SYNOPSIS
-+ decrease_user_connections()
-+ uc User connection object
-+
-+ NOTES
-+ If there is a n user connection object for a connection
-+ (which only happens if 'max_user_connections' is defined or
-+ if someone has created a resource grant for a user), then
-+ the connection count is always incremented on connect.
-+
-+ The user connect object is not freed if some users has
-+ 'max connections per hour' defined as we need to be able to hold
-+ count over the lifetime of the connection.
-+*/
-+
-+static void decrease_user_connections(USER_CONN *uc)
-+{
-+ DBUG_ENTER("decrease_user_connections");
-+ (void) pthread_mutex_lock(&LOCK_user_conn);
-+ DBUG_ASSERT(uc->connections);
-+ if (!--uc->connections && !mqh_used)
-+ {
-+ /* Last connection for user; Delete it */
-+ (void) hash_delete(&hash_user_connections,(byte*) uc);
-+ }
-+ (void) pthread_mutex_unlock(&LOCK_user_conn);
-+ DBUG_VOID_RETURN;
-+}
-+
-+#endif /* NO_EMBEDDED_ACCESS_CHECKS */
-+
-+
-+void free_max_user_conn(void)
-+{
-+#ifndef NO_EMBEDDED_ACCESS_CHECKS
-+ hash_free(&hash_user_connections);
-+#endif /* NO_EMBEDDED_ACCESS_CHECKS */
-+}
-+
-+
-+
-+/*
-+ Mark all commands that somehow changes a table
-+ This is used to check number of updates / hour
-+
-+ sql_command is actually set to SQLCOM_END sometimes
-+ so we need the +1 to include it in the array.
-+
-+ numbers are:
-+ 0 - read-only query
-+ != 0 - query that may change a table
-+ 2 - query that returns meaningful ROW_COUNT() -
-+ a number of modified rows
-+*/
-+
-+char uc_update_queries[SQLCOM_END+1];
-+
-+void init_update_queries(void)
-+{
-+ bzero((gptr) &uc_update_queries, sizeof(uc_update_queries));
-+
-+ uc_update_queries[SQLCOM_CREATE_TABLE]=1;
-+ uc_update_queries[SQLCOM_CREATE_INDEX]=1;
-+ uc_update_queries[SQLCOM_ALTER_TABLE]=1;
-+ uc_update_queries[SQLCOM_UPDATE]=2;
-+ uc_update_queries[SQLCOM_UPDATE_MULTI]=2;
-+ uc_update_queries[SQLCOM_INSERT]=2;
-+ uc_update_queries[SQLCOM_INSERT_SELECT]=2;
-+ uc_update_queries[SQLCOM_DELETE]=2;
-+ uc_update_queries[SQLCOM_DELETE_MULTI]=2;
-+ uc_update_queries[SQLCOM_TRUNCATE]=1;
-+ uc_update_queries[SQLCOM_DROP_TABLE]=1;
-+ uc_update_queries[SQLCOM_LOAD]=1;
-+ uc_update_queries[SQLCOM_CREATE_DB]=1;
-+ uc_update_queries[SQLCOM_DROP_DB]=1;
-+ uc_update_queries[SQLCOM_REPLACE]=2;
-+ uc_update_queries[SQLCOM_REPLACE_SELECT]=2;
-+ uc_update_queries[SQLCOM_RENAME_TABLE]=1;
-+ uc_update_queries[SQLCOM_BACKUP_TABLE]=1;
-+ uc_update_queries[SQLCOM_RESTORE_TABLE]=1;
-+ uc_update_queries[SQLCOM_DROP_INDEX]=1;
-+ uc_update_queries[SQLCOM_CREATE_VIEW]=1;
-+ uc_update_queries[SQLCOM_DROP_VIEW]=1;
-+}
-+
-+bool is_update_query(enum enum_sql_command command)
-+{
-+ DBUG_ASSERT(command >= 0 && command <= SQLCOM_END);
-+ return uc_update_queries[command] != 0;
-+}
-+
-+/*
-+ Reset per-hour user resource limits when it has been more than
-+ an hour since they were last checked
-+
-+ SYNOPSIS:
-+ time_out_user_resource_limits()
-+ thd Thread handler
-+ uc User connection details
-+
-+ NOTE:
-+ This assumes that the LOCK_user_conn mutex has been acquired, so it is
-+ safe to test and modify members of the USER_CONN structure.
-+*/
-+
-+static void time_out_user_resource_limits(THD *thd, USER_CONN *uc)
-+{
-+ time_t check_time = thd->start_time ? thd->start_time : time(NULL);
-+ DBUG_ENTER("time_out_user_resource_limits");
-+
-+ /* If more than a hour since last check, reset resource checking */
-+ if (check_time - uc->intime >= 3600)
-+ {
-+ uc->questions=1;
-+ uc->updates=0;
-+ uc->conn_per_hour=0;
-+ uc->intime=check_time;
-+ }
-+
-+ DBUG_VOID_RETURN;
-+}
-+
-+
-+/*
-+ Check if maximum queries per hour limit has been reached
-+ returns 0 if OK.
-+*/
-+
-+static bool check_mqh(THD *thd, uint check_command)
-+{
-+#ifndef NO_EMBEDDED_ACCESS_CHECKS
-+ bool error= 0;
-+ USER_CONN *uc=thd->user_connect;
-+ DBUG_ENTER("check_mqh");
-+ DBUG_ASSERT(uc != 0);
-+
-+ (void) pthread_mutex_lock(&LOCK_user_conn);
-+
-+ time_out_user_resource_limits(thd, uc);
-+
-+ /* Check that we have not done too many questions / hour */
-+ if (uc->user_resources.questions &&
-+ uc->questions++ >= uc->user_resources.questions)
-+ {
-+ net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_questions",
-+ (long) uc->user_resources.questions);
-+ error=1;
-+ goto end;
-+ }
-+ if (check_command < (uint) SQLCOM_END)
-+ {
-+ /* Check that we have not done too many updates / hour */
-+ if (uc->user_resources.updates && uc_update_queries[check_command] &&
-+ uc->updates++ >= uc->user_resources.updates)
-+ {
-+ net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_updates",
-+ (long) uc->user_resources.updates);
-+ error=1;
-+ goto end;
-+ }
-+ }
-+end:
-+ (void) pthread_mutex_unlock(&LOCK_user_conn);
-+ DBUG_RETURN(error);
-+#else
-+ return (0);
-+#endif /* NO_EMBEDDED_ACCESS_CHECKS */
-+}
-+
-+
-+static void reset_mqh(LEX_USER *lu, bool get_them= 0)
-+{
-+#ifndef NO_EMBEDDED_ACCESS_CHECKS
-+ (void) pthread_mutex_lock(&LOCK_user_conn);
-+ if (lu) // for GRANT
-+ {
-+ USER_CONN *uc;
-+ uint temp_len=lu->user.length+lu->host.length+2;
-+ char temp_user[USER_HOST_BUFF_SIZE];
-+
-+ memcpy(temp_user,lu->user.str,lu->user.length);
-+ memcpy(temp_user+lu->user.length+1,lu->host.str,lu->host.length);
-+ temp_user[lu->user.length]='\0'; temp_user[temp_len-1]=0;
-+ if ((uc = (struct user_conn *) hash_search(&hash_user_connections,
-+ (byte*) temp_user, temp_len)))
-+ {
-+ uc->questions=0;
-+ get_mqh(temp_user,&temp_user[lu->user.length+1],uc);
-+ uc->updates=0;
-+ uc->conn_per_hour=0;
-+ }
-+ }
-+ else
-+ {
-+ /* for FLUSH PRIVILEGES and FLUSH USER_RESOURCES */
-+ for (uint idx=0;idx < hash_user_connections.records; idx++)
-+ {
-+ USER_CONN *uc=(struct user_conn *) hash_element(&hash_user_connections,
-+ idx);
-+ if (get_them)
-+ get_mqh(uc->user,uc->host,uc);
-+ uc->questions=0;
-+ uc->updates=0;
-+ uc->conn_per_hour=0;
-+ }
-+ }
-+ (void) pthread_mutex_unlock(&LOCK_user_conn);
-+#endif /* NO_EMBEDDED_ACCESS_CHECKS */
-+}
-+
-+void thd_init_client_charset(THD *thd, uint cs_number)
-+{
-+ /*
-+ Use server character set and collation if
-+ - opt_character_set_client_handshake is not set
-+ - client has not specified a character set
-+ - client character set is the same as the servers
-+ - client character set doesn't exists in server
-+ */
-+ if (!opt_character_set_client_handshake ||
-+ !(thd->variables.character_set_client= get_charset(cs_number, MYF(0))) ||
-+ !my_strcasecmp(&my_charset_latin1,
-+ global_system_variables.character_set_client->name,
-+ thd->variables.character_set_client->name))
-+ {
-+ thd->variables.character_set_client=
-+ global_system_variables.character_set_client;
-+ thd->variables.collation_connection=
-+ global_system_variables.collation_connection;
-+ thd->variables.character_set_results=
-+ global_system_variables.character_set_results;
-+ }
-+ else
-+ {
-+ thd->variables.character_set_results=
-+ thd->variables.collation_connection=
-+ thd->variables.character_set_client;
-+ }
-+}
-+
-+
-+/*
-+ Perform handshake, authorize client and update thd ACL variables.
-+ SYNOPSIS
-+ check_connection()
-+ thd thread handle
-+
-+ RETURN
-+ 0 success, OK is sent to user, thd is updated.
-+ -1 error, which is sent to user
-+ > 0 error code (not sent to user)
-+*/
-+
-+#ifndef EMBEDDED_LIBRARY
-+static int check_connection(THD *thd)
-+{
-+ uint connect_errors= 0;
-+ NET *net= &thd->net;
-+ ulong pkt_len= 0;
-+ char *end;
-+
-+ DBUG_PRINT("info",
-+ ("New connection received on %s", vio_description(net->vio)));
-+#ifdef SIGNAL_WITH_VIO_CLOSE
-+ thd->set_active_vio(net->vio);
-+#endif
-+
-+ if (!thd->main_security_ctx.host) // If TCP/IP connection
-+ {
-+ char ip[30];
-+
-+ if (vio_peer_addr(net->vio, ip, &thd->peer_port))
-+ return (ER_BAD_HOST_ERROR);
-+ if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(0))))
-+ return (ER_OUT_OF_RESOURCES);
-+ thd->main_security_ctx.host_or_ip= thd->main_security_ctx.ip;
-+ vio_in_addr(net->vio,&thd->remote.sin_addr);
-+ if (!(specialflag & SPECIAL_NO_RESOLVE))
-+ {
-+ vio_in_addr(net->vio,&thd->remote.sin_addr);
-+ thd->main_security_ctx.host=
-+ ip_to_hostname(&thd->remote.sin_addr, &connect_errors);
-+ /* Cut very long hostnames to avoid possible overflows */
-+ if (thd->main_security_ctx.host)
-+ {
-+ if (thd->main_security_ctx.host != my_localhost)
-+ thd->main_security_ctx.host[min(strlen(thd->main_security_ctx.host),
-+ HOSTNAME_LENGTH)]= 0;
-+ thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host;
-+ }
-+ if (connect_errors > max_connect_errors)
-+ return(ER_HOST_IS_BLOCKED);
-+ }
-+ DBUG_PRINT("info",("Host: %s ip: %s",
-+ (thd->main_security_ctx.host ?
-+ thd->main_security_ctx.host : "unknown host"),
-+ (thd->main_security_ctx.ip ?
-+ thd->main_security_ctx.ip : "unknown ip")));
-+ if (acl_check_host(thd->main_security_ctx.host, thd->main_security_ctx.ip))
-+ return(ER_HOST_NOT_PRIVILEGED);
-+ }
-+ else /* Hostname given means that the connection was on a socket */
-+ {
-+ DBUG_PRINT("info",("Host: %s", thd->main_security_ctx.host));
-+ thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host;
-+ thd->main_security_ctx.ip= 0;
-+ /* Reset sin_addr */
-+ bzero((char*) &thd->remote, sizeof(thd->remote));
-+ }
-+ vio_keepalive(net->vio, TRUE);
-+ {
-+ /* buff[] needs to big enough to hold the server_version variable */
-+ char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64];
-+ ulong client_flags = (CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB |
-+ CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION);
-+
-+ if (opt_using_transactions)
-+ client_flags|=CLIENT_TRANSACTIONS;
-+#ifdef HAVE_COMPRESS
-+ client_flags |= CLIENT_COMPRESS;
-+#endif /* HAVE_COMPRESS */
-+#ifdef HAVE_OPENSSL
-+ if (ssl_acceptor_fd)
-+ client_flags |= CLIENT_SSL; /* Wow, SSL is available! */
-+#endif /* HAVE_OPENSSL */
-+
-+ end= strnmov(buff, server_version, SERVER_VERSION_LENGTH) + 1;
-+ int4store((uchar*) end, thd->thread_id);
-+ end+= 4;
-+ /*
-+ So as check_connection is the only entry point to authorization
-+ procedure, scramble is set here. This gives us new scramble for
-+ each handshake.
-+ */
-+ create_random_string(thd->scramble, SCRAMBLE_LENGTH, &thd->rand);
-+ /*
-+ Old clients does not understand long scrambles, but can ignore packet
-+ tail: that's why first part of the scramble is placed here, and second
-+ part at the end of packet.
-+ */
-+ end= strmake(end, thd->scramble, SCRAMBLE_LENGTH_323) + 1;
-+
-+ int2store(end, client_flags);
-+ /* write server characteristics: up to 16 bytes allowed */
-+ end[2]=(char) default_charset_info->number;
-+ int2store(end+3, thd->server_status);
-+ bzero(end+5, 13);
-+ end+= 18;
-+ /* write scramble tail */
-+ end= strmake(end, thd->scramble + SCRAMBLE_LENGTH_323,
-+ SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323) + 1;
-+
-+ /* At this point we write connection message and read reply */
-+ if (net_write_command(net, (uchar) protocol_version, "", 0, buff,
-+ (uint) (end-buff)) ||
-+ (pkt_len= my_net_read(net)) == packet_error ||
-+ pkt_len < MIN_HANDSHAKE_SIZE)
-+ {
-+ inc_host_errors(&thd->remote.sin_addr);
-+ return(ER_HANDSHAKE_ERROR);
-+ }
-+ }
-+#ifdef _CUSTOMCONFIG_
-+#include "_cust_sql_parse.h"
-+#endif
-+ if (connect_errors)
-+ reset_host_errors(&thd->remote.sin_addr);
-+ if (thd->packet.alloc(thd->variables.net_buffer_length))
-+ return(ER_OUT_OF_RESOURCES);
-+
-+ thd->client_capabilities=uint2korr(net->read_pos);
-+ if (thd->client_capabilities & CLIENT_PROTOCOL_41)
-+ {
-+ thd->client_capabilities|= ((ulong) uint2korr(net->read_pos+2)) << 16;
-+ thd->max_client_packet_length= uint4korr(net->read_pos+4);
-+ DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8]));
-+ thd_init_client_charset(thd, (uint) net->read_pos[8]);
-+ thd->update_charset();
-+ end= (char*) net->read_pos+32;
-+ }
-+ else
-+ {
-+ thd->max_client_packet_length= uint3korr(net->read_pos+2);
-+ end= (char*) net->read_pos+5;
-+ }
-+
-+ if (thd->client_capabilities & CLIENT_IGNORE_SPACE)
-+ thd->variables.sql_mode|= MODE_IGNORE_SPACE;
-+#ifdef HAVE_OPENSSL
-+ DBUG_PRINT("info", ("client capabilities: %lu", thd->client_capabilities));
-+ if (thd->client_capabilities & CLIENT_SSL)
-+ {
-+ /* Do the SSL layering. */
-+ if (!ssl_acceptor_fd)
-+ {
-+ inc_host_errors(&thd->remote.sin_addr);
-+ return(ER_HANDSHAKE_ERROR);
-+ }
-+ DBUG_PRINT("info", ("IO layer change in progress..."));
-+ if (sslaccept(ssl_acceptor_fd, net->vio, thd->variables.net_wait_timeout))
-+ {
-+ DBUG_PRINT("error", ("Failed to accept new SSL connection"));
-+ inc_host_errors(&thd->remote.sin_addr);
-+ return(ER_HANDSHAKE_ERROR);
-+ }
-+ DBUG_PRINT("info", ("Reading user information over SSL layer"));
-+ if ((pkt_len= my_net_read(net)) == packet_error ||
-+ pkt_len < NORMAL_HANDSHAKE_SIZE)
-+ {
-+ DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
-+ pkt_len));
-+ inc_host_errors(&thd->remote.sin_addr);
-+ return(ER_HANDSHAKE_ERROR);
-+ }
-+ }
-+#endif
-+
-+ if (end >= (char*) net->read_pos+ pkt_len +2)
-+ {
-+ inc_host_errors(&thd->remote.sin_addr);
-+ return(ER_HANDSHAKE_ERROR);
-+ }
-+
-+ if (thd->client_capabilities & CLIENT_INTERACTIVE)
-+ thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
-+ if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
-+ opt_using_transactions)
-+ net->return_status= &thd->server_status;
-+ net->read_timeout=(uint) thd->variables.net_read_timeout;
-+
-+ char *user= end;
-+ char *passwd= strend(user)+1;
-+ uint user_len= passwd - user - 1;
-+ char *db= passwd;
-+ char db_buff[NAME_LEN + 1]; // buffer to store db in utf8
-+ char user_buff[USERNAME_LENGTH + 1]; // buffer to store user in utf8
-+ uint dummy_errors;
-+
-+ /*
-+ Old clients send null-terminated string as password; new clients send
-+ the size (1 byte) + string (not null-terminated). Hence in case of empty
-+ password both send '\0'.
-+ */
-+ uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
-+ *passwd++ : strlen(passwd);
-+ db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ?
-+ db + passwd_len + 1 : 0;
-+ uint db_len= db ? strlen(db) : 0;
-+
-+ if (passwd + passwd_len + db_len > (char *)net->read_pos + pkt_len)
-+ {
-+ inc_host_errors(&thd->remote.sin_addr);
-+ return ER_HANDSHAKE_ERROR;
-+ }
-+
-+ /* Since 4.1 all database names are stored in utf8 */
-+ if (db)
-+ {
-+ db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
-+ system_charset_info,
-+ db, db_len,
-+ thd->charset(), &dummy_errors)]= 0;
-+ db= db_buff;
-+ }
-+
-+ user_buff[user_len= copy_and_convert(user_buff, sizeof(user_buff)-1,
-+ system_charset_info, user, user_len,
-+ thd->charset(), &dummy_errors)]= '\0';
-+ user= user_buff;
-+
-+ /* If username starts and ends in "'", chop them off */
-+ if (user_len > 1 && user[0] == '\'' && user[user_len - 1] == '\'')
-+ {
-+ user[user_len-1]= 0;
-+ user++;
-+ user_len-= 2;
-+ }
-+
-+ if (thd->main_security_ctx.user)
-+ x_free(thd->main_security_ctx.user);
-+ if (!(thd->main_security_ctx.user= my_strdup(user, MYF(0))))
-+ return (ER_OUT_OF_RESOURCES);
-+ return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE);
-+}
-+
-+
-+void execute_init_command(THD *thd, sys_var_str *init_command_var,
-+ rw_lock_t *var_mutex)
-+{
-+ Vio* save_vio;
-+ ulong save_client_capabilities;
-+
-+ thd->proc_info= "Execution of init_command";
-+ /*
-+ We need to lock init_command_var because
-+ during execution of init_command_var query
-+ values of init_command_var can't be changed
-+ */
-+ rw_rdlock(var_mutex);
-+ thd->query= init_command_var->value;
-+ thd->query_length= init_command_var->value_length;
-+ save_client_capabilities= thd->client_capabilities;
-+ thd->client_capabilities|= CLIENT_MULTI_QUERIES;
-+ /*
-+ We don't need return result of execution to client side.
-+ To forbid this we should set thd->net.vio to 0.
-+ */
-+ save_vio= thd->net.vio;
-+ thd->net.vio= 0;
-+ thd->net.no_send_error= 0;
-+ dispatch_command(COM_QUERY, thd, thd->query, thd->query_length+1);
-+ rw_unlock(var_mutex);
-+ thd->client_capabilities= save_client_capabilities;
-+ thd->net.vio= save_vio;
-+}
-+
-+
-+pthread_handler_t handle_one_connection(void *arg)
-+{
-+ THD *thd=(THD*) arg;
-+ uint launch_time =
-+ (uint) ((thd->thr_create_time = time(NULL)) - thd->connect_time);
-+ if (launch_time >= slow_launch_time)
-+ statistic_increment(slow_launch_threads,&LOCK_status );
-+
-+ pthread_detach_this_thread();
-+
-+#if !defined( __WIN__) && !defined(OS2) // Win32 calls this in pthread_create
-+ /* The following calls needs to be done before we call DBUG_ macros */
-+ if (!(test_flags & TEST_NO_THREADS) & my_thread_init())
-+ {
-+ close_connection(thd, ER_OUT_OF_RESOURCES, 1);
-+ statistic_increment(aborted_connects,&LOCK_status);
-+ end_thread(thd,0);
-+ return 0;
-+ }
-+#endif
-+
-+ /*
-+ handle_one_connection() is the only way a thread would start
-+ and would always be on top of the stack, therefore, the thread
-+ stack always starts at the address of the first local variable
-+ of handle_one_connection, which is thd. We need to know the
-+ start of the stack so that we could check for stack overruns.
-+ */
-+ DBUG_PRINT("info", ("handle_one_connection called by thread %lu\n",
-+ thd->thread_id));
-+ /* now that we've called my_thread_init(), it is safe to call DBUG_* */
-+
-+#if defined(__WIN__)
-+ init_signals();
-+#elif !defined(OS2) && !defined(__NETWARE__)
-+ sigset_t set;
-+ VOID(sigemptyset(&set)); // Get mask in use
-+ VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
-+#endif
-+ thd->thread_stack= (char*) &thd;
-+ if (thd->store_globals())
-+ {
-+ close_connection(thd, ER_OUT_OF_RESOURCES, 1);
-+ statistic_increment(aborted_connects,&LOCK_status);
-+ end_thread(thd,0);
-+ return 0;
-+ }
-+
-+ do
-+ {
-+ int error;
-+ NET *net= &thd->net;
-+ Security_context *sctx= thd->security_ctx;
-+ net->no_send_error= 0;
-+
-+ if ((error=check_connection(thd)))
-+ { // Wrong permissions
-+ if (error > 0)
-+ net_printf_error(thd, error, sctx->host_or_ip);
-+#ifdef __NT__
-+ if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE)
-+ my_sleep(1000); /* must wait after eof() */
-+#endif
-+ statistic_increment(aborted_connects,&LOCK_status);
-+ goto end_thread;
-+ }
-+#ifdef __NETWARE__
-+ netware_reg_user(sctx->ip, sctx->user, "MySQL");
-+#endif
-+ if (thd->variables.max_join_size == HA_POS_ERROR)
-+ thd->options |= OPTION_BIG_SELECTS;
-+ if (thd->client_capabilities & CLIENT_COMPRESS)
-+ net->compress=1; // Use compression
-+
-+ thd->version= refresh_version;
-+ thd->proc_info= 0;
-+ thd->command= COM_SLEEP;
-+ thd->set_time();
-+ thd->init_for_queries();
-+
-+ if (sys_init_connect.value_length && !(sctx->master_access & SUPER_ACL))
-+ {
-+ execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect);
-+ if (thd->query_error)
-+ {
-+ thd->killed= THD::KILL_CONNECTION;
-+ sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
-+ thd->thread_id,(thd->db ? thd->db : "unconnected"),
-+ sctx->user ? sctx->user : "unauthenticated",
-+ sctx->host_or_ip, "init_connect command failed");
-+ sql_print_warning("%s", net->last_error);
-+ }
-+ thd->proc_info=0;
-+ thd->set_time();
-+ thd->init_for_queries();
-+ }
-+
-+ while (!net->error && net->vio != 0 &&
-+ !(thd->killed == THD::KILL_CONNECTION))
-+ {
-+ net->no_send_error= 0;
-+ if (do_command(thd))
-+ break;
-+ }
-+ if (thd->user_connect)
-+ decrease_user_connections(thd->user_connect);
-+ if (net->error && net->vio != 0 && net->report_error)
-+ {
-+ if (!thd->killed && thd->variables.log_warnings > 1)
-+ sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
-+ thd->thread_id,(thd->db ? thd->db : "unconnected"),
-+ sctx->user ? sctx->user : "unauthenticated",
-+ sctx->host_or_ip,
-+ (net->last_errno ? ER(net->last_errno) :
-+ ER(ER_UNKNOWN_ERROR)));
-+ net_send_error(thd, net->last_errno, NullS);
-+ statistic_increment(aborted_threads,&LOCK_status);
-+ }
-+ else if (thd->killed)
-+ {
-+ statistic_increment(aborted_threads,&LOCK_status);
-+ }
-+
-+end_thread:
-+ close_connection(thd, 0, 1);
-+ end_thread(thd,1);
-+ /*
-+ If end_thread returns, we are either running with --one-thread
-+ or this thread has been schedule to handle the next query
-+ */
-+ thd= current_thd;
-+ thd->thread_stack= (char*) &thd;
-+ } while (!(test_flags & TEST_NO_THREADS));
-+ /* The following is only executed if we are not using --one-thread */
-+ return(0); /* purecov: deadcode */
-+}
-+
-+#endif /* EMBEDDED_LIBRARY */
-+
-+/*
-+ Execute commands from bootstrap_file.
-+ Used when creating the initial grant tables
-+*/
-+
-+pthread_handler_t handle_bootstrap(void *arg)
-+{
-+ THD *thd=(THD*) arg;
-+ FILE *file=bootstrap_file;
-+ char *buff;
-+
-+ /* The following must be called before DBUG_ENTER */
-+ thd->thread_stack= (char*) &thd;
-+ if (my_thread_init() || thd->store_globals())
-+ {
-+#ifndef EMBEDDED_LIBRARY
-+ close_connection(thd, ER_OUT_OF_RESOURCES, 1);
-+#endif
-+ thd->fatal_error();
-+ goto end;
-+ }
-+ DBUG_ENTER("handle_bootstrap");
-+
-+#ifndef EMBEDDED_LIBRARY
-+ pthread_detach_this_thread();
-+ thd->thread_stack= (char*) &thd;
-+#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
-+ sigset_t set;
-+ VOID(sigemptyset(&set)); // Get mask in use
-+ VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
-+#endif
-+#endif /* EMBEDDED_LIBRARY */
-+
-+ if (thd->variables.max_join_size == HA_POS_ERROR)
-+ thd->options |= OPTION_BIG_SELECTS;
-+
-+ thd->proc_info=0;
-+ thd->version=refresh_version;
-+ thd->security_ctx->priv_user=
-+ thd->security_ctx->user= (char*) my_strdup("boot", MYF(MY_WME));
-+ /*
-+ Make the "client" handle multiple results. This is necessary
-+ to enable stored procedures with SELECTs and Dynamic SQL
-+ in init-file.
-+ */
-+ thd->client_capabilities|= CLIENT_MULTI_RESULTS;
-+
-+ buff= (char*) thd->net.buff;
-+ thd->init_for_queries();
-+ while (fgets(buff, thd->net.max_packet, file))
-+ {
-+ ulong length= (ulong) strlen(buff);
-+ while (buff[length-1] != '\n' && !feof(file))
-+ {
-+ /*
-+ We got only a part of the current string. Will try to increase
-+ net buffer then read the rest of the current string.
-+ */
-+ if (net_realloc(&(thd->net), 2 * thd->net.max_packet))
-+ {
-+ net_send_error(thd, ER_NET_PACKET_TOO_LARGE, NullS);
-+ thd->fatal_error();
-+ break;
-+ }
-+ buff= (char*) thd->net.buff;
-+ fgets(buff + length, thd->net.max_packet - length, file);
-+ length+= (ulong) strlen(buff + length);
-+ }
-+ if (thd->is_fatal_error)
-+ break;
-+
-+ while (length && (my_isspace(thd->charset(), buff[length-1]) ||
-+ buff[length-1] == ';'))
-+ length--;
-+ buff[length]=0;
-+ thd->query_length=length;
-+ thd->query= thd->memdup_w_gap(buff, length+1,
-+ thd->db_length+1+QUERY_CACHE_FLAGS_SIZE);
-+ thd->query[length] = '\0';
-+ /*
-+ We don't need to obtain LOCK_thread_count here because in bootstrap
-+ mode we have only one thread.
-+ */
-+ thd->query_id=next_query_id();
-+ mysql_parse(thd,thd->query,length);
-+ close_thread_tables(thd); // Free tables
-+ if (thd->is_fatal_error)
-+ break;
-+ free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
-+#ifdef USING_TRANSACTIONS
-+ free_root(&thd->transaction.mem_root,MYF(MY_KEEP_PREALLOC));
-+#endif
-+ }
-+
-+ /* thd->fatal_error should be set in case something went wrong */
-+end:
-+ bootstrap_error= thd->is_fatal_error;
-+
-+ net_end(&thd->net);
-+ thd->cleanup();
-+ delete thd;
-+
-+#ifndef EMBEDDED_LIBRARY
-+ (void) pthread_mutex_lock(&LOCK_thread_count);
-+ thread_count--;
-+ (void) pthread_mutex_unlock(&LOCK_thread_count);
-+ (void) pthread_cond_broadcast(&COND_thread_count);
-+ my_thread_end();
-+ pthread_exit(0);
-+#endif
-+ DBUG_RETURN(0);
-+}
-+
-+
-+ /* This works because items are allocated with sql_alloc() */
-+
-+void cleanup_items(Item *item)
-+{
-+ DBUG_ENTER("cleanup_items");
-+ for (; item ; item=item->next)
-+ item->cleanup();
-+ DBUG_VOID_RETURN;
-+}
-+
-+/*
-+ Handle COM_TABLE_DUMP command
-+
-+ SYNOPSIS
-+ mysql_table_dump
-+ thd thread handle
-+ db database name or an empty string. If empty,
-+ the current database of the connection is used
-+ tbl_name name of the table to dump
-+
-+ NOTES
-+ This function is written to handle one specific command only.
-+
-+ RETURN VALUE
-+ 0 success
-+ 1 error, the error message is set in THD
-+*/
-+
-+static
-+int mysql_table_dump(THD* thd, char* db, char* tbl_name)
-+{
-+ TABLE* table;
-+ TABLE_LIST* table_list;
-+ int error = 0;
-+ DBUG_ENTER("mysql_table_dump");
-+ db = (db && db[0]) ? db : thd->db;
-+ if (!(table_list = (TABLE_LIST*) thd->calloc(sizeof(TABLE_LIST))))
-+ DBUG_RETURN(1); // out of memory
-+ table_list->db= db;
-+ table_list->table_name= table_list->alias= tbl_name;
-+ table_list->lock_type= TL_READ_NO_INSERT;
-+ table_list->prev_global= &table_list; // can be removed after merge with 4.1
-+
-+ if (!db || check_db_name(db))
-+ {
-+ my_error(ER_WRONG_DB_NAME ,MYF(0), db ? db : "NULL");
-+ goto err;
-+ }
-+ if (lower_case_table_names)
-+ my_casedn_str(files_charset_info, tbl_name);
-+ remove_escape(table_list->table_name);
-+
-+ if (!(table=open_ltable(thd, table_list, TL_READ_NO_INSERT)))
-+ DBUG_RETURN(1);
-+
-+ if (check_one_table_access(thd, SELECT_ACL, table_list))
-+ goto err;
-+ thd->free_list = 0;
-+ thd->query_length=(uint) strlen(tbl_name);
-+ thd->query = tbl_name;
-+ if ((error = mysqld_dump_create_info(thd, table_list, -1)))
-+ {
-+ my_error(ER_GET_ERRNO, MYF(0), my_errno);
-+ goto err;
-+ }
-+ net_flush(&thd->net);
-+ if ((error= table->file->dump(thd,-1)))
-+ my_error(ER_GET_ERRNO, MYF(0), error);
-+
-+err:
-+ DBUG_RETURN(error);
-+}
-+
-+/*
-+ Ends the current transaction and (maybe) begin the next
-+
-+ SYNOPSIS
-+ end_trans()
-+ thd Current thread
-+ completion Completion type
-+
-+ RETURN
-+ 0 - OK
-+*/
-+
-+int end_trans(THD *thd, enum enum_mysql_completiontype completion)
-+{
-+ bool do_release= 0;
-+ int res= 0;
-+ DBUG_ENTER("end_trans");
-+
-+ if (unlikely(thd->in_sub_stmt))
-+ {
-+ my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
-+ DBUG_RETURN(1);
-+ }
-+ if (thd->transaction.xid_state.xa_state != XA_NOTR)
-+ {
-+ my_error(ER_XAER_RMFAIL, MYF(0),
-+ xa_state_names[thd->transaction.xid_state.xa_state]);
-+ DBUG_RETURN(1);
-+ }
-+ switch (completion) {
-+ case COMMIT:
-+ /*
-+ We don't use end_active_trans() here to ensure that this works
-+ even if there is a problem with the OPTION_AUTO_COMMIT flag
-+ (Which of course should never happen...)
-+ */
-+ thd->server_status&= ~SERVER_STATUS_IN_TRANS;
-+ res= ha_commit(thd);
-+ thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
-+ break;
-+ case COMMIT_RELEASE:
-+ do_release= 1; /* fall through */
-+ case COMMIT_AND_CHAIN:
-+ res= end_active_trans(thd);
-+ if (!res && completion == COMMIT_AND_CHAIN)
-+ res= begin_trans(thd);
-+ break;
-+ case ROLLBACK_RELEASE:
-+ do_release= 1; /* fall through */
-+ case ROLLBACK:
-+ case ROLLBACK_AND_CHAIN:
-+ {
-+ thd->server_status&= ~SERVER_STATUS_IN_TRANS;
-+ if (ha_rollback(thd))
-+ res= -1;
-+ thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
-+ if (!res && (completion == ROLLBACK_AND_CHAIN))
-+ res= begin_trans(thd);
-+ break;
-+ }
-+ default:
-+ res= -1;
-+ my_error(ER_UNKNOWN_COM_ERROR, MYF(0));
-+ DBUG_RETURN(-1);
-+ }
-+
-+ if (res < 0)
-+ my_error(thd->killed_errno(), MYF(0));
-+ else if ((res == 0) && do_release)
-+ thd->killed= THD::KILL_CONNECTION;
-+
-+ DBUG_RETURN(res);
-+}
-+
-+#ifndef EMBEDDED_LIBRARY
-+
-+/*
-+ Read one command from socket and execute it (query or simple command).
-+ This function is called in loop from thread function.
-+ SYNOPSIS
-+ do_command()
-+ RETURN VALUE
-+ 0 success
-+ 1 request of thread shutdown (see dispatch_command() description)
-+*/
-+
-+bool do_command(THD *thd)
-+{
-+ char *packet;
-+ uint old_timeout;
-+ ulong packet_length;
-+ NET *net;
-+ enum enum_server_command command;
-+ DBUG_ENTER("do_command");
-+
-+ net= &thd->net;
-+ /*
-+ indicator of uninitialized lex => normal flow of errors handling
-+ (see my_message_sql)
-+ */
-+ thd->lex->current_select= 0;
-+
-+ packet=0;
-+ old_timeout=net->read_timeout;
-+ /* Wait max for 8 hours */
-+ net->read_timeout=(uint) thd->variables.net_wait_timeout;
-+ thd->clear_error(); // Clear error message
-+
-+ net_new_transaction(net);
-+ if ((packet_length=my_net_read(net)) == packet_error)
-+ {
-+ DBUG_PRINT("info",("Got error %d reading command from socket %s",
-+ net->error,
-+ vio_description(net->vio)));
-+ /* Check if we can continue without closing the connection */
-+ if (net->error != 3)
-+ {
-+ statistic_increment(aborted_threads,&LOCK_status);
-+ DBUG_RETURN(TRUE); // We have to close it.
-+ }
-+ net_send_error(thd, net->last_errno, NullS);
-+ net->error= 0;
-+ DBUG_RETURN(FALSE);
-+ }
-+ else
-+ {
-+ packet=(char*) net->read_pos;
-+ command = (enum enum_server_command) (uchar) packet[0];
-+ if (command >= COM_END)
-+ command= COM_END; // Wrong command
-+ DBUG_PRINT("info",("Command on %s = %d (%s)",
-+ vio_description(net->vio), command,
-+ command_name[command]));
-+ }
-+ net->read_timeout=old_timeout; // restore it
-+ /*
-+ packet_length contains length of data, as it was stored in packet
-+ header. In case of malformed header, packet_length can be zero.
-+ If packet_length is not zero, my_net_read ensures that this number
-+ of bytes was actually read from network. Additionally my_net_read
-+ sets packet[packet_length]= 0 (thus if packet_length == 0,
-+ command == packet[0] == COM_SLEEP).
-+ In dispatch_command packet[packet_length] points beyond the end of packet.
-+ */
-+ DBUG_RETURN(dispatch_command(command,thd, packet+1, (uint) packet_length));
-+}
-+#endif /* EMBEDDED_LIBRARY */
-+
-+
-+/*
-+ Perform one connection-level (COM_XXXX) command.
-+
-+ SYNOPSIS
-+ dispatch_command()
-+ thd connection handle
-+ command type of command to perform
-+ packet data for the command, packet is always null-terminated
-+ packet_length length of packet + 1 (to show that data is
-+ null-terminated) except for COM_SLEEP, where it
-+ can be zero.
-+ RETURN VALUE
-+ 0 ok
-+ 1 request of thread shutdown, i. e. if command is
-+ COM_QUIT/COM_SHUTDOWN
-+*/
-+
-+bool dispatch_command(enum enum_server_command command, THD *thd,
-+ char* packet, uint packet_length)
-+{
-+ NET *net= &thd->net;
-+ bool error= 0;
-+ DBUG_ENTER("dispatch_command");
-+
-+ if (thd->killed == THD::KILL_QUERY || thd->killed == THD::KILL_BAD_DATA)
-+ thd->killed= THD::NOT_KILLED;
-+
-+ thd->command=command;
-+ /*
-+ Commands which always take a long time are logged into
-+ the slow log only if opt_log_slow_admin_statements is set.
-+ */
-+ thd->enable_slow_log= TRUE;
-+ thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */
-+ thd->set_time();
-+ VOID(pthread_mutex_lock(&LOCK_thread_count));
-+ thd->query_id=query_id;
-+ if (command != COM_STATISTICS && command != COM_PING)
-+ next_query_id();
-+ thread_running++;
-+ /* TODO: set thd->lex->sql_command to SQLCOM_END here */
-+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
-+
-+ thd->server_status&=
-+ ~(SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED);
-+ switch (command) {
-+ case COM_INIT_DB:
-+ {
-+ LEX_STRING tmp;
-+ statistic_increment(thd->status_var.com_stat[SQLCOM_CHANGE_DB],
-+ &LOCK_status);
-+ thd->convert_string(&tmp, system_charset_info,
-+ packet, strlen(packet), thd->charset());
-+ if (!mysql_change_db(thd, tmp.str, FALSE))
-+ {
-+ mysql_log.write(thd,command,"%s",thd->db);
-+ send_ok(thd);
-+ }
-+ break;
-+ }
-+#ifdef HAVE_REPLICATION
-+ case COM_REGISTER_SLAVE:
-+ {
-+ if (!register_slave(thd, (uchar*)packet, packet_length))
-+ send_ok(thd);
-+ break;
-+ }
-+#endif
-+ case COM_TABLE_DUMP:
-+ {
-+ char *db, *tbl_name;
-+ uint db_len= *(uchar*) packet;
-+ if (db_len >= packet_length || db_len > NAME_LEN)
-+ {
-+ my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
-+ break;
-+ }
-+ uint tbl_len= *(uchar*) (packet + db_len + 1);
-+ if (db_len+tbl_len+2 > packet_length || tbl_len > NAME_LEN)
-+ {
-+ my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
-+ break;
-+ }
-+
-+ statistic_increment(thd->status_var.com_other, &LOCK_status);
-+ thd->enable_slow_log= opt_log_slow_admin_statements;
-+ db= thd->alloc(db_len + tbl_len + 2);
-+ if (!db)
-+ {
-+ my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
-+ break;
-+ }
-+ tbl_name= strmake(db, packet + 1, db_len)+1;
-+ strmake(tbl_name, packet + db_len + 2, tbl_len);
-+ mysql_table_dump(thd, db, tbl_name);
-+ break;
-+ }
-+ case COM_CHANGE_USER:
-+ {
-+ thd->change_user();
-+ thd->clear_error(); // if errors from rollback
-+
-+ statistic_increment(thd->status_var.com_other, &LOCK_status);
-+ char *user= (char*) packet;
-+ char *passwd= strend(user)+1;
-+ /*
-+ Old clients send null-terminated string ('\0' for empty string) for
-+ password. New clients send the size (1 byte) + string (not null
-+ terminated, so also '\0' for empty string).
-+ */
-+ char db_buff[NAME_LEN+1]; // buffer to store db in utf8
-+ char *db= passwd;
-+ uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
-+ *passwd++ : strlen(passwd);
-+ db+= passwd_len + 1;
-+#ifndef EMBEDDED_LIBRARY
-+ /* Small check for incoming packet */
-+ if ((uint) ((uchar*) db - net->read_pos) > packet_length)
-+ {
-+ my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
-+ break;
-+ }
-+#endif
-+ /* Convert database name to utf8 */
-+ uint dummy_errors;
-+ db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
-+ system_charset_info, db, strlen(db),
-+ thd->charset(), &dummy_errors)]= 0;
-+ db= db_buff;
-+
-+ /* Save user and privileges */
-+ uint save_db_length= thd->db_length;
-+ char *save_db= thd->db;
-+ Security_context save_security_ctx= *thd->security_ctx;
-+ USER_CONN *save_user_connect= thd->user_connect;
-+
-+ if (!(thd->security_ctx->user= my_strdup(user, MYF(0))))
-+ {
-+ thd->security_ctx->user= save_security_ctx.user;
-+ my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
-+ break;
-+ }
-+
-+ /* Clear variables that are allocated */
-+ thd->user_connect= 0;
-+ int res= check_user(thd, COM_CHANGE_USER, passwd, passwd_len, db, FALSE);
-+
-+ if (res)
-+ {
-+ /* authentication failure, we shall restore old user */
-+ if (res > 0)
-+ my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
-+ x_free(thd->security_ctx->user);
-+ *thd->security_ctx= save_security_ctx;
-+ thd->user_connect= save_user_connect;
-+ thd->db= save_db;
-+ thd->db_length= save_db_length;
-+ }
-+ else
-+ {
-+#ifndef NO_EMBEDDED_ACCESS_CHECKS
-+ /* we've authenticated new user */
-+ if (save_user_connect)
-+ decrease_user_connections(save_user_connect);
-+#endif /* NO_EMBEDDED_ACCESS_CHECKS */
-+ x_free((gptr) save_db);
-+ x_free((gptr) save_security_ctx.user);
-+ }
-+ break;
-+ }
-+ case COM_STMT_EXECUTE:
-+ {
-+ mysql_stmt_execute(thd, packet, packet_length);
-+ break;
-+ }
-+ case COM_STMT_FETCH:
-+ {
-+ mysql_stmt_fetch(thd, packet, packet_length);
-+ break;
-+ }
-+ case COM_STMT_SEND_LONG_DATA:
-+ {
-+ mysql_stmt_get_longdata(thd, packet, packet_length);
-+ break;
-+ }
-+ case COM_STMT_PREPARE:
-+ {
-+ mysql_stmt_prepare(thd, packet, packet_length);
-+ break;
-+ }
-+ case COM_STMT_CLOSE:
-+ {
-+ mysql_stmt_close(thd, packet);
-+ break;
-+ }
-+ case COM_STMT_RESET:
-+ {
-+ mysql_stmt_reset(thd, packet);
-+ break;
-+ }
-+ case COM_QUERY:
-+ {
-+ if (alloc_query(thd, packet, packet_length))
-+ break; // fatal error is set
-+ char *packet_end= thd->query + thd->query_length;
-+ /* 'b' stands for 'buffer' parameter', special for 'my_snprintf' */
-+ const char *format= "%.*b";
-+ mysql_log.write(thd,command, format, thd->query_length, thd->query);
-+ DBUG_PRINT("query",("%-.4096s",thd->query));
-+
-+ if (!(specialflag & SPECIAL_NO_PRIOR))
-+ my_pthread_setprio(pthread_self(),QUERY_PRIOR);
-+
-+ mysql_parse(thd,thd->query, thd->query_length);
-+
-+ while (!thd->killed && thd->lex->found_semicolon && !thd->net.report_error)
-+ {
-+ char *packet= thd->lex->found_semicolon;
-+ net->no_send_error= 0;
-+ /*
-+ Multiple queries exits, execute them individually
-+ */
-+ if (thd->lock || thd->open_tables || thd->derived_tables ||
-+ thd->prelocked_mode)
-+ close_thread_tables(thd);
-+ ulong length= (ulong)(packet_end-packet);
-+
-+ log_slow_statement(thd);
-+
-+ /* Remove garbage at start of query */
-+ while (my_isspace(thd->charset(), *packet) && length > 0)
-+ {
-+ packet++;
-+ length--;
-+ }
-+ VOID(pthread_mutex_lock(&LOCK_thread_count));
-+ thd->query_length= length;
-+ thd->query= packet;
-+ thd->query_id= next_query_id();
-+ thd->set_time(); /* Reset the query start time. */
-+ /* TODO: set thd->lex->sql_command to SQLCOM_END here */
-+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
-+ mysql_parse(thd, packet, length);
-+ }
-+
-+ if (!(specialflag & SPECIAL_NO_PRIOR))
-+ my_pthread_setprio(pthread_self(),WAIT_PRIOR);
-+ DBUG_PRINT("info",("query ready"));
-+ break;
-+ }
-+ case COM_FIELD_LIST: // This isn't actually needed
-+#ifdef DONT_ALLOW_SHOW_COMMANDS
-+ my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
-+ MYF(0)); /* purecov: inspected */
-+ break;
-+#else
-+ {
-+ char *fields, *pend;
-+ /* Locked closure of all tables */
-+ TABLE_LIST *locked_tables= NULL;
-+ TABLE_LIST table_list;
-+ LEX_STRING conv_name;
-+ /* Saved variable value */
-+ my_bool old_innodb_table_locks=
-+ IF_INNOBASE_DB(thd->variables.innodb_table_locks, FALSE);
-+ /* used as fields initializator */
-+ lex_start(thd, 0, 0);
-+
-+
-+ statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_FIELDS],
-+ &LOCK_status);
-+ bzero((char*) &table_list,sizeof(table_list));
-+ if (thd->copy_db_to(&table_list.db, 0))
-+ break;
-+ pend= strend(packet);
-+ thd->convert_string(&conv_name, system_charset_info,
-+ packet, (uint) (pend-packet), thd->charset());
-+ table_list.alias= table_list.table_name= conv_name.str;
-+ packet= pend+1;
-+
-+ if (!my_strcasecmp(system_charset_info, table_list.db,
-+ information_schema_name.str))
-+ {
-+ ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, table_list.alias);
-+ if (schema_table)
-+ table_list.schema_table= schema_table;
-+ }
-+
-+ thd->query_length= strlen(packet); // for simplicity: don't optimize
-+ if (!(thd->query=fields=thd->memdup(packet,thd->query_length+1)))
-+ break;
-+ mysql_log.write(thd,command,"%s %s",table_list.table_name, fields);
-+ if (lower_case_table_names)
-+ my_casedn_str(files_charset_info, table_list.table_name);
-+ remove_escape(table_list.table_name); // This can't have wildcards
-+
-+ if (check_access(thd,SELECT_ACL,table_list.db,&table_list.grant.privilege,
-+ 0, 0, test(table_list.schema_table)))
-+ break;
-+ if (grant_option &&
-+ check_grant(thd, SELECT_ACL, &table_list, 2, UINT_MAX, 0))
-+ break;
-+ /* init structures for VIEW processing */
-+ table_list.select_lex= &(thd->lex->select_lex);
-+ mysql_init_query(thd, (uchar*)"", 0);
-+ thd->lex->
-+ select_lex.table_list.link_in_list((byte*) &table_list,
-+ (byte**) &table_list.next_local);
-+ thd->lex->add_to_query_tables(&table_list);
-+
-+ /* 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();
-+ break;
-+ }
-+#endif
-+ case COM_QUIT:
-+ /* We don't calculate statistics for this command */
-+ mysql_log.write(thd,command,NullS);
-+ net->error=0; // Don't give 'abort' message
-+ error=TRUE; // End server
-+ break;
-+
-+ case COM_CREATE_DB: // QQ: To be removed
-+ {
-+ char *db=thd->strdup(packet), *alias;
-+ HA_CREATE_INFO create_info;
-+
-+ statistic_increment(thd->status_var.com_stat[SQLCOM_CREATE_DB],
-+ &LOCK_status);
-+ // null test to handle EOM
-+ if (!db || !(alias= thd->strdup(db)) || check_db_name(db))
-+ {
-+ my_error(ER_WRONG_DB_NAME, MYF(0), db ? db : "NULL");
-+ break;
-+ }
-+ if (check_access(thd,CREATE_ACL,db,0,1,0,is_schema_db(db)))
-+ break;
-+ mysql_log.write(thd,command,packet);
-+ bzero(&create_info, sizeof(create_info));
-+ mysql_create_db(thd, (lower_case_table_names == 2 ? alias : db),
-+ &create_info, 0);
-+ break;
-+ }
-+ case COM_DROP_DB: // QQ: To be removed
-+ {
-+ statistic_increment(thd->status_var.com_stat[SQLCOM_DROP_DB],
-+ &LOCK_status);
-+ char *db=thd->strdup(packet);
-+ /* null test to handle EOM */
-+ if (!db || check_db_name(db))
-+ {
-+ my_error(ER_WRONG_DB_NAME, MYF(0), db ? db : "NULL");
-+ break;
-+ }
-+ if (check_access(thd,DROP_ACL,db,0,1,0,is_schema_db(db)))
-+ break;
-+ if (thd->locked_tables || thd->active_transaction())
-+ {
-+ my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
-+ ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
-+ break;
-+ }
-+ mysql_log.write(thd,command,db);
-+ mysql_rm_db(thd, db, 0, 0);
-+ break;
-+ }
-+#ifndef EMBEDDED_LIBRARY
-+ case COM_BINLOG_DUMP:
-+ {
-+ ulong pos;
-+ ushort flags;
-+ uint32 slave_server_id;
-+
-+ statistic_increment(thd->status_var.com_other,&LOCK_status);
-+ thd->enable_slow_log= opt_log_slow_admin_statements;
-+ if (check_global_access(thd, REPL_SLAVE_ACL))
-+ break;
-+
-+ /* TODO: The following has to be changed to an 8 byte integer */
-+ pos = uint4korr(packet);
-+ flags = uint2korr(packet + 4);
-+ thd->server_id=0; /* avoid suicide */
-+ if ((slave_server_id= uint4korr(packet+6))) // mysqlbinlog.server_id==0
-+ kill_zombie_dump_threads(slave_server_id);
-+ thd->server_id = slave_server_id;
-+
-+ mysql_log.write(thd, command, "Log: '%s' Pos: %ld", packet+10,
-+ (long) pos);
-+ mysql_binlog_send(thd, thd->strdup(packet + 10), (my_off_t) pos, flags);
-+ unregister_slave(thd,1,1);
-+ /* fake COM_QUIT -- if we get here, the thread needs to terminate */
-+ error = TRUE;
-+ net->error = 0;
-+ break;
-+ }
-+#endif
-+ case COM_REFRESH:
-+ {
-+ bool not_used;
-+ statistic_increment(thd->status_var.com_stat[SQLCOM_FLUSH],
-+ &LOCK_status);
-+ ulong options= (ulong) (uchar) packet[0];
-+ if (check_global_access(thd,RELOAD_ACL))
-+ break;
-+ mysql_log.write(thd,command,NullS);
-+ if (!reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, ¬_used))
-+ send_ok(thd);
-+ break;
-+ }
-+#ifndef EMBEDDED_LIBRARY
-+ case COM_SHUTDOWN:
-+ {
-+ statistic_increment(thd->status_var.com_other, &LOCK_status);
-+ if (check_global_access(thd,SHUTDOWN_ACL))
-+ break; /* purecov: inspected */
-+ /*
-+ If the client is < 4.1.3, it is going to send us no argument; then
-+ packet_length is 1, packet[0] is the end 0 of the packet. Note that
-+ SHUTDOWN_DEFAULT is 0. If client is >= 4.1.3, the shutdown level is in
-+ packet[0].
-+ */
-+ enum mysql_enum_shutdown_level level=
-+ (enum mysql_enum_shutdown_level) (uchar) packet[0];
-+ DBUG_PRINT("quit",("Got shutdown command for level %u", level));
-+ if (level == SHUTDOWN_DEFAULT)
-+ level= SHUTDOWN_WAIT_ALL_BUFFERS; // soon default will be configurable
-+ else if (level != SHUTDOWN_WAIT_ALL_BUFFERS)
-+ {
-+ my_error(ER_NOT_SUPPORTED_YET, MYF(0), "this shutdown level");
-+ break;
-+ }
-+ DBUG_PRINT("quit",("Got shutdown command for level %u", level));
-+ mysql_log.write(thd,command,NullS);
-+ send_eof(thd);
-+#ifdef __WIN__
-+ sleep(1); // must wait after eof()
-+#endif
-+#ifndef OS2
-+ send_eof(thd); // This is for 'quit request'
-+#endif
-+ close_connection(thd, 0, 1);
-+ close_thread_tables(thd); // Free before kill
-+ kill_mysql();
-+ error=TRUE;
-+ break;
-+ }
-+#endif
-+ case COM_STATISTICS:
-+ {
-+ mysql_log.write(thd,command,NullS);
-+ statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_STATUS],
-+ &LOCK_status);
-+#ifndef EMBEDDED_LIBRARY
-+ char buff[200];
-+#else
-+ char *buff= thd->net.last_error;
-+#endif
-+
-+ STATUS_VAR current_global_status_var;
-+ calc_sum_of_all_status(¤t_global_status_var);
-+
-+ ulong uptime = (ulong) (thd->start_time - start_time);
-+ sprintf((char*) buff,
-+ "Uptime: %lu Threads: %d Questions: %lu Slow queries: %lu Opens: %lu Flush tables: %lu Open tables: %u Queries per second avg: %.3f",
-+ uptime,
-+ (int) thread_count, (ulong) thd->query_id,
-+ current_global_status_var.long_query_count,
-+ current_global_status_var.opened_tables, refresh_version, cached_tables(),
-+ (uptime ? (ulonglong2double(thd->query_id) / (double) uptime) :
-+ (double) 0));
-+#ifdef SAFEMALLOC
-+ if (sf_malloc_cur_memory) // Using SAFEMALLOC
-+ sprintf(strend(buff), " Memory in use: %ldK Max memory used: %ldK",
-+ (sf_malloc_cur_memory+1023L)/1024L,
-+ (sf_malloc_max_memory+1023L)/1024L);
-+#endif
-+#ifndef EMBEDDED_LIBRARY
-+ VOID(my_net_write(net, buff,(uint) strlen(buff)));
-+ VOID(net_flush(net));
-+#endif
-+ break;
-+ }
-+ case COM_PING:
-+ statistic_increment(thd->status_var.com_other, &LOCK_status);
-+ send_ok(thd); // Tell client we are alive
-+ break;
-+ case COM_PROCESS_INFO:
-+ statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_PROCESSLIST],
-+ &LOCK_status);
-+ if (!thd->security_ctx->priv_user[0] &&
-+ check_global_access(thd, PROCESS_ACL))
-+ break;
-+ mysql_log.write(thd,command,NullS);
-+ mysqld_list_processes(thd,
-+ thd->security_ctx->master_access & PROCESS_ACL ?
-+ NullS : thd->security_ctx->priv_user, 0);
-+ break;
-+ case COM_PROCESS_KILL:
-+ {
-+ statistic_increment(thd->status_var.com_stat[SQLCOM_KILL], &LOCK_status);
-+ ulong id=(ulong) uint4korr(packet);
-+ kill_one_thread(thd,id,false);
-+ break;
-+ }
-+ case COM_SET_OPTION:
-+ {
-+ statistic_increment(thd->status_var.com_stat[SQLCOM_SET_OPTION],
-+ &LOCK_status);
-+ enum_mysql_set_option command= (enum_mysql_set_option) uint2korr(packet);
-+ switch (command) {
-+ case MYSQL_OPTION_MULTI_STATEMENTS_ON:
-+ thd->client_capabilities|= CLIENT_MULTI_STATEMENTS;
-+ send_eof(thd);
-+ break;
-+ case MYSQL_OPTION_MULTI_STATEMENTS_OFF:
-+ thd->client_capabilities&= ~CLIENT_MULTI_STATEMENTS;
-+ send_eof(thd);
-+ break;
-+ default:
-+ my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
-+ break;
-+ }
-+ break;
-+ }
-+ case COM_DEBUG:
-+ statistic_increment(thd->status_var.com_other, &LOCK_status);
-+ if (check_global_access(thd, SUPER_ACL))
-+ break; /* purecov: inspected */
-+ mysql_print_status();
-+ mysql_log.write(thd,command,NullS);
-+ send_eof(thd);
-+ break;
-+ case COM_SLEEP:
-+ case COM_CONNECT: // Impossible here
-+ case COM_TIME: // Impossible from client
-+ case COM_DELAYED_INSERT:
-+ case COM_END:
-+ default:
-+ my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
-+ break;
-+ }
-+ if (thd->lock || thd->open_tables || thd->derived_tables ||
-+ thd->prelocked_mode)
-+ {
-+ thd->proc_info="closing tables";
-+ close_thread_tables(thd); /* Free tables */
-+ }
-+ /*
-+ assume handlers auto-commit (if some doesn't - transaction handling
-+ in MySQL should be redesigned to support it; it's a big change,
-+ and it's not worth it - better to commit explicitly only writing
-+ transactions, read-only ones should better take care of themselves.
-+ saves some work in 2pc too)
-+ see also sql_base.cc - close_thread_tables()
-+ */
-+ bzero(&thd->transaction.stmt, sizeof(thd->transaction.stmt));
-+ if (!thd->active_transaction())
-+ thd->transaction.xid_state.xid.null();
-+
-+ /* report error issued during command execution */
-+ if (thd->killed_errno() && !thd->net.report_error)
-+ thd->send_kill_message();
-+ if (thd->net.report_error)
-+ net_send_error(thd);
-+
-+ log_slow_statement(thd);
-+
-+ thd->proc_info="cleaning up";
-+ VOID(pthread_mutex_lock(&LOCK_thread_count)); // For process list
-+ thd->proc_info=0;
-+ thd->command=COM_SLEEP;
-+ thd->query=0;
-+ thd->query_length=0;
-+ thread_running--;
-+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
-+ thd->packet.shrink(thd->variables.net_buffer_length); // Reclaim some memory
-+ free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
-+ DBUG_RETURN(error);
-+}
-+
-+
-+void log_slow_statement(THD *thd)
-+{
-+ time_t start_of_query;
-+
-+ /*
-+ The following should never be true with our current code base,
-+ but better to keep this here so we don't accidently try to log a
-+ statement in a trigger or stored function
-+ */
-+ if (unlikely(thd->in_sub_stmt))
-+ return; // Don't set time for sub stmt
-+
-+ start_of_query= thd->start_time;
-+ thd->end_time(); // Set start time
-+
-+ /*
-+ Do not log administrative statements unless the appropriate option is
-+ set; do not log into slow log if reading from backup.
-+ */
-+ if (thd->enable_slow_log && !thd->user_time)
-+ {
-+ thd->proc_info="logging slow query";
-+
-+ if ((ulong) (thd->start_time - thd->time_after_lock) >
-+ thd->variables.long_query_time ||
-+ (thd->server_status &
-+ (SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) &&
-+ (specialflag & SPECIAL_LOG_QUERIES_NOT_USING_INDEXES) &&
-+ /* == SQLCOM_END unless this is a SHOW command */
-+ thd->lex->orig_sql_command == SQLCOM_END)
-+ {
-+ thd->status_var.long_query_count++;
-+ mysql_slow_log.write(thd, thd->query, thd->query_length, start_of_query);
-+ }
-+ }
-+}
-+
-+
-+/*
-+ Create a TABLE_LIST object for an INFORMATION_SCHEMA table.
-+
-+ SYNOPSIS
-+ prepare_schema_table()
-+ thd thread handle
-+ lex current lex
-+ table_ident table alias if it's used
-+ schema_table_idx the type of the INFORMATION_SCHEMA table to be
-+ created
-+
-+ DESCRIPTION
-+ This function is used in the parser to convert a SHOW or DESCRIBE
-+ table_name command to a SELECT from INFORMATION_SCHEMA.
-+ It prepares a SELECT_LEX and a TABLE_LIST object to represent the
-+ given command as a SELECT parse tree.
-+
-+ NOTES
-+ Due to the way this function works with memory and LEX it cannot
-+ be used outside the parser (parse tree transformations outside
-+ the parser break PS and SP).
-+
-+ RETURN VALUE
-+ 0 success
-+ 1 out of memory or SHOW commands are not allowed
-+ in this version of the server.
-+*/
-+
-+int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
-+ enum enum_schema_tables schema_table_idx)
-+{
-+ DBUG_ENTER("prepare_schema_table");
-+ SELECT_LEX *sel= 0;
-+ switch (schema_table_idx) {
-+ case SCH_SCHEMATA:
-+#if defined(DONT_ALLOW_SHOW_COMMANDS)
-+ my_message(ER_NOT_ALLOWED_COMMAND,
-+ ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
-+ DBUG_RETURN(1);
-+#else
-+ if ((specialflag & SPECIAL_SKIP_SHOW_DB) &&
-+ check_global_access(thd, SHOW_DB_ACL))
-+ DBUG_RETURN(1);
-+ break;
-+#endif
-+ case SCH_TABLE_NAMES:
-+ case SCH_TABLES:
-+ case SCH_VIEWS:
-+ case SCH_TRIGGERS:
-+#ifdef DONT_ALLOW_SHOW_COMMANDS
-+ my_message(ER_NOT_ALLOWED_COMMAND,
-+ ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
-+ DBUG_RETURN(1);
-+#else
-+ {
-+ char *db;
-+ if (lex->select_lex.db == NULL &&
-+ thd->copy_db_to(&lex->select_lex.db, 0))
-+ {
-+ DBUG_RETURN(1);
-+ }
-+ db= lex->select_lex.db;
-+ remove_escape(db); // Fix escaped '_'
-+ if (check_db_name(db))
-+ {
-+ my_error(ER_WRONG_DB_NAME, MYF(0), db);
-+ DBUG_RETURN(1);
-+ }
-+ if (check_access(thd, SELECT_ACL, db, &thd->col_access, 0, 0,
-+ is_schema_db(db)))
-+ DBUG_RETURN(1); /* purecov: inspected */
-+ if (!thd->col_access && check_grant_db(thd,db))
-+ {
-+ my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
-+ thd->security_ctx->priv_user, thd->security_ctx->priv_host,
-+ db);
-+ DBUG_RETURN(1);
-+ }
-+ break;
-+ }
-+#endif
-+ case SCH_COLUMNS:
-+ case SCH_STATISTICS:
-+#ifdef DONT_ALLOW_SHOW_COMMANDS
-+ my_message(ER_NOT_ALLOWED_COMMAND,
-+ ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
-+ DBUG_RETURN(1);
-+#else
-+ if (table_ident)
-+ {
-+ TABLE_LIST **query_tables_last= lex->query_tables_last;
-+ sel= new SELECT_LEX();
-+ /* 'parent_lex' is used in init_query() so it must be before it. */
-+ sel->parent_lex= lex;
-+ sel->init_query();
-+ if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ,
-+ (List<String> *) 0, (List<String> *) 0))
-+ DBUG_RETURN(1);
-+ lex->query_tables_last= query_tables_last;
-+ TABLE_LIST *table_list= (TABLE_LIST*) sel->table_list.first;
-+ char *db= table_list->db;
-+ remove_escape(db); // Fix escaped '_'
-+ remove_escape(table_list->table_name);
-+ if (check_access(thd,SELECT_ACL | EXTRA_ACL,db,
-+ &table_list->grant.privilege, 0, 0,
-+ test(table_list->schema_table)))
-+ DBUG_RETURN(1); /* purecov: inspected */
-+ if (grant_option && check_grant(thd, SELECT_ACL, table_list, 2,
-+ UINT_MAX, 0))
-+ DBUG_RETURN(1);
-+ break;
-+ }
-+#endif
-+ case SCH_OPEN_TABLES:
-+ case SCH_VARIABLES:
-+ case SCH_STATUS:
-+ case SCH_PROCEDURES:
-+ case SCH_CHARSETS:
-+ case SCH_COLLATIONS:
-+ case SCH_COLLATION_CHARACTER_SET_APPLICABILITY:
-+ case SCH_USER_PRIVILEGES:
-+ case SCH_SCHEMA_PRIVILEGES:
-+ case SCH_TABLE_PRIVILEGES:
-+ case SCH_COLUMN_PRIVILEGES:
-+ case SCH_TABLE_CONSTRAINTS:
-+ case SCH_KEY_COLUMN_USAGE:
-+ default:
-+ break;
-+ }
-+
-+ SELECT_LEX *select_lex= lex->current_select;
-+ if (make_schema_select(thd, select_lex, schema_table_idx))
-+ {
-+ DBUG_RETURN(1);
-+ }
-+ TABLE_LIST *table_list= (TABLE_LIST*) select_lex->table_list.first;
-+ table_list->schema_select_lex= sel;
-+ table_list->schema_table_reformed= 1;
-+ statistic_increment(thd->status_var.com_stat[lex->orig_sql_command],
-+ &LOCK_status);
-+ DBUG_RETURN(0);
-+}
-+
-+
-+/*
-+ Read query from packet and store in thd->query
-+ Used in COM_QUERY and COM_STMT_PREPARE
-+
-+ DESCRIPTION
-+ Sets the following THD variables:
-+ query
-+ query_length
-+
-+ RETURN VALUES
-+ FALSE ok
-+ TRUE error; In this case thd->fatal_error is set
-+*/
-+
-+bool alloc_query(THD *thd, const char *packet, uint packet_length)
-+{
-+ packet_length--; // Remove end null
-+ /* Remove garbage at start and end of query */
-+ while (my_isspace(thd->charset(),packet[0]) && packet_length > 0)
-+ {
-+ packet++;
-+ packet_length--;
-+ }
-+ const char *pos= packet + packet_length; // Point at end null
-+ while (packet_length > 0 &&
-+ (pos[-1] == ';' || my_isspace(thd->charset() ,pos[-1])))
-+ {
-+ pos--;
-+ packet_length--;
-+ }
-+ /* We must allocate some extra memory for query cache */
-+ thd->query_length= 0; // Extra safety: Avoid races
-+ if (!(thd->query= (char*) thd->memdup_w_gap((gptr) (packet),
-+ packet_length,
-+ thd->db_length+ 1 +
-+ QUERY_CACHE_FLAGS_SIZE)))
-+ return TRUE;
-+ thd->query[packet_length]=0;
-+ thd->query_length= packet_length;
-+
-+ /* Reclaim some memory */
-+ thd->packet.shrink(thd->variables.net_buffer_length);
-+ thd->convert_buffer.shrink(thd->variables.net_buffer_length);
-+
-+ return FALSE;
-+}
-+
-+static void reset_one_shot_variables(THD *thd)
-+{
-+ thd->variables.character_set_client=
-+ global_system_variables.character_set_client;
-+ thd->variables.collation_connection=
-+ global_system_variables.collation_connection;
-+ thd->variables.collation_database=
-+ global_system_variables.collation_database;
-+ thd->variables.collation_server=
-+ global_system_variables.collation_server;
-+ thd->update_charset();
-+ thd->variables.time_zone=
-+ global_system_variables.time_zone;
-+ thd->one_shot_set= 0;
-+}
-+
-+
-+/*
-+ Execute command saved in thd and lex->sql_command
-+
-+ SYNOPSIS
-+ mysql_execute_command()
-+ thd Thread handle
-+
-+ IMPLEMENTATION
-+
-+ Before every operation that can request a write lock for a table
-+ wait if a global read lock exists. However do not wait if this
-+ thread has locked tables already. No new locks can be requested
-+ until the other locks are released. The thread that requests the
-+ global read lock waits for write locked tables to become unlocked.
-+
-+ Note that wait_if_global_read_lock() sets a protection against a new
-+ global read lock when it succeeds. This needs to be released by
-+ start_waiting_global_read_lock() after the operation.
-+
-+ RETURN
-+ FALSE OK
-+ TRUE Error
-+*/
-+
-+bool
-+mysql_execute_command(THD *thd)
-+{
-+ bool res= FALSE;
-+ bool need_start_waiting= FALSE; // have protection against global read lock
-+ int result= 0;
-+ LEX *lex= thd->lex;
-+ /* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */
-+ SELECT_LEX *select_lex= &lex->select_lex;
-+ /* first table of first SELECT_LEX */
-+ TABLE_LIST *first_table= (TABLE_LIST*) select_lex->table_list.first;
-+ /* list of all tables in query */
-+ TABLE_LIST *all_tables;
-+ /* most outer SELECT_LEX_UNIT of query */
-+ SELECT_LEX_UNIT *unit= &lex->unit;
-+ /* Saved variable value */
-+ DBUG_ENTER("mysql_execute_command");
-+ thd->net.no_send_error= 0;
-+
-+ /*
-+ Remember first generated insert id value of the previous
-+ statement. We remember it here at the beginning of the statement,
-+ and also in Item_func_last_insert_id::fix_fields() and
-+ sys_var_last_insert_id::value_ptr(). Last two places are required
-+ because LAST_INSERT_ID() and @@LAST_INSERT_ID may also be used in
-+ expression that is not executed with mysql_execute_command().
-+
-+ And we remember it here because some statements read
-+ @@LAST_INSERT_ID indirectly, like "SELECT * FROM t1 WHERE id IS
-+ NULL", that may replace "id IS NULL" with "id = <LAST_INSERT_ID>".
-+ */
-+ thd->current_insert_id= thd->last_insert_id;
-+
-+ /*
-+ In many cases first table of main SELECT_LEX have special meaning =>
-+ check that it is first table in global list and relink it first in
-+ queries_tables list if it is necessary (we need such relinking only
-+ for queries with subqueries in select list, in this case tables of
-+ subqueries will go to global list first)
-+
-+ all_tables will differ from first_table only if most upper SELECT_LEX
-+ do not contain tables.
-+
-+ Because of above in place where should be at least one table in most
-+ outer SELECT_LEX we have following check:
-+ DBUG_ASSERT(first_table == all_tables);
-+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
-+ */
-+ lex->first_lists_tables_same();
-+ /* should be assigned after making first tables same */
-+ all_tables= lex->query_tables;
-+ /* set context for commands which do not use setup_tables */
-+ select_lex->
-+ context.resolve_in_table_list_only((TABLE_LIST*)select_lex->
-+ table_list.first);
-+
-+ /*
-+ 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.
-+ Don't reset warnings when executing a stored routine.
-+ */
-+ if ((all_tables || &lex->select_lex != lex->all_selects_list ||
-+ lex->sroutines.records) && !thd->spcont ||
-+ lex->time_zone_tables_used)
-+ mysql_reset_errors(thd, 0);
-+
-+#ifdef HAVE_REPLICATION
-+ if (unlikely(thd->slave_thread))
-+ {
-+ /*
-+ Check if statment should be skipped because of slave filtering
-+ rules
-+
-+ Exceptions are:
-+ - UPDATE MULTI: For this statement, we want to check the filtering
-+ rules later in the code
-+ - SET: we always execute it (Not that many SET commands exists in
-+ the binary log anyway -- only 4.1 masters write SET statements,
-+ in 5.0 there are no SET statements in the binary log)
-+ - DROP TEMPORARY TABLE IF EXISTS: we always execute it (otherwise we
-+ have stale files on slave caused by exclusion of one tmp table).
-+ */
-+ if (!(lex->sql_command == SQLCOM_UPDATE_MULTI) &&
-+ !(lex->sql_command == SQLCOM_SET_OPTION) &&
-+ !(lex->sql_command == SQLCOM_DROP_TABLE &&
-+ lex->drop_temporary && lex->drop_if_exists) &&
-+ all_tables_not_ok(thd, all_tables))
-+ {
-+ /* we warn the slave SQL thread */
-+ my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
-+ if (thd->one_shot_set)
-+ {
-+ /*
-+ It's ok to check thd->one_shot_set here:
-+
-+ The charsets in a MySQL 5.0 slave can change by both a binlogged
-+ SET ONE_SHOT statement and the event-internal charset setting,
-+ and these two ways to change charsets do not seems to work
-+ together.
-+
-+ At least there seems to be problems in the rli cache for
-+ charsets if we are using ONE_SHOT. Note that this is normally no
-+ problem because either the >= 5.0 slave reads a 4.1 binlog (with
-+ ONE_SHOT) *or* or 5.0 binlog (without ONE_SHOT) but never both."
-+ */
-+ reset_one_shot_variables(thd);
-+ }
-+ DBUG_RETURN(0);
-+ }
-+ }
-+ else
-+ {
-+#endif /* HAVE_REPLICATION */
-+ /*
-+ When option readonly is set deny operations which change non-temporary
-+ tables. Except for the replication thread and the 'super' users.
-+ */
-+ if (opt_readonly &&
-+ !(thd->security_ctx->master_access & SUPER_ACL) &&
-+ uc_update_queries[lex->sql_command] &&
-+ !((lex->sql_command == SQLCOM_CREATE_TABLE) &&
-+ (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)) &&
-+ !((lex->sql_command == SQLCOM_DROP_TABLE) && lex->drop_temporary) &&
-+ ((lex->sql_command != SQLCOM_UPDATE_MULTI) &&
-+ some_non_temp_table_to_be_updated(thd, all_tables)))
-+ {
-+ my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
-+ DBUG_RETURN(-1);
-+ }
-+#ifdef HAVE_REPLICATION
-+ } /* endif unlikely slave */
-+#endif
-+ if(lex->orig_sql_command == SQLCOM_END)
-+ statistic_increment(thd->status_var.com_stat[lex->sql_command],
-+ &LOCK_status);
-+
-+ switch (lex->sql_command) {
-+ case SQLCOM_SELECT:
-+ {
-+ /* assign global limit variable if limit is not given */
-+ {
-+ SELECT_LEX *param= lex->unit.global_parameters;
-+ if (!param->explicit_limit)
-+ param->select_limit=
-+ new Item_int((ulonglong)thd->variables.select_limit);
-+ }
-+
-+ select_result *result=lex->result;
-+ if (all_tables)
-+ {
-+ if (lex->orig_sql_command != SQLCOM_SHOW_STATUS_PROC &&
-+ lex->orig_sql_command != SQLCOM_SHOW_STATUS_FUNC)
-+ res= check_table_access(thd,
-+ lex->exchange ? SELECT_ACL | FILE_ACL :
-+ SELECT_ACL,
-+ all_tables, 0);
-+ }
-+ else
-+ res= check_access(thd,
-+ lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL,
-+ any_db, 0, 0, 0, 0);
-+ if (res)
-+ goto error;
-+
-+ if (!(res= open_and_lock_tables(thd, all_tables)))
-+ {
-+ if (lex->describe)
-+ {
-+ /*
-+ We always use select_send for EXPLAIN, even if it's an EXPLAIN
-+ for SELECT ... INTO OUTFILE: a user application should be able
-+ to prepend EXPLAIN to any query and receive output for it,
-+ even if the query itself redirects the output.
-+ */
-+ if (!(result= new select_send()))
-+ goto error;
-+ else
-+ thd->send_explain_fields(result);
-+ res= mysql_explain_union(thd, &thd->lex->unit, result);
-+ if (lex->describe & DESCRIBE_EXTENDED)
-+ {
-+ char buff[1024];
-+ String str(buff,(uint32) sizeof(buff), system_charset_info);
-+ str.length(0);
-+ thd->lex->unit.print(&str);
-+ str.append('\0');
-+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
-+ ER_YES, str.ptr());
-+ }
-+ result->send_eof();
-+ delete result;
-+ }
-+ else
-+ {
-+ if (!result && !(result= new select_send()))
-+ goto error;
-+ query_cache_store_query(thd, all_tables);
-+ res= handle_select(thd, lex, result, 0);
-+ if (result != lex->result)
-+ delete result;
-+ }
-+ }
-+ break;
-+ }
-+ case SQLCOM_PREPARE:
-+ {
-+ mysql_sql_stmt_prepare(thd);
-+ break;
-+ }
-+ case SQLCOM_EXECUTE:
-+ {
-+ mysql_sql_stmt_execute(thd);
-+ break;
-+ }
-+ case SQLCOM_DEALLOCATE_PREPARE:
-+ {
-+ mysql_sql_stmt_close(thd);
-+ break;
-+ }
-+ case SQLCOM_DO:
-+ 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);
-+ break;
-+
-+ case SQLCOM_EMPTY_QUERY:
-+ send_ok(thd);
-+ break;
-+
-+ case SQLCOM_HELP:
-+ res= mysqld_help(thd,lex->help_arg);
-+ break;
-+
-+#ifndef EMBEDDED_LIBRARY
-+ case SQLCOM_PURGE:
-+ {
-+ if (check_global_access(thd, SUPER_ACL))
-+ goto error;
-+ /* PURGE MASTER LOGS TO 'file' */
-+ res = purge_master_logs(thd, lex->to_log);
-+ break;
-+ }
-+ case SQLCOM_PURGE_BEFORE:
-+ {
-+ Item *it;
-+
-+ if (check_global_access(thd, SUPER_ACL))
-+ goto error;
-+ /* PURGE MASTER LOGS BEFORE 'data' */
-+ it= (Item *)lex->value_list.head();
-+ if ((!it->fixed && it->fix_fields(lex->thd, &it)) ||
-+ it->check_cols(1))
-+ {
-+ my_error(ER_WRONG_ARGUMENTS, MYF(0), "PURGE LOGS BEFORE");
-+ goto error;
-+ }
-+ it= new Item_func_unix_timestamp(it);
-+ /*
-+ it is OK only emulate fix_fieds, because we need only
-+ value of constant
-+ */
-+ it->quick_fix_field();
-+ res = purge_master_logs_before_date(thd, (ulong)it->val_int());
-+ break;
-+ }
-+#endif
-+ case SQLCOM_SHOW_WARNS:
-+ {
-+ res= mysqld_show_warnings(thd, (ulong)
-+ ((1L << (uint) MYSQL_ERROR::WARN_LEVEL_NOTE) |
-+ (1L << (uint) MYSQL_ERROR::WARN_LEVEL_WARN) |
-+ (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR)
-+ ));
-+ break;
-+ }
-+ case SQLCOM_SHOW_ERRORS:
-+ {
-+ res= mysqld_show_warnings(thd, (ulong)
-+ (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR));
-+ break;
-+ }
-+ case SQLCOM_SHOW_NEW_MASTER:
-+ {
-+ if (check_global_access(thd, REPL_SLAVE_ACL))
-+ goto error;
-+ /* This query don't work now. See comment in repl_failsafe.cc */
-+#ifndef WORKING_NEW_MASTER
-+ my_error(ER_NOT_SUPPORTED_YET, MYF(0), "SHOW NEW MASTER");
-+ goto error;
-+#else
-+ res = show_new_master(thd);
-+ break;
-+#endif
-+ }
-+
-+#ifdef HAVE_REPLICATION
-+ case SQLCOM_SHOW_SLAVE_HOSTS:
-+ {
-+ if (check_global_access(thd, REPL_SLAVE_ACL))
-+ goto error;
-+ res = show_slave_hosts(thd);
-+ break;
-+ }
-+ case SQLCOM_SHOW_BINLOG_EVENTS:
-+ {
-+ if (check_global_access(thd, REPL_SLAVE_ACL))
-+ goto error;
-+ res = mysql_show_binlog_events(thd);
-+ break;
-+ }
-+#endif
-+
-+ case SQLCOM_BACKUP_TABLE:
-+ {
-+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
-+ if (check_db_used(thd, all_tables) ||
-+ check_table_access(thd, SELECT_ACL, all_tables, 0) ||
-+ check_global_access(thd, FILE_ACL))
-+ goto error; /* purecov: inspected */
-+ thd->enable_slow_log= opt_log_slow_admin_statements;
-+ res = mysql_backup_table(thd, first_table);
-+ select_lex->table_list.first= (byte*) first_table;
-+ lex->query_tables=all_tables;
-+ break;
-+ }
-+ case SQLCOM_RESTORE_TABLE:
-+ {
-+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
-+ if (check_db_used(thd, all_tables) ||
-+ check_table_access(thd, INSERT_ACL, all_tables, 0) ||
-+ check_global_access(thd, FILE_ACL))
-+ goto error; /* purecov: inspected */
-+ thd->enable_slow_log= opt_log_slow_admin_statements;
-+ res = mysql_restore_table(thd, first_table);
-+ select_lex->table_list.first= (byte*) first_table;
-+ lex->query_tables=all_tables;
-+ break;
-+ }
-+ case SQLCOM_ASSIGN_TO_KEYCACHE:
-+ {
-+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
-+ if (check_db_used(thd, all_tables) ||
-+ check_access(thd, INDEX_ACL, first_table->db,
-+ &first_table->grant.privilege, 0, 0,
-+ test(first_table->schema_table)))
-+ goto error;
-+ res= mysql_assign_to_keycache(thd, first_table, &lex->ident);
-+ break;
-+ }
-+ case SQLCOM_PRELOAD_KEYS:
-+ {
-+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
-+ if (check_db_used(thd, all_tables) ||
-+ check_access(thd, INDEX_ACL, first_table->db,
-+ &first_table->grant.privilege, 0, 0,
-+ test(first_table->schema_table)))
-+ goto error;
-+ res = mysql_preload_keys(thd, first_table);
-+ break;
-+ }
-+#ifdef HAVE_REPLICATION
-+ case SQLCOM_CHANGE_MASTER:
-+ {
-+ if (check_global_access(thd, SUPER_ACL))
-+ goto error;
-+ pthread_mutex_lock(&LOCK_active_mi);
-+ res = change_master(thd,active_mi);
-+ pthread_mutex_unlock(&LOCK_active_mi);
-+ break;
-+ }
-+ case SQLCOM_SHOW_SLAVE_STAT:
-+ {
-+ /* Accept one of two privileges */
-+ if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
-+ goto error;
-+ pthread_mutex_lock(&LOCK_active_mi);
-+ res = show_master_info(thd,active_mi);
-+ pthread_mutex_unlock(&LOCK_active_mi);
-+ break;
-+ }
-+ case SQLCOM_SHOW_MASTER_STAT:
-+ {
-+ /* Accept one of two privileges */
-+ if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
-+ goto error;
-+ res = show_binlog_info(thd);
-+ break;
-+ }
-+
-+ case SQLCOM_LOAD_MASTER_DATA: // sync with master
-+ if (check_global_access(thd, SUPER_ACL))
-+ goto error;
-+ if (end_active_trans(thd))
-+ goto error;
-+ else
-+ res = load_master_data(thd);
-+ break;
-+#endif /* HAVE_REPLICATION */
-+#ifdef HAVE_NDBCLUSTER_DB
-+ case SQLCOM_SHOW_NDBCLUSTER_STATUS:
-+ {
-+ res = ndbcluster_show_status(thd);
-+ break;
-+ }
-+#endif
-+#ifdef HAVE_INNOBASE_DB
-+ case SQLCOM_SHOW_INNODB_STATUS:
-+ {
-+ if (check_global_access(thd, SUPER_ACL))
-+ goto error;
-+ res = innodb_show_status(thd);
-+ break;
-+ }
-+ case SQLCOM_SHOW_MUTEX_STATUS:
-+ {
-+ if (check_global_access(thd, SUPER_ACL))
-+ goto error;
-+ res = innodb_mutex_show_status(thd);
-+ break;
-+ }
-+#endif
-+#ifdef HAVE_REPLICATION
-+ case SQLCOM_LOAD_MASTER_TABLE:
-+ {
-+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
-+ DBUG_ASSERT(first_table->db); /* Must be set in the parser */
-+
-+ if (check_access(thd, CREATE_ACL, first_table->db,
-+ &first_table->grant.privilege, 0, 0,
-+ test(first_table->schema_table)))
-+ goto error; /* purecov: inspected */
-+ if (grant_option)
-+ {
-+ /* Check that the first table has CREATE privilege */
-+ if (check_grant(thd, CREATE_ACL, all_tables, 0, 1, 0))
-+ goto error;
-+ }
-+ if (strlen(first_table->table_name) > NAME_LEN)
-+ {
-+ my_error(ER_WRONG_TABLE_NAME, MYF(0), first_table->table_name);
-+ break;
-+ }
-+ pthread_mutex_lock(&LOCK_active_mi);
-+ /*
-+ fetch_master_table will send the error to the client on failure.
-+ Give error if the table already exists.
-+ */
-+ if (!fetch_master_table(thd, first_table->db, first_table->table_name,
-+ active_mi, 0, 0))
-+ {
-+ send_ok(thd);
-+ }
-+ pthread_mutex_unlock(&LOCK_active_mi);
-+ break;
-+ }
-+#endif /* HAVE_REPLICATION */
-+
-+ case SQLCOM_CREATE_TABLE:
-+ {
-+ /* If CREATE TABLE of non-temporary table, do implicit commit */
-+ if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
-+ {
-+ if (end_active_trans(thd))
-+ {
-+ res= -1;
-+ break;
-+ }
-+ }
-+ else
-+ {
-+ /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
-+ thd->options|= OPTION_STATUS_NO_TRANS_UPDATE;
-+ }
-+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
-+ bool link_to_local;
-+ // Skip first table, which is the table we are creating
-+ TABLE_LIST *create_table= lex->unlink_first_table(&link_to_local);
-+ TABLE_LIST *select_tables= lex->query_tables;
-+
-+ if ((res= create_table_precheck(thd, select_tables, create_table)))
-+ goto end_with_restore_list;
-+
-+#ifndef HAVE_READLINK
-+ lex->create_info.data_file_name=lex->create_info.index_file_name=0;
-+#else
-+ /* Fix names if symlinked tables */
-+ if (append_file_to_dir(thd, &lex->create_info.data_file_name,
-+ create_table->table_name) ||
-+ append_file_to_dir(thd, &lex->create_info.index_file_name,
-+ create_table->table_name))
-+ goto end_with_restore_list;
-+#endif
-+ /*
-+ If we are using SET CHARSET without DEFAULT, add an implicit
-+ DEFAULT to not confuse old users. (This may change).
-+ */
-+ if ((lex->create_info.used_fields &
-+ (HA_CREATE_USED_DEFAULT_CHARSET | HA_CREATE_USED_CHARSET)) ==
-+ HA_CREATE_USED_CHARSET)
-+ {
-+ lex->create_info.used_fields&= ~HA_CREATE_USED_CHARSET;
-+ lex->create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
-+ lex->create_info.default_table_charset= lex->create_info.table_charset;
-+ lex->create_info.table_charset= 0;
-+ }
-+ /*
-+ The create-select command will open and read-lock the select table
-+ and then create, open and write-lock the new table. If a global
-+ read lock steps in, we get a deadlock. The write lock waits for
-+ the global read lock, while the global read lock waits for the
-+ select table to be closed. So we wait until the global readlock is
-+ gone before starting both steps. Note that
-+ wait_if_global_read_lock() sets a protection against a new global
-+ read lock when it succeeds. This needs to be released by
-+ start_waiting_global_read_lock(). We protect the normal CREATE
-+ TABLE in the same way. That way we avoid that a new table is
-+ created during a gobal read lock.
-+ */
-+ if (!thd->locked_tables &&
-+ !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
-+ {
-+ res= 1;
-+ goto end_with_restore_list;
-+ }
-+ if (select_lex->item_list.elements) // With select
-+ {
-+ select_result *result;
-+
-+ select_lex->options|= SELECT_NO_UNLOCK;
-+ unit->set_limit(select_lex);
-+
-+ if (!(res= open_and_lock_tables(thd, select_tables)))
-+ {
-+ /*
-+ Is table which we are changing used somewhere in other parts
-+ of query
-+ */
-+ if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
-+ {
-+ TABLE_LIST *duplicate;
-+ if ((duplicate= unique_table(thd, create_table, select_tables)))
-+ {
-+ update_non_unique_table_error(create_table, "CREATE", duplicate);
-+ res= 1;
-+ goto end_with_restore_list;
-+ }
-+ }
-+ /* If we create merge table, we have to test tables in merge, too */
-+ if (lex->create_info.used_fields & HA_CREATE_USED_UNION)
-+ {
-+ TABLE_LIST *tab;
-+ for (tab= (TABLE_LIST*) lex->create_info.merge_list.first;
-+ tab;
-+ tab= tab->next_local)
-+ {
-+ TABLE_LIST *duplicate;
-+ if ((duplicate= unique_table(thd, tab, select_tables)))
-+ {
-+ update_non_unique_table_error(tab, "CREATE", duplicate);
-+ res= 1;
-+ goto end_with_restore_list;
-+ }
-+ }
-+ }
-+
-+ if ((result= new select_create(create_table,
-+ &lex->create_info,
-+ lex->create_list,
-+ lex->key_list,
-+ select_lex->item_list,
-+ lex->duplicates,
-+ lex->ignore)))
-+ {
-+ /*
-+ CREATE from SELECT give its SELECT_LEX for SELECT,
-+ and item_list belong to SELECT
-+ */
-+ res= handle_select(thd, lex, result, 0);
-+ delete result;
-+ }
-+ /* reset for PS */
-+ lex->create_list.empty();
-+ lex->key_list.empty();
-+ }
-+ }
-+ else
-+ {
-+ /* regular create */
-+ if (lex->name)
-+ res= mysql_create_like_table(thd, create_table, &lex->create_info,
-+ (Table_ident *)lex->name);
-+ else
-+ {
-+ res= mysql_create_table(thd, create_table->db,
-+ create_table->table_name, &lex->create_info,
-+ lex->create_list,
-+ lex->key_list, 0, 0);
-+ }
-+ if (!res)
-+ send_ok(thd);
-+ }
-+
-+ /* put tables back for PS rexecuting */
-+end_with_restore_list:
-+ lex->link_first_table_back(create_table, link_to_local);
-+ break;
-+ }
-+ case SQLCOM_CREATE_INDEX:
-+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
-+ if (check_one_table_access(thd, INDEX_ACL, all_tables))
-+ goto error; /* purecov: inspected */
-+ thd->enable_slow_log= opt_log_slow_admin_statements;
-+ if (end_active_trans(thd))
-+ goto error;
-+ else
-+ res = mysql_create_index(thd, first_table, lex->key_list);
-+ break;
-+
-+#ifdef HAVE_REPLICATION
-+ case SQLCOM_SLAVE_START:
-+ {
-+ pthread_mutex_lock(&LOCK_active_mi);
-+ start_slave(thd,active_mi,1 /* net report*/);
-+ pthread_mutex_unlock(&LOCK_active_mi);
-+ break;
-+ }
-+ case SQLCOM_SLAVE_STOP:
-+ /*
-+ If the client thread has locked tables, a deadlock is possible.
-+ Assume that
-+ - the client thread does LOCK TABLE t READ.
-+ - then the master updates t.
-+ - then the SQL slave thread wants to update t,
-+ so it waits for the client thread because t is locked by it.
-+ - then the client thread does SLAVE STOP.
-+ SLAVE STOP waits for the SQL slave thread to terminate its
-+ update t, which waits for the client thread because t is locked by it.
-+ To prevent that, refuse SLAVE STOP if the
-+ client thread has locked tables
-+ */
-+ if (thd->locked_tables || thd->active_transaction() || thd->global_read_lock)
-+ {
-+ my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
-+ ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
-+ goto error;
-+ }
-+ {
-+ pthread_mutex_lock(&LOCK_active_mi);
-+ stop_slave(thd,active_mi,1/* net report*/);
-+ pthread_mutex_unlock(&LOCK_active_mi);
-+ break;
-+ }
-+#endif /* HAVE_REPLICATION */
-+
-+ case SQLCOM_ALTER_TABLE:
-+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
-+ {
-+ ulong priv=0;
-+ if (lex->name && (!lex->name[0] || strlen(lex->name) > NAME_LEN))
-+ {
-+ my_error(ER_WRONG_TABLE_NAME, MYF(0), lex->name);
-+ goto error;
-+ }
-+ /* Must be set in the parser */
-+ DBUG_ASSERT(select_lex->db);
-+ if (check_access(thd, ALTER_ACL, first_table->db,
-+ &first_table->grant.privilege, 0, 0,
-+ test(first_table->schema_table)) ||
-+ check_access(thd,INSERT_ACL | CREATE_ACL,select_lex->db,&priv,0,0,
-+ is_schema_db(select_lex->db))||
-+ check_merge_table_access(thd, first_table->db,
-+ (TABLE_LIST *)
-+ lex->create_info.merge_list.first))
-+ goto error; /* purecov: inspected */
-+ if (grant_option)
-+ {
-+ if (check_grant(thd, ALTER_ACL, all_tables, 0, UINT_MAX, 0))
-+ goto error;
-+ if (lex->name && !test_all_bits(priv,INSERT_ACL | CREATE_ACL))
-+ { // Rename of table
-+ TABLE_LIST tmp_table;
-+ bzero((char*) &tmp_table,sizeof(tmp_table));
-+ tmp_table.table_name=lex->name;
-+ tmp_table.db=select_lex->db;
-+ tmp_table.grant.privilege=priv;
-+ if (check_grant(thd, INSERT_ACL | CREATE_ACL, &tmp_table, 0,
-+ UINT_MAX, 0))
-+ goto error;
-+ }
-+ }
-+ /* Don't yet allow changing of symlinks with ALTER TABLE */
-+ if (lex->create_info.data_file_name)
-+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
-+ "DATA DIRECTORY option ignored");
-+ if (lex->create_info.index_file_name)
-+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
-+ "INDEX DIRECTORY option ignored");
-+ lex->create_info.data_file_name=lex->create_info.index_file_name=0;
-+ /* ALTER TABLE ends previous transaction */
-+ if (end_active_trans(thd))
-+ goto error;
-+ else
-+ {
-+ if (!thd->locked_tables &&
-+ !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
-+ {
-+ res= 1;
-+ break;
-+ }
-+
-+ thd->enable_slow_log= opt_log_slow_admin_statements;
-+ res= mysql_alter_table(thd, select_lex->db, lex->name,
-+ &lex->create_info,
-+ first_table, lex->create_list,
-+ lex->key_list,
-+ select_lex->order_list.elements,
-+ (ORDER *) select_lex->order_list.first,
-+ lex->ignore, &lex->alter_info, 1);
-+ }
-+ break;
-+ }
-+ case SQLCOM_RENAME_TABLE:
-+ {
-+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
-+ TABLE_LIST *table;
-+ if (check_db_used(thd, all_tables))
-+ goto error;
-+ for (table= first_table; table; table= table->next_local->next_local)
-+ {
-+ if (check_access(thd, ALTER_ACL | DROP_ACL, table->db,
-+ &table->grant.privilege,0,0, test(table->schema_table)) ||
-+ check_access(thd, INSERT_ACL | CREATE_ACL, table->next_local->db,
-+ &table->next_local->grant.privilege, 0, 0,
-+ test(table->next_local->schema_table)))
-+ goto error;
-+ if (grant_option)
-+ {
-+ TABLE_LIST old_list, new_list;
-+ /*
-+ we do not need initialize old_list and new_list because we will
-+ come table[0] and table->next[0] there
-+ */
-+ old_list= table[0];
-+ new_list= table->next_local[0];
-+ if (check_grant(thd, ALTER_ACL | DROP_ACL, &old_list, 0, 1, 0) ||
-+ (!test_all_bits(table->next_local->grant.privilege,
-+ INSERT_ACL | CREATE_ACL) &&
-+ check_grant(thd, INSERT_ACL | CREATE_ACL, &new_list, 0, 1, 0)))
-+ goto error;
-+ }
-+ }
-+ query_cache_invalidate3(thd, first_table, 0);
-+ if (end_active_trans(thd) || mysql_rename_tables(thd, first_table))
-+ goto error;
-+ break;
-+ }
-+#ifndef EMBEDDED_LIBRARY
-+ case SQLCOM_SHOW_BINLOGS:
-+#ifdef DONT_ALLOW_SHOW_COMMANDS
-+ my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
-+ MYF(0)); /* purecov: inspected */
-+ goto error;
-+#else
-+ {
-+ if (check_global_access(thd, SUPER_ACL))
-+ goto error;
-+ res = show_binlogs(thd);
-+ break;
-+ }
-+#endif
-+#endif /* EMBEDDED_LIBRARY */
-+ case SQLCOM_SHOW_CREATE:
-+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
-+#ifdef DONT_ALLOW_SHOW_COMMANDS
-+ my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
-+ MYF(0)); /* purecov: inspected */
-+ goto error;
-+#else
-+ {
-+ /* Ignore temporary tables if this is "SHOW CREATE VIEW" */
-+ if (lex->only_view)
-+ first_table->skip_temporary= 1;
-+
-+ if (check_db_used(thd, all_tables) ||
-+ check_access(thd, SELECT_ACL | EXTRA_ACL, first_table->db,
-+ &first_table->grant.privilege, 0, 0,
-+ test(first_table->schema_table)))
-+ goto error;
-+ if (grant_option && check_grant(thd, SELECT_ACL, all_tables, 2, UINT_MAX, 0))
-+ goto error;
-+ res= mysqld_show_create(thd, first_table);
-+ break;
-+ }
-+#endif
-+ case SQLCOM_CHECKSUM:
-+ {
-+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
-+ if (check_db_used(thd, all_tables) ||
-+ check_table_access(thd, SELECT_ACL | EXTRA_ACL, all_tables, 0))
-+ goto error; /* purecov: inspected */
-+ res = mysql_checksum_table(thd, first_table, &lex->check_opt);
-+ break;
-+ }
-+ case SQLCOM_REPAIR:
-+ {
-+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
-+ if (check_db_used(thd, all_tables) ||
-+ check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0))
-+ goto error; /* purecov: inspected */
-+ thd->enable_slow_log= opt_log_slow_admin_statements;
-+ res= mysql_repair_table(thd, first_table, &lex->check_opt);
-+ /* ! we write after unlocking the table */
-+ if (!res && !lex->no_write_to_binlog)
-+ {
-+ /* Presumably, REPAIR and binlog writing doesn't require synchronization */
-+ if (mysql_bin_log.is_open())
-+ {
-+ thd->clear_error(); // No binlog error generated
-+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
-+ mysql_bin_log.write(&qinfo);
-+ }
-+ }
-+ select_lex->table_list.first= (byte*) first_table;
-+ lex->query_tables=all_tables;
-+ break;
-+ }
-+ case SQLCOM_CHECK:
-+ {
-+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
-+ if (check_db_used(thd, all_tables) ||
-+ check_table_access(thd, SELECT_ACL | EXTRA_ACL , all_tables, 0))
-+ goto error; /* purecov: inspected */
-+ thd->enable_slow_log= opt_log_slow_admin_statements;
-+ res = mysql_check_table(thd, first_table, &lex->check_opt);
-+ select_lex->table_list.first= (byte*) first_table;
-+ lex->query_tables=all_tables;
-+ break;
-+ }
-+ case SQLCOM_ANALYZE:
-+ {
-+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
-+ if (check_db_used(thd, all_tables) ||
-+ check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0))
-+ goto error; /* purecov: inspected */
-+ thd->enable_slow_log= opt_log_slow_admin_statements;
-+ res = mysql_analyze_table(thd, first_table, &lex->check_opt);
-+ /* ! we write after unlocking the table */
-+ if (!res && !lex->no_write_to_binlog)
-+ {
-+ /* Presumably, ANALYZE and binlog writing doesn't require synchronization */
-+ if (mysql_bin_log.is_open())
-+ {
-+ thd->clear_error(); // No binlog error generated
-+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
-+ mysql_bin_log.write(&qinfo);
-+ }
-+ }
-+ select_lex->table_list.first= (byte*) first_table;
-+ lex->query_tables=all_tables;
-+ break;
-+ }
-+
-+ case SQLCOM_OPTIMIZE:
-+ {
-+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
-+ if (check_db_used(thd, all_tables) ||
-+ check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0))
-+ goto error; /* purecov: inspected */
-+ thd->enable_slow_log= opt_log_slow_admin_statements;
-+ res= (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC)) ?
-+ mysql_recreate_table(thd, first_table, 1) :
-+ mysql_optimize_table(thd, first_table, &lex->check_opt);
-+ /* ! we write after unlocking the table */
-+ if (!res && !lex->no_write_to_binlog)
-+ {
-+ /* Presumably, OPTIMIZE and binlog writing doesn't require synchronization */
-+ if (mysql_bin_log.is_open())
-+ {
-+ thd->clear_error(); // No binlog error generated
-+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
-+ mysql_bin_log.write(&qinfo);
-+ }
-+ }
-+ select_lex->table_list.first= (byte*) first_table;
-+ lex->query_tables=all_tables;
-+ break;
-+ }
-+ case SQLCOM_UPDATE:
-+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
-+ if (update_precheck(thd, all_tables))
-+ break;
-+ DBUG_ASSERT(select_lex->offset_limit == 0);
-+ unit->set_limit(select_lex);
-+ res= (result= mysql_update(thd, all_tables,
-+ select_lex->item_list,
-+ lex->value_list,
-+ select_lex->where,
-+ select_lex->order_list.elements,
-+ (ORDER *) select_lex->order_list.first,
-+ unit->select_limit_cnt,
-+ lex->duplicates, lex->ignore));
-+ /* mysql_update return 2 if we need to switch to multi-update */
-+ if (result != 2)
-+ break;
-+ case SQLCOM_UPDATE_MULTI:
-+ {
-+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
-+ /* if we switched from normal update, rights are checked */
-+ if (result != 2)
-+ {
-+ if ((res= multi_update_precheck(thd, all_tables)))
-+ break;
-+ }
-+ else
-+ res= 0;
-+
-+ res= mysql_multi_update_prepare(thd);
-+
-+#ifdef HAVE_REPLICATION
-+ /* Check slave filtering rules */
-+ if (unlikely(thd->slave_thread))
-+ {
-+ if (all_tables_not_ok(thd, all_tables))
-+ {
-+ if (res!= 0)
-+ {
-+ res= 0; /* don't care of prev failure */
-+ thd->clear_error(); /* filters are of highest prior */
-+ }
-+ /* we warn the slave SQL thread */
-+ my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
-+ break;
-+ }
-+ if (res)
-+ break;
-+ }
-+ else
-+ {
-+#endif /* HAVE_REPLICATION */
-+ if (res)
-+ break;
-+ if (opt_readonly &&
-+ !(thd->security_ctx->master_access & SUPER_ACL) &&
-+ some_non_temp_table_to_be_updated(thd, all_tables))
-+ {
-+ my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
-+ break;
-+ }
-+#ifdef HAVE_REPLICATION
-+ } /* unlikely */
-+#endif
-+
-+ res= mysql_multi_update(thd, all_tables,
-+ &select_lex->item_list,
-+ &lex->value_list,
-+ select_lex->where,
-+ select_lex->options,
-+ lex->duplicates, lex->ignore, unit, select_lex);
-+ break;
-+ }
-+ case SQLCOM_REPLACE:
-+ case SQLCOM_INSERT:
-+ {
-+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
-+ if ((res= insert_precheck(thd, all_tables)))
-+ break;
-+
-+ if (!thd->locked_tables &&
-+ !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
-+ {
-+ res= 1;
-+ break;
-+ }
-+
-+ res= mysql_insert(thd, all_tables, lex->field_list, lex->many_values,
-+ lex->update_list, lex->value_list,
-+ lex->duplicates, lex->ignore);
-+
-+ /*
-+ If we have inserted into a VIEW, and the base table has
-+ AUTO_INCREMENT column, but this column is not accessible through
-+ a view, then we should restore LAST_INSERT_ID to the value it
-+ had before the statement.
-+ */
-+ if (first_table->view && !first_table->contain_auto_increment)
-+ thd->last_insert_id= thd->current_insert_id;
-+
-+ break;
-+ }
-+ case SQLCOM_REPLACE_SELECT:
-+ case SQLCOM_INSERT_SELECT:
-+ {
-+ select_result *result;
-+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
-+ if ((res= insert_precheck(thd, all_tables)))
-+ break;
-+
-+ /* Fix lock for first table */
-+ if (first_table->lock_type == TL_WRITE_DELAYED)
-+ first_table->lock_type= TL_WRITE;
-+
-+ /* Don't unlock tables until command is written to binary log */
-+ select_lex->options|= SELECT_NO_UNLOCK;
-+
-+ unit->set_limit(select_lex);
-+
-+ if (! thd->locked_tables &&
-+ ! (need_start_waiting= ! wait_if_global_read_lock(thd, 0, 1)))
-+ {
-+ res= 1;
-+ break;
-+ }
-+
-+ if (!(res= open_and_lock_tables(thd, all_tables)))
-+ {
-+ /* Skip first table, which is the table we are inserting in */
-+ TABLE_LIST *second_table= first_table->next_local;
-+ select_lex->table_list.first= (byte*) second_table;
-+ select_lex->context.table_list=
-+ select_lex->context.first_name_resolution_table= second_table;
-+ res= mysql_insert_select_prepare(thd);
-+ if (!res && (result= new select_insert(first_table, first_table->table,
-+ &lex->field_list,
-+ &lex->update_list,
-+ &lex->value_list,
-+ lex->duplicates, lex->ignore)))
-+ {
-+ res= handle_select(thd, lex, result, OPTION_SETUP_TABLES_DONE);
-+ /*
-+ Invalidate the table in the query cache if something changed
-+ after unlocking when changes become visible.
-+ TODO: this is workaround. right way will be move invalidating in
-+ the unlock procedure.
-+ */
-+ if (first_table->lock_type == TL_WRITE_CONCURRENT_INSERT &&
-+ thd->lock)
-+ {
-+ /* INSERT ... SELECT should invalidate only the very first table */
-+ TABLE_LIST *save_table= first_table->next_local;
-+ first_table->next_local= 0;
-+ mysql_unlock_tables(thd, thd->lock);
-+ query_cache_invalidate3(thd, first_table, 1);
-+ first_table->next_local= save_table;
-+ thd->lock=0;
-+ }
-+ delete result;
-+ }
-+ /* revert changes for SP */
-+ select_lex->table_list.first= (byte*) first_table;
-+ }
-+
-+ /*
-+ If we have inserted into a VIEW, and the base table has
-+ AUTO_INCREMENT column, but this column is not accessible through
-+ a view, then we should restore LAST_INSERT_ID to the value it
-+ had before the statement.
-+ */
-+ if (first_table->view && !first_table->contain_auto_increment)
-+ thd->last_insert_id= thd->current_insert_id;
-+
-+ break;
-+ }
-+ case SQLCOM_TRUNCATE:
-+ if (end_active_trans(thd))
-+ {
-+ res= -1;
-+ break;
-+ }
-+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
-+ if (check_one_table_access(thd, DELETE_ACL, all_tables))
-+ goto error;
-+ /*
-+ Don't allow this within a transaction because we want to use
-+ re-generate table
-+ */
-+ if (thd->locked_tables || thd->active_transaction())
-+ {
-+ my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
-+ ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
-+ goto error;
-+ }
-+
-+ res= mysql_truncate(thd, first_table, 0);
-+ break;
-+ case SQLCOM_DELETE:
-+ {
-+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
-+ if ((res= delete_precheck(thd, all_tables)))
-+ break;
-+ DBUG_ASSERT(select_lex->offset_limit == 0);
-+ unit->set_limit(select_lex);
-+
-+ if (!thd->locked_tables &&
-+ !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
-+ {
-+ res= 1;
-+ break;
-+ }
-+
-+ res = mysql_delete(thd, all_tables, select_lex->where,
-+ &select_lex->order_list,
-+ unit->select_limit_cnt, select_lex->options,
-+ FALSE);
-+ break;
-+ }
-+ case SQLCOM_DELETE_MULTI:
-+ {
-+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
-+ TABLE_LIST *aux_tables=
-+ (TABLE_LIST *)thd->lex->auxiliary_table_list.first;
-+ multi_delete *result;
-+
-+ if (!thd->locked_tables &&
-+ !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
-+ {
-+ res= 1;
-+ break;
-+ }
-+
-+ if ((res= multi_delete_precheck(thd, all_tables)))
-+ break;
-+
-+ /* condition will be TRUE on SP re-excuting */
-+ if (select_lex->item_list.elements != 0)
-+ select_lex->item_list.empty();
-+ if (add_item_to_list(thd, new Item_null()))
-+ goto error;
-+
-+ thd->proc_info="init";
-+ if ((res= open_and_lock_tables(thd, all_tables)))
-+ break;
-+
-+ if ((res= mysql_multi_delete_prepare(thd)))
-+ goto error;
-+
-+ if (!thd->is_fatal_error && (result= new multi_delete(aux_tables,
-+ lex->table_count)))
-+ {
-+ res= mysql_select(thd, &select_lex->ref_pointer_array,
-+ select_lex->get_table_list(),
-+ select_lex->with_wild,
-+ select_lex->item_list,
-+ select_lex->where,
-+ 0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL,
-+ (ORDER *)NULL,
-+ select_lex->options | thd->options |
-+ SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK |
-+ OPTION_SETUP_TABLES_DONE,
-+ result, unit, select_lex);
-+ delete result;
-+ }
-+ else
-+ res= TRUE; // Error
-+ break;
-+ }
-+ case SQLCOM_DROP_TABLE:
-+ {
-+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
-+ if (!lex->drop_temporary)
-+ {
-+ if (check_table_access(thd, DROP_ACL, all_tables, 0))
-+ goto error; /* purecov: inspected */
-+ if (end_active_trans(thd))
-+ goto error;
-+ }
-+ else
-+ {
-+ /*
-+ If this is a slave thread, we may sometimes execute some
-+ DROP / * 40005 TEMPORARY * / TABLE
-+ that come from parts of binlogs (likely if we use RESET SLAVE or CHANGE
-+ MASTER TO), while the temporary table has already been dropped.
-+ To not generate such irrelevant "table does not exist errors",
-+ we silently add IF EXISTS if TEMPORARY was used.
-+ */
-+ if (thd->slave_thread)
-+ lex->drop_if_exists= 1;
-+
-+ /* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */
-+ thd->options|= OPTION_STATUS_NO_TRANS_UPDATE;
-+ }
-+ /* DDL and binlog write order protected by LOCK_open */
-+ res= mysql_rm_table(thd, first_table, lex->drop_if_exists,
-+ lex->drop_temporary);
-+ }
-+ break;
-+ case SQLCOM_DROP_INDEX:
-+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
-+ if (check_one_table_access(thd, INDEX_ACL, all_tables))
-+ goto error; /* purecov: inspected */
-+ if (end_active_trans(thd))
-+ goto error;
-+ else
-+ res = mysql_drop_index(thd, first_table, &lex->alter_info);
-+ break;
-+ case SQLCOM_SHOW_PROCESSLIST:
-+ if (!thd->security_ctx->priv_user[0] &&
-+ check_global_access(thd,PROCESS_ACL))
-+ break;
-+ mysqld_list_processes(thd,
-+ (thd->security_ctx->master_access & PROCESS_ACL ?
-+ NullS :
-+ thd->security_ctx->priv_user),
-+ lex->verbose);
-+ break;
-+ case SQLCOM_SHOW_STORAGE_ENGINES:
-+ res= mysqld_show_storage_engines(thd);
-+ break;
-+ case SQLCOM_SHOW_PRIVILEGES:
-+ res= mysqld_show_privileges(thd);
-+ break;
-+ case SQLCOM_SHOW_COLUMN_TYPES:
-+ res= mysqld_show_column_types(thd);
-+ break;
-+ case SQLCOM_SHOW_LOGS:
-+#ifdef DONT_ALLOW_SHOW_COMMANDS
-+ my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
-+ MYF(0)); /* purecov: inspected */
-+ goto error;
-+#else
-+ {
-+ if (grant_option && check_access(thd, FILE_ACL, any_db,0,0,0,0))
-+ goto error;
-+ res= mysqld_show_logs(thd);
-+ break;
-+ }
-+#endif
-+ case SQLCOM_CHANGE_DB:
-+ if (!mysql_change_db(thd,select_lex->db,FALSE))
-+ send_ok(thd);
-+ break;
-+
-+ case SQLCOM_LOAD:
-+ {
-+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
-+ uint privilege= (lex->duplicates == DUP_REPLACE ?
-+ INSERT_ACL | DELETE_ACL : INSERT_ACL) |
-+ (lex->local_file ? 0 : FILE_ACL);
-+
-+ if (lex->local_file)
-+ {
-+ if (!(thd->client_capabilities & CLIENT_LOCAL_FILES) ||
-+ !opt_local_infile)
-+ {
-+ my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND), MYF(0));
-+ goto error;
-+ }
-+ }
-+
-+ if (check_one_table_access(thd, privilege, all_tables))
-+ goto error;
-+
-+ res= mysql_load(thd, lex->exchange, first_table, lex->field_list,
-+ lex->update_list, lex->value_list, lex->duplicates,
-+ lex->ignore, (bool) lex->local_file);
-+ break;
-+ }
-+
-+ case SQLCOM_SET_OPTION:
-+ {
-+ List<set_var_base> *lex_var_list= &lex->var_list;
-+ 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))
-+ {
-+ my_error(ER_RESERVED_SYNTAX, MYF(0), "SET ONE_SHOT");
-+ goto error;
-+ }
-+ if (!(res= sql_set_variables(thd, lex_var_list)))
-+ {
-+ /*
-+ If the previous command was a SET ONE_SHOT, we don't want to forget
-+ about the ONE_SHOT property of that SET. So we use a |= instead of = .
-+ */
-+ thd->one_shot_set|= lex->one_shot_set;
-+ send_ok(thd);
-+ }
-+ break;
-+ }
-+
-+ case SQLCOM_UNLOCK_TABLES:
-+ /*
-+ It is critical for mysqldump --single-transaction --master-data that
-+ UNLOCK TABLES does not implicitely commit a connection which has only
-+ done FLUSH TABLES WITH READ LOCK + BEGIN. If this assumption becomes
-+ false, mysqldump will not work.
-+ */
-+ unlock_locked_tables(thd);
-+ if (thd->options & OPTION_TABLE_LOCK)
-+ {
-+ end_active_trans(thd);
-+ thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
-+ }
-+ if (thd->global_read_lock)
-+ unlock_global_read_lock(thd);
-+ send_ok(thd);
-+ break;
-+ case SQLCOM_LOCK_TABLES:
-+ unlock_locked_tables(thd);
-+ if (check_db_used(thd, all_tables) || end_active_trans(thd))
-+ goto error;
-+ if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables, 0))
-+ goto error;
-+ thd->in_lock_tables=1;
-+ thd->options|= OPTION_TABLE_LOCK;
-+
-+ if (!(res= simple_open_n_lock_tables(thd, all_tables)))
-+ {
-+#ifdef HAVE_QUERY_CACHE
-+ if (thd->variables.query_cache_wlock_invalidate)
-+ query_cache.invalidate_locked_for_write(first_table);
-+#endif /*HAVE_QUERY_CACHE*/
-+ thd->locked_tables=thd->lock;
-+ thd->lock=0;
-+ send_ok(thd);
-+ }
-+ else
-+ thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
-+ thd->in_lock_tables=0;
-+ break;
-+ case SQLCOM_CREATE_DB:
-+ {
-+ if (end_active_trans(thd))
-+ {
-+ res= -1;
-+ break;
-+ }
-+ char *alias;
-+ if (!(alias=thd->strdup(lex->name)) || check_db_name(lex->name))
-+ {
-+ my_error(ER_WRONG_DB_NAME, MYF(0), lex->name);
-+ break;
-+ }
-+ /*
-+ If in a slave thread :
-+ CREATE DATABASE DB was certainly not preceded by USE DB.
-+ For that reason, db_ok() in sql/slave.cc did not check the
-+ do_db/ignore_db. And as this query involves no tables, tables_ok()
-+ above was not called. So we have to check rules again here.
-+ */
-+#ifdef HAVE_REPLICATION
-+ if (thd->slave_thread &&
-+ (!db_ok(lex->name, replicate_do_db, replicate_ignore_db) ||
-+ !db_ok_with_wild_table(lex->name)))
-+ {
-+ my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
-+ break;
-+ }
-+#endif
-+ if (check_access(thd,CREATE_ACL,lex->name,0,1,0,is_schema_db(lex->name)))
-+ break;
-+ res= mysql_create_db(thd,(lower_case_table_names == 2 ? alias : lex->name),
-+ &lex->create_info, 0);
-+ break;
-+ }
-+ case SQLCOM_DROP_DB:
-+ {
-+ if (end_active_trans(thd))
-+ {
-+ res= -1;
-+ break;
-+ }
-+ if (check_db_name(lex->name))
-+ {
-+ my_error(ER_WRONG_DB_NAME, MYF(0), lex->name);
-+ break;
-+ }
-+ /*
-+ If in a slave thread :
-+ DROP DATABASE DB may not be preceded by USE DB.
-+ For that reason, maybe db_ok() in sql/slave.cc did not check the
-+ do_db/ignore_db. And as this query involves no tables, tables_ok()
-+ above was not called. So we have to check rules again here.
-+ */
-+#ifdef HAVE_REPLICATION
-+ if (thd->slave_thread &&
-+ (!db_ok(lex->name, replicate_do_db, replicate_ignore_db) ||
-+ !db_ok_with_wild_table(lex->name)))
-+ {
-+ my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
-+ break;
-+ }
-+#endif
-+ if (check_access(thd,DROP_ACL,lex->name,0,1,0,is_schema_db(lex->name)))
-+ break;
-+ if (thd->locked_tables || thd->active_transaction())
-+ {
-+ my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
-+ ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
-+ goto error;
-+ }
-+ res= mysql_rm_db(thd, lex->name, lex->drop_if_exists, 0);
-+ break;
-+ }
-+ case SQLCOM_ALTER_DB:
-+ {
-+ char *db= lex->name;
-+ DBUG_ASSERT(db); /* Must be set in the parser */
-+ if (!strip_sp(db) || check_db_name(db))
-+ {
-+ my_error(ER_WRONG_DB_NAME, MYF(0), lex->name);
-+ break;
-+ }
-+ /*
-+ If in a slave thread :
-+ ALTER DATABASE DB may not be preceded by USE DB.
-+ For that reason, maybe db_ok() in sql/slave.cc did not check the
-+ do_db/ignore_db. And as this query involves no tables, tables_ok()
-+ above was not called. So we have to check rules again here.
-+ */
-+#ifdef HAVE_REPLICATION
-+ if (thd->slave_thread &&
-+ (!db_ok(db, replicate_do_db, replicate_ignore_db) ||
-+ !db_ok_with_wild_table(db)))
-+ {
-+ my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
-+ break;
-+ }
-+#endif
-+ if (check_access(thd, ALTER_ACL, db, 0, 1, 0, is_schema_db(db)))
-+ break;
-+ if (thd->locked_tables || thd->active_transaction())
-+ {
-+ my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
-+ ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
-+ goto error;
-+ }
-+ res= mysql_alter_db(thd, db, &lex->create_info);
-+ break;
-+ }
-+ case SQLCOM_SHOW_CREATE_DB:
-+ {
-+ if (!strip_sp(lex->name) || check_db_name(lex->name))
-+ {
-+ my_error(ER_WRONG_DB_NAME, MYF(0), lex->name);
-+ break;
-+ }
-+ if (check_access(thd,SELECT_ACL,lex->name,0,1,0,is_schema_db(lex->name)))
-+ break;
-+ res=mysqld_show_create_db(thd,lex->name,&lex->create_info);
-+ break;
-+ }
-+ case SQLCOM_CREATE_FUNCTION: // UDF function
-+ {
-+ if (check_access(thd,INSERT_ACL,"mysql",0,1,0,0))
-+ break;
-+#ifdef HAVE_DLOPEN
-+ if (sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname,
-+ &thd->sp_func_cache, FALSE))
-+ {
-+ my_error(ER_UDF_EXISTS, MYF(0), lex->spname->m_name.str);
-+ goto error;
-+ }
-+ if (!(res = mysql_create_function(thd, &lex->udf)))
-+ send_ok(thd);
-+#else
-+ my_error(ER_CANT_OPEN_LIBRARY, MYF(0), lex->udf.dl, 0, "feature disabled");
-+ res= TRUE;
-+#endif
-+ break;
-+ }
-+#ifndef NO_EMBEDDED_ACCESS_CHECKS
-+ case SQLCOM_CREATE_USER:
-+ {
-+ if (check_access(thd, INSERT_ACL, "mysql", 0, 1, 1, 0) &&
-+ check_global_access(thd,CREATE_USER_ACL))
-+ break;
-+ if (end_active_trans(thd))
-+ goto error;
-+ /* Conditionally writes to binlog */
-+ if (!(res= mysql_create_user(thd, lex->users_list)))
-+ send_ok(thd);
-+ break;
-+ }
-+ case SQLCOM_DROP_USER:
-+ {
-+ if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 1, 0) &&
-+ check_global_access(thd,CREATE_USER_ACL))
-+ break;
-+ if (end_active_trans(thd))
-+ goto error;
-+ /* Conditionally writes to binlog */
-+ if (!(res= mysql_drop_user(thd, lex->users_list)))
-+ send_ok(thd);
-+ break;
-+ }
-+ case SQLCOM_RENAME_USER:
-+ {
-+ if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1, 0) &&
-+ check_global_access(thd,CREATE_USER_ACL))
-+ break;
-+ if (end_active_trans(thd))
-+ goto error;
-+ /* Conditionally writes to binlog */
-+ if (!(res= mysql_rename_user(thd, lex->users_list)))
-+ send_ok(thd);
-+ break;
-+ }
-+ case SQLCOM_REVOKE_ALL:
-+ {
-+ if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1, 0) &&
-+ check_global_access(thd,CREATE_USER_ACL))
-+ break;
-+ /* Conditionally writes to binlog */
-+ if (!(res = mysql_revoke_all(thd, lex->users_list)))
-+ send_ok(thd);
-+ break;
-+ }
-+ case SQLCOM_REVOKE:
-+ case SQLCOM_GRANT:
-+ {
-+ if (check_access(thd, lex->grant | lex->grant_tot_col | GRANT_ACL,
-+ first_table ? first_table->db : select_lex->db,
-+ first_table ? &first_table->grant.privilege : 0,
-+ first_table ? 0 : 1, 0,
-+ first_table ? (bool) first_table->schema_table :
-+ select_lex->db ? is_schema_db(select_lex->db) : 0))
-+ goto error;
-+
-+ if (thd->security_ctx->user) // If not replication
-+ {
-+ LEX_USER *user, *tmp_user;
-+
-+ List_iterator <LEX_USER> user_list(lex->users_list);
-+ while ((tmp_user= user_list++))
-+ {
-+ if (!(user= get_current_user(thd, tmp_user)))
-+ goto error;
-+ if (specialflag & SPECIAL_NO_RESOLVE &&
-+ hostname_requires_resolving(user->host.str))
-+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
-+ ER_WARN_HOSTNAME_WONT_WORK,
-+ ER(ER_WARN_HOSTNAME_WONT_WORK),
-+ user->host.str);
-+ // Are we trying to change a password of another user
-+ DBUG_ASSERT(user->host.str != 0);
-+ if (strcmp(thd->security_ctx->user, user->user.str) ||
-+ my_strcasecmp(system_charset_info,
-+ user->host.str, thd->security_ctx->host_or_ip))
-+ {
-+ // TODO: use check_change_password()
-+ if (is_acl_user(user->host.str, user->user.str) &&
-+ user->password.str &&
-+ check_access(thd, UPDATE_ACL,"mysql",0,1,1,0))
-+ {
-+ my_message(ER_PASSWORD_NOT_ALLOWED,
-+ ER(ER_PASSWORD_NOT_ALLOWED), MYF(0));
-+ goto error;
-+ }
-+ }
-+ }
-+ }
-+ if (first_table)
-+ {
-+ if (lex->type == TYPE_ENUM_PROCEDURE ||
-+ lex->type == TYPE_ENUM_FUNCTION)
-+ {
-+ uint grants= lex->all_privileges
-+ ? (PROC_ACLS & ~GRANT_ACL) | (lex->grant & GRANT_ACL)
-+ : lex->grant;
-+ if (grant_option &&
-+ check_grant_routine(thd, grants | GRANT_ACL, all_tables,
-+ lex->type == TYPE_ENUM_PROCEDURE, 0))
-+ goto error;
-+ /* Conditionally writes to binlog */
-+ res= mysql_routine_grant(thd, all_tables,
-+ lex->type == TYPE_ENUM_PROCEDURE,
-+ lex->users_list, grants,
-+ lex->sql_command == SQLCOM_REVOKE, 0);
-+ }
-+ else
-+ {
-+ if (grant_option && check_grant(thd,
-+ (lex->grant | lex->grant_tot_col |
-+ GRANT_ACL),
-+ all_tables, 0, UINT_MAX, 0))
-+ goto error;
-+ /* Conditionally writes to binlog */
-+ res= mysql_table_grant(thd, all_tables, lex->users_list,
-+ lex->columns, lex->grant,
-+ lex->sql_command == SQLCOM_REVOKE);
-+ }
-+ }
-+ else
-+ {
-+ if (lex->columns.elements || lex->type)
-+ {
-+ my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER(ER_ILLEGAL_GRANT_FOR_TABLE),
-+ MYF(0));
-+ goto error;
-+ }
-+ else
-+ /* Conditionally writes to binlog */
-+ res = mysql_grant(thd, select_lex->db, lex->users_list, lex->grant,
-+ lex->sql_command == SQLCOM_REVOKE);
-+ if (!res)
-+ {
-+ if (lex->sql_command == SQLCOM_GRANT)
-+ {
-+ List_iterator <LEX_USER> str_list(lex->users_list);
-+ LEX_USER *user, *tmp_user;
-+ while ((tmp_user=str_list++))
-+ {
-+ if (!(user= get_current_user(thd, tmp_user)))
-+ goto error;
-+ reset_mqh(user);
-+ }
-+ }
-+ }
-+ }
-+ break;
-+ }
-+#endif /*!NO_EMBEDDED_ACCESS_CHECKS*/
-+ case SQLCOM_RESET:
-+ /*
-+ RESET commands are never written to the binary log, so we have to
-+ initialize this variable because RESET shares the same code as FLUSH
-+ */
-+ lex->no_write_to_binlog= 1;
-+ case SQLCOM_FLUSH:
-+ {
-+ bool write_to_binlog;
-+ if (check_global_access(thd,RELOAD_ACL))
-+ goto error;
-+
-+ /*
-+ reload_acl_and_cache() will tell us if we are allowed to write to the
-+ binlog or not.
-+ */
-+ if (!reload_acl_and_cache(thd, lex->type, first_table, &write_to_binlog))
-+ {
-+ /*
-+ We WANT to write and we CAN write.
-+ ! we write after unlocking the table.
-+ */
-+ /* Presumably, RESET and binlog writing doesn't require synchronization */
-+ if (!lex->no_write_to_binlog && write_to_binlog)
-+ {
-+ if (mysql_bin_log.is_open())
-+ {
-+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
-+ mysql_bin_log.write(&qinfo);
-+ }
-+ }
-+ send_ok(thd);
-+ }
-+
-+ break;
-+ }
-+ case SQLCOM_KILL:
-+ {
-+ Item *it= (Item *)lex->value_list.head();
-+
-+ if ((!it->fixed && it->fix_fields(lex->thd, &it)) || it->check_cols(1))
-+ {
-+ my_message(ER_SET_CONSTANTS_ONLY, ER(ER_SET_CONSTANTS_ONLY),
-+ MYF(0));
-+ goto error;
-+ }
-+ kill_one_thread(thd, (ulong)it->val_int(), lex->type & ONLY_KILL_QUERY);
-+ break;
-+ }
-+#ifndef NO_EMBEDDED_ACCESS_CHECKS
-+ case SQLCOM_SHOW_GRANTS:
-+ {
-+ LEX_USER *grant_user= get_current_user(thd, lex->grant_user);
-+ if (!grant_user)
-+ goto error;
-+ if ((thd->security_ctx->priv_user &&
-+ !strcmp(thd->security_ctx->priv_user, grant_user->user.str)) ||
-+ !check_access(thd, SELECT_ACL, "mysql",0,1,0,0))
-+ {
-+ res = mysql_show_grants(thd, grant_user);
-+ }
-+ break;
-+ }
-+#endif
-+ case SQLCOM_HA_OPEN:
-+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
-+ if (check_db_used(thd, all_tables) ||
-+ check_table_access(thd, SELECT_ACL, all_tables, 0))
-+ goto error;
-+ res= mysql_ha_open(thd, first_table, 0);
-+ break;
-+ case SQLCOM_HA_CLOSE:
-+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
-+ if (check_db_used(thd, all_tables))
-+ goto error;
-+ res= mysql_ha_close(thd, first_table);
-+ break;
-+ case SQLCOM_HA_READ:
-+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
-+ /*
-+ There is no need to check for table permissions here, because
-+ if a user has no permissions to read a table, he won't be
-+ able to open it (with SQLCOM_HA_OPEN) in the first place.
-+ */
-+ if (check_db_used(thd, all_tables))
-+ goto error;
-+ unit->set_limit(select_lex);
-+ res= mysql_ha_read(thd, first_table, lex->ha_read_mode, lex->ident.str,
-+ lex->insert_list, lex->ha_rkey_mode, select_lex->where,
-+ unit->select_limit_cnt, unit->offset_limit_cnt);
-+ break;
-+
-+ case SQLCOM_BEGIN:
-+ if (thd->transaction.xid_state.xa_state != XA_NOTR)
-+ {
-+ my_error(ER_XAER_RMFAIL, MYF(0),
-+ xa_state_names[thd->transaction.xid_state.xa_state]);
-+ break;
-+ }
-+ if (begin_trans(thd))
-+ goto error;
-+ send_ok(thd);
-+ break;
-+ case SQLCOM_COMMIT:
-+ if (end_trans(thd, lex->tx_release ? COMMIT_RELEASE :
-+ lex->tx_chain ? COMMIT_AND_CHAIN : COMMIT))
-+ goto error;
-+ send_ok(thd);
-+ break;
-+ case SQLCOM_ROLLBACK:
-+ if (end_trans(thd, lex->tx_release ? ROLLBACK_RELEASE :
-+ lex->tx_chain ? ROLLBACK_AND_CHAIN : ROLLBACK))
-+ goto error;
-+ send_ok(thd);
-+ break;
-+ case SQLCOM_RELEASE_SAVEPOINT:
-+ {
-+ SAVEPOINT *sv;
-+ for (sv=thd->transaction.savepoints; sv; sv=sv->prev)
-+ {
-+ if (my_strnncoll(system_charset_info,
-+ (uchar *)lex->ident.str, lex->ident.length,
-+ (uchar *)sv->name, sv->length) == 0)
-+ break;
-+ }
-+ if (sv)
-+ {
-+ if (ha_release_savepoint(thd, sv))
-+ res= TRUE; // cannot happen
-+ else
-+ send_ok(thd);
-+ thd->transaction.savepoints=sv->prev;
-+ }
-+ else
-+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", lex->ident.str);
-+ break;
-+ }
-+ case SQLCOM_ROLLBACK_TO_SAVEPOINT:
-+ {
-+ SAVEPOINT *sv;
-+ for (sv=thd->transaction.savepoints; sv; sv=sv->prev)
-+ {
-+ if (my_strnncoll(system_charset_info,
-+ (uchar *)lex->ident.str, lex->ident.length,
-+ (uchar *)sv->name, sv->length) == 0)
-+ break;
-+ }
-+ if (sv)
-+ {
-+ if (ha_rollback_to_savepoint(thd, sv))
-+ res= TRUE; // cannot happen
-+ else
-+ {
-+ if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) &&
-+ !thd->slave_thread)
-+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
-+ ER_WARNING_NOT_COMPLETE_ROLLBACK,
-+ ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
-+ send_ok(thd);
-+ }
-+ thd->transaction.savepoints=sv;
-+ }
-+ else
-+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", lex->ident.str);
-+ break;
-+ }
-+ case SQLCOM_SAVEPOINT:
-+ if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN) ||
-+ thd->in_sub_stmt) || !opt_using_transactions)
-+ send_ok(thd);
-+ else
-+ {
-+ SAVEPOINT **sv, *newsv;
-+ for (sv=&thd->transaction.savepoints; *sv; sv=&(*sv)->prev)
-+ {
-+ if (my_strnncoll(system_charset_info,
-+ (uchar *)lex->ident.str, lex->ident.length,
-+ (uchar *)(*sv)->name, (*sv)->length) == 0)
-+ break;
-+ }
-+ if (*sv) /* old savepoint of the same name exists */
-+ {
-+ newsv=*sv;
-+ ha_release_savepoint(thd, *sv); // it cannot fail
-+ *sv=(*sv)->prev;
-+ }
-+ else if ((newsv=(SAVEPOINT *) alloc_root(&thd->transaction.mem_root,
-+ savepoint_alloc_size)) == 0)
-+ {
-+ my_error(ER_OUT_OF_RESOURCES, MYF(0));
-+ break;
-+ }
-+ newsv->name=strmake_root(&thd->transaction.mem_root,
-+ lex->ident.str, lex->ident.length);
-+ newsv->length=lex->ident.length;
-+ /*
-+ if we'll get an error here, don't add new savepoint to the list.
-+ we'll lose a little bit of memory in transaction mem_root, but it'll
-+ be free'd when transaction ends anyway
-+ */
-+ if (ha_savepoint(thd, newsv))
-+ res= TRUE;
-+ else
-+ {
-+ newsv->prev=thd->transaction.savepoints;
-+ thd->transaction.savepoints=newsv;
-+ send_ok(thd);
-+ }
-+ }
-+ break;
-+ case SQLCOM_CREATE_PROCEDURE:
-+ case SQLCOM_CREATE_SPFUNCTION:
-+ {
-+ uint namelen;
-+ char *name;
-+ int result= SP_INTERNAL_ERROR;
-+
-+ DBUG_ASSERT(lex->sphead != 0);
-+ DBUG_ASSERT(lex->sphead->m_db.str); /* Must be initialized in the parser */
-+ /*
-+ Verify that the database name is allowed, optionally
-+ lowercase it.
-+ */
-+ if (check_db_name(lex->sphead->m_db.str))
-+ {
-+ my_error(ER_WRONG_DB_NAME, MYF(0), lex->sphead->m_db.str);
-+ goto create_sp_error;
-+ }
-+
-+ /*
-+ Check that a database directory with this name
-+ exists. Design note: This won't work on virtual databases
-+ like information_schema.
-+ */
-+ if (check_db_dir_existence(lex->sphead->m_db.str))
-+ {
-+ my_error(ER_BAD_DB_ERROR, MYF(0), lex->sphead->m_db.str);
-+ goto create_sp_error;
-+ }
-+
-+ if (check_access(thd, CREATE_PROC_ACL, lex->sphead->m_db.str, 0, 0, 0,
-+ is_schema_db(lex->sphead->m_db.str)))
-+ goto create_sp_error;
-+
-+ if (end_active_trans(thd))
-+ goto create_sp_error;
-+
-+ name= lex->sphead->name(&namelen);
-+#ifdef HAVE_DLOPEN
-+ if (lex->sphead->m_type == TYPE_ENUM_FUNCTION)
-+ {
-+ udf_func *udf = find_udf(name, namelen);
-+
-+ if (udf)
-+ {
-+ my_error(ER_UDF_EXISTS, MYF(0), name);
-+ goto create_sp_error;
-+ }
-+ }
-+#endif
-+
-+ /*
-+ If the definer is not specified, this means that CREATE-statement missed
-+ DEFINER-clause. DEFINER-clause can be missed in two cases:
-+
-+ - The user submitted a statement w/o the clause. This is a normal
-+ case, we should assign CURRENT_USER as definer.
-+
-+ - Our slave received an updated from the master, that does not
-+ replicate definer for stored rountines. We should also assign
-+ CURRENT_USER as definer here, but also we should mark this routine
-+ as NON-SUID. This is essential for the sake of backward
-+ compatibility.
-+
-+ The problem is the slave thread is running under "special" user (@),
-+ that actually does not exist. In the older versions we do not fail
-+ execution of a stored routine if its definer does not exist and
-+ continue the execution under the authorization of the invoker
-+ (BUG#13198). And now if we try to switch to slave-current-user (@),
-+ we will fail.
-+
-+ Actually, this leads to the inconsistent state of master and
-+ slave (different definers, different SUID behaviour), but it seems,
-+ this is the best we can do.
-+ */
-+
-+ if (!lex->definer)
-+ {
-+ bool res= FALSE;
-+ Query_arena original_arena;
-+ Query_arena *ps_arena = thd->activate_stmt_arena_if_needed(&original_arena);
-+
-+ if (!(lex->definer= create_default_definer(thd)))
-+ res= TRUE;
-+
-+ if (ps_arena)
-+ thd->restore_active_arena(ps_arena, &original_arena);
-+
-+ /* Error has been already reported. */
-+ if (res)
-+ goto create_sp_error;
-+
-+ if (thd->slave_thread)
-+ lex->sphead->m_chistics->suid= SP_IS_NOT_SUID;
-+ }
-+
-+ /*
-+ If the specified definer differs from the current user, we should check
-+ that the current user has SUPER privilege (in order to create a stored
-+ routine under another user one must have SUPER privilege).
-+ */
-+
-+ else if (strcmp(lex->definer->user.str, thd->security_ctx->priv_user) ||
-+ my_strcasecmp(system_charset_info,
-+ lex->definer->host.str,
-+ thd->security_ctx->priv_host))
-+ {
-+ if (check_global_access(thd, SUPER_ACL))
-+ {
-+ my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER");
-+ goto create_sp_error;
-+ }
-+ }
-+
-+ /* Check that the specified definer exists. Emit a warning if not. */
-+
-+#ifndef NO_EMBEDDED_ACCESS_CHECKS
-+ if (!is_acl_user(lex->definer->host.str,
-+ lex->definer->user.str))
-+ {
-+ push_warning_printf(thd,
-+ MYSQL_ERROR::WARN_LEVEL_NOTE,
-+ ER_NO_SUCH_USER,
-+ ER(ER_NO_SUCH_USER),
-+ lex->definer->user.str,
-+ lex->definer->host.str);
-+ }
-+#endif /* NO_EMBEDDED_ACCESS_CHECKS */
-+
-+ res= (result= lex->sphead->create(thd));
-+ switch (result) {
-+ case SP_OK:
-+#ifndef NO_EMBEDDED_ACCESS_CHECKS
-+ /* only add privileges if really neccessary */
-+ if (sp_automatic_privileges && !opt_noacl &&
-+ check_routine_access(thd, DEFAULT_CREATE_PROC_ACLS,
-+ lex->sphead->m_db.str, name,
-+ lex->sql_command == SQLCOM_CREATE_PROCEDURE, 1))
-+ {
-+ if (sp_grant_privileges(thd, lex->sphead->m_db.str, name,
-+ lex->sql_command == SQLCOM_CREATE_PROCEDURE))
-+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
-+ ER_PROC_AUTO_GRANT_FAIL,
-+ ER(ER_PROC_AUTO_GRANT_FAIL));
-+ close_thread_tables(thd);
-+ }
-+#endif
-+ break;
-+ case SP_WRITE_ROW_FAILED:
-+ my_error(ER_SP_ALREADY_EXISTS, MYF(0), SP_TYPE_STRING(lex), name);
-+ break;
-+ case SP_BAD_IDENTIFIER:
-+ my_error(ER_TOO_LONG_IDENT, MYF(0), name);
-+ break;
-+ case SP_BODY_TOO_LONG:
-+ my_error(ER_TOO_LONG_BODY, MYF(0), name);
-+ break;
-+ default:
-+ my_error(ER_SP_STORE_FAILED, MYF(0), SP_TYPE_STRING(lex), name);
-+ break;
-+ } /* end switch */
-+
-+ /*
-+ Capture all errors within this CASE and
-+ clean up the environment.
-+ */
-+create_sp_error:
-+ lex->unit.cleanup();
-+ delete lex->sphead;
-+ lex->sphead= 0;
-+ if (result != SP_OK )
-+ goto error;
-+ send_ok(thd);
-+ break; /* break super switch */
-+ } /* end case group bracket */
-+ case SQLCOM_CALL:
-+ {
-+ sp_head *sp;
-+
-+ /*
-+ 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.
-+ */
-+ if (!(sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname,
-+ &thd->sp_proc_cache, TRUE)))
-+ {
-+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PROCEDURE",
-+ lex->spname->m_qname.str);
-+ goto error;
-+ }
-+ else
-+ {
-+ ha_rows select_limit;
-+ /* bits that should be cleared in thd->server_status */
-+ uint bits_to_be_cleared= 0;
-+ /*
-+ Check that the stored procedure doesn't contain Dynamic SQL
-+ and doesn't return result sets: such stored procedures can't
-+ be called from a function or trigger.
-+ */
-+ if (thd->in_sub_stmt)
-+ {
-+ const char *where= (thd->in_sub_stmt & SUB_STMT_TRIGGER ?
-+ "trigger" : "function");
-+ if (sp->is_not_allowed_in_function(where))
-+ goto error;
-+ }
-+
-+ my_bool nsok= thd->net.no_send_ok;
-+ thd->net.no_send_ok= TRUE;
-+ if (sp->m_flags & sp_head::MULTI_RESULTS)
-+ {
-+ if (! (thd->client_capabilities & CLIENT_MULTI_RESULTS))
-+ {
-+ /*
-+ The client does not support multiple result sets being sent
-+ back
-+ */
-+ my_error(ER_SP_BADSELECT, MYF(0), sp->m_qname.str);
-+ thd->net.no_send_ok= nsok;
-+ goto error;
-+ }
-+ /*
-+ If SERVER_MORE_RESULTS_EXISTS is not set,
-+ then remember that it should be cleared
-+ */
-+ bits_to_be_cleared= (~thd->server_status &
-+ SERVER_MORE_RESULTS_EXISTS);
-+ thd->server_status|= SERVER_MORE_RESULTS_EXISTS;
-+ }
-+
-+#ifndef NO_EMBEDDED_ACCESS_CHECKS
-+ if (check_routine_access(thd, EXECUTE_ACL,
-+ sp->m_db.str, sp->m_name.str, TRUE, FALSE))
-+ {
-+ thd->net.no_send_ok= nsok;
-+ goto error;
-+ }
-+#endif
-+ select_limit= thd->variables.select_limit;
-+ thd->variables.select_limit= HA_POS_ERROR;
-+
-+ /*
-+ We never write CALL statements into binlog:
-+ - If the mode is non-prelocked, each statement will be logged
-+ separately.
-+ - If the mode is prelocked, the invoking statement will care
-+ about writing into binlog.
-+ So just execute the statement.
-+ */
-+ res= sp->execute_procedure(thd, &lex->value_list);
-+ /*
-+ If warnings have been cleared, we have to clear total_warn_count
-+ too, otherwise the clients get confused.
-+ */
-+ if (thd->warn_list.is_empty())
-+ thd->total_warn_count= 0;
-+
-+ thd->variables.select_limit= select_limit;
-+
-+ thd->net.no_send_ok= nsok;
-+ thd->server_status&= ~bits_to_be_cleared;
-+
-+ if (!res)
-+ send_ok(thd, (ulong) (thd->row_count_func < 0 ? 0 :
-+ thd->row_count_func));
-+ else
-+ goto error; // Substatement should already have sent error
-+ }
-+ break;
-+ }
-+ case SQLCOM_ALTER_PROCEDURE:
-+ case SQLCOM_ALTER_FUNCTION:
-+ {
-+ int result;
-+ sp_head *sp;
-+ st_sp_chistics chistics;
-+
-+ memcpy(&chistics, &lex->sp_chistics, sizeof(chistics));
-+ if (lex->sql_command == SQLCOM_ALTER_PROCEDURE)
-+ sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname,
-+ &thd->sp_proc_cache, FALSE);
-+ else
-+ sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname,
-+ &thd->sp_func_cache, FALSE);
-+ mysql_reset_errors(thd, 0);
-+ if (! sp)
-+ {
-+ if (lex->spname->m_db.str)
-+ result= SP_KEY_NOT_FOUND;
-+ else
-+ {
-+ my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
-+ goto error;
-+ }
-+ }
-+ else
-+ {
-+ if (check_routine_access(thd, ALTER_PROC_ACL, sp->m_db.str,
-+ sp->m_name.str,
-+ lex->sql_command == SQLCOM_ALTER_PROCEDURE, 0))
-+ goto error;
-+
-+ if (end_active_trans(thd))
-+ goto error;
-+ memcpy(&lex->sp_chistics, &chistics, sizeof(lex->sp_chistics));
-+ if ((sp->m_type == TYPE_ENUM_FUNCTION) &&
-+ !trust_function_creators && mysql_bin_log.is_open() &&
-+ !sp->m_chistics->detistic &&
-+ (chistics.daccess == SP_CONTAINS_SQL ||
-+ chistics.daccess == SP_MODIFIES_SQL_DATA))
-+ {
-+ my_message(ER_BINLOG_UNSAFE_ROUTINE,
-+ ER(ER_BINLOG_UNSAFE_ROUTINE), MYF(0));
-+ result= SP_INTERNAL_ERROR;
-+ }
-+ else
-+ {
-+ /*
-+ Note that if you implement the capability of ALTER FUNCTION to
-+ alter the body of the function, this command should be made to
-+ follow the restrictions that log-bin-trust-function-creators=0
-+ already puts on CREATE FUNCTION.
-+ */
-+ if (lex->sql_command == SQLCOM_ALTER_PROCEDURE)
-+ /* Conditionally writes to binlog */
-+ result= sp_update_procedure(thd, lex->spname, &lex->sp_chistics);
-+ else
-+ /* Conditionally writes to binlog */
-+ result= sp_update_function(thd, lex->spname, &lex->sp_chistics);
-+ }
-+ }
-+ switch (result)
-+ {
-+ case SP_OK:
-+ send_ok(thd);
-+ break;
-+ case SP_KEY_NOT_FOUND:
-+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
-+ SP_COM_STRING(lex), lex->spname->m_qname.str);
-+ goto error;
-+ default:
-+ my_error(ER_SP_CANT_ALTER, MYF(0),
-+ SP_COM_STRING(lex), lex->spname->m_qname.str);
-+ goto error;
-+ }
-+ break;
-+ }
-+ case SQLCOM_DROP_PROCEDURE:
-+ case SQLCOM_DROP_FUNCTION:
-+ {
-+ int result;
-+ int type= (lex->sql_command == SQLCOM_DROP_PROCEDURE ?
-+ TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION);
-+
-+ result= sp_routine_exists_in_table(thd, type, lex->spname);
-+ mysql_reset_errors(thd, 0);
-+ if (result == SP_OK)
-+ {
-+ char *db= lex->spname->m_db.str;
-+ char *name= lex->spname->m_name.str;
-+
-+ if (check_routine_access(thd, ALTER_PROC_ACL, db, name,
-+ lex->sql_command == SQLCOM_DROP_PROCEDURE, 0))
-+ goto error;
-+
-+ if (end_active_trans(thd))
-+ goto error;
-+#ifndef NO_EMBEDDED_ACCESS_CHECKS
-+ if (sp_automatic_privileges && !opt_noacl &&
-+ sp_revoke_privileges(thd, db, name,
-+ lex->sql_command == SQLCOM_DROP_PROCEDURE))
-+ {
-+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
-+ ER_PROC_AUTO_REVOKE_FAIL,
-+ ER(ER_PROC_AUTO_REVOKE_FAIL));
-+ }
-+#endif
-+ if (lex->sql_command == SQLCOM_DROP_PROCEDURE)
-+ /* Conditionally writes to binlog */
-+ result= sp_drop_procedure(thd, lex->spname); /* Conditionally writes to binlog */
-+ else
-+ /* Conditionally writes to binlog */
-+ result= sp_drop_function(thd, lex->spname); /* Conditionally writes to binlog */
-+ }
-+ else
-+ {
-+#ifdef HAVE_DLOPEN
-+ if (lex->sql_command == SQLCOM_DROP_FUNCTION)
-+ {
-+ udf_func *udf = find_udf(lex->spname->m_name.str,
-+ lex->spname->m_name.length);
-+ if (udf)
-+ {
-+ if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 0, 0))
-+ goto error;
-+
-+ /* Does NOT write to binlog */
-+ if (!(res = mysql_drop_function(thd, &lex->spname->m_name)))
-+ {
-+ send_ok(thd);
-+ break;
-+ }
-+ }
-+ }
-+#endif
-+ if (lex->spname->m_db.str)
-+ result= SP_KEY_NOT_FOUND;
-+ else
-+ {
-+ my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
-+ goto error;
-+ }
-+ }
-+ res= result;
-+ switch (result)
-+ {
-+ case SP_OK:
-+ send_ok(thd);
-+ break;
-+ case SP_KEY_NOT_FOUND:
-+ if (lex->drop_if_exists)
-+ {
-+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
-+ ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST),
-+ SP_COM_STRING(lex), lex->spname->m_name.str);
-+ res= FALSE;
-+ send_ok(thd);
-+ break;
-+ }
-+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
-+ SP_COM_STRING(lex), lex->spname->m_qname.str);
-+ goto error;
-+ default:
-+ my_error(ER_SP_DROP_FAILED, MYF(0),
-+ SP_COM_STRING(lex), lex->spname->m_qname.str);
-+ goto error;
-+ }
-+ break;
-+ }
-+ case SQLCOM_SHOW_CREATE_PROC:
-+ {
-+ if (lex->spname->m_name.length > NAME_LEN)
-+ {
-+ my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str);
-+ goto error;
-+ }
-+ if (sp_show_create_procedure(thd, lex->spname) != SP_OK)
-+ { /* We don't distinguish between errors for now */
-+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
-+ SP_COM_STRING(lex), lex->spname->m_name.str);
-+ goto error;
-+ }
-+ break;
-+ }
-+ case SQLCOM_SHOW_CREATE_FUNC:
-+ {
-+ if (lex->spname->m_name.length > NAME_LEN)
-+ {
-+ my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str);
-+ goto error;
-+ }
-+ if (sp_show_create_function(thd, lex->spname) != SP_OK)
-+ { /* We don't distinguish between errors for now */
-+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
-+ SP_COM_STRING(lex), lex->spname->m_name.str);
-+ goto error;
-+ }
-+ break;
-+ }
-+ case SQLCOM_SHOW_STATUS_PROC:
-+ {
-+ res= sp_show_status_procedure(thd, (lex->wild ?
-+ lex->wild->ptr() : NullS));
-+ break;
-+ }
-+ case SQLCOM_SHOW_STATUS_FUNC:
-+ {
-+ res= sp_show_status_function(thd, (lex->wild ?
-+ lex->wild->ptr() : NullS));
-+ break;
-+ }
-+#ifndef DBUG_OFF
-+ case SQLCOM_SHOW_PROC_CODE:
-+ case SQLCOM_SHOW_FUNC_CODE:
-+ {
-+ sp_head *sp;
-+
-+ if (lex->spname->m_name.length > NAME_LEN)
-+ {
-+ my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str);
-+ goto error;
-+ }
-+ if (lex->sql_command == SQLCOM_SHOW_PROC_CODE)
-+ sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname,
-+ &thd->sp_proc_cache, FALSE);
-+ else
-+ sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname,
-+ &thd->sp_func_cache, FALSE);
-+ if (!sp || sp->show_routine_code(thd))
-+ {
-+ /* We don't distinguish between errors for now */
-+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
-+ SP_COM_STRING(lex), lex->spname->m_name.str);
-+ goto error;
-+ }
-+ break;
-+ }
-+#endif // ifndef DBUG_OFF
-+ case SQLCOM_CREATE_VIEW:
-+ {
-+ if (end_active_trans(thd))
-+ goto error;
-+
-+ res= mysql_create_view(thd, first_table, thd->lex->create_view_mode);
-+ break;
-+ }
-+ case SQLCOM_DROP_VIEW:
-+ {
-+ if (check_table_access(thd, DROP_ACL, all_tables, 0) ||
-+ end_active_trans(thd))
-+ goto error;
-+ /* Conditionally writes to binlog. */
-+ res= mysql_drop_view(thd, first_table, thd->lex->drop_mode);
-+ break;
-+ }
-+ case SQLCOM_CREATE_TRIGGER:
-+ {
-+ if (end_active_trans(thd))
-+ goto error;
-+
-+ /* Conditionally writes to binlog. */
-+ res= mysql_create_or_drop_trigger(thd, all_tables, 1);
-+
-+ /* We don't care about trigger body after this point */
-+ delete lex->sphead;
-+ lex->sphead= 0;
-+ break;
-+ }
-+ case SQLCOM_DROP_TRIGGER:
-+ {
-+ if (end_active_trans(thd))
-+ goto error;
-+
-+ /* Conditionally writes to binlog. */
-+ res= mysql_create_or_drop_trigger(thd, all_tables, 0);
-+ break;
-+ }
-+ case SQLCOM_XA_START:
-+ if (thd->transaction.xid_state.xa_state == XA_IDLE &&
-+ thd->lex->xa_opt == XA_RESUME)
-+ {
-+ if (! thd->transaction.xid_state.xid.eq(thd->lex->xid))
-+ {
-+ my_error(ER_XAER_NOTA, MYF(0));
-+ break;
-+ }
-+ thd->transaction.xid_state.xa_state=XA_ACTIVE;
-+ send_ok(thd);
-+ break;
-+ }
-+ if (thd->lex->xa_opt != XA_NONE)
-+ { // JOIN is not supported yet. TODO
-+ my_error(ER_XAER_INVAL, MYF(0));
-+ break;
-+ }
-+ if (thd->transaction.xid_state.xa_state != XA_NOTR)
-+ {
-+ my_error(ER_XAER_RMFAIL, MYF(0),
-+ xa_state_names[thd->transaction.xid_state.xa_state]);
-+ break;
-+ }
-+ if (thd->active_transaction() || thd->locked_tables)
-+ {
-+ my_error(ER_XAER_OUTSIDE, MYF(0));
-+ break;
-+ }
-+ if (xid_cache_search(thd->lex->xid))
-+ {
-+ my_error(ER_XAER_DUPID, MYF(0));
-+ break;
-+ }
-+ DBUG_ASSERT(thd->transaction.xid_state.xid.is_null());
-+ thd->transaction.xid_state.xa_state=XA_ACTIVE;
-+ thd->transaction.xid_state.xid.set(thd->lex->xid);
-+ xid_cache_insert(&thd->transaction.xid_state);
-+ thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) |
-+ OPTION_BEGIN);
-+ thd->server_status|= SERVER_STATUS_IN_TRANS;
-+ send_ok(thd);
-+ break;
-+ case SQLCOM_XA_END:
-+ /* fake it */
-+ if (thd->lex->xa_opt != XA_NONE)
-+ { // SUSPEND and FOR MIGRATE are not supported yet. TODO
-+ my_error(ER_XAER_INVAL, MYF(0));
-+ break;
-+ }
-+ if (thd->transaction.xid_state.xa_state != XA_ACTIVE)
-+ {
-+ my_error(ER_XAER_RMFAIL, MYF(0),
-+ xa_state_names[thd->transaction.xid_state.xa_state]);
-+ break;
-+ }
-+ if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
-+ {
-+ my_error(ER_XAER_NOTA, MYF(0));
-+ break;
-+ }
-+ thd->transaction.xid_state.xa_state=XA_IDLE;
-+ send_ok(thd);
-+ break;
-+ case SQLCOM_XA_PREPARE:
-+ if (thd->transaction.xid_state.xa_state != XA_IDLE)
-+ {
-+ my_error(ER_XAER_RMFAIL, MYF(0),
-+ xa_state_names[thd->transaction.xid_state.xa_state]);
-+ break;
-+ }
-+ if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
-+ {
-+ my_error(ER_XAER_NOTA, MYF(0));
-+ break;
-+ }
-+ if (ha_prepare(thd))
-+ {
-+ my_error(ER_XA_RBROLLBACK, MYF(0));
-+ xid_cache_delete(&thd->transaction.xid_state);
-+ thd->transaction.xid_state.xa_state=XA_NOTR;
-+ break;
-+ }
-+ thd->transaction.xid_state.xa_state=XA_PREPARED;
-+ send_ok(thd);
-+ break;
-+ case SQLCOM_XA_COMMIT:
-+ if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
-+ {
-+ XID_STATE *xs=xid_cache_search(thd->lex->xid);
-+ if (!xs || xs->in_thd)
-+ my_error(ER_XAER_NOTA, MYF(0));
-+ else
-+ {
-+ ha_commit_or_rollback_by_xid(thd->lex->xid, 1);
-+ xid_cache_delete(xs);
-+ send_ok(thd);
-+ }
-+ break;
-+ }
-+ if (thd->transaction.xid_state.xa_state == XA_IDLE &&
-+ thd->lex->xa_opt == XA_ONE_PHASE)
-+ {
-+ int r;
-+ if ((r= ha_commit(thd)))
-+ my_error(r == 1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0));
-+ else
-+ send_ok(thd);
-+ }
-+ else if (thd->transaction.xid_state.xa_state == XA_PREPARED &&
-+ thd->lex->xa_opt == XA_NONE)
-+ {
-+ if (wait_if_global_read_lock(thd, 0, 0))
-+ {
-+ ha_rollback(thd);
-+ my_error(ER_XAER_RMERR, MYF(0));
-+ }
-+ else
-+ {
-+ if (ha_commit_one_phase(thd, 1))
-+ my_error(ER_XAER_RMERR, MYF(0));
-+ else
-+ send_ok(thd);
-+ start_waiting_global_read_lock(thd);
-+ }
-+ }
-+ else
-+ {
-+ my_error(ER_XAER_RMFAIL, MYF(0),
-+ xa_state_names[thd->transaction.xid_state.xa_state]);
-+ break;
-+ }
-+ thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
-+ thd->server_status&= ~SERVER_STATUS_IN_TRANS;
-+ xid_cache_delete(&thd->transaction.xid_state);
-+ thd->transaction.xid_state.xa_state=XA_NOTR;
-+ break;
-+ case SQLCOM_XA_ROLLBACK:
-+ if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
-+ {
-+ XID_STATE *xs=xid_cache_search(thd->lex->xid);
-+ if (!xs || xs->in_thd)
-+ my_error(ER_XAER_NOTA, MYF(0));
-+ else
-+ {
-+ ha_commit_or_rollback_by_xid(thd->lex->xid, 0);
-+ xid_cache_delete(xs);
-+ send_ok(thd);
-+ }
-+ break;
-+ }
-+ if (thd->transaction.xid_state.xa_state != XA_IDLE &&
-+ thd->transaction.xid_state.xa_state != XA_PREPARED)
-+ {
-+ my_error(ER_XAER_RMFAIL, MYF(0),
-+ xa_state_names[thd->transaction.xid_state.xa_state]);
-+ break;
-+ }
-+ if (ha_rollback(thd))
-+ my_error(ER_XAER_RMERR, MYF(0));
-+ else
-+ send_ok(thd);
-+ thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
-+ thd->server_status&= ~SERVER_STATUS_IN_TRANS;
-+ xid_cache_delete(&thd->transaction.xid_state);
-+ thd->transaction.xid_state.xa_state=XA_NOTR;
-+ break;
-+ case SQLCOM_XA_RECOVER:
-+ res= mysql_xa_recover(thd);
-+ break;
-+ default:
-+#ifndef EMBEDDED_LIBRARY
-+ DBUG_ASSERT(0); /* Impossible */
-+#endif
-+ send_ok(thd);
-+ break;
-+ }
-+ thd->proc_info="query end";
-+ /* Two binlog-related cleanups: */
-+
-+ /*
-+ Reset system variables temporarily modified by SET ONE SHOT.
-+
-+ Exception: If this is a SET, do nothing. This is to allow
-+ mysqlbinlog to print many SET commands (in this case we want the
-+ charset temp setting to live until the real query). This is also
-+ needed so that SET CHARACTER_SET_CLIENT... does not cancel itself
-+ immediately.
-+ */
-+ if (thd->one_shot_set && lex->sql_command != SQLCOM_SET_OPTION)
-+ reset_one_shot_variables(thd);
-+
-+ /*
-+ The return value for ROW_COUNT() is "implementation dependent" if the
-+ statement is not DELETE, INSERT or UPDATE, but -1 is what JDBC and ODBC
-+ wants.
-+
-+ We do not change the value for a CALL or EXECUTE statement, so the value
-+ generated by the last called (or executed) statement is preserved.
-+ */
-+ if (lex->sql_command != SQLCOM_CALL && lex->sql_command != SQLCOM_EXECUTE &&
-+ uc_update_queries[lex->sql_command]<2)
-+ thd->row_count_func= -1;
-+
-+ goto end;
-+
-+error:
-+ res= TRUE;
-+
-+end:
-+ if (need_start_waiting)
-+ {
-+ /*
-+ Release the protection against the global read lock and wake
-+ everyone, who might want to set a global read lock.
-+ */
-+ start_waiting_global_read_lock(thd);
-+ }
-+ DBUG_RETURN(res || thd->net.report_error);
-+}
-+
-+
-+/*
-+ Check grants for commands which work only with one table.
-+
-+ SYNOPSIS
-+ check_single_table_access()
-+ thd Thread handler
-+ privilege requested privilege
-+ all_tables global table list of query
-+
-+ RETURN
-+ 0 - OK
-+ 1 - access denied, error is sent to client
-+*/
-+
-+bool check_single_table_access(THD *thd, ulong privilege,
-+ TABLE_LIST *all_tables)
-+{
-+ Security_context * backup_ctx= thd->security_ctx;
-+
-+ /* we need to switch to the saved context (if any) */
-+ if (all_tables->security_ctx)
-+ thd->security_ctx= all_tables->security_ctx;
-+
-+ const char *db_name;
-+ if ((all_tables->view || all_tables->field_translation) &&
-+ !all_tables->schema_table)
-+ db_name= all_tables->view_db.str;
-+ else
-+ db_name= all_tables->db;
-+
-+ if (check_access(thd, privilege, db_name,
-+ &all_tables->grant.privilege, 0, 0,
-+ test(all_tables->schema_table)))
-+ goto deny;
-+
-+ /* Show only 1 table for check_grant */
-+ if (grant_option && check_grant(thd, privilege, all_tables, 0, 1, 0))
-+ goto deny;
-+
-+ thd->security_ctx= backup_ctx;
-+ return 0;
-+
-+deny:
-+ thd->security_ctx= backup_ctx;
-+ return 1;
-+}
-+
-+/*
-+ Check grants for commands which work only with one table and all other
-+ tables belonging to subselects or implicitly opened tables.
-+
-+ SYNOPSIS
-+ check_one_table_access()
-+ thd Thread handler
-+ privilege requested privilege
-+ all_tables global table list of query
-+
-+ RETURN
-+ 0 - OK
-+ 1 - access denied, error is sent to client
-+*/
-+
-+bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables)
-+{
-+ if (check_single_table_access (thd,privilege,all_tables))
-+ return 1;
-+
-+ /* Check rights on tables of subselects and implictly opened tables */
-+ TABLE_LIST *subselects_tables, *view= all_tables->view ? all_tables : 0;
-+ if ((subselects_tables= all_tables->next_global))
-+ {
-+ /*
-+ Access rights asked for the first table of a view should be the same
-+ as for the view
-+ */
-+ if (view && subselects_tables->belong_to_view == view)
-+ {
-+ if (check_single_table_access (thd, privilege, subselects_tables))
-+ return 1;
-+ subselects_tables= subselects_tables->next_global;
-+ }
-+ if (subselects_tables &&
-+ (check_table_access(thd, SELECT_ACL, subselects_tables, 0)))
-+ return 1;
-+ }
-+ return 0;
-+}
-+
-+
-+/****************************************************************************
-+ Get the user (global) and database privileges for all used tables
-+
-+ NOTES
-+ The idea of EXTRA_ACL is that one will be granted access to the table if
-+ one has the asked privilege on any column combination of the table; For
-+ example to be able to check a table one needs to have SELECT privilege on
-+ any column of the table.
-+
-+ RETURN
-+ 0 ok
-+ 1 If we can't get the privileges and we don't use table/column grants.
-+
-+ save_priv In this we store global and db level grants for the table
-+ Note that we don't store db level grants if the global grants
-+ is enough to satisfy the request and the global grants contains
-+ a SELECT grant.
-+****************************************************************************/
-+
-+bool
-+check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
-+ bool dont_check_global_grants, bool no_errors, bool schema_db)
-+{
-+ Security_context *sctx= thd->security_ctx;
-+#ifndef NO_EMBEDDED_ACCESS_CHECKS
-+ ulong db_access;
-+ bool db_is_pattern= test(want_access & GRANT_ACL);
-+#endif
-+ ulong dummy;
-+ DBUG_ENTER("check_access");
-+ DBUG_PRINT("enter",("db: %s want_access: %lu master_access: %lu",
-+ db ? db : "", want_access, sctx->master_access));
-+ if (save_priv)
-+ *save_priv=0;
-+ else
-+ save_priv= &dummy;
-+
-+ if ((!db || !db[0]) && !thd->db && !dont_check_global_grants)
-+ {
-+ DBUG_PRINT("error",("No database"));
-+ if (!no_errors)
-+ my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR),
-+ MYF(0)); /* purecov: tested */
-+ DBUG_RETURN(TRUE); /* purecov: tested */
-+ }
-+
-+ if (schema_db)
-+ {
-+ if (want_access & ~(SELECT_ACL | EXTRA_ACL))
-+ {
-+ if (!no_errors)
-+ {
-+ const char *db_name= db ? db : thd->db;
-+ my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
-+ sctx->priv_user, sctx->priv_host, db_name);
-+ }
-+ DBUG_RETURN(TRUE);
-+ }
-+ else
-+ {
-+ *save_priv= SELECT_ACL;
-+ DBUG_RETURN(FALSE);
-+ }
-+ }
-+
-+#ifdef NO_EMBEDDED_ACCESS_CHECKS
-+ DBUG_RETURN(0);
-+#else
-+ if ((sctx->master_access & want_access) == want_access)
-+ {
-+ /*
-+ If we don't have a global SELECT privilege, we have to get the database
-+ specific access rights to be able to handle queries of type
-+ UPDATE t1 SET a=1 WHERE b > 0
-+ */
-+ db_access= sctx->db_access;
-+ if (!(sctx->master_access & SELECT_ACL) &&
-+ (db && (!thd->db || db_is_pattern || strcmp(db,thd->db))))
-+ db_access=acl_get(sctx->host, sctx->ip, sctx->priv_user, db,
-+ db_is_pattern);
-+ *save_priv=sctx->master_access | db_access;
-+ DBUG_RETURN(FALSE);
-+ }
-+ if (((want_access & ~sctx->master_access) & ~(DB_ACLS | EXTRA_ACL)) ||
-+ ! db && dont_check_global_grants)
-+ { // We can never grant this
-+ DBUG_PRINT("error",("No possible access"));
-+ if (!no_errors)
-+ my_error(ER_ACCESS_DENIED_ERROR, MYF(0),
-+ sctx->priv_user,
-+ sctx->priv_host,
-+ (thd->password ?
-+ ER(ER_YES) :
-+ ER(ER_NO))); /* purecov: tested */
-+ DBUG_RETURN(TRUE); /* purecov: tested */
-+ }
-+
-+ if (db == any_db)
-+ DBUG_RETURN(FALSE); // Allow select on anything
-+
-+ if (db && (!thd->db || db_is_pattern || strcmp(db,thd->db)))
-+ db_access= acl_get(sctx->host, sctx->ip, sctx->priv_user, db,
-+ db_is_pattern);
-+ else
-+ db_access= sctx->db_access;
-+ DBUG_PRINT("info",("db_access: %lu", db_access));
-+ /* Remove SHOW attribute and access rights we already have */
-+ want_access &= ~(sctx->master_access | EXTRA_ACL);
-+ DBUG_PRINT("info",("db_access: %lu want_access: %lu",
-+ db_access, want_access));
-+ db_access= ((*save_priv=(db_access | sctx->master_access)) & want_access);
-+
-+ /* grant_option is set if there exists a single table or column grant */
-+ if (db_access == want_access ||
-+ (grant_option && !dont_check_global_grants &&
-+ !(want_access & ~(db_access | TABLE_ACLS | PROC_ACLS))))
-+ DBUG_RETURN(FALSE); /* Ok */
-+
-+ DBUG_PRINT("error",("Access denied"));
-+ if (!no_errors)
-+ my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
-+ sctx->priv_user, sctx->priv_host,
-+ (db ? db : (thd->db ?
-+ thd->db :
-+ "unknown"))); /* purecov: tested */
-+ DBUG_RETURN(TRUE); /* purecov: tested */
-+#endif /* NO_EMBEDDED_ACCESS_CHECKS */
-+}
-+
-+
-+/*
-+ check for global access and give descriptive error message if it fails
-+
-+ SYNOPSIS
-+ check_global_access()
-+ thd Thread handler
-+ want_access Use should have any of these global rights
-+
-+ WARNING
-+ One gets access right if one has ANY of the rights in want_access
-+ This is useful as one in most cases only need one global right,
-+ but in some case we want to check if the user has SUPER or
-+ REPL_CLIENT_ACL rights.
-+
-+ RETURN
-+ 0 ok
-+ 1 Access denied. In this case an error is sent to the client
-+*/
-+
-+bool check_global_access(THD *thd, ulong want_access)
-+{
-+#ifdef NO_EMBEDDED_ACCESS_CHECKS
-+ return 0;
-+#else
-+ char command[128];
-+ if ((thd->security_ctx->master_access & want_access))
-+ return 0;
-+ get_privilege_desc(command, sizeof(command), want_access);
-+ my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), command);
-+ return 1;
-+#endif /* NO_EMBEDDED_ACCESS_CHECKS */
-+}
-+
-+
-+/*
-+ Check the privilege for all used tables.
-+
-+ SYNOPSYS
-+ check_table_access()
-+ thd Thread context
-+ want_access Privileges requested
-+ tables List of tables to be checked
-+ no_errors FALSE/TRUE - report/don't report error to
-+ the client (using my_error() call).
-+
-+ NOTES
-+ Table privileges are cached in the table list for GRANT checking.
-+ This functions assumes that table list used and
-+ thd->lex->query_tables_own_last value correspond to each other
-+ (the latter should be either 0 or point to next_global member
-+ of one of elements of this table list).
-+
-+ RETURN VALUE
-+ FALSE - OK
-+ TRUE - Access denied
-+*/
-+
-+bool
-+check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
-+ bool no_errors)
-+{
-+ uint found=0;
-+ ulong found_access=0;
-+ TABLE_LIST *org_tables= tables;
-+ TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table();
-+ Security_context *sctx= thd->security_ctx, *backup_ctx= thd->security_ctx;
-+ /*
-+ The check that first_not_own_table is not reached is for the case when
-+ the given table list refers to the list for prelocking (contains tables
-+ of other queries). For simple queries first_not_own_table is 0.
-+ */
-+ for (; tables != first_not_own_table; tables= tables->next_global)
-+ {
-+ if (tables->security_ctx)
-+ sctx= tables->security_ctx;
-+ else
-+ sctx= backup_ctx;
-+
-+ if (tables->schema_table &&
-+ (want_access & ~(SELECT_ACL | EXTRA_ACL | FILE_ACL)))
-+ {
-+ if (!no_errors)
-+ my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
-+ sctx->priv_user, sctx->priv_host,
-+ information_schema_name.str);
-+ return TRUE;
-+ }
-+ /*
-+ Register access for view underlying table.
-+ Remove SHOW_VIEW_ACL, because it will be checked during making view
-+ */
-+ tables->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL);
-+ if (tables->derived || tables->schema_table ||
-+ (tables->table && (int)tables->table->s->tmp_table) ||
-+ my_tz_check_n_skip_implicit_tables(&tables,
-+ thd->lex->time_zone_tables_used))
-+ continue;
-+ thd->security_ctx= sctx;
-+ if ((sctx->master_access & want_access) ==
-+ (want_access & ~EXTRA_ACL) &&
-+ thd->db)
-+ tables->grant.privilege= want_access;
-+ else if (tables->db && thd->db && strcmp(tables->db, thd->db) == 0)
-+ {
-+ if (found && !grant_option) // db already checked
-+ tables->grant.privilege=found_access;
-+ else
-+ {
-+ if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
-+ 0, no_errors, test(tables->schema_table)))
-+ goto deny; // Access denied
-+ found_access=tables->grant.privilege;
-+ found=1;
-+ }
-+ }
-+ else if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
-+ 0, no_errors, test(tables->schema_table)))
-+ goto deny;
-+ }
-+ thd->security_ctx= backup_ctx;
-+ if (grant_option)
-+ return check_grant(thd,want_access & ~EXTRA_ACL,org_tables,
-+ test(want_access & EXTRA_ACL), UINT_MAX, no_errors);
-+ return FALSE;
-+deny:
-+ thd->security_ctx= backup_ctx;
-+ return TRUE;
-+}
-+
-+
-+bool
-+check_routine_access(THD *thd, ulong want_access,char *db, char *name,
-+ bool is_proc, bool no_errors)
-+{
-+ TABLE_LIST tables[1];
-+
-+ bzero((char *)tables, sizeof(TABLE_LIST));
-+ tables->db= db;
-+ tables->table_name= tables->alias= name;
-+
-+ /*
-+ The following test is just a shortcut for check_access() (to avoid
-+ calculating db_access) under the assumption that it's common to
-+ give persons global right to execute all stored SP (but not
-+ necessary to create them).
-+ */
-+ if ((thd->security_ctx->master_access & want_access) == want_access)
-+ tables->grant.privilege= want_access;
-+ else if (check_access(thd,want_access,db,&tables->grant.privilege,
-+ 0, no_errors, 0))
-+ return TRUE;
-+
-+#ifndef NO_EMBEDDED_ACCESS_CHECKS
-+ if (grant_option)
-+ return check_grant_routine(thd, want_access, tables, is_proc, no_errors);
-+#endif
-+
-+ 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, const char *db, const char *name,
-+ bool is_proc)
-+{
-+ ulong save_priv;
-+ if (thd->security_ctx->master_access & SHOW_PROC_ACLS)
-+ return FALSE;
-+ /*
-+ There are no routines in information_schema db. So we can safely
-+ pass zero to last paramter of check_access function
-+ */
-+ if (!check_access(thd, SHOW_PROC_ACLS, db, &save_priv, 0, 1, 0) ||
-+ (save_priv & SHOW_PROC_ACLS))
-+ return FALSE;
-+ return check_routine_level_acl(thd, db, name, is_proc);
-+}
-+
-+
-+/*
-+ Check if the given table has any of the asked privileges
-+
-+ SYNOPSIS
-+ check_some_access()
-+ thd Thread handler
-+ want_access Bitmap of possible privileges to check for
-+
-+ RETURN
-+ 0 ok
-+ 1 error
-+*/
-+
-+
-+bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table)
-+{
-+ ulong access;
-+ DBUG_ENTER("check_some_access");
-+
-+ /* This loop will work as long as we have less than 32 privileges */
-+ for (access= 1; access < want_access ; access<<= 1)
-+ {
-+ if (access & want_access)
-+ {
-+ if (!check_access(thd, access, table->db,
-+ &table->grant.privilege, 0, 1,
-+ test(table->schema_table)) &&
-+ !grant_option || !check_grant(thd, access, table, 0, 1, 1))
-+ DBUG_RETURN(0);
-+ }
-+ }
-+ DBUG_PRINT("exit",("no matching access rights"));
-+ DBUG_RETURN(1);
-+}
-+
-+
-+bool check_merge_table_access(THD *thd, char *db,
-+ TABLE_LIST *table_list)
-+{
-+ int error=0;
-+ if (table_list)
-+ {
-+ /* Check that all tables use the current database */
-+ TABLE_LIST *tmp;
-+ for (tmp= table_list; tmp; tmp= tmp->next_local)
-+ {
-+ if (!tmp->db || !tmp->db[0])
-+ tmp->db=db;
-+ }
-+ error=check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL,
-+ table_list,0);
-+ }
-+ return error;
-+}
-+
-+
-+static bool check_db_used(THD *thd,TABLE_LIST *tables)
-+{
-+ char *current_db= NULL;
-+ for (; tables; tables= tables->next_global)
-+ {
-+ if (tables->db == NULL)
-+ {
-+ /*
-+ This code never works and should be removed in 5.1. All tables
-+ that are added to the list of tables should already have its
-+ database field initialized properly (see st_lex::add_table_to_list).
-+ */
-+ DBUG_ASSERT(0);
-+ if (thd->copy_db_to(¤t_db, 0))
-+ return TRUE;
-+ tables->db= current_db;
-+ }
-+ }
-+ return FALSE;
-+}
-+
-+/****************************************************************************
-+ Check stack size; Send error if there isn't enough stack to continue
-+****************************************************************************/
-+
-+#if STACK_DIRECTION < 0
-+#define used_stack(A,B) (long) (A - B)
-+#else
-+#define used_stack(A,B) (long) (B - A)
-+#endif
-+
-+#ifndef DBUG_OFF
-+long max_stack_used;
-+#endif
-+
-+#ifndef EMBEDDED_LIBRARY
-+/*
-+ Note: The 'buf' parameter is necessary, even if it is unused here.
-+ - fix_fields functions has a "dummy" buffer large enough for the
-+ corresponding exec. (Thus we only have to check in fix_fields.)
-+ - Passing to check_stack_overrun() prevents the compiler from removing it.
-+ */
-+bool check_stack_overrun(THD *thd, long margin,
-+ char *buf __attribute__((unused)))
-+{
-+ long stack_used;
-+ DBUG_ASSERT(thd == current_thd);
-+ if ((stack_used=used_stack(thd->thread_stack,(char*) &stack_used)) >=
-+ (long) (thread_stack - margin))
-+ {
-+ sprintf(errbuff[0],ER(ER_STACK_OVERRUN_NEED_MORE),
-+ stack_used,thread_stack,margin);
-+ my_message(ER_STACK_OVERRUN_NEED_MORE,errbuff[0],MYF(0));
-+ thd->fatal_error();
-+ return 1;
-+ }
-+#ifndef DBUG_OFF
-+ max_stack_used= max(max_stack_used, stack_used);
-+#endif
-+ return 0;
-+}
-+#endif /* EMBEDDED_LIBRARY */
-+
-+#define MY_YACC_INIT 1000 // Start with big alloc
-+#define MY_YACC_MAX 32000 // Because of 'short'
-+
-+bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, ulong *yystacksize)
-+{
-+ LEX *lex= current_thd->lex;
-+ ulong old_info=0;
-+ if ((uint) *yystacksize >= MY_YACC_MAX)
-+ return 1;
-+ if (!lex->yacc_yyvs)
-+ old_info= *yystacksize;
-+ *yystacksize= set_zone((*yystacksize)*2,MY_YACC_INIT,MY_YACC_MAX);
-+ if (!(lex->yacc_yyvs= (char*)
-+ my_realloc((gptr) lex->yacc_yyvs,
-+ *yystacksize*sizeof(**yyvs),
-+ MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))) ||
-+ !(lex->yacc_yyss= (char*)
-+ my_realloc((gptr) lex->yacc_yyss,
-+ *yystacksize*sizeof(**yyss),
-+ MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))))
-+ return 1;
-+ if (old_info)
-+ { // Copy old info from stack
-+ memcpy(lex->yacc_yyss, (gptr) *yyss, old_info*sizeof(**yyss));
-+ memcpy(lex->yacc_yyvs, (gptr) *yyvs, old_info*sizeof(**yyvs));
-+ }
-+ *yyss=(short*) lex->yacc_yyss;
-+ *yyvs=(YYSTYPE*) lex->yacc_yyvs;
-+ return 0;
-+}
-+
-+
-+/****************************************************************************
-+ Initialize global thd variables needed for query
-+****************************************************************************/
-+
-+void
-+mysql_init_query(THD *thd, uchar *buf, uint length)
-+{
-+ DBUG_ENTER("mysql_init_query");
-+ lex_start(thd, buf, length);
-+ mysql_reset_thd_for_next_command(thd);
-+ DBUG_VOID_RETURN;
-+}
-+
-+
-+/*
-+ Reset THD part responsible for command processing state.
-+
-+ DESCRIPTION
-+ This needs to be called before execution of every statement
-+ (prepared or conventional).
-+
-+ TODO
-+ Make it a method of THD and align its name with the rest of
-+ reset/end/start/init methods.
-+ Call it after we use THD for queries, not before.
-+*/
-+
-+void mysql_reset_thd_for_next_command(THD *thd)
-+{
-+ DBUG_ENTER("mysql_reset_thd_for_next_command");
-+ thd->free_list= 0;
-+ thd->select_number= 1;
-+ thd->query_start_used= thd->insert_id_used=0;
-+ thd->last_insert_id_used_bin_log= FALSE;
-+ thd->is_fatal_error= thd->time_zone_used= 0;
-+ thd->server_status&= ~ (SERVER_MORE_RESULTS_EXISTS |
-+ SERVER_QUERY_NO_INDEX_USED |
-+ SERVER_QUERY_NO_GOOD_INDEX_USED);
-+ DBUG_ASSERT(thd->security_ctx== &thd->main_security_ctx);
-+ thd->tmp_table_used= 0;
-+ if (!thd->in_sub_stmt)
-+ {
-+ if (opt_bin_log)
-+ {
-+ reset_dynamic(&thd->user_var_events);
-+ thd->user_var_events_alloc= thd->mem_root;
-+ }
-+ thd->clear_error();
-+ thd->total_warn_count=0; // Warnings for this query
-+ thd->rand_used= 0;
-+ thd->sent_row_count= thd->examined_row_count= 0;
-+ }
-+ DBUG_VOID_RETURN;
-+}
-+
-+
-+void
-+mysql_init_select(LEX *lex)
-+{
-+ SELECT_LEX *select_lex= lex->current_select;
-+ select_lex->init_select();
-+ lex->wild= 0;
-+ if (select_lex == &lex->select_lex)
-+ {
-+ DBUG_ASSERT(lex->result == 0);
-+ lex->exchange= 0;
-+ }
-+}
-+
-+
-+bool
-+mysql_new_select(LEX *lex, bool move_down)
-+{
-+ SELECT_LEX *select_lex;
-+ THD *thd= lex->thd;
-+ DBUG_ENTER("mysql_new_select");
-+
-+ if (!(select_lex= new (thd->mem_root) SELECT_LEX()))
-+ DBUG_RETURN(1);
-+ select_lex->select_number= ++thd->select_number;
-+ select_lex->parent_lex= lex; /* Used in init_query. */
-+ select_lex->init_query();
-+ select_lex->init_select();
-+ lex->nest_level++;
-+ select_lex->nest_level= lex->nest_level;
-+ /*
-+ Don't evaluate this subquery during statement prepare even if
-+ it's a constant one. The flag is switched off in the end of
-+ mysql_stmt_prepare.
-+ */
-+ if (thd->stmt_arena->is_stmt_prepare())
-+ select_lex->uncacheable|= UNCACHEABLE_PREPARE;
-+ if (move_down)
-+ {
-+ SELECT_LEX_UNIT *unit;
-+ lex->subqueries= TRUE;
-+ /* first select_lex of subselect or derived table */
-+ if (!(unit= new (thd->mem_root) SELECT_LEX_UNIT()))
-+ DBUG_RETURN(1);
-+
-+ unit->init_query();
-+ unit->init_select();
-+ unit->thd= thd;
-+ unit->include_down(lex->current_select);
-+ unit->link_next= 0;
-+ unit->link_prev= 0;
-+ unit->return_to= lex->current_select;
-+ select_lex->include_down(unit);
-+ /*
-+ By default we assume that it is usual subselect and we have outer name
-+ resolution context, if no we will assign it to 0 later
-+ */
-+ select_lex->context.outer_context= &select_lex->outer_select()->context;
-+ }
-+ else
-+ {
-+ if (lex->current_select->order_list.first && !lex->current_select->braces)
-+ {
-+ my_error(ER_WRONG_USAGE, MYF(0), "UNION", "ORDER BY");
-+ DBUG_RETURN(1);
-+ }
-+ select_lex->include_neighbour(lex->current_select);
-+ SELECT_LEX_UNIT *unit= select_lex->master_unit();
-+ if (!unit->fake_select_lex && unit->add_fake_select_lex(lex->thd))
-+ DBUG_RETURN(1);
-+ select_lex->context.outer_context=
-+ unit->first_select()->context.outer_context;
-+ }
-+
-+ select_lex->master_unit()->global_parameters= select_lex;
-+ select_lex->include_global((st_select_lex_node**)&lex->all_selects_list);
-+ lex->current_select= select_lex;
-+ /*
-+ in subquery is SELECT query and we allow resolution of names in SELECT
-+ list
-+ */
-+ select_lex->context.resolve_in_select_list= TRUE;
-+ DBUG_RETURN(0);
-+}
-+
-+/*
-+ Create a select to return the same output as 'SELECT @@var_name'.
-+
-+ SYNOPSIS
-+ create_select_for_variable()
-+ var_name Variable name
-+
-+ DESCRIPTION
-+ Used for SHOW COUNT(*) [ WARNINGS | ERROR]
-+
-+ This will crash with a core dump if the variable doesn't exists
-+*/
-+
-+void create_select_for_variable(const char *var_name)
-+{
-+ THD *thd;
-+ LEX *lex;
-+ LEX_STRING tmp, null_lex_string;
-+ Item *var;
-+ char buff[MAX_SYS_VAR_LENGTH*2+4+8], *end;
-+ DBUG_ENTER("create_select_for_variable");
-+
-+ thd= current_thd;
-+ lex= thd->lex;
-+ mysql_init_select(lex);
-+ lex->sql_command= SQLCOM_SELECT;
-+ tmp.str= (char*) var_name;
-+ tmp.length=strlen(var_name);
-+ bzero((char*) &null_lex_string.str, sizeof(null_lex_string));
-+ /*
-+ We set the name of Item to @@session.var_name because that then is used
-+ as the column name in the output.
-+ */
-+ if ((var= get_system_var(thd, OPT_SESSION, tmp, null_lex_string)))
-+ {
-+ end= strxmov(buff, "@@session.", var_name, NullS);
-+ var->set_name(buff, end-buff, system_charset_info);
-+ add_item_to_list(thd, var);
-+ }
-+ DBUG_VOID_RETURN;
-+}
-+
-+
-+void mysql_init_multi_delete(LEX *lex)
-+{
-+ lex->sql_command= SQLCOM_DELETE_MULTI;
-+ mysql_init_select(lex);
-+ lex->select_lex.select_limit= 0;
-+ lex->unit.select_limit_cnt= HA_POS_ERROR;
-+ lex->select_lex.table_list.save_and_clear(&lex->auxiliary_table_list);
-+ lex->lock_option= using_update_log ? TL_READ_NO_INSERT : TL_READ;
-+ lex->query_tables= 0;
-+ lex->query_tables_last= &lex->query_tables;
-+}
-+
-+/*
-+ When you modify mysql_parse(), you may need to mofify
-+ mysql_test_parse_for_slave() in this same file.
-+*/
-+
-+void mysql_parse(THD *thd, char *inBuf, uint length)
-+{
-+ DBUG_ENTER("mysql_parse");
-+
-+ DBUG_EXECUTE_IF("parser_debug", turn_parser_debug_on(););
-+
-+ mysql_init_query(thd, (uchar*) inBuf, length);
-+ if (query_cache_send_result_to_client(thd, inBuf, length) <= 0)
-+ {
-+ LEX *lex= thd->lex;
-+
-+ sp_cache_flush_obsolete(&thd->sp_proc_cache);
-+ sp_cache_flush_obsolete(&thd->sp_func_cache);
-+
-+ if (!MYSQLparse((void *)thd) && ! thd->is_fatal_error)
-+ {
-+#ifndef NO_EMBEDDED_ACCESS_CHECKS
-+ if (mqh_used && thd->user_connect &&
-+ check_mqh(thd, lex->sql_command))
-+ {
-+ thd->net.error = 0;
-+ }
-+ else
-+#endif
-+ {
-+ if (thd->net.report_error)
-+ {
-+ if (thd->lex->sphead)
-+ {
-+ delete thd->lex->sphead;
-+ thd->lex->sphead= NULL;
-+ }
-+ }
-+ else
-+ {
-+ /*
-+ Binlog logs a string starting from thd->query and having length
-+ thd->query_length; so we set thd->query_length correctly (to not
-+ log several statements in one event, when we executed only first).
-+ We set it to not see the ';' (otherwise it would get into binlog
-+ and Query_log_event::print() would give ';;' output).
-+ This also helps display only the current query in SHOW
-+ PROCESSLIST.
-+ Note that we don't need LOCK_thread_count to modify query_length.
-+ */
-+ if (lex->found_semicolon &&
-+ (thd->query_length= (ulong)(lex->found_semicolon - thd->query)))
-+ thd->query_length--;
-+ /* Actually execute the query */
-+ mysql_execute_command(thd);
-+ query_cache_end_of_result(thd);
-+ }
-+ }
-+ lex->unit.cleanup();
-+ }
-+ else
-+ {
-+ DBUG_ASSERT(thd->net.report_error);
-+ DBUG_PRINT("info",("Command aborted. Fatal_error: %d",
-+ thd->is_fatal_error));
-+
-+ /*
-+ The first thing we do after parse error is freeing sp_head to
-+ ensure that we have restored original memroot.
-+ */
-+ if (thd->lex->sphead)
-+ {
-+ /* Clean up after failed stored procedure/function */
-+ delete thd->lex->sphead;
-+ thd->lex->sphead= NULL;
-+ }
-+ query_cache_abort(&thd->net);
-+ lex->unit.cleanup();
-+ }
-+ thd->proc_info="freeing items";
-+ thd->end_statement();
-+ thd->cleanup_after_query();
-+ DBUG_ASSERT(thd->change_list.is_empty());
-+ }
-+ DBUG_VOID_RETURN;
-+}
-+
-+
-+#ifdef HAVE_REPLICATION
-+/*
-+ Usable by the replication SQL thread only: just parse a query to know if it
-+ can be ignored because of replicate-*-table rules.
-+
-+ RETURN VALUES
-+ 0 cannot be ignored
-+ 1 can be ignored
-+*/
-+
-+bool mysql_test_parse_for_slave(THD *thd, char *inBuf, uint length)
-+{
-+ LEX *lex= thd->lex;
-+ bool error= 0;
-+ DBUG_ENTER("mysql_test_parse_for_slave");
-+
-+ mysql_init_query(thd, (uchar*) inBuf, length);
-+ if (!MYSQLparse((void*) thd) && ! thd->is_fatal_error &&
-+ all_tables_not_ok(thd,(TABLE_LIST*) lex->select_lex.table_list.first))
-+ error= 1; /* Ignore question */
-+ thd->end_statement();
-+ thd->cleanup_after_query();
-+ DBUG_RETURN(error);
-+}
-+#endif
-+
-+
-+
-+/*****************************************************************************
-+** Store field definition for create
-+** Return 0 if ok
-+******************************************************************************/
-+
-+bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
-+ char *length, char *decimals,
-+ uint type_modifier,
-+ Item *default_value, Item *on_update_value,
-+ LEX_STRING *comment,
-+ char *change,
-+ List<String> *interval_list, CHARSET_INFO *cs,
-+ uint uint_geom_type)
-+{
-+ register create_field *new_field;
-+ LEX *lex= thd->lex;
-+ DBUG_ENTER("add_field_to_list");
-+
-+ if (strlen(field_name) > NAME_LEN)
-+ {
-+ my_error(ER_TOO_LONG_IDENT, MYF(0), field_name); /* purecov: inspected */
-+ DBUG_RETURN(1); /* purecov: inspected */
-+ }
-+ if (type_modifier & PRI_KEY_FLAG)
-+ {
-+ lex->col_list.push_back(new key_part_spec(field_name,0));
-+ lex->key_list.push_back(new Key(Key::PRIMARY, NullS, HA_KEY_ALG_UNDEF,
-+ 0, lex->col_list));
-+ lex->col_list.empty();
-+ }
-+ if (type_modifier & (UNIQUE_FLAG | UNIQUE_KEY_FLAG))
-+ {
-+ lex->col_list.push_back(new key_part_spec(field_name,0));
-+ lex->key_list.push_back(new Key(Key::UNIQUE, NullS, HA_KEY_ALG_UNDEF, 0,
-+ lex->col_list));
-+ lex->col_list.empty();
-+ }
-+
-+ if (default_value)
-+ {
-+ /*
-+ Default value should be literal => basic constants =>
-+ no need fix_fields()
-+
-+ We allow only one function as part of default value -
-+ NOW() as default for TIMESTAMP type.
-+ */
-+ if (default_value->type() == Item::FUNC_ITEM &&
-+ !(((Item_func*)default_value)->functype() == Item_func::NOW_FUNC &&
-+ type == FIELD_TYPE_TIMESTAMP))
-+ {
-+ my_error(ER_INVALID_DEFAULT, MYF(0), field_name);
-+ DBUG_RETURN(1);
-+ }
-+ else if (default_value->type() == Item::NULL_ITEM)
-+ {
-+ default_value= 0;
-+ if ((type_modifier & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) ==
-+ NOT_NULL_FLAG)
-+ {
-+ my_error(ER_INVALID_DEFAULT, MYF(0), field_name);
-+ DBUG_RETURN(1);
-+ }
-+ }
-+ else if (type_modifier & AUTO_INCREMENT_FLAG)
-+ {
-+ my_error(ER_INVALID_DEFAULT, MYF(0), field_name);
-+ DBUG_RETURN(1);
-+ }
-+ }
-+
-+ if (on_update_value && type != FIELD_TYPE_TIMESTAMP)
-+ {
-+ my_error(ER_INVALID_ON_UPDATE, MYF(0), field_name);
-+ DBUG_RETURN(1);
-+ }
-+
-+ if (type == FIELD_TYPE_TIMESTAMP && length)
-+ {
-+ /* Display widths are no longer supported for TIMSTAMP as of MySQL 4.1.
-+ In other words, for declarations such as TIMESTAMP(2), TIMESTAMP(4),
-+ and so on, the display width is ignored.
-+ */
-+ char buf[32];
-+ my_snprintf(buf, sizeof(buf), "TIMESTAMP(%s)", length);
-+ push_warning_printf(thd,MYSQL_ERROR::WARN_LEVEL_WARN,
-+ ER_WARN_DEPRECATED_SYNTAX,
-+ ER(ER_WARN_DEPRECATED_SYNTAX),
-+ buf, "TIMESTAMP");
-+ }
-+
-+ if (!(new_field= new create_field()) ||
-+ new_field->init(thd, field_name, type, length, decimals, type_modifier,
-+ default_value, on_update_value, comment, change,
-+ interval_list, cs, uint_geom_type))
-+ DBUG_RETURN(1);
-+
-+ lex->create_list.push_back(new_field);
-+ lex->last_field=new_field;
-+ DBUG_RETURN(0);
-+}
-+
-+
-+/* Store position for column in ALTER TABLE .. ADD column */
-+
-+void store_position_for_column(const char *name)
-+{
-+ current_thd->lex->last_field->after=my_const_cast(char*) (name);
-+}
-+
-+bool
-+add_proc_to_list(THD* thd, Item *item)
-+{
-+ ORDER *order;
-+ Item **item_ptr;
-+
-+ if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)+sizeof(Item*))))
-+ return 1;
-+ item_ptr = (Item**) (order+1);
-+ *item_ptr= item;
-+ order->item=item_ptr;
-+ order->free_me=0;
-+ thd->lex->proc_list.link_in_list((byte*) order,(byte**) &order->next);
-+ return 0;
-+}
-+
-+
-+/* Fix escaping of _, % and \ in database and table names (for ODBC) */
-+
-+static void remove_escape(char *name)
-+{
-+ if (!*name) // For empty DB names
-+ return;
-+ char *to;
-+#ifdef USE_MB
-+ char *strend=name+(uint) strlen(name);
-+#endif
-+ for (to=name; *name ; name++)
-+ {
-+#ifdef USE_MB
-+ int l;
-+ if (use_mb(system_charset_info) &&
-+ (l = my_ismbchar(system_charset_info, name, strend)))
-+ {
-+ while (l--)
-+ *to++ = *name++;
-+ name--;
-+ continue;
-+ }
-+#endif
-+ if (*name == '\\' && name[1])
-+ name++; // Skip '\\'
-+ *to++= *name;
-+ }
-+ *to=0;
-+}
-+
-+/****************************************************************************
-+** save order by and tables in own lists
-+****************************************************************************/
-+
-+
-+bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc)
-+{
-+ ORDER *order;
-+ DBUG_ENTER("add_to_list");
-+ if (!(order = (ORDER *) thd->alloc(sizeof(ORDER))))
-+ DBUG_RETURN(1);
-+ order->item_ptr= item;
-+ order->item= &order->item_ptr;
-+ order->asc = asc;
-+ order->free_me=0;
-+ order->used=0;
-+ order->counter_used= 0;
-+ list.link_in_list((byte*) order,(byte**) &order->next);
-+ DBUG_RETURN(0);
-+}
-+
-+
-+/*
-+ Add a table to list of used tables
-+
-+ SYNOPSIS
-+ add_table_to_list()
-+ table Table to add
-+ alias alias for table (or null if no alias)
-+ table_options A set of the following bits:
-+ TL_OPTION_UPDATING Table will be updated
-+ TL_OPTION_FORCE_INDEX Force usage of index
-+ TL_OPTION_ALIAS an alias in multi table DELETE
-+ lock_type How table should be locked
-+ use_index List of indexed used in USE INDEX
-+ ignore_index List of indexed used in IGNORE INDEX
-+
-+ RETURN
-+ 0 Error
-+ # Pointer to TABLE_LIST element added to the total table list
-+*/
-+
-+TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
-+ Table_ident *table,
-+ LEX_STRING *alias,
-+ ulong table_options,
-+ thr_lock_type lock_type,
-+ List<String> *use_index_arg,
-+ List<String> *ignore_index_arg,
-+ LEX_STRING *option)
-+{
-+ register TABLE_LIST *ptr;
-+ TABLE_LIST *previous_table_ref; /* The table preceding the current one. */
-+ char *alias_str;
-+ LEX *lex= thd->lex;
-+ DBUG_ENTER("add_table_to_list");
-+ LINT_INIT(previous_table_ref);
-+
-+ if (!table)
-+ DBUG_RETURN(0); // End of memory
-+ alias_str= alias ? alias->str : table->table.str;
-+ if (!test(table_options & TL_OPTION_ALIAS) &&
-+ check_table_name(table->table.str, table->table.length))
-+ {
-+ my_error(ER_WRONG_TABLE_NAME, MYF(0), table->table.str);
-+ DBUG_RETURN(0);
-+ }
-+
-+ if (!alias) /* Alias is case sensitive */
-+ {
-+ if (table->sel)
-+ {
-+ my_message(ER_DERIVED_MUST_HAVE_ALIAS,
-+ ER(ER_DERIVED_MUST_HAVE_ALIAS), MYF(0));
-+ DBUG_RETURN(0);
-+ }
-+ if (!(alias_str=thd->memdup(alias_str,table->table.length+1)))
-+ DBUG_RETURN(0);
-+ }
-+ if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
-+ DBUG_RETURN(0); /* purecov: inspected */
-+ if (table->db.str)
-+ {
-+ if (table->is_derived_table() == FALSE && check_db_name(table->db.str))
-+ {
-+ my_error(ER_WRONG_DB_NAME, MYF(0), table->db.str);
-+ DBUG_RETURN(0);
-+ }
-+ ptr->db= table->db.str;
-+ ptr->db_length= table->db.length;
-+ }
-+ else if (thd->copy_db_to(&ptr->db, &ptr->db_length))
-+ DBUG_RETURN(0);
-+
-+ ptr->alias= alias_str;
-+ if (lower_case_table_names && table->table.length)
-+ table->table.length= my_casedn_str(files_charset_info, table->table.str);
-+ ptr->table_name=table->table.str;
-+ ptr->table_name_length=table->table.length;
-+ ptr->lock_type= lock_type;
-+ ptr->updating= test(table_options & TL_OPTION_UPDATING);
-+ ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX);
-+ ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES);
-+ ptr->derived= table->sel;
-+ if (!ptr->derived && !my_strcasecmp(system_charset_info, ptr->db,
-+ information_schema_name.str))
-+ {
-+ ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, ptr->table_name);
-+ if (!schema_table ||
-+ (schema_table->hidden &&
-+ lex->orig_sql_command == SQLCOM_END)) // not a 'show' command
-+ {
-+ my_error(ER_UNKNOWN_TABLE, MYF(0),
-+ ptr->table_name, information_schema_name.str);
-+ DBUG_RETURN(0);
-+ }
-+ ptr->schema_table_name= ptr->table_name;
-+ ptr->schema_table= schema_table;
-+ }
-+ ptr->select_lex= lex->current_select;
-+ ptr->cacheable_table= 1;
-+ if (use_index_arg)
-+ ptr->use_index=(List<String> *) thd->memdup((gptr) use_index_arg,
-+ sizeof(*use_index_arg));
-+ if (ignore_index_arg)
-+ ptr->ignore_index=(List<String> *) thd->memdup((gptr) ignore_index_arg,
-+ sizeof(*ignore_index_arg));
-+ ptr->option= option ? option->str : 0;
-+ /* check that used name is unique */
-+ if (lock_type != TL_IGNORE)
-+ {
-+ TABLE_LIST *first_table= (TABLE_LIST*) table_list.first;
-+ if (lex->sql_command == SQLCOM_CREATE_VIEW)
-+ first_table= first_table ? first_table->next_local : NULL;
-+ for (TABLE_LIST *tables= first_table ;
-+ tables ;
-+ tables=tables->next_local)
-+ {
-+ if (!my_strcasecmp(table_alias_charset, alias_str, tables->alias) &&
-+ !strcmp(ptr->db, tables->db))
-+ {
-+ my_error(ER_NONUNIQ_TABLE, MYF(0), alias_str); /* purecov: tested */
-+ DBUG_RETURN(0); /* purecov: tested */
-+ }
-+ }
-+ }
-+ /* Store the table reference preceding the current one. */
-+ if (table_list.elements > 0)
-+ {
-+ /*
-+ table_list.next points to the last inserted TABLE_LIST->next_local'
-+ element
-+ We don't use the offsetof() macro here to avoid warnings from gcc
-+ */
-+ previous_table_ref= (TABLE_LIST*) ((char*) table_list.next -
-+ ((char*) &(ptr->next_local) -
-+ (char*) ptr));
-+ /*
-+ Set next_name_resolution_table of the previous table reference to point
-+ to the current table reference. In effect the list
-+ TABLE_LIST::next_name_resolution_table coincides with
-+ TABLE_LIST::next_local. Later this may be changed in
-+ store_top_level_join_columns() for NATURAL/USING joins.
-+ */
-+ previous_table_ref->next_name_resolution_table= ptr;
-+ }
-+
-+ /*
-+ Link the current table reference in a local list (list for current select).
-+ Notice that as a side effect here we set the next_local field of the
-+ previous table reference to 'ptr'. Here we also add one element to the
-+ list 'table_list'.
-+ */
-+ table_list.link_in_list((byte*) ptr, (byte**) &ptr->next_local);
-+ ptr->next_name_resolution_table= NULL;
-+ /* Link table in global list (all used tables) */
-+ lex->add_to_query_tables(ptr);
-+ DBUG_RETURN(ptr);
-+}
-+
-+
-+/*
-+ Initialize a new table list for a nested join
-+
-+ SYNOPSIS
-+ init_nested_join()
-+ thd current thread
-+
-+ DESCRIPTION
-+ The function initializes a structure of the TABLE_LIST type
-+ for a nested join. It sets up its nested join list as empty.
-+ The created structure is added to the front of the current
-+ join list in the st_select_lex object. Then the function
-+ changes the current nest level for joins to refer to the newly
-+ created empty list after having saved the info on the old level
-+ in the initialized structure.
-+
-+ RETURN VALUE
-+ 0, if success
-+ 1, otherwise
-+*/
-+
-+bool st_select_lex::init_nested_join(THD *thd)
-+{
-+ TABLE_LIST *ptr;
-+ NESTED_JOIN *nested_join;
-+ DBUG_ENTER("init_nested_join");
-+
-+ if (!(ptr= (TABLE_LIST*) thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST))+
-+ sizeof(NESTED_JOIN))))
-+ DBUG_RETURN(1);
-+ nested_join= ptr->nested_join=
-+ ((NESTED_JOIN*) ((byte*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST))));
-+
-+ join_list->push_front(ptr);
-+ ptr->embedding= embedding;
-+ ptr->join_list= join_list;
-+ embedding= ptr;
-+ join_list= &nested_join->join_list;
-+ join_list->empty();
-+ DBUG_RETURN(0);
-+}
-+
-+
-+/*
-+ End a nested join table list
-+
-+ SYNOPSIS
-+ end_nested_join()
-+ thd current thread
-+
-+ DESCRIPTION
-+ The function returns to the previous join nest level.
-+ If the current level contains only one member, the function
-+ moves it one level up, eliminating the nest.
-+
-+ RETURN VALUE
-+ Pointer to TABLE_LIST element added to the total table list, if success
-+ 0, otherwise
-+*/
-+
-+TABLE_LIST *st_select_lex::end_nested_join(THD *thd)
-+{
-+ TABLE_LIST *ptr;
-+ NESTED_JOIN *nested_join;
-+ DBUG_ENTER("end_nested_join");
-+
-+ DBUG_ASSERT(embedding);
-+ ptr= embedding;
-+ join_list= ptr->join_list;
-+ embedding= ptr->embedding;
-+ nested_join= ptr->nested_join;
-+ if (nested_join->join_list.elements == 1)
-+ {
-+ TABLE_LIST *embedded= nested_join->join_list.head();
-+ join_list->pop();
-+ embedded->join_list= join_list;
-+ embedded->embedding= embedding;
-+ join_list->push_front(embedded);
-+ ptr= embedded;
-+ }
-+ else if (nested_join->join_list.elements == 0)
-+ {
-+ join_list->pop();
-+ ptr= 0; // return value
-+ }
-+ DBUG_RETURN(ptr);
-+}
-+
-+
-+/*
-+ Nest last join operation
-+
-+ SYNOPSIS
-+ nest_last_join()
-+ thd current thread
-+
-+ DESCRIPTION
-+ The function nest last join operation as if it was enclosed in braces.
-+
-+ RETURN VALUE
-+ 0 Error
-+ # Pointer to TABLE_LIST element created for the new nested join
-+
-+*/
-+
-+TABLE_LIST *st_select_lex::nest_last_join(THD *thd)
-+{
-+ TABLE_LIST *ptr;
-+ NESTED_JOIN *nested_join;
-+ List<TABLE_LIST> *embedded_list;
-+ DBUG_ENTER("nest_last_join");
-+
-+ if (!(ptr= (TABLE_LIST*) thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST))+
-+ sizeof(NESTED_JOIN))))
-+ DBUG_RETURN(0);
-+ nested_join= ptr->nested_join=
-+ ((NESTED_JOIN*) ((byte*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST))));
-+
-+ ptr->embedding= embedding;
-+ ptr->join_list= join_list;
-+ embedded_list= &nested_join->join_list;
-+ embedded_list->empty();
-+
-+ for (uint i=0; i < 2; i++)
-+ {
-+ TABLE_LIST *table= join_list->pop();
-+ table->join_list= embedded_list;
-+ table->embedding= ptr;
-+ embedded_list->push_back(table);
-+ if (table->natural_join)
-+ {
-+ ptr->is_natural_join= TRUE;
-+ /*
-+ If this is a JOIN ... USING, move the list of joined fields to the
-+ table reference that describes the join.
-+ */
-+ if (table->join_using_fields)
-+ {
-+ ptr->join_using_fields= table->join_using_fields;
-+ table->join_using_fields= NULL;
-+ }
-+ }
-+ }
-+ join_list->push_front(ptr);
-+ nested_join->used_tables= nested_join->not_null_tables= (table_map) 0;
-+ DBUG_RETURN(ptr);
-+}
-+
-+
-+/*
-+ Add a table to the current join list
-+
-+ SYNOPSIS
-+ add_joined_table()
-+ table the table to add
-+
-+ DESCRIPTION
-+ The function puts a table in front of the current join list
-+ of st_select_lex object.
-+ Thus, joined tables are put into this list in the reverse order
-+ (the most outer join operation follows first).
-+
-+ RETURN VALUE
-+ None
-+*/
-+
-+void st_select_lex::add_joined_table(TABLE_LIST *table)
-+{
-+ DBUG_ENTER("add_joined_table");
-+ join_list->push_front(table);
-+ table->join_list= join_list;
-+ table->embedding= embedding;
-+ DBUG_VOID_RETURN;
-+}
-+
-+
-+/*
-+ Convert a right join into equivalent left join
-+
-+ SYNOPSIS
-+ convert_right_join()
-+ thd current thread
-+
-+ DESCRIPTION
-+ The function takes the current join list t[0],t[1] ... and
-+ effectively converts it into the list t[1],t[0] ...
-+ Although the outer_join flag for the new nested table contains
-+ JOIN_TYPE_RIGHT, it will be handled as the inner table of a left join
-+ operation.
-+
-+ EXAMPLES
-+ SELECT * FROM t1 RIGHT JOIN t2 ON on_expr =>
-+ SELECT * FROM t2 LEFT JOIN t1 ON on_expr
-+
-+ SELECT * FROM t1,t2 RIGHT JOIN t3 ON on_expr =>
-+ SELECT * FROM t1,t3 LEFT JOIN t2 ON on_expr
-+
-+ SELECT * FROM t1,t2 RIGHT JOIN (t3,t4) ON on_expr =>
-+ SELECT * FROM t1,(t3,t4) LEFT JOIN t2 ON on_expr
-+
-+ SELECT * FROM t1 LEFT JOIN t2 ON on_expr1 RIGHT JOIN t3 ON on_expr2 =>
-+ SELECT * FROM t3 LEFT JOIN (t1 LEFT JOIN t2 ON on_expr2) ON on_expr1
-+
-+ RETURN
-+ Pointer to the table representing the inner table, if success
-+ 0, otherwise
-+*/
-+
-+TABLE_LIST *st_select_lex::convert_right_join()
-+{
-+ TABLE_LIST *tab2= join_list->pop();
-+ TABLE_LIST *tab1= join_list->pop();
-+ DBUG_ENTER("convert_right_join");
-+
-+ join_list->push_front(tab2);
-+ join_list->push_front(tab1);
-+ tab1->outer_join|= JOIN_TYPE_RIGHT;
-+
-+ DBUG_RETURN(tab1);
-+}
-+
-+/*
-+ Set lock for all tables in current select level
-+
-+ SYNOPSIS:
-+ set_lock_for_tables()
-+ lock_type Lock to set for tables
-+
-+ NOTE:
-+ If lock is a write lock, then tables->updating is set 1
-+ This is to get tables_ok to know that the table is updated by the
-+ query
-+*/
-+
-+void st_select_lex::set_lock_for_tables(thr_lock_type lock_type)
-+{
-+ bool for_update= lock_type >= TL_READ_NO_INSERT;
-+ DBUG_ENTER("set_lock_for_tables");
-+ DBUG_PRINT("enter", ("lock_type: %d for_update: %d", lock_type,
-+ for_update));
-+
-+ for (TABLE_LIST *tables= (TABLE_LIST*) table_list.first;
-+ tables;
-+ tables= tables->next_local)
-+ {
-+ tables->lock_type= lock_type;
-+ tables->updating= for_update;
-+ }
-+ DBUG_VOID_RETURN;
-+}
-+
-+
-+/*
-+ Create a fake SELECT_LEX for a unit
-+
-+ SYNOPSIS:
-+ add_fake_select_lex()
-+ thd thread handle
-+
-+ DESCRIPTION
-+ The method create a fake SELECT_LEX object for a unit.
-+ This object is created for any union construct containing a union
-+ operation and also for any single select union construct of the form
-+ (SELECT ... ORDER BY order_list [LIMIT n]) ORDER BY ...
-+ or of the form
-+ (SELECT ... ORDER BY LIMIT n) ORDER BY ...
-+
-+ NOTES
-+ The object is used to retrieve rows from the temporary table
-+ where the result on the union is obtained.
-+
-+ RETURN VALUES
-+ 1 on failure to create the object
-+ 0 on success
-+*/
-+
-+bool st_select_lex_unit::add_fake_select_lex(THD *thd)
-+{
-+ SELECT_LEX *first_sl= first_select();
-+ DBUG_ENTER("add_fake_select_lex");
-+ DBUG_ASSERT(!fake_select_lex);
-+
-+ if (!(fake_select_lex= new (thd->mem_root) SELECT_LEX()))
-+ DBUG_RETURN(1);
-+ fake_select_lex->include_standalone(this,
-+ (SELECT_LEX_NODE**)&fake_select_lex);
-+ fake_select_lex->select_number= INT_MAX;
-+ fake_select_lex->parent_lex= thd->lex; /* Used in init_query. */
-+ fake_select_lex->make_empty_select();
-+ fake_select_lex->linkage= GLOBAL_OPTIONS_TYPE;
-+ fake_select_lex->select_limit= 0;
-+
-+ fake_select_lex->context.outer_context=first_sl->context.outer_context;
-+ /* allow item list resolving in fake select for ORDER BY */
-+ fake_select_lex->context.resolve_in_select_list= TRUE;
-+ fake_select_lex->context.select_lex= fake_select_lex;
-+
-+ if (!first_sl->next_select())
-+ {
-+ /*
-+ This works only for
-+ (SELECT ... ORDER BY list [LIMIT n]) ORDER BY order_list [LIMIT m],
-+ (SELECT ... LIMIT n) ORDER BY order_list [LIMIT m]
-+ just before the parser starts processing order_list
-+ */
-+ global_parameters= fake_select_lex;
-+ fake_select_lex->no_table_names_allowed= 1;
-+ thd->lex->current_select= fake_select_lex;
-+ }
-+ thd->lex->pop_context();
-+ DBUG_RETURN(0);
-+}
-+
-+
-+/*
-+ Push a new name resolution context for a JOIN ... ON clause to the
-+ context stack of a query block.
-+
-+ SYNOPSIS
-+ push_new_name_resolution_context()
-+ thd pointer to current thread
-+ left_op left operand of the JOIN
-+ right_op rigth operand of the JOIN
-+
-+ DESCRIPTION
-+ Create a new name resolution context for a JOIN ... ON clause,
-+ set the first and last leaves of the list of table references
-+ to be used for name resolution, and push the newly created
-+ context to the stack of contexts of the query.
-+
-+ RETURN
-+ FALSE if all is OK
-+ TRUE if a memory allocation error occured
-+*/
-+
-+bool
-+push_new_name_resolution_context(THD *thd,
-+ TABLE_LIST *left_op, TABLE_LIST *right_op)
-+{
-+ Name_resolution_context *on_context;
-+ if (!(on_context= new (thd->mem_root) Name_resolution_context))
-+ return TRUE;
-+ on_context->init();
-+ on_context->first_name_resolution_table=
-+ left_op->first_leaf_for_name_resolution();
-+ on_context->last_name_resolution_table=
-+ right_op->last_leaf_for_name_resolution();
-+ return thd->lex->push_context(on_context);
-+}
-+
-+
-+/*
-+ Add an ON condition to the second operand of a JOIN ... ON.
-+
-+ SYNOPSIS
-+ add_join_on
-+ b the second operand of a JOIN ... ON
-+ expr the condition to be added to the ON clause
-+
-+ DESCRIPTION
-+ Add an ON condition to the right operand of a JOIN ... ON clause.
-+
-+ RETURN
-+ FALSE if there was some error
-+ TRUE if all is OK
-+*/
-+
-+void add_join_on(TABLE_LIST *b, Item *expr)
-+{
-+ if (expr)
-+ {
-+ if (!b->on_expr)
-+ b->on_expr= expr;
-+ else
-+ {
-+ /*
-+ If called from the parser, this happens if you have both a
-+ right and left join. If called later, it happens if we add more
-+ than one condition to the ON clause.
-+ */
-+ b->on_expr= new Item_cond_and(b->on_expr,expr);
-+ }
-+ b->on_expr->top_level_item();
-+ }
-+}
-+
-+
-+/*
-+ Mark that there is a NATURAL JOIN or JOIN ... USING between two
-+ tables.
-+
-+ SYNOPSIS
-+ add_join_natural()
-+ a Left join argument
-+ b Right join argument
-+ using_fields Field names from USING clause
-+
-+ IMPLEMENTATION
-+ This function marks that table b should be joined with a either via
-+ a NATURAL JOIN or via JOIN ... USING. Both join types are special
-+ cases of each other, so we treat them together. The function
-+ setup_conds() creates a list of equal condition between all fields
-+ of the same name for NATURAL JOIN or the fields in 'using_fields'
-+ for JOIN ... USING. The list of equality conditions is stored
-+ either in b->on_expr, or in JOIN::conds, depending on whether there
-+ was an outer join.
-+
-+ EXAMPLE
-+ SELECT * FROM t1 NATURAL LEFT JOIN t2
-+ <=>
-+ SELECT * FROM t1 LEFT JOIN t2 ON (t1.i=t2.i and t1.j=t2.j ... )
-+
-+ SELECT * FROM t1 NATURAL JOIN t2 WHERE <some_cond>
-+ <=>
-+ SELECT * FROM t1, t2 WHERE (t1.i=t2.i and t1.j=t2.j and <some_cond>)
-+
-+ SELECT * FROM t1 JOIN t2 USING(j) WHERE <some_cond>
-+ <=>
-+ SELECT * FROM t1, t2 WHERE (t1.j=t2.j and <some_cond>)
-+
-+ RETURN
-+ None
-+*/
-+
-+void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List<String> *using_fields)
-+{
-+ b->natural_join= a;
-+ b->join_using_fields= using_fields;
-+}
-+
-+
-+/*
-+ Reload/resets privileges and the different caches.
-+
-+ SYNOPSIS
-+ reload_acl_and_cache()
-+ thd Thread handler (can be NULL!)
-+ options What should be reset/reloaded (tables, privileges,
-+ slave...)
-+ tables Tables to flush (if any)
-+ write_to_binlog Depending on 'options', it may be very bad to write the
-+ query to the binlog (e.g. FLUSH SLAVE); this is a
-+ pointer where reload_acl_and_cache() will put 0 if
-+ it thinks we really should not write to the binlog.
-+ Otherwise it will put 1.
-+
-+ RETURN
-+ 0 ok
-+ !=0 error. thd->killed or thd->net.report_error is set
-+*/
-+
-+bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
-+ bool *write_to_binlog)
-+{
-+ bool result=0;
-+ select_errors=0; /* Write if more errors */
-+ bool tmp_write_to_binlog= 1;
-+
-+ DBUG_ASSERT(!thd || !thd->in_sub_stmt);
-+
-+#ifndef NO_EMBEDDED_ACCESS_CHECKS
-+ if (options & REFRESH_GRANT)
-+ {
-+ THD *tmp_thd= 0;
-+ /*
-+ If reload_acl_and_cache() is called from SIGHUP handler we have to
-+ allocate temporary THD for execution of acl_reload()/grant_reload().
-+ */
-+ if (!thd && (thd= (tmp_thd= new THD)))
-+ {
-+ thd->thread_stack= (char*) &tmp_thd;
-+ thd->store_globals();
-+ }
-+ if (thd)
-+ {
-+ (void)acl_reload(thd);
-+ (void)grant_reload(thd);
-+ }
-+ if (tmp_thd)
-+ {
-+ delete tmp_thd;
-+ /* Remember that we don't have a THD */
-+ my_pthread_setspecific_ptr(THR_THD, 0);
-+ thd= 0;
-+ }
-+ reset_mqh((LEX_USER *)NULL, TRUE);
-+ }
-+#endif
-+ if (options & REFRESH_LOG)
-+ {
-+ /*
-+ Flush the normal query log, the update log, the binary log,
-+ the slow query log, and the relay log (if it exists).
-+ */
-+
-+ /*
-+ Writing this command to the binlog may result in infinite loops
-+ when doing mysqlbinlog|mysql, and anyway it does not really make
-+ sense to log it automatically (would cause more trouble to users
-+ than it would help them)
-+ */
-+ tmp_write_to_binlog= 0;
-+ mysql_log.new_file(1);
-+ mysql_slow_log.new_file(1);
-+ if( mysql_bin_log.is_open() )
-+ {
-+ mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE);
-+ }
-+#ifdef HAVE_REPLICATION
-+ pthread_mutex_lock(&LOCK_active_mi);
-+ rotate_relay_log(active_mi);
-+ pthread_mutex_unlock(&LOCK_active_mi);
-+#endif
-+ if (ha_flush_logs())
-+ result=1;
-+ if (flush_error_log())
-+ result=1;
-+ }
-+#ifdef HAVE_QUERY_CACHE
-+ if (options & REFRESH_QUERY_CACHE_FREE)
-+ {
-+ query_cache.pack(); // FLUSH QUERY CACHE
-+ options &= ~REFRESH_QUERY_CACHE; // Don't flush cache, just free memory
-+ }
-+ if (options & (REFRESH_TABLES | REFRESH_QUERY_CACHE))
-+ {
-+ query_cache.flush(); // RESET QUERY CACHE
-+ }
-+#endif /*HAVE_QUERY_CACHE*/
-+ /*
-+ Note that if REFRESH_READ_LOCK bit is set then REFRESH_TABLES is set too
-+ (see sql_yacc.yy)
-+ */
-+ if (options & (REFRESH_TABLES | REFRESH_READ_LOCK))
-+ {
-+ if ((options & REFRESH_READ_LOCK) && thd)
-+ {
-+ /*
-+ We must not try to aspire a global read lock if we have a write
-+ locked table. This would lead to a deadlock when trying to
-+ reopen (and re-lock) the table after the flush.
-+ */
-+ if (thd->locked_tables)
-+ {
-+ THR_LOCK_DATA **lock_p= thd->locked_tables->locks;
-+ THR_LOCK_DATA **end_p= lock_p + thd->locked_tables->lock_count;
-+
-+ for (; lock_p < end_p; lock_p++)
-+ {
-+ if ((*lock_p)->type == TL_WRITE)
-+ {
-+ my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
-+ return 1;
-+ }
-+ }
-+ }
-+ /*
-+ Writing to the binlog could cause deadlocks, as we don't log
-+ UNLOCK TABLES
-+ */
-+ tmp_write_to_binlog= 0;
-+ if (lock_global_read_lock(thd))
-+ return 1; // Killed
-+ result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1,
-+ tables);
-+ if (make_global_read_lock_block_commit(thd)) // Killed
-+ {
-+ /* Don't leave things in a half-locked state */
-+ unlock_global_read_lock(thd);
-+ return 1;
-+ }
-+ }
-+ else
-+ result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1, tables);
-+ my_dbopt_cleanup();
-+ }
-+ if (options & REFRESH_HOSTS)
-+ hostname_cache_refresh();
-+ if (thd && (options & REFRESH_STATUS))
-+ refresh_status(thd);
-+ if (options & REFRESH_THREADS)
-+ flush_thread_cache();
-+#ifdef HAVE_REPLICATION
-+ if (options & REFRESH_MASTER)
-+ {
-+ DBUG_ASSERT(thd);
-+ tmp_write_to_binlog= 0;
-+ if (reset_master(thd))
-+ {
-+ result=1;
-+ thd->fatal_error(); // Ensure client get error
-+ }
-+ }
-+#endif
-+#ifdef OPENSSL
-+ if (options & REFRESH_DES_KEY_FILE)
-+ {
-+ if (des_key_file)
-+ result=load_des_key_file(des_key_file);
-+ }
-+#endif
-+#ifdef HAVE_REPLICATION
-+ if (options & REFRESH_SLAVE)
-+ {
-+ tmp_write_to_binlog= 0;
-+ pthread_mutex_lock(&LOCK_active_mi);
-+ if (reset_slave(thd, active_mi))
-+ result=1;
-+ pthread_mutex_unlock(&LOCK_active_mi);
-+ }
-+#endif
-+ if (options & REFRESH_USER_RESOURCES)
-+ reset_mqh((LEX_USER *) NULL);
-+ *write_to_binlog= tmp_write_to_binlog;
-+ return result;
-+}
-+
-+/*
-+ kill on thread
-+
-+ SYNOPSIS
-+ kill_one_thread()
-+ thd Thread class
-+ id Thread id
-+
-+ NOTES
-+ This is written such that we have a short lock on LOCK_thread_count
-+*/
-+
-+void kill_one_thread(THD *thd, ulong id, bool only_kill_query)
-+{
-+ THD *tmp;
-+ uint error=ER_NO_SUCH_THREAD;
-+ VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
-+ I_List_iterator<THD> it(threads);
-+ while ((tmp=it++))
-+ {
-+ if (tmp->thread_id == id)
-+ {
-+ pthread_mutex_lock(&tmp->LOCK_delete); // Lock from delete
-+ break;
-+ }
-+ }
-+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
-+ if (tmp)
-+ {
-+ if ((thd->security_ctx->master_access & SUPER_ACL) ||
-+ !strcmp(thd->security_ctx->user, tmp->security_ctx->user))
-+ {
-+ tmp->awake(only_kill_query ? THD::KILL_QUERY : THD::KILL_CONNECTION);
-+ error=0;
-+ }
-+ else
-+ error=ER_KILL_DENIED_ERROR;
-+ pthread_mutex_unlock(&tmp->LOCK_delete);
-+ }
-+
-+ if (!error)
-+ send_ok(thd);
-+ else
-+ my_error(error, MYF(0), id);
-+}
-+
-+
-+ /* If pointer is not a null pointer, append filename to it */
-+
-+static bool append_file_to_dir(THD *thd, const char **filename_ptr,
-+ const char *table_name)
-+{
-+ char buff[FN_REFLEN],*ptr, *end;
-+ if (!*filename_ptr)
-+ return 0; // nothing to do
-+
-+ /* Check that the filename is not too long and it's a hard path */
-+ if (strlen(*filename_ptr)+strlen(table_name) >= FN_REFLEN-1 ||
-+ !test_if_hard_path(*filename_ptr))
-+ {
-+ my_error(ER_WRONG_TABLE_NAME, MYF(0), *filename_ptr);
-+ return 1;
-+ }
-+ /* Fix is using unix filename format on dos */
-+ strmov(buff,*filename_ptr);
-+ end=convert_dirname(buff, *filename_ptr, NullS);
-+ if (!(ptr=thd->alloc((uint) (end-buff)+(uint) strlen(table_name)+1)))
-+ return 1; // End of memory
-+ *filename_ptr=ptr;
-+ strxmov(ptr,buff,table_name,NullS);
-+ return 0;
-+}
-+
-+
-+/*
-+ Check if the select is a simple select (not an union)
-+
-+ SYNOPSIS
-+ check_simple_select()
-+
-+ RETURN VALUES
-+ 0 ok
-+ 1 error ; In this case the error messege is sent to the client
-+*/
-+
-+bool check_simple_select()
-+{
-+ THD *thd= current_thd;
-+ LEX *lex= thd->lex;
-+ if (lex->current_select != &lex->select_lex)
-+ {
-+ char command[80];
-+ strmake(command, lex->yylval->symbol.str,
-+ min(lex->yylval->symbol.length, sizeof(command)-1));
-+ my_error(ER_CANT_USE_OPTION_HERE, MYF(0), command);
-+ return 1;
-+ }
-+ return 0;
-+}
-+
-+
-+Comp_creator *comp_eq_creator(bool invert)
-+{
-+ return invert?(Comp_creator *)&ne_creator:(Comp_creator *)&eq_creator;
-+}
-+
-+
-+Comp_creator *comp_ge_creator(bool invert)
-+{
-+ return invert?(Comp_creator *)<_creator:(Comp_creator *)&ge_creator;
-+}
-+
-+
-+Comp_creator *comp_gt_creator(bool invert)
-+{
-+ return invert?(Comp_creator *)&le_creator:(Comp_creator *)>_creator;
-+}
-+
-+
-+Comp_creator *comp_le_creator(bool invert)
-+{
-+ return invert?(Comp_creator *)>_creator:(Comp_creator *)&le_creator;
-+}
-+
-+
-+Comp_creator *comp_lt_creator(bool invert)
-+{
-+ return invert?(Comp_creator *)&ge_creator:(Comp_creator *)<_creator;
-+}
-+
-+
-+Comp_creator *comp_ne_creator(bool invert)
-+{
-+ return invert?(Comp_creator *)&eq_creator:(Comp_creator *)&ne_creator;
-+}
-+
-+
-+/*
-+ Construct ALL/ANY/SOME subquery Item
-+
-+ SYNOPSIS
-+ all_any_subquery_creator()
-+ left_expr - pointer to left expression
-+ cmp - compare function creator
-+ all - true if we create ALL subquery
-+ select_lex - pointer on parsed subquery structure
-+
-+ RETURN VALUE
-+ constructed Item (or 0 if out of memory)
-+*/
-+Item * all_any_subquery_creator(Item *left_expr,
-+ chooser_compare_func_creator cmp,
-+ bool all,
-+ SELECT_LEX *select_lex)
-+{
-+ if ((cmp == &comp_eq_creator) && !all) // = ANY <=> IN
-+ return new Item_in_subselect(left_expr, select_lex);
-+
-+ if ((cmp == &comp_ne_creator) && all) // <> ALL <=> NOT IN
-+ return new Item_func_not(new Item_in_subselect(left_expr, select_lex));
-+
-+ Item_allany_subselect *it=
-+ new Item_allany_subselect(left_expr, cmp, select_lex, all);
-+ if (all)
-+ return it->upper_item= new Item_func_not_all(it); /* ALL */
-+
-+ return it->upper_item= new Item_func_nop_all(it); /* ANY/SOME */
-+}
-+
-+
-+/*
-+ CREATE INDEX and DROP INDEX are implemented by calling ALTER TABLE with
-+ the proper arguments. This isn't very fast but it should work for most
-+ cases.
-+
-+ In the future ALTER TABLE will notice that only added indexes
-+ and create these one by one for the existing table without having to do
-+ a full rebuild.
-+
-+ One should normally create all indexes with CREATE TABLE or ALTER TABLE.
-+*/
-+
-+bool mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys)
-+{
-+ List<create_field> fields;
-+ ALTER_INFO alter_info;
-+ alter_info.flags= ALTER_ADD_INDEX;
-+ HA_CREATE_INFO create_info;
-+ DBUG_ENTER("mysql_create_index");
-+ bzero((char*) &create_info,sizeof(create_info));
-+ create_info.db_type=DB_TYPE_DEFAULT;
-+ create_info.default_table_charset= thd->variables.collation_database;
-+ DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->table_name,
-+ &create_info, table_list,
-+ fields, keys, 0, (ORDER*)0,
-+ 0, &alter_info, 1));
-+}
-+
-+
-+bool mysql_drop_index(THD *thd, TABLE_LIST *table_list, ALTER_INFO *alter_info)
-+{
-+ List<create_field> fields;
-+ List<Key> keys;
-+ HA_CREATE_INFO create_info;
-+ DBUG_ENTER("mysql_drop_index");
-+ bzero((char*) &create_info,sizeof(create_info));
-+ create_info.db_type=DB_TYPE_DEFAULT;
-+ create_info.default_table_charset= thd->variables.collation_database;
-+ alter_info->clear();
-+ alter_info->flags= ALTER_DROP_INDEX;
-+ DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->table_name,
-+ &create_info, table_list,
-+ fields, keys, 0, (ORDER*)0,
-+ 0, alter_info, 1));
-+}
-+
-+
-+/*
-+ Multi update query pre-check
-+
-+ SYNOPSIS
-+ multi_update_precheck()
-+ thd Thread handler
-+ tables Global/local table list (have to be the same)
-+
-+ RETURN VALUE
-+ FALSE OK
-+ TRUE Error
-+*/
-+
-+bool multi_update_precheck(THD *thd, TABLE_LIST *tables)
-+{
-+ const char *msg= 0;
-+ TABLE_LIST *table;
-+ LEX *lex= thd->lex;
-+ SELECT_LEX *select_lex= &lex->select_lex;
-+ DBUG_ENTER("multi_update_precheck");
-+
-+ if (select_lex->item_list.elements != lex->value_list.elements)
-+ {
-+ my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
-+ DBUG_RETURN(TRUE);
-+ }
-+ /*
-+ Ensure that we have UPDATE or SELECT privilege for each table
-+ The exact privilege is checked in mysql_multi_update()
-+ */
-+ for (table= tables; table; table= table->next_local)
-+ {
-+ if (table->derived)
-+ table->grant.privilege= SELECT_ACL;
-+ else if ((check_access(thd, UPDATE_ACL, table->db,
-+ &table->grant.privilege, 0, 1,
-+ test(table->schema_table)) ||
-+ grant_option &&
-+ check_grant(thd, UPDATE_ACL, table, 0, 1, 1)) &&
-+ (check_access(thd, SELECT_ACL, table->db,
-+ &table->grant.privilege, 0, 0,
-+ test(table->schema_table)) ||
-+ grant_option && check_grant(thd, SELECT_ACL, table, 0, 1, 0)))
-+ DBUG_RETURN(TRUE);
-+
-+ table->table_in_first_from_clause= 1;
-+ }
-+ /*
-+ Is there tables of subqueries?
-+ */
-+ if (&lex->select_lex != lex->all_selects_list || lex->time_zone_tables_used)
-+ {
-+ DBUG_PRINT("info",("Checking sub query list"));
-+ for (table= tables; table; table= table->next_global)
-+ {
-+ if (!my_tz_check_n_skip_implicit_tables(&table,
-+ lex->time_zone_tables_used) &&
-+ !table->table_in_first_from_clause)
-+ {
-+ if (check_access(thd, SELECT_ACL, table->db,
-+ &table->grant.privilege, 0, 0,
-+ test(table->schema_table)) ||
-+ grant_option && check_grant(thd, SELECT_ACL, table, 0, 1, 0))
-+ DBUG_RETURN(TRUE);
-+ }
-+ }
-+ }
-+
-+ if (select_lex->order_list.elements)
-+ msg= "ORDER BY";
-+ else if (select_lex->select_limit)
-+ msg= "LIMIT";
-+ if (msg)
-+ {
-+ my_error(ER_WRONG_USAGE, MYF(0), "UPDATE", msg);
-+ DBUG_RETURN(TRUE);
-+ }
-+ DBUG_RETURN(FALSE);
-+}
-+
-+/*
-+ Multi delete query pre-check
-+
-+ SYNOPSIS
-+ multi_delete_precheck()
-+ thd Thread handler
-+ tables Global/local table list
-+
-+ RETURN VALUE
-+ FALSE OK
-+ TRUE error
-+*/
-+
-+bool multi_delete_precheck(THD *thd, TABLE_LIST *tables)
-+{
-+ SELECT_LEX *select_lex= &thd->lex->select_lex;
-+ TABLE_LIST *aux_tables=
-+ (TABLE_LIST *)thd->lex->auxiliary_table_list.first;
-+ TABLE_LIST **save_query_tables_own_last= thd->lex->query_tables_own_last;
-+ DBUG_ENTER("multi_delete_precheck");
-+
-+ /* sql_yacc guarantees that tables and aux_tables are not zero */
-+ DBUG_ASSERT(aux_tables != 0);
-+ if (check_db_used(thd, tables) || check_db_used(thd,aux_tables) ||
-+ check_table_access(thd, SELECT_ACL, tables, 0))
-+ DBUG_RETURN(TRUE);
-+
-+ /*
-+ Since aux_tables list is not part of LEX::query_tables list we
-+ have to juggle with LEX::query_tables_own_last value to be able
-+ call check_table_access() safely.
-+ */
-+ thd->lex->query_tables_own_last= 0;
-+ if (check_table_access(thd, DELETE_ACL, aux_tables, 0))
-+ {
-+ thd->lex->query_tables_own_last= save_query_tables_own_last;
-+ DBUG_RETURN(TRUE);
-+ }
-+ thd->lex->query_tables_own_last= save_query_tables_own_last;
-+
-+ if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where)
-+ {
-+ my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
-+ ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
-+ DBUG_RETURN(TRUE);
-+ }
-+ DBUG_RETURN(FALSE);
-+}
-+
-+
-+/*
-+ Link tables in auxilary table list of multi-delete with corresponding
-+ elements in main table list, and set proper locks for them.
-+
-+ SYNOPSIS
-+ multi_delete_set_locks_and_link_aux_tables()
-+ lex - pointer to LEX representing multi-delete
-+
-+ RETURN VALUE
-+ FALSE - success
-+ TRUE - error
-+*/
-+
-+bool multi_delete_set_locks_and_link_aux_tables(LEX *lex)
-+{
-+ TABLE_LIST *tables= (TABLE_LIST*)lex->select_lex.table_list.first;
-+ TABLE_LIST *target_tbl;
-+ DBUG_ENTER("multi_delete_set_locks_and_link_aux_tables");
-+
-+ lex->table_count= 0;
-+
-+ for (target_tbl= (TABLE_LIST *)lex->auxiliary_table_list.first;
-+ target_tbl; target_tbl= target_tbl->next_local)
-+ {
-+ lex->table_count++;
-+ /* All tables in aux_tables must be found in FROM PART */
-+ TABLE_LIST *walk;
-+ for (walk= tables; walk; walk= walk->next_local)
-+ {
-+ if (!my_strcasecmp(table_alias_charset,
-+ target_tbl->alias, walk->alias) &&
-+ !strcmp(walk->db, target_tbl->db))
-+ break;
-+ }
-+ if (!walk)
-+ {
-+ my_error(ER_UNKNOWN_TABLE, MYF(0),
-+ target_tbl->table_name, "MULTI DELETE");
-+ DBUG_RETURN(TRUE);
-+ }
-+ if (!walk->derived)
-+ {
-+ target_tbl->table_name= walk->table_name;
-+ target_tbl->table_name_length= walk->table_name_length;
-+ }
-+ walk->updating= target_tbl->updating;
-+ walk->lock_type= target_tbl->lock_type;
-+ target_tbl->correspondent_table= walk; // Remember corresponding table
-+ }
-+ DBUG_RETURN(FALSE);
-+}
-+
-+
-+/*
-+ simple UPDATE query pre-check
-+
-+ SYNOPSIS
-+ update_precheck()
-+ thd Thread handler
-+ tables Global table list
-+
-+ RETURN VALUE
-+ FALSE OK
-+ TRUE Error
-+*/
-+
-+bool update_precheck(THD *thd, TABLE_LIST *tables)
-+{
-+ DBUG_ENTER("update_precheck");
-+ if (thd->lex->select_lex.item_list.elements != thd->lex->value_list.elements)
-+ {
-+ my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
-+ DBUG_RETURN(TRUE);
-+ }
-+ DBUG_RETURN(check_db_used(thd, tables) ||
-+ check_one_table_access(thd, UPDATE_ACL, tables));
-+}
-+
-+
-+/*
-+ simple DELETE query pre-check
-+
-+ SYNOPSIS
-+ delete_precheck()
-+ thd Thread handler
-+ tables Global table list
-+
-+ RETURN VALUE
-+ FALSE OK
-+ TRUE error
-+*/
-+
-+bool delete_precheck(THD *thd, TABLE_LIST *tables)
-+{
-+ DBUG_ENTER("delete_precheck");
-+ if (check_one_table_access(thd, DELETE_ACL, tables))
-+ DBUG_RETURN(TRUE);
-+ /* Set privilege for the WHERE clause */
-+ tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
-+ DBUG_RETURN(FALSE);
-+}
-+
-+
-+/*
-+ simple INSERT query pre-check
-+
-+ SYNOPSIS
-+ insert_precheck()
-+ thd Thread handler
-+ tables Global table list
-+
-+ RETURN VALUE
-+ FALSE OK
-+ TRUE error
-+*/
-+
-+bool insert_precheck(THD *thd, TABLE_LIST *tables)
-+{
-+ LEX *lex= thd->lex;
-+ DBUG_ENTER("insert_precheck");
-+
-+ /*
-+ Check that we have modify privileges for the first table and
-+ select privileges for the rest
-+ */
-+ ulong privilege= (INSERT_ACL |
-+ (lex->duplicates == DUP_REPLACE ? DELETE_ACL : 0) |
-+ (lex->value_list.elements ? UPDATE_ACL : 0));
-+
-+ if (check_one_table_access(thd, privilege, tables))
-+ DBUG_RETURN(TRUE);
-+
-+ if (lex->update_list.elements != lex->value_list.elements)
-+ {
-+ my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
-+ DBUG_RETURN(TRUE);
-+ }
-+ if (check_db_used(thd, tables))
-+ DBUG_RETURN(TRUE);
-+ DBUG_RETURN(FALSE);
-+}
-+
-+
-+/*
-+ CREATE TABLE query pre-check
-+
-+ SYNOPSIS
-+ create_table_precheck()
-+ thd Thread handler
-+ tables Global table list
-+ create_table Table which will be created
-+
-+ RETURN VALUE
-+ FALSE OK
-+ TRUE Error
-+*/
-+
-+bool create_table_precheck(THD *thd, TABLE_LIST *tables,
-+ TABLE_LIST *create_table)
-+{
-+ LEX *lex= thd->lex;
-+ SELECT_LEX *select_lex= &lex->select_lex;
-+ ulong want_priv;
-+ bool error= TRUE; // Error message is given
-+ DBUG_ENTER("create_table_precheck");
-+
-+ want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
-+ CREATE_TMP_ACL : CREATE_ACL);
-+ lex->create_info.alias= create_table->alias;
-+ if (check_access(thd, want_priv, create_table->db,
-+ &create_table->grant.privilege, 0, 0,
-+ test(create_table->schema_table)) ||
-+ check_merge_table_access(thd, create_table->db,
-+ (TABLE_LIST *)
-+ lex->create_info.merge_list.first))
-+ goto err;
-+ if (grant_option && want_priv != CREATE_TMP_ACL &&
-+ check_grant(thd, want_priv, create_table, 0, 1, 0))
-+ goto err;
-+
-+ if (select_lex->item_list.elements)
-+ {
-+ /* Check permissions for used tables in CREATE TABLE ... SELECT */
-+
-+#ifdef NOT_NECESSARY_TO_CHECK_CREATE_TABLE_EXIST_WHEN_PREPARING_STATEMENT
-+ /* This code throws an ill error for CREATE TABLE t1 SELECT * FROM t1 */
-+ /*
-+ Only do the check for PS, becasue we on execute we have to check that
-+ against the opened tables to ensure we don't use a table that is part
-+ of the view (which can only be done after the table has been opened).
-+ */
-+ if (thd->stmt_arena->is_stmt_prepare_or_first_sp_execute())
-+ {
-+ /*
-+ For temporary tables we don't have to check if the created table exists
-+ */
-+ if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
-+ find_table_in_global_list(tables, create_table->db,
-+ create_table->table_name))
-+ {
-+ error= FALSE;
-+ goto err;
-+ }
-+ }
-+#endif
-+ if (tables && check_table_access(thd, SELECT_ACL, tables,0))
-+ goto err;
-+ }
-+ error= FALSE;
-+
-+err:
-+ DBUG_RETURN(error);
-+}
-+
-+
-+/*
-+ negate given expression
-+
-+ SYNOPSIS
-+ negate_expression()
-+ thd thread handler
-+ expr expression for negation
-+
-+ RETURN
-+ negated expression
-+*/
-+
-+Item *negate_expression(THD *thd, Item *expr)
-+{
-+ Item *negated;
-+ if (expr->type() == Item::FUNC_ITEM &&
-+ ((Item_func *) expr)->functype() == Item_func::NOT_FUNC)
-+ {
-+ /* it is NOT(NOT( ... )) */
-+ Item *arg= ((Item_func *) expr)->arguments()[0];
-+ enum_parsing_place place= thd->lex->current_select->parsing_place;
-+ if (arg->is_bool_func() || place == IN_WHERE || place == IN_HAVING)
-+ return arg;
-+ /*
-+ if it is not boolean function then we have to emulate value of
-+ not(not(a)), it will be a != 0
-+ */
-+ return new Item_func_ne(arg, new Item_int((char*) "0", 0, 1));
-+ }
-+
-+ if ((negated= expr->neg_transformer(thd)) != 0)
-+ return negated;
-+ return new Item_func_not(expr);
-+}
-+
-+/*
-+ Set the specified definer to the default value, which is the current user in
-+ the thread.
-+
-+ SYNOPSIS
-+ get_default_definer()
-+ thd [in] thread handler
-+ definer [out] definer
-+*/
-+
-+void get_default_definer(THD *thd, LEX_USER *definer)
-+{
-+ const Security_context *sctx= thd->security_ctx;
-+
-+ definer->user.str= (char *) sctx->priv_user;
-+ definer->user.length= strlen(definer->user.str);
-+
-+ definer->host.str= (char *) sctx->priv_host;
-+ definer->host.length= strlen(definer->host.str);
-+}
-+
-+
-+/*
-+ Create default definer for the specified THD.
-+
-+ SYNOPSIS
-+ create_default_definer()
-+ thd [in] thread handler
-+
-+ RETURN
-+ On success, return a valid pointer to the created and initialized
-+ LEX_USER, which contains definer information.
-+ On error, return 0.
-+*/
-+
-+LEX_USER *create_default_definer(THD *thd)
-+{
-+ LEX_USER *definer;
-+
-+ if (! (definer= (LEX_USER*) thd->alloc(sizeof(LEX_USER))))
-+ return 0;
-+
-+ get_default_definer(thd, definer);
-+
-+ return definer;
-+}
-+
-+
-+/*
-+ Create definer with the given user and host names.
-+
-+ SYNOPSIS
-+ create_definer()
-+ thd [in] thread handler
-+ user_name [in] user name
-+ host_name [in] host name
-+
-+ RETURN
-+ On success, return a valid pointer to the created and initialized
-+ LEX_USER, which contains definer information.
-+ On error, return 0.
-+*/
-+
-+LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name)
-+{
-+ LEX_USER *definer;
-+
-+ /* Create and initialize. */
-+
-+ if (! (definer= (LEX_USER*) thd->alloc(sizeof(LEX_USER))))
-+ return 0;
-+
-+ definer->user= *user_name;
-+ definer->host= *host_name;
-+
-+ return definer;
-+}
-+
-+
-+/*
-+ Retuns information about user or current user.
-+
-+ SYNOPSIS
-+ get_current_user()
-+ thd [in] thread handler
-+ user [in] user
-+
-+ RETURN
-+ On success, return a valid pointer to initialized
-+ LEX_USER, which contains user information.
-+ On error, return 0.
-+*/
-+
-+LEX_USER *get_current_user(THD *thd, LEX_USER *user)
-+{
-+ if (!user->user.str) // current_user
-+ return create_default_definer(thd);
-+
-+ return user;
-+}
-+
-+
-+/*
-+ Check that length of a string does not exceed some limit.
-+
-+ SYNOPSIS
-+ check_string_length()
-+ str string to be checked
-+ err_msg error message to be displayed if the string is too long
-+ max_length max length
-+
-+ RETURN
-+ FALSE the passed string is not longer than max_length
-+ TRUE the passed string is longer than max_length
-+*/
-+
-+bool check_string_length(LEX_STRING *str, const char *err_msg,
-+ uint max_length)
-+{
-+ if (str->length <= max_length)
-+ return FALSE;
-+
-+ my_error(ER_WRONG_STRING_LENGTH, MYF(0), str->str, err_msg, max_length);
-+
-+ return TRUE;
-+}
-diff -urNad mysql-5.0-etch~/sql/sql_show.cc mysql-5.0-etch/sql/sql_show.cc
---- mysql-5.0-etch~/sql/sql_show.cc 2007-05-28 18:56:15.000000000 +0200
-+++ mysql-5.0-etch/sql/sql_show.cc 2007-05-28 19:12:52.000000000 +0200
-@@ -2141,7 +2141,7 @@
- */
- thd->reset_n_backup_open_tables_state(&open_tables_state_backup);
-
-- if (lsel)
-+ if (lsel && lsel->table_list.first)
- {
- TABLE_LIST *show_table_list= (TABLE_LIST*) lsel->table_list.first;
- bool res;
-diff -urNad mysql-5.0-etch~/sql/sql_show.cc.orig mysql-5.0-etch/sql/sql_show.cc.orig
---- mysql-5.0-etch~/sql/sql_show.cc.orig 1970-01-01 01:00:00.000000000 +0100
-+++ mysql-5.0-etch/sql/sql_show.cc.orig 2007-05-28 18:56:15.000000000 +0200
-@@ -0,0 +1,4350 @@
-+/* Copyright (C) 2000-2004 MySQL AB
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License as published by
-+ the Free Software Foundation; either version 2 of the License, or
-+ (at your option) any later version.
-+
-+ This program is distributed in the hope that it will be useful,
-+ but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ GNU General Public License for more details.
-+
-+ You should have received a copy of the GNU General Public License
-+ along with this program; if not, write to the Free Software
-+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-+
-+
-+/* Function with list databases, tables or fields */
-+
-+#include "mysql_priv.h"
-+#include "sql_select.h" // For select_describe
-+#include "repl_failsafe.h"
-+#include "sp.h"
-+#include "sp_head.h"
-+#include "sql_trigger.h"
-+#include <my_dir.h>
-+
-+#ifdef HAVE_BERKELEY_DB
-+#include "ha_berkeley.h" // For berkeley_show_logs
-+#endif
-+
-+static const char *grant_names[]={
-+ "select","insert","update","delete","create","drop","reload","shutdown",
-+ "process","file","grant","references","index","alter"};
-+
-+#ifndef NO_EMBEDDED_ACCESS_CHECKS
-+static TYPELIB grant_types = { sizeof(grant_names)/sizeof(char **),
-+ "grant_types",
-+ grant_names, NULL};
-+#endif
-+
-+static int
-+store_create_info(THD *thd, TABLE_LIST *table_list, String *packet);
-+static void
-+append_algorithm(TABLE_LIST *table, String *buff);
-+static int
-+view_store_create_info(THD *thd, TABLE_LIST *table, String *buff);
-+static bool schema_table_store_record(THD *thd, TABLE *table);
-+
-+
-+/***************************************************************************
-+** List all table types supported
-+***************************************************************************/
-+
-+bool mysqld_show_storage_engines(THD *thd)
-+{
-+ List<Item> field_list;
-+ Protocol *protocol= thd->protocol;
-+ DBUG_ENTER("mysqld_show_storage_engines");
-+
-+ field_list.push_back(new Item_empty_string("Engine",10));
-+ field_list.push_back(new Item_empty_string("Support",10));
-+ field_list.push_back(new Item_empty_string("Comment",80));
-+
-+ if (protocol->send_fields(&field_list,
-+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
-+ DBUG_RETURN(TRUE);
-+
-+ const char *default_type_name=
-+ ha_get_storage_engine((enum db_type)thd->variables.table_type);
-+
-+ handlerton **types;
-+ for (types= sys_table_types; *types; types++)
-+ {
-+ if (!((*types)->flags & HTON_HIDDEN))
-+ {
-+ protocol->prepare_for_resend();
-+ protocol->store((*types)->name, system_charset_info);
-+ const char *option_name= show_comp_option_name[(int) (*types)->state];
-+
-+ if ((*types)->state == SHOW_OPTION_YES &&
-+ !my_strcasecmp(system_charset_info, default_type_name, (*types)->name))
-+ option_name= "DEFAULT";
-+ protocol->store(option_name, system_charset_info);
-+ protocol->store((*types)->comment, system_charset_info);
-+ if (protocol->write())
-+ DBUG_RETURN(TRUE);
-+ }
-+ }
-+ send_eof(thd);
-+ DBUG_RETURN(FALSE);
-+}
-+
-+
-+/***************************************************************************
-+ List all privileges supported
-+***************************************************************************/
-+
-+struct show_privileges_st {
-+ const char *privilege;
-+ const char *context;
-+ const char *comment;
-+};
-+
-+static struct show_privileges_st sys_privileges[]=
-+{
-+ {"Alter", "Tables", "To alter the table"},
-+ {"Alter routine", "Functions,Procedures", "To alter or drop stored functions/procedures"},
-+ {"Create", "Databases,Tables,Indexes", "To create new databases and tables"},
-+ {"Create routine","Functions,Procedures","To use CREATE FUNCTION/PROCEDURE"},
-+ {"Create temporary tables","Databases","To use CREATE TEMPORARY TABLE"},
-+ {"Create view", "Tables", "To create new views"},
-+ {"Create user", "Server Admin", "To create new users"},
-+ {"Delete", "Tables", "To delete existing rows"},
-+ {"Drop", "Databases,Tables", "To drop databases, tables, and views"},
-+ {"Execute", "Functions,Procedures", "To execute stored routines"},
-+ {"File", "File access on server", "To read and write files on the server"},
-+ {"Grant option", "Databases,Tables,Functions,Procedures", "To give to other users those privileges you possess"},
-+ {"Index", "Tables", "To create or drop indexes"},
-+ {"Insert", "Tables", "To insert data into tables"},
-+ {"Lock tables","Databases","To use LOCK TABLES (together with SELECT privilege)"},
-+ {"Process", "Server Admin", "To view the plain text of currently executing queries"},
-+ {"References", "Databases,Tables", "To have references on tables"},
-+ {"Reload", "Server Admin", "To reload or refresh tables, logs and privileges"},
-+ {"Replication client","Server Admin","To ask where the slave or master servers are"},
-+ {"Replication slave","Server Admin","To read binary log events from the master"},
-+ {"Select", "Tables", "To retrieve rows from table"},
-+ {"Show databases","Server Admin","To see all databases with SHOW DATABASES"},
-+ {"Show view","Tables","To see views with SHOW CREATE VIEW"},
-+ {"Shutdown","Server Admin", "To shut down the server"},
-+ {"Super","Server Admin","To use KILL thread, SET GLOBAL, CHANGE MASTER, etc."},
-+ {"Update", "Tables", "To update existing rows"},
-+ {"Usage","Server Admin","No privileges - allow connect only"},
-+ {NullS, NullS, NullS}
-+};
-+
-+bool mysqld_show_privileges(THD *thd)
-+{
-+ List<Item> field_list;
-+ Protocol *protocol= thd->protocol;
-+ DBUG_ENTER("mysqld_show_privileges");
-+
-+ field_list.push_back(new Item_empty_string("Privilege",10));
-+ field_list.push_back(new Item_empty_string("Context",15));
-+ field_list.push_back(new Item_empty_string("Comment",NAME_LEN));
-+
-+ if (protocol->send_fields(&field_list,
-+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
-+ DBUG_RETURN(TRUE);
-+
-+ show_privileges_st *privilege= sys_privileges;
-+ for (privilege= sys_privileges; privilege->privilege ; privilege++)
-+ {
-+ protocol->prepare_for_resend();
-+ protocol->store(privilege->privilege, system_charset_info);
-+ protocol->store(privilege->context, system_charset_info);
-+ protocol->store(privilege->comment, system_charset_info);
-+ if (protocol->write())
-+ DBUG_RETURN(TRUE);
-+ }
-+ send_eof(thd);
-+ DBUG_RETURN(FALSE);
-+}
-+
-+
-+/***************************************************************************
-+ List all column types
-+***************************************************************************/
-+
-+struct show_column_type_st
-+{
-+ const char *type;
-+ uint size;
-+ const char *min_value;
-+ const char *max_value;
-+ uint precision;
-+ uint scale;
-+ const char *nullable;
-+ const char *auto_increment;
-+ const char *unsigned_attr;
-+ const char *zerofill;
-+ const char *searchable;
-+ const char *case_sensitivity;
-+ const char *default_value;
-+ const char *comment;
-+};
-+
-+/* TODO: Add remaning types */
-+
-+static struct show_column_type_st sys_column_types[]=
-+{
-+ {"tinyint",
-+ 1, "-128", "127", 0, 0, "YES", "YES",
-+ "NO", "YES", "YES", "NO", "NULL,0",
-+ "A very small integer"},
-+ {"tinyint unsigned",
-+ 1, "0" , "255", 0, 0, "YES", "YES",
-+ "YES", "YES", "YES", "NO", "NULL,0",
-+ "A very small integer"},
-+};
-+
-+bool mysqld_show_column_types(THD *thd)
-+{
-+ List<Item> field_list;
-+ Protocol *protocol= thd->protocol;
-+ DBUG_ENTER("mysqld_show_column_types");
-+
-+ field_list.push_back(new Item_empty_string("Type",30));
-+ field_list.push_back(new Item_int("Size",(longlong) 1,21));
-+ field_list.push_back(new Item_empty_string("Min_Value",20));
-+ field_list.push_back(new Item_empty_string("Max_Value",20));
-+ field_list.push_back(new Item_return_int("Prec", 4, MYSQL_TYPE_SHORT));
-+ field_list.push_back(new Item_return_int("Scale", 4, MYSQL_TYPE_SHORT));
-+ field_list.push_back(new Item_empty_string("Nullable",4));
-+ field_list.push_back(new Item_empty_string("Auto_Increment",4));
-+ field_list.push_back(new Item_empty_string("Unsigned",4));
-+ field_list.push_back(new Item_empty_string("Zerofill",4));
-+ field_list.push_back(new Item_empty_string("Searchable",4));
-+ field_list.push_back(new Item_empty_string("Case_Sensitive",4));
-+ field_list.push_back(new Item_empty_string("Default",NAME_LEN));
-+ field_list.push_back(new Item_empty_string("Comment",NAME_LEN));
-+
-+ if (protocol->send_fields(&field_list,
-+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
-+ DBUG_RETURN(TRUE);
-+
-+ /* TODO: Change the loop to not use 'i' */
-+ for (uint i=0; i < sizeof(sys_column_types)/sizeof(sys_column_types[0]); i++)
-+ {
-+ protocol->prepare_for_resend();
-+ protocol->store(sys_column_types[i].type, system_charset_info);
-+ protocol->store((ulonglong) sys_column_types[i].size);
-+ protocol->store(sys_column_types[i].min_value, system_charset_info);
-+ protocol->store(sys_column_types[i].max_value, system_charset_info);
-+ protocol->store_short((longlong) sys_column_types[i].precision);
-+ protocol->store_short((longlong) sys_column_types[i].scale);
-+ protocol->store(sys_column_types[i].nullable, system_charset_info);
-+ protocol->store(sys_column_types[i].auto_increment, system_charset_info);
-+ protocol->store(sys_column_types[i].unsigned_attr, system_charset_info);
-+ protocol->store(sys_column_types[i].zerofill, system_charset_info);
-+ protocol->store(sys_column_types[i].searchable, system_charset_info);
-+ protocol->store(sys_column_types[i].case_sensitivity, system_charset_info);
-+ protocol->store(sys_column_types[i].default_value, system_charset_info);
-+ protocol->store(sys_column_types[i].comment, system_charset_info);
-+ if (protocol->write())
-+ DBUG_RETURN(TRUE);
-+ }
-+ send_eof(thd);
-+ DBUG_RETURN(FALSE);
-+}
-+
-+
-+/*
-+ find_files() - find files in a given directory.
-+
-+ SYNOPSIS
-+ find_files()
-+ thd thread handler
-+ files put found files in this list
-+ db database name to set in TABLE_LIST structure
-+ path path to database
-+ wild filter for found files
-+ dir read databases in path if TRUE, read .frm files in
-+ database otherwise
-+
-+ RETURN
-+ FIND_FILES_OK success
-+ FIND_FILES_OOM out of memory error
-+ FIND_FILES_DIR no such directory, or directory can't be read
-+*/
-+
-+enum find_files_result {
-+ FIND_FILES_OK,
-+ FIND_FILES_OOM,
-+ FIND_FILES_DIR
-+};
-+
-+static
-+find_files_result
-+find_files(THD *thd, List<char> *files, const char *db,
-+ const char *path, const char *wild, bool dir)
-+{
-+ uint i;
-+ char *ext;
-+ MY_DIR *dirp;
-+ FILEINFO *file;
-+#ifndef NO_EMBEDDED_ACCESS_CHECKS
-+ uint col_access=thd->col_access;
-+#endif
-+ TABLE_LIST table_list;
-+ DBUG_ENTER("find_files");
-+
-+ if (wild && !wild[0])
-+ wild=0;
-+
-+ bzero((char*) &table_list,sizeof(table_list));
-+
-+ if (!(dirp = my_dir(path,MYF(dir ? MY_WANT_STAT : 0))))
-+ {
-+ if (my_errno == ENOENT)
-+ my_error(ER_BAD_DB_ERROR, MYF(ME_BELL+ME_WAITTANG), db);
-+ else
-+ my_error(ER_CANT_READ_DIR, MYF(ME_BELL+ME_WAITTANG), path, my_errno);
-+ DBUG_RETURN(FIND_FILES_DIR);
-+ }
-+
-+ for (i=0 ; i < (uint) dirp->number_off_files ; i++)
-+ {
-+ file=dirp->dir_entry+i;
-+ if (dir)
-+ { /* Return databases */
-+#ifdef USE_SYMDIR
-+ char *ext;
-+ char buff[FN_REFLEN];
-+ if (my_use_symdir && !strcmp(ext=fn_ext(file->name), ".sym"))
-+ {
-+ /* Only show the sym file if it points to a directory */
-+ char *end;
-+ *ext=0; /* Remove extension */
-+ unpack_dirname(buff, file->name);
-+ end= strend(buff);
-+ if (end != buff && end[-1] == FN_LIBCHAR)
-+ end[-1]= 0; // Remove end FN_LIBCHAR
-+ if (!my_stat(buff, file->mystat, MYF(0)))
-+ continue;
-+ }
-+#endif
-+ if (file->name[0] == '.' || !MY_S_ISDIR(file->mystat->st_mode) ||
-+ (wild && wild_compare(file->name,wild,0)))
-+ continue;
-+ }
-+ else
-+ {
-+ // Return only .frm files which aren't temp files.
-+ if (my_strcasecmp(system_charset_info, ext=fn_ext(file->name),reg_ext) ||
-+ is_prefix(file->name,tmp_file_prefix))
-+ continue;
-+ *ext=0;
-+ if (wild)
-+ {
-+ if (lower_case_table_names)
-+ {
-+ if (wild_case_compare(files_charset_info, file->name, wild))
-+ continue;
-+ }
-+ else if (wild_compare(file->name,wild,0))
-+ continue;
-+ }
-+ }
-+#ifndef NO_EMBEDDED_ACCESS_CHECKS
-+ /* Don't show tables where we don't have any privileges */
-+ if (db && !(col_access & TABLE_ACLS))
-+ {
-+ table_list.db= (char*) db;
-+ table_list.db_length= strlen(db);
-+ table_list.table_name= file->name;
-+ table_list.table_name_length= strlen(file->name);
-+ table_list.grant.privilege=col_access;
-+ if (check_grant(thd, TABLE_ACLS, &table_list, 1, 1, 1))
-+ continue;
-+ }
-+#endif
-+ if (files->push_back(thd->strdup(file->name)))
-+ {
-+ my_dirend(dirp);
-+ DBUG_RETURN(FIND_FILES_OOM);
-+ }
-+ }
-+ DBUG_PRINT("info",("found: %d files", files->elements));
-+ my_dirend(dirp);
-+
-+ VOID(ha_find_files(thd,db,path,wild,dir,files));
-+
-+ DBUG_RETURN(FIND_FILES_OK);
-+}
-+
-+
-+bool
-+mysqld_show_create(THD *thd, TABLE_LIST *table_list)
-+{
-+ Protocol *protocol= thd->protocol;
-+ char buff[2048];
-+ String buffer(buff, sizeof(buff), system_charset_info);
-+ DBUG_ENTER("mysqld_show_create");
-+ DBUG_PRINT("enter",("db: %s table: %s",table_list->db,
-+ table_list->table_name));
-+
-+ /* We want to preserve the tree for views. */
-+ thd->lex->view_prepare_mode= TRUE;
-+
-+ /* Only one table for now, but VIEW can involve several tables */
-+ if (open_normal_and_derived_tables(thd, table_list, 0))
-+ {
-+ if (!table_list->view || thd->net.last_errno != ER_VIEW_INVALID)
-+ DBUG_RETURN(TRUE);
-+
-+ /*
-+ Clear all messages with 'error' level status and
-+ issue a warning with 'warning' level status in
-+ case of invalid view and last error is ER_VIEW_INVALID
-+ */
-+ mysql_reset_errors(thd, true);
-+ thd->clear_error();
-+
-+ push_warning_printf(thd,MYSQL_ERROR::WARN_LEVEL_WARN,
-+ ER_VIEW_INVALID,
-+ ER(ER_VIEW_INVALID),
-+ table_list->view_db.str,
-+ table_list->view_name.str);
-+ }
-+
-+ /* TODO: add environment variables show when it become possible */
-+ if (thd->lex->only_view && !table_list->view)
-+ {
-+ my_error(ER_WRONG_OBJECT, MYF(0),
-+ table_list->db, table_list->table_name, "VIEW");
-+ DBUG_RETURN(TRUE);
-+ }
-+
-+ buffer.length(0);
-+ if ((table_list->view ?
-+ view_store_create_info(thd, table_list, &buffer) :
-+ store_create_info(thd, table_list, &buffer)))
-+ DBUG_RETURN(TRUE);
-+
-+ List<Item> field_list;
-+ if (table_list->view)
-+ {
-+ field_list.push_back(new Item_empty_string("View",NAME_LEN));
-+ field_list.push_back(new Item_empty_string("Create View",
-+ max(buffer.length(),1024)));
-+ }
-+ else
-+ {
-+ field_list.push_back(new Item_empty_string("Table",NAME_LEN));
-+ // 1024 is for not to confuse old clients
-+ field_list.push_back(new Item_empty_string("Create Table",
-+ max(buffer.length(),1024)));
-+ }
-+
-+ if (protocol->send_fields(&field_list,
-+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
-+ DBUG_RETURN(TRUE);
-+ protocol->prepare_for_resend();
-+ if (table_list->view)
-+ protocol->store(table_list->view_name.str, system_charset_info);
-+ else
-+ {
-+ if (table_list->schema_table)
-+ protocol->store(table_list->schema_table->table_name,
-+ system_charset_info);
-+ else
-+ protocol->store(table_list->table->alias, system_charset_info);
-+ }
-+ protocol->store(buffer.ptr(), buffer.length(), buffer.charset());
-+
-+ if (protocol->write())
-+ DBUG_RETURN(TRUE);
-+ send_eof(thd);
-+ DBUG_RETURN(FALSE);
-+}
-+
-+bool mysqld_show_create_db(THD *thd, char *dbname,
-+ HA_CREATE_INFO *create_info)
-+{
-+ Security_context *sctx= thd->security_ctx;
-+ char buff[2048];
-+ String buffer(buff, sizeof(buff), system_charset_info);
-+#ifndef NO_EMBEDDED_ACCESS_CHECKS
-+ uint db_access;
-+#endif
-+ HA_CREATE_INFO create;
-+ uint create_options = create_info ? create_info->options : 0;
-+ Protocol *protocol=thd->protocol;
-+ DBUG_ENTER("mysql_show_create_db");
-+
-+ if (check_db_name(dbname))
-+ {
-+ my_error(ER_WRONG_DB_NAME, MYF(0), dbname);
-+ DBUG_RETURN(TRUE);
-+ }
-+
-+#ifndef NO_EMBEDDED_ACCESS_CHECKS
-+ if (test_all_bits(sctx->master_access, DB_ACLS))
-+ db_access=DB_ACLS;
-+ else
-+ db_access= (acl_get(sctx->host, sctx->ip, sctx->priv_user, dbname, 0) |
-+ sctx->master_access);
-+ if (!(db_access & DB_ACLS) && (!grant_option || check_grant_db(thd,dbname)))
-+ {
-+ my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
-+ sctx->priv_user, sctx->host_or_ip, dbname);
-+ mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR),
-+ sctx->priv_user, sctx->host_or_ip, dbname);
-+ DBUG_RETURN(TRUE);
-+ }
-+#endif
-+ if (!my_strcasecmp(system_charset_info, dbname,
-+ information_schema_name.str))
-+ {
-+ dbname= information_schema_name.str;
-+ create.default_table_charset= system_charset_info;
-+ }
-+ else
-+ {
-+ if (check_db_dir_existence(dbname))
-+ {
-+ my_error(ER_BAD_DB_ERROR, MYF(0), dbname);
-+ DBUG_RETURN(TRUE);
-+ }
-+
-+ load_db_opt_by_name(thd, dbname, &create);
-+ }
-+ List<Item> field_list;
-+ field_list.push_back(new Item_empty_string("Database",NAME_LEN));
-+ field_list.push_back(new Item_empty_string("Create Database",1024));
-+
-+ if (protocol->send_fields(&field_list,
-+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
-+ DBUG_RETURN(TRUE);
-+
-+ protocol->prepare_for_resend();
-+ protocol->store(dbname, strlen(dbname), system_charset_info);
-+ buffer.length(0);
-+ buffer.append(STRING_WITH_LEN("CREATE DATABASE "));
-+ if (create_options & HA_LEX_CREATE_IF_NOT_EXISTS)
-+ buffer.append(STRING_WITH_LEN("/*!32312 IF NOT EXISTS*/ "));
-+ append_identifier(thd, &buffer, dbname, strlen(dbname));
-+
-+ if (create.default_table_charset)
-+ {
-+ buffer.append(STRING_WITH_LEN(" /*!40100"));
-+ buffer.append(STRING_WITH_LEN(" DEFAULT CHARACTER SET "));
-+ buffer.append(create.default_table_charset->csname);
-+ if (!(create.default_table_charset->state & MY_CS_PRIMARY))
-+ {
-+ buffer.append(STRING_WITH_LEN(" COLLATE "));
-+ buffer.append(create.default_table_charset->name);
-+ }
-+ buffer.append(STRING_WITH_LEN(" */"));
-+ }
-+ protocol->store(buffer.ptr(), buffer.length(), buffer.charset());
-+
-+ if (protocol->write())
-+ DBUG_RETURN(TRUE);
-+ send_eof(thd);
-+ DBUG_RETURN(FALSE);
-+}
-+
-+bool
-+mysqld_show_logs(THD *thd)
-+{
-+ List<Item> field_list;
-+ Protocol *protocol= thd->protocol;
-+ DBUG_ENTER("mysqld_show_logs");
-+
-+ field_list.push_back(new Item_empty_string("File",FN_REFLEN));
-+ field_list.push_back(new Item_empty_string("Type",10));
-+ field_list.push_back(new Item_empty_string("Status",10));
-+
-+ if (protocol->send_fields(&field_list,
-+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
-+ DBUG_RETURN(TRUE);
-+
-+#ifdef HAVE_BERKELEY_DB
-+ if ((have_berkeley_db == SHOW_OPTION_YES) && berkeley_show_logs(protocol))
-+ DBUG_RETURN(TRUE);
-+#endif
-+
-+ send_eof(thd);
-+ DBUG_RETURN(FALSE);
-+}
-+
-+
-+/****************************************************************************
-+ Return only fields for API mysql_list_fields
-+ Use "show table wildcard" in mysql instead of this
-+****************************************************************************/
-+
-+void
-+mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild)
-+{
-+ TABLE *table;
-+ DBUG_ENTER("mysqld_list_fields");
-+ DBUG_PRINT("enter",("table: %s",table_list->table_name));
-+
-+ if (open_normal_and_derived_tables(thd, table_list, 0))
-+ DBUG_VOID_RETURN;
-+ table= table_list->table;
-+
-+ List<Item> field_list;
-+
-+ Field **ptr,*field;
-+ for (ptr=table->field ; (field= *ptr); ptr++)
-+ {
-+ if (!wild || !wild[0] ||
-+ !wild_case_compare(system_charset_info, field->field_name,wild))
-+ {
-+ if (table_list->view)
-+ field_list.push_back(new Item_ident_for_show(field,
-+ table_list->view_db.str,
-+ table_list->view_name.str));
-+ else
-+ field_list.push_back(new Item_field(field));
-+ }
-+ }
-+ restore_record(table, s->default_values); // Get empty record
-+ if (thd->protocol->send_fields(&field_list, Protocol::SEND_DEFAULTS |
-+ Protocol::SEND_EOF))
-+ DBUG_VOID_RETURN;
-+ thd->protocol->flush();
-+ DBUG_VOID_RETURN;
-+}
-+
-+
-+int
-+mysqld_dump_create_info(THD *thd, TABLE_LIST *table_list, int fd)
-+{
-+ Protocol *protocol= thd->protocol;
-+ String *packet= protocol->storage_packet();
-+ DBUG_ENTER("mysqld_dump_create_info");
-+ DBUG_PRINT("enter",("table: %s",table_list->table->s->table_name));
-+
-+ protocol->prepare_for_resend();
-+ if (store_create_info(thd, table_list, packet))
-+ DBUG_RETURN(-1);
-+
-+ if (fd < 0)
-+ {
-+ if (protocol->write())
-+ DBUG_RETURN(-1);
-+ protocol->flush();
-+ }
-+ else
-+ {
-+ if (my_write(fd, (const byte*) packet->ptr(), packet->length(),
-+ MYF(MY_WME)))
-+ DBUG_RETURN(-1);
-+ }
-+ DBUG_RETURN(0);
-+}
-+
-+/*
-+ Go through all character combinations and ensure that sql_lex.cc can
-+ parse it as an identifier.
-+
-+ SYNOPSIS
-+ require_quotes()
-+ name attribute name
-+ name_length length of name
-+
-+ RETURN
-+ # Pointer to conflicting character
-+ 0 No conflicting character
-+*/
-+
-+static const char *require_quotes(const char *name, uint name_length)
-+{
-+ uint length;
-+ const char *end= name + name_length;
-+
-+ for (; name < end ; name++)
-+ {
-+ uchar chr= (uchar) *name;
-+ length= my_mbcharlen(system_charset_info, chr);
-+ if (length == 1 && !system_charset_info->ident_map[chr])
-+ return name;
-+ }
-+ return 0;
-+}
-+
-+
-+/*
-+ Quote the given identifier if needed and append it to the target string.
-+ If the given identifier is empty, it will be quoted.
-+
-+ SYNOPSIS
-+ append_identifier()
-+ thd thread handler
-+ packet target string
-+ name the identifier to be appended
-+ name_length length of the appending identifier
-+*/
-+
-+void
-+append_identifier(THD *thd, String *packet, const char *name, uint length)
-+{
-+ const char *name_end;
-+ char quote_char;
-+ int q= get_quote_char_for_identifier(thd, name, length);
-+
-+ if (q == EOF)
-+ {
-+ packet->append(name, length, system_charset_info);
-+ return;
-+ }
-+
-+ /*
-+ The identifier must be quoted as it includes a quote character or
-+ it's a keyword
-+ */
-+
-+ VOID(packet->reserve(length*2 + 2));
-+ quote_char= (char) q;
-+ packet->append("e_char, 1, system_charset_info);
-+
-+ for (name_end= name+length ; name < name_end ; name+= length)
-+ {
-+ uchar chr= (uchar) *name;
-+ length= my_mbcharlen(system_charset_info, chr);
-+ /*
-+ my_mbcharlen can retur 0 on a wrong multibyte
-+ sequence. It is possible when upgrading from 4.0,
-+ and identifier contains some accented characters.
-+ The manual says it does not work. So we'll just
-+ change length to 1 not to hang in the endless loop.
-+ */
-+ if (!length)
-+ length= 1;
-+ if (length == 1 && chr == (uchar) quote_char)
-+ packet->append("e_char, 1, system_charset_info);
-+ packet->append(name, length, packet->charset());
-+ }
-+ packet->append("e_char, 1, system_charset_info);
-+}
-+
-+
-+/*
-+ Get the quote character for displaying an identifier.
-+
-+ SYNOPSIS
-+ get_quote_char_for_identifier()
-+ thd Thread handler
-+ name name to quote
-+ length length of name
-+
-+ IMPLEMENTATION
-+ Force quoting in the following cases:
-+ - name is empty (for one, it is possible when we use this function for
-+ quoting user and host names for DEFINER clause);
-+ - name is a keyword;
-+ - name includes a special character;
-+ Otherwise identifier is quoted only if the option OPTION_QUOTE_SHOW_CREATE
-+ is set.
-+
-+ RETURN
-+ EOF No quote character is needed
-+ # Quote character
-+*/
-+
-+int get_quote_char_for_identifier(THD *thd, const char *name, uint length)
-+{
-+ if (length &&
-+ !is_keyword(name,length) &&
-+ !require_quotes(name, length) &&
-+ !(thd->options & OPTION_QUOTE_SHOW_CREATE))
-+ return EOF;
-+ if (thd->variables.sql_mode & MODE_ANSI_QUOTES)
-+ return '"';
-+ return '`';
-+}
-+
-+
-+/* Append directory name (if exists) to CREATE INFO */
-+
-+static void append_directory(THD *thd, String *packet, const char *dir_type,
-+ const char *filename)
-+{
-+ if (filename && !(thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE))
-+ {
-+ uint length= dirname_length(filename);
-+ packet->append(' ');
-+ packet->append(dir_type);
-+ packet->append(STRING_WITH_LEN(" DIRECTORY='"));
-+#ifdef __WIN__
-+ /* Convert \ to / to be able to create table on unix */
-+ char *winfilename= (char*) thd->memdup(filename, length);
-+ char *pos, *end;
-+ for (pos= winfilename, end= pos+length ; pos < end ; pos++)
-+ {
-+ if (*pos == '\\')
-+ *pos = '/';
-+ }
-+ filename= winfilename;
-+#endif
-+ packet->append(filename, length);
-+ packet->append('\'');
-+ }
-+}
-+
-+
-+#define LIST_PROCESS_HOST_LEN 64
-+
-+static int
-+store_create_info(THD *thd, TABLE_LIST *table_list, String *packet)
-+{
-+ List<Item> field_list;
-+ char tmp[MAX_FIELD_WIDTH], *for_str, buff[128], *end;
-+ const char *alias;
-+ String type(tmp, sizeof(tmp), system_charset_info);
-+ Field **ptr,*field;
-+ uint primary_key;
-+ KEY *key_info;
-+ TABLE *table= table_list->table;
-+ handler *file= table->file;
-+ TABLE_SHARE *share= table->s;
-+ HA_CREATE_INFO create_info;
-+ my_bool foreign_db_mode= (thd->variables.sql_mode & (MODE_POSTGRESQL |
-+ MODE_ORACLE |
-+ MODE_MSSQL |
-+ MODE_DB2 |
-+ MODE_MAXDB |
-+ MODE_ANSI)) != 0;
-+ my_bool limited_mysql_mode= (thd->variables.sql_mode &
-+ (MODE_NO_FIELD_OPTIONS | MODE_MYSQL323 |
-+ MODE_MYSQL40)) != 0;
-+ DBUG_ENTER("store_create_info");
-+ DBUG_PRINT("enter",("table: %s", table->s->table_name));
-+
-+ restore_record(table, s->default_values); // Get empty record
-+
-+ if (share->tmp_table)
-+ packet->append(STRING_WITH_LEN("CREATE TEMPORARY TABLE "));
-+ else
-+ packet->append(STRING_WITH_LEN("CREATE TABLE "));
-+ if (table_list->schema_table)
-+ alias= table_list->schema_table->table_name;
-+ else
-+ alias= (lower_case_table_names == 2 ? table->alias :
-+ share->table_name);
-+ append_identifier(thd, packet, alias, strlen(alias));
-+ packet->append(STRING_WITH_LEN(" (\n"));
-+
-+ for (ptr=table->field ; (field= *ptr); ptr++)
-+ {
-+ bool has_default;
-+ bool has_now_default;
-+ uint flags = field->flags;
-+
-+ if (ptr != table->field)
-+ packet->append(STRING_WITH_LEN(",\n"));
-+
-+ packet->append(STRING_WITH_LEN(" "));
-+ append_identifier(thd,packet,field->field_name, strlen(field->field_name));
-+ packet->append(' ');
-+ // check for surprises from the previous call to Field::sql_type()
-+ if (type.ptr() != tmp)
-+ type.set(tmp, sizeof(tmp), system_charset_info);
-+ else
-+ type.set_charset(system_charset_info);
-+
-+ field->sql_type(type);
-+ packet->append(type.ptr(), type.length(), system_charset_info);
-+
-+ if (field->has_charset() &&
-+ !(thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)))
-+ {
-+ if (field->charset() != share->table_charset)
-+ {
-+ packet->append(STRING_WITH_LEN(" character set "));
-+ packet->append(field->charset()->csname);
-+ }
-+ /*
-+ For string types dump collation name only if
-+ collation is not primary for the given charset
-+ */
-+ if (!(field->charset()->state & MY_CS_PRIMARY))
-+ {
-+ packet->append(STRING_WITH_LEN(" collate "));
-+ packet->append(field->charset()->name);
-+ }
-+ }
-+
-+ if (flags & NOT_NULL_FLAG)
-+ packet->append(STRING_WITH_LEN(" NOT NULL"));
-+ else if (field->type() == FIELD_TYPE_TIMESTAMP)
-+ {
-+ /*
-+ TIMESTAMP field require explicit NULL flag, because unlike
-+ all other fields they are treated as NOT NULL by default.
-+ */
-+ packet->append(STRING_WITH_LEN(" NULL"));
-+ }
-+
-+ /*
-+ Again we are using CURRENT_TIMESTAMP instead of NOW because it is
-+ more standard
-+ */
-+ has_now_default= table->timestamp_field == field &&
-+ field->unireg_check != Field::TIMESTAMP_UN_FIELD;
-+
-+ has_default= (field->type() != FIELD_TYPE_BLOB &&
-+ !(field->flags & NO_DEFAULT_VALUE_FLAG) &&
-+ field->unireg_check != Field::NEXT_NUMBER &&
-+ !((thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40))
-+ && has_now_default));
-+
-+ if (has_default)
-+ {
-+ packet->append(STRING_WITH_LEN(" default "));
-+ if (has_now_default)
-+ packet->append(STRING_WITH_LEN("CURRENT_TIMESTAMP"));
-+ else if (!field->is_null())
-+ { // Not null by default
-+ type.set(tmp, sizeof(tmp), field->charset());
-+ field->val_str(&type);
-+ if (type.length())
-+ {
-+ String def_val;
-+ uint dummy_errors;
-+ /* convert to system_charset_info == utf8 */
-+ def_val.copy(type.ptr(), type.length(), field->charset(),
-+ system_charset_info, &dummy_errors);
-+ append_unescaped(packet, def_val.ptr(), def_val.length());
-+ }
-+ else
-+ packet->append(STRING_WITH_LEN("''"));
-+ }
-+ else if (field->maybe_null())
-+ packet->append(STRING_WITH_LEN("NULL")); // Null as default
-+ else
-+ packet->append(tmp);
-+ }
-+
-+ if (!limited_mysql_mode && table->timestamp_field == field &&
-+ field->unireg_check != Field::TIMESTAMP_DN_FIELD)
-+ packet->append(STRING_WITH_LEN(" on update CURRENT_TIMESTAMP"));
-+
-+ if (field->unireg_check == Field::NEXT_NUMBER &&
-+ !(thd->variables.sql_mode & MODE_NO_FIELD_OPTIONS))
-+ packet->append(STRING_WITH_LEN(" auto_increment"));
-+
-+ if (field->comment.length)
-+ {
-+ packet->append(STRING_WITH_LEN(" COMMENT "));
-+ append_unescaped(packet, field->comment.str, field->comment.length);
-+ }
-+ }
-+
-+ key_info= table->key_info;
-+ bzero((char*) &create_info, sizeof(create_info));
-+ file->update_create_info(&create_info);
-+ primary_key= share->primary_key;
-+
-+ for (uint i=0 ; i < share->keys ; i++,key_info++)
-+ {
-+ KEY_PART_INFO *key_part= key_info->key_part;
-+ bool found_primary=0;
-+ packet->append(STRING_WITH_LEN(",\n "));
-+
-+ if (i == primary_key && !strcmp(key_info->name, primary_key_name))
-+ {
-+ found_primary=1;
-+ packet->append(STRING_WITH_LEN("PRIMARY "));
-+ }
-+ else if (key_info->flags & HA_NOSAME)
-+ packet->append(STRING_WITH_LEN("UNIQUE "));
-+ else if (key_info->flags & HA_FULLTEXT)
-+ packet->append(STRING_WITH_LEN("FULLTEXT "));
-+ else if (key_info->flags & HA_SPATIAL)
-+ packet->append(STRING_WITH_LEN("SPATIAL "));
-+ packet->append(STRING_WITH_LEN("KEY "));
-+
-+ if (!found_primary)
-+ append_identifier(thd, packet, key_info->name, strlen(key_info->name));
-+
-+ if (!(thd->variables.sql_mode & MODE_NO_KEY_OPTIONS) &&
-+ !limited_mysql_mode && !foreign_db_mode)
-+ {
-+ if (key_info->algorithm == HA_KEY_ALG_BTREE)
-+ packet->append(STRING_WITH_LEN(" USING BTREE"));
-+
-+ if (key_info->algorithm == HA_KEY_ALG_HASH)
-+ packet->append(STRING_WITH_LEN(" USING HASH"));
-+
-+ // +BAR: send USING only in non-default case: non-spatial rtree
-+ if ((key_info->algorithm == HA_KEY_ALG_RTREE) &&
-+ !(key_info->flags & HA_SPATIAL))
-+ packet->append(STRING_WITH_LEN(" USING RTREE"));
-+
-+ // No need to send USING FULLTEXT, it is sent as FULLTEXT KEY
-+ }
-+ packet->append(STRING_WITH_LEN(" ("));
-+
-+ for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
-+ {
-+ if (j)
-+ packet->append(',');
-+
-+ if (key_part->field)
-+ append_identifier(thd,packet,key_part->field->field_name,
-+ strlen(key_part->field->field_name));
-+ if (key_part->field &&
-+ (key_part->length !=
-+ table->field[key_part->fieldnr-1]->key_length() &&
-+ !(key_info->flags & HA_FULLTEXT)))
-+ {
-+ buff[0] = '(';
-+ char* end=int10_to_str((long) key_part->length /
-+ key_part->field->charset()->mbmaxlen,
-+ buff + 1,10);
-+ *end++ = ')';
-+ packet->append(buff,(uint) (end-buff));
-+ }
-+ }
-+ packet->append(')');
-+ }
-+
-+ /*
-+ Get possible foreign key definitions stored in InnoDB and append them
-+ to the CREATE TABLE statement
-+ */
-+
-+ if ((for_str= file->get_foreign_key_create_info()))
-+ {
-+ packet->append(for_str, strlen(for_str));
-+ file->free_foreign_key_create_info(for_str);
-+ }
-+
-+ packet->append(STRING_WITH_LEN("\n)"));
-+ if (!(thd->variables.sql_mode & MODE_NO_TABLE_OPTIONS) && !foreign_db_mode)
-+ {
-+ if (thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40))
-+ packet->append(STRING_WITH_LEN(" TYPE="));
-+ else
-+ packet->append(STRING_WITH_LEN(" ENGINE="));
-+ packet->append(file->table_type());
-+
-+ /*
-+ Add AUTO_INCREMENT=... if there is an AUTO_INCREMENT column,
-+ and NEXT_ID > 1 (the default). We must not print the clause
-+ for engines that do not support this as it would break the
-+ import of dumps, but as of this writing, the test for whether
-+ AUTO_INCREMENT columns are allowed and wether AUTO_INCREMENT=...
-+ is supported is identical, !(file->table_flags() & HA_NO_AUTO_INCREMENT))
-+ Because of that, we do not explicitly test for the feature,
-+ but may extrapolate its existence from that of an AUTO_INCREMENT column.
-+ */
-+
-+ if(create_info.auto_increment_value > 1)
-+ {
-+ packet->append(" AUTO_INCREMENT=", 16);
-+ end= longlong10_to_str(create_info.auto_increment_value, buff,10);
-+ packet->append(buff, (uint) (end - buff));
-+ }
-+
-+
-+ if (share->table_charset &&
-+ !(thd->variables.sql_mode & MODE_MYSQL323) &&
-+ !(thd->variables.sql_mode & MODE_MYSQL40))
-+ {
-+ packet->append(STRING_WITH_LEN(" DEFAULT CHARSET="));
-+ packet->append(share->table_charset->csname);
-+ if (!(share->table_charset->state & MY_CS_PRIMARY))
-+ {
-+ packet->append(STRING_WITH_LEN(" COLLATE="));
-+ packet->append(table->s->table_charset->name);
-+ }
-+ }
-+
-+ if (share->min_rows)
-+ {
-+ packet->append(STRING_WITH_LEN(" MIN_ROWS="));
-+ end= longlong10_to_str(share->min_rows, buff, 10);
-+ packet->append(buff, (uint) (end- buff));
-+ }
-+
-+ if (share->max_rows && !table_list->schema_table)
-+ {
-+ packet->append(STRING_WITH_LEN(" MAX_ROWS="));
-+ end= longlong10_to_str(share->max_rows, buff, 10);
-+ packet->append(buff, (uint) (end - buff));
-+ }
-+
-+ if (share->avg_row_length)
-+ {
-+ packet->append(STRING_WITH_LEN(" AVG_ROW_LENGTH="));
-+ end= longlong10_to_str(share->avg_row_length, buff,10);
-+ packet->append(buff, (uint) (end - buff));
-+ }
-+
-+ if (share->db_create_options & HA_OPTION_PACK_KEYS)
-+ packet->append(STRING_WITH_LEN(" PACK_KEYS=1"));
-+ if (share->db_create_options & HA_OPTION_NO_PACK_KEYS)
-+ packet->append(STRING_WITH_LEN(" PACK_KEYS=0"));
-+ if (share->db_create_options & HA_OPTION_CHECKSUM)
-+ packet->append(STRING_WITH_LEN(" CHECKSUM=1"));
-+ if (share->db_create_options & HA_OPTION_DELAY_KEY_WRITE)
-+ packet->append(STRING_WITH_LEN(" DELAY_KEY_WRITE=1"));
-+ if (share->row_type != ROW_TYPE_DEFAULT)
-+ {
-+ packet->append(STRING_WITH_LEN(" ROW_FORMAT="));
-+ packet->append(ha_row_type[(uint) share->row_type]);
-+ }
-+ table->file->append_create_info(packet);
-+ if (share->comment.length)
-+ {
-+ packet->append(STRING_WITH_LEN(" COMMENT="));
-+ append_unescaped(packet, share->comment.str, share->comment.length);
-+ }
-+ if (share->connect_string.length)
-+ {
-+ packet->append(STRING_WITH_LEN(" CONNECTION="));
-+ append_unescaped(packet, share->connect_string.str, share->connect_string.length);
-+ }
-+ if (file->raid_type)
-+ {
-+ uint length;
-+ length= my_snprintf(buff,sizeof(buff),
-+ " RAID_TYPE=%s RAID_CHUNKS=%d RAID_CHUNKSIZE=%ld",
-+ my_raid_type(file->raid_type), file->raid_chunks,
-+ file->raid_chunksize/RAID_BLOCK_SIZE);
-+ packet->append(buff, length);
-+ }
-+ append_directory(thd, packet, "DATA", create_info.data_file_name);
-+ append_directory(thd, packet, "INDEX", create_info.index_file_name);
-+ }
-+ DBUG_RETURN(0);
-+}
-+
-+void
-+view_store_options(THD *thd, TABLE_LIST *table, String *buff)
-+{
-+ append_algorithm(table, buff);
-+ append_definer(thd, buff, &table->definer.user, &table->definer.host);
-+ if (table->view_suid)
-+ buff->append(STRING_WITH_LEN("SQL SECURITY DEFINER "));
-+ else
-+ buff->append(STRING_WITH_LEN("SQL SECURITY INVOKER "));
-+}
-+
-+
-+/*
-+ Append DEFINER clause to the given buffer.
-+
-+ SYNOPSIS
-+ append_definer()
-+ thd [in] thread handle
-+ buffer [inout] buffer to hold DEFINER clause
-+ definer_user [in] user name part of definer
-+ definer_host [in] host name part of definer
-+*/
-+
-+static void append_algorithm(TABLE_LIST *table, String *buff)
-+{
-+ buff->append(STRING_WITH_LEN("ALGORITHM="));
-+ switch ((int8)table->algorithm) {
-+ case VIEW_ALGORITHM_UNDEFINED:
-+ buff->append(STRING_WITH_LEN("UNDEFINED "));
-+ break;
-+ case VIEW_ALGORITHM_TMPTABLE:
-+ buff->append(STRING_WITH_LEN("TEMPTABLE "));
-+ break;
-+ case VIEW_ALGORITHM_MERGE:
-+ buff->append(STRING_WITH_LEN("MERGE "));
-+ break;
-+ default:
-+ DBUG_ASSERT(0); // never should happen
-+ }
-+}
-+
-+
-+/*
-+ Append DEFINER clause to the given buffer.
-+
-+ SYNOPSIS
-+ append_definer()
-+ thd [in] thread handle
-+ buffer [inout] buffer to hold DEFINER clause
-+ definer_user [in] user name part of definer
-+ definer_host [in] host name part of definer
-+*/
-+
-+void append_definer(THD *thd, String *buffer, const LEX_STRING *definer_user,
-+ const LEX_STRING *definer_host)
-+{
-+ buffer->append(STRING_WITH_LEN("DEFINER="));
-+ append_identifier(thd, buffer, definer_user->str, definer_user->length);
-+ buffer->append('@');
-+ append_identifier(thd, buffer, definer_host->str, definer_host->length);
-+ buffer->append(' ');
-+}
-+
-+
-+static int
-+view_store_create_info(THD *thd, TABLE_LIST *table, String *buff)
-+{
-+ my_bool foreign_db_mode= (thd->variables.sql_mode & (MODE_POSTGRESQL |
-+ MODE_ORACLE |
-+ MODE_MSSQL |
-+ MODE_DB2 |
-+ MODE_MAXDB |
-+ MODE_ANSI)) != 0;
-+ /*
-+ Compact output format for view can be used
-+ - if user has db of this view as current db
-+ - if this view only references table inside it's own db
-+ */
-+ if (!thd->db || strcmp(thd->db, table->view_db.str))
-+ table->compact_view_format= FALSE;
-+ else
-+ {
-+ TABLE_LIST *tbl;
-+ table->compact_view_format= TRUE;
-+ for (tbl= thd->lex->query_tables;
-+ tbl;
-+ tbl= tbl->next_global)
-+ {
-+ if (strcmp(table->view_db.str, tbl->view ? tbl->view_db.str :tbl->db)!= 0)
-+ {
-+ table->compact_view_format= FALSE;
-+ break;
-+ }
-+ }
-+ }
-+
-+ buff->append(STRING_WITH_LEN("CREATE "));
-+ if (!foreign_db_mode)
-+ {
-+ view_store_options(thd, table, buff);
-+ }
-+ buff->append(STRING_WITH_LEN("VIEW "));
-+ if (!table->compact_view_format)
-+ {
-+ append_identifier(thd, buff, table->view_db.str, table->view_db.length);
-+ buff->append('.');
-+ }
-+ append_identifier(thd, buff, table->view_name.str, table->view_name.length);
-+ buff->append(STRING_WITH_LEN(" AS "));
-+
-+ /*
-+ We can't just use table->query, because our SQL_MODE may trigger
-+ a different syntax, like when ANSI_QUOTES is defined.
-+ */
-+ table->view->unit.print(buff);
-+
-+ if (table->with_check != VIEW_CHECK_NONE)
-+ {
-+ if (table->with_check == VIEW_CHECK_LOCAL)
-+ buff->append(STRING_WITH_LEN(" WITH LOCAL CHECK OPTION"));
-+ else
-+ buff->append(STRING_WITH_LEN(" WITH CASCADED CHECK OPTION"));
-+ }
-+ return 0;
-+}
-+
-+
-+/****************************************************************************
-+ Return info about all processes
-+ returns for each thread: thread id, user, host, db, command, info
-+****************************************************************************/
-+
-+class thread_info :public ilink {
-+public:
-+ static void *operator new(size_t size)
-+ {
-+ return (void*) sql_alloc((uint) size);
-+ }
-+ static void operator delete(void *ptr __attribute__((unused)),
-+ size_t size __attribute__((unused)))
-+ { TRASH(ptr, size); }
-+
-+ ulong thread_id;
-+ time_t start_time;
-+ uint command;
-+ const char *user,*host,*db,*proc_info,*state_info;
-+ char *query;
-+};
-+
-+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
-+template class I_List<thread_info>;
-+#endif
-+
-+void mysqld_list_processes(THD *thd,const char *user, bool verbose)
-+{
-+ Item *field;
-+ List<Item> field_list;
-+ I_List<thread_info> thread_infos;
-+ ulong max_query_length= (verbose ? thd->variables.max_allowed_packet :
-+ PROCESS_LIST_WIDTH);
-+ Protocol *protocol= thd->protocol;
-+ DBUG_ENTER("mysqld_list_processes");
-+
-+ field_list.push_back(new Item_int("Id",0,11));
-+ field_list.push_back(new Item_empty_string("User",16));
-+ field_list.push_back(new Item_empty_string("Host",LIST_PROCESS_HOST_LEN));
-+ field_list.push_back(field=new Item_empty_string("db",NAME_LEN));
-+ field->maybe_null=1;
-+ field_list.push_back(new Item_empty_string("Command",16));
-+ field_list.push_back(new Item_return_int("Time",7, FIELD_TYPE_LONG));
-+ field_list.push_back(field=new Item_empty_string("State",30));
-+ field->maybe_null=1;
-+ field_list.push_back(field=new Item_empty_string("Info",max_query_length));
-+ field->maybe_null=1;
-+ if (protocol->send_fields(&field_list,
-+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
-+ DBUG_VOID_RETURN;
-+
-+ VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
-+ if (!thd->killed)
-+ {
-+ I_List_iterator<THD> it(threads);
-+ THD *tmp;
-+ while ((tmp=it++))
-+ {
-+ Security_context *tmp_sctx= tmp->security_ctx;
-+ struct st_my_thread_var *mysys_var;
-+ if ((tmp->vio_ok() || tmp->system_thread) &&
-+ (!user || (tmp_sctx->user && !strcmp(tmp_sctx->user, user))))
-+ {
-+ thread_info *thd_info= new thread_info;
-+
-+ thd_info->thread_id=tmp->thread_id;
-+ thd_info->user= thd->strdup(tmp_sctx->user ? tmp_sctx->user :
-+ (tmp->system_thread ?
-+ "system user" : "unauthenticated user"));
-+ if (tmp->peer_port && (tmp_sctx->host || tmp_sctx->ip) &&
-+ thd->security_ctx->host_or_ip[0])
-+ {
-+ if ((thd_info->host= thd->alloc(LIST_PROCESS_HOST_LEN+1)))
-+ my_snprintf((char *) thd_info->host, LIST_PROCESS_HOST_LEN,
-+ "%s:%u", tmp_sctx->host_or_ip, tmp->peer_port);
-+ }
-+ else
-+ thd_info->host= thd->strdup(tmp_sctx->host_or_ip[0] ?
-+ tmp_sctx->host_or_ip :
-+ tmp_sctx->host ? tmp_sctx->host : "");
-+ if ((thd_info->db=tmp->db)) // Safe test
-+ thd_info->db=thd->strdup(thd_info->db);
-+ thd_info->command=(int) tmp->command;
-+ if ((mysys_var= tmp->mysys_var))
-+ pthread_mutex_lock(&mysys_var->mutex);
-+ thd_info->proc_info= (char*) (tmp->killed == THD::KILL_CONNECTION? "Killed" : 0);
-+#ifndef EMBEDDED_LIBRARY
-+ thd_info->state_info= (char*) (tmp->locked ? "Locked" :
-+ tmp->net.reading_or_writing ?
-+ (tmp->net.reading_or_writing == 2 ?
-+ "Writing to net" :
-+ thd_info->command == COM_SLEEP ? "" :
-+ "Reading from net") :
-+ tmp->proc_info ? tmp->proc_info :
-+ tmp->mysys_var &&
-+ tmp->mysys_var->current_cond ?
-+ "Waiting on cond" : NullS);
-+#else
-+ thd_info->state_info= (char*)"Writing to net";
-+#endif
-+ if (mysys_var)
-+ pthread_mutex_unlock(&mysys_var->mutex);
-+
-+#if !defined(DONT_USE_THR_ALARM) && ! defined(SCO)
-+ if (pthread_kill(tmp->real_id,0))
-+ tmp->proc_info="*** DEAD ***"; // This shouldn't happen
-+#endif
-+#ifdef EXTRA_DEBUG
-+ thd_info->start_time= tmp->time_after_lock;
-+#else
-+ thd_info->start_time= tmp->start_time;
-+#endif
-+ thd_info->query=0;
-+ if (tmp->query)
-+ {
-+ /*
-+ query_length is always set to 0 when we set query = NULL; see
-+ the comment in sql_class.h why this prevents crashes in possible
-+ races with query_length
-+ */
-+ uint length= min(max_query_length, tmp->query_length);
-+ thd_info->query=(char*) thd->strmake(tmp->query,length);
-+ }
-+ thread_infos.append(thd_info);
-+ }
-+ }
-+ }
-+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
-+
-+ thread_info *thd_info;
-+ time_t now= time(0);
-+ while ((thd_info=thread_infos.get()))
-+ {
-+ protocol->prepare_for_resend();
-+ protocol->store((ulonglong) thd_info->thread_id);
-+ protocol->store(thd_info->user, system_charset_info);
-+ protocol->store(thd_info->host, system_charset_info);
-+ protocol->store(thd_info->db, system_charset_info);
-+ if (thd_info->proc_info)
-+ protocol->store(thd_info->proc_info, system_charset_info);
-+ else
-+ protocol->store(command_name[thd_info->command], system_charset_info);
-+ if (thd_info->start_time)
-+ protocol->store((uint32) (now - thd_info->start_time));
-+ else
-+ protocol->store_null();
-+ protocol->store(thd_info->state_info, system_charset_info);
-+ protocol->store(thd_info->query, system_charset_info);
-+ if (protocol->write())
-+ break; /* purecov: inspected */
-+ }
-+ send_eof(thd);
-+ DBUG_VOID_RETURN;
-+}
-+
-+/*****************************************************************************
-+ Status functions
-+*****************************************************************************/
-+
-+
-+static bool show_status_array(THD *thd, const char *wild,
-+ show_var_st *variables,
-+ enum enum_var_type value_type,
-+ struct system_status_var *status_var,
-+ const char *prefix, TABLE *table)
-+{
-+ char buff[1024], *prefix_end;
-+ /* the variable name should not be longer then 80 characters */
-+ char name_buffer[80];
-+ int len;
-+ LEX_STRING null_lex_str;
-+ DBUG_ENTER("show_status_array");
-+
-+ null_lex_str.str= 0; // For sys_var->value_ptr()
-+ null_lex_str.length= 0;
-+
-+ prefix_end=strnmov(name_buffer, prefix, sizeof(name_buffer)-1);
-+ len=name_buffer + sizeof(name_buffer) - prefix_end;
-+
-+ for (; variables->name; variables++)
-+ {
-+ strnmov(prefix_end, variables->name, len);
-+ name_buffer[sizeof(name_buffer)-1]=0; /* Safety */
-+ SHOW_TYPE show_type=variables->type;
-+ if (show_type == SHOW_VARS)
-+ {
-+ show_status_array(thd, wild, (show_var_st *) variables->value,
-+ value_type, status_var, variables->name, table);
-+ }
-+ else
-+ {
-+ if (!(wild && wild[0] && wild_case_compare(system_charset_info,
-+ name_buffer, wild)))
-+ {
-+ char *value=variables->value;
-+ const char *pos, *end; // We assign a lot of const's
-+ long nr;
-+ if (show_type == SHOW_SYS)
-+ {
-+ show_type= ((sys_var*) value)->type();
-+ value= (char*) ((sys_var*) value)->value_ptr(thd, value_type,
-+ &null_lex_str);
-+ }
-+
-+ pos= end= buff;
-+ switch (show_type) {
-+ case SHOW_LONG_STATUS:
-+ case SHOW_LONG_CONST_STATUS:
-+ value= ((char *) status_var + (ulong) value);
-+ /* fall through */
-+ case SHOW_LONG:
-+ case SHOW_LONG_CONST:
-+ end= int10_to_str(*(long*) value, buff, 10);
-+ break;
-+ case SHOW_LONGLONG:
-+ end= longlong10_to_str(*(longlong*) value, buff, 10);
-+ break;
-+ case SHOW_HA_ROWS:
-+ end= longlong10_to_str((longlong) *(ha_rows*) value, buff, 10);
-+ break;
-+ case SHOW_BOOL:
-+ end= strmov(buff, *(bool*) value ? "ON" : "OFF");
-+ break;
-+ case SHOW_MY_BOOL:
-+ end= strmov(buff, *(my_bool*) value ? "ON" : "OFF");
-+ break;
-+ case SHOW_INT_CONST:
-+ case SHOW_INT:
-+ end= int10_to_str((long) *(uint32*) value, buff, 10);
-+ break;
-+ case SHOW_HAVE:
-+ {
-+ SHOW_COMP_OPTION tmp= *(SHOW_COMP_OPTION*) value;
-+ pos= show_comp_option_name[(int) tmp];
-+ end= strend(pos);
-+ break;
-+ }
-+ case SHOW_CHAR:
-+ {
-+ if (!(pos= value))
-+ pos= "";
-+ end= strend(pos);
-+ break;
-+ }
-+ case SHOW_STARTTIME:
-+ nr= (long) (thd->query_start() - start_time);
-+ end= int10_to_str(nr, buff, 10);
-+ break;
-+ case SHOW_QUESTION:
-+ end= int10_to_str((long) thd->query_id, buff, 10);
-+ break;
-+#ifdef HAVE_REPLICATION
-+ case SHOW_RPL_STATUS:
-+ end= strmov(buff, rpl_status_type[(int)rpl_status]);
-+ break;
-+ case SHOW_SLAVE_RUNNING:
-+ {
-+ pthread_mutex_lock(&LOCK_active_mi);
-+ end= strmov(buff, (active_mi && active_mi->slave_running &&
-+ active_mi->rli.slave_running) ? "ON" : "OFF");
-+ pthread_mutex_unlock(&LOCK_active_mi);
-+ break;
-+ }
-+ case SHOW_SLAVE_RETRIED_TRANS:
-+ {
-+ /*
-+ TODO: in 5.1 with multimaster, have one such counter per line in
-+ SHOW SLAVE STATUS, and have the sum over all lines here.
-+ */
-+ pthread_mutex_lock(&LOCK_active_mi);
-+ if (active_mi)
-+ {
-+ pthread_mutex_lock(&active_mi->rli.data_lock);
-+ end= int10_to_str(active_mi->rli.retried_trans, buff, 10);
-+ pthread_mutex_unlock(&active_mi->rli.data_lock);
-+ }
-+ pthread_mutex_unlock(&LOCK_active_mi);
-+ break;
-+ }
-+ case SHOW_SLAVE_SKIP_ERRORS:
-+ {
-+ MY_BITMAP *bitmap= (MY_BITMAP *)value;
-+ if (!use_slave_mask || bitmap_is_clear_all(bitmap))
-+ {
-+ end= strmov(buff, "OFF");
-+ }
-+ else if (bitmap_is_set_all(bitmap))
-+ {
-+ end= strmov(buff, "ALL");
-+ }
-+ else
-+ {
-+ /* 10 is enough assuming errors are max 4 digits */
-+ int i;
-+ for (i= 1;
-+ i < MAX_SLAVE_ERROR && (uint) (end-buff) < sizeof(buff)-10;
-+ i++)
-+ {
-+ if (bitmap_is_set(bitmap, i))
-+ {
-+ end= int10_to_str(i, (char*) end, 10);
-+ *(char*) end++= ',';
-+ }
-+ }
-+ if (end != buff)
-+ end--; // Remove last ','
-+ if (i < MAX_SLAVE_ERROR)
-+ end= strmov((char*) end, "..."); // Couldn't show all errors
-+ }
-+ break;
-+ }
-+#endif /* HAVE_REPLICATION */
-+ case SHOW_OPENTABLES:
-+ end= int10_to_str((long) cached_tables(), buff, 10);
-+ break;
-+ case SHOW_CHAR_PTR:
-+ {
-+ if (!(pos= *(char**) value))
-+ pos= "";
-+ end= strend(pos);
-+ break;
-+ }
-+ case SHOW_DOUBLE_STATUS:
-+ {
-+ value= ((char *) status_var + (ulong) value);
-+ end= buff + sprintf(buff, "%f", *(double*) value);
-+ break;
-+ }
-+#ifdef HAVE_OPENSSL
-+ /* First group - functions relying on CTX */
-+ case SHOW_SSL_CTX_SESS_ACCEPT:
-+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
-+ SSL_CTX_sess_accept(ssl_acceptor_fd->
-+ ssl_context)),
-+ buff, 10);
-+ break;
-+ case SHOW_SSL_CTX_SESS_ACCEPT_GOOD:
-+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
-+ SSL_CTX_sess_accept_good(ssl_acceptor_fd->
-+ ssl_context)),
-+ buff, 10);
-+ break;
-+ case SHOW_SSL_CTX_SESS_CONNECT_GOOD:
-+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
-+ SSL_CTX_sess_connect_good(ssl_acceptor_fd->
-+ ssl_context)),
-+ buff, 10);
-+ break;
-+ case SHOW_SSL_CTX_SESS_ACCEPT_RENEGOTIATE:
-+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
-+ SSL_CTX_sess_accept_renegotiate(ssl_acceptor_fd->ssl_context)),
-+ buff, 10);
-+ break;
-+ case SHOW_SSL_CTX_SESS_CONNECT_RENEGOTIATE:
-+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
-+ SSL_CTX_sess_connect_renegotiate(ssl_acceptor_fd-> ssl_context)),
-+ buff, 10);
-+ break;
-+ case SHOW_SSL_CTX_SESS_CB_HITS:
-+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
-+ SSL_CTX_sess_cb_hits(ssl_acceptor_fd->
-+ ssl_context)),
-+ buff, 10);
-+ break;
-+ case SHOW_SSL_CTX_SESS_HITS:
-+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
-+ SSL_CTX_sess_hits(ssl_acceptor_fd->
-+ ssl_context)),
-+ buff, 10);
-+ break;
-+ case SHOW_SSL_CTX_SESS_CACHE_FULL:
-+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
-+ SSL_CTX_sess_cache_full(ssl_acceptor_fd->
-+ ssl_context)),
-+ buff, 10);
-+ break;
-+ case SHOW_SSL_CTX_SESS_MISSES:
-+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
-+ SSL_CTX_sess_misses(ssl_acceptor_fd->
-+ ssl_context)),
-+ buff, 10);
-+ break;
-+ case SHOW_SSL_CTX_SESS_TIMEOUTS:
-+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
-+ SSL_CTX_sess_timeouts(ssl_acceptor_fd->ssl_context)),
-+ buff,10);
-+ break;
-+ case SHOW_SSL_CTX_SESS_NUMBER:
-+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
-+ SSL_CTX_sess_number(ssl_acceptor_fd->ssl_context)),
-+ buff,10);
-+ break;
-+ case SHOW_SSL_CTX_SESS_CONNECT:
-+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
-+ SSL_CTX_sess_connect(ssl_acceptor_fd->ssl_context)),
-+ buff,10);
-+ break;
-+ case SHOW_SSL_CTX_SESS_GET_CACHE_SIZE:
-+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
-+ SSL_CTX_sess_get_cache_size(ssl_acceptor_fd->ssl_context)),
-+ buff,10);
-+ break;
-+ case SHOW_SSL_CTX_GET_VERIFY_MODE:
-+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
-+ SSL_CTX_get_verify_mode(ssl_acceptor_fd->ssl_context)),
-+ buff,10);
-+ break;
-+ case SHOW_SSL_CTX_GET_VERIFY_DEPTH:
-+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
-+ SSL_CTX_get_verify_depth(ssl_acceptor_fd->ssl_context)),
-+ buff,10);
-+ break;
-+ case SHOW_SSL_CTX_GET_SESSION_CACHE_MODE:
-+ if (!ssl_acceptor_fd)
-+ {
-+ pos= "NONE";
-+ end= pos+4;
-+ break;
-+ }
-+ switch (SSL_CTX_get_session_cache_mode(ssl_acceptor_fd->ssl_context))
-+ {
-+ case SSL_SESS_CACHE_OFF:
-+ pos= "OFF";
-+ break;
-+ case SSL_SESS_CACHE_CLIENT:
-+ pos= "CLIENT";
-+ break;
-+ case SSL_SESS_CACHE_SERVER:
-+ pos= "SERVER";
-+ break;
-+ case SSL_SESS_CACHE_BOTH:
-+ pos= "BOTH";
-+ break;
-+ case SSL_SESS_CACHE_NO_AUTO_CLEAR:
-+ pos= "NO_AUTO_CLEAR";
-+ break;
-+ case SSL_SESS_CACHE_NO_INTERNAL_LOOKUP:
-+ pos= "NO_INTERNAL_LOOKUP";
-+ break;
-+ default:
-+ pos= "Unknown";
-+ break;
-+ }
-+ end= strend(pos);
-+ break;
-+ /* First group - functions relying on SSL */
-+ case SHOW_SSL_GET_VERSION:
-+ pos= (thd->net.vio->ssl_arg ?
-+ SSL_get_version((SSL*) thd->net.vio->ssl_arg) : "");
-+ end= strend(pos);
-+ break;
-+ case SHOW_SSL_SESSION_REUSED:
-+ end= int10_to_str((long) (thd->net.vio->ssl_arg ?
-+ SSL_session_reused((SSL*) thd->net.vio->
-+ ssl_arg) :
-+ 0),
-+ buff, 10);
-+ break;
-+ case SHOW_SSL_GET_DEFAULT_TIMEOUT:
-+ end= int10_to_str((long) (thd->net.vio->ssl_arg ?
-+ SSL_get_default_timeout((SSL*) thd->net.vio->
-+ ssl_arg) :
-+ 0),
-+ buff, 10);
-+ break;
-+ case SHOW_SSL_GET_VERIFY_MODE:
-+ end= int10_to_str((long) (thd->net.vio->ssl_arg ?
-+ SSL_get_verify_mode((SSL*) thd->net.vio->
-+ ssl_arg):
-+ 0),
-+ buff, 10);
-+ break;
-+ case SHOW_SSL_GET_VERIFY_DEPTH:
-+ end= int10_to_str((long) (thd->net.vio->ssl_arg ?
-+ SSL_get_verify_depth((SSL*) thd->net.vio->
-+ ssl_arg):
-+ 0),
-+ buff, 10);
-+ break;
-+ case SHOW_SSL_GET_CIPHER:
-+ pos= (thd->net.vio->ssl_arg ?
-+ SSL_get_cipher((SSL*) thd->net.vio->ssl_arg) : "" );
-+ end= strend(pos);
-+ break;
-+ case SHOW_SSL_GET_CIPHER_LIST:
-+ if (thd->net.vio->ssl_arg)
-+ {
-+ char *to= buff;
-+ for (int i=0 ; i++ ;)
-+ {
-+ const char *p= SSL_get_cipher_list((SSL*) thd->net.vio->ssl_arg,i);
-+ if (p == NULL)
-+ break;
-+ to= strmov(to, p);
-+ *to++= ':';
-+ }
-+ if (to != buff)
-+ to--; // Remove last ':'
-+ end= to;
-+ }
-+ break;
-+
-+#endif /* HAVE_OPENSSL */
-+ case SHOW_KEY_CACHE_LONG:
-+ case SHOW_KEY_CACHE_CONST_LONG:
-+ value= (value-(char*) &dflt_key_cache_var)+ (char*) dflt_key_cache;
-+ end= int10_to_str(*(long*) value, buff, 10);
-+ break;
-+ case SHOW_KEY_CACHE_LONGLONG:
-+ value= (value-(char*) &dflt_key_cache_var)+ (char*) dflt_key_cache;
-+ end= longlong10_to_str(*(longlong*) value, buff, 10);
-+ break;
-+ case SHOW_NET_COMPRESSION:
-+ end= strmov(buff, thd->net.compress ? "ON" : "OFF");
-+ break;
-+ case SHOW_UNDEF: // Show never happen
-+ case SHOW_SYS:
-+ break; // Return empty string
-+ default:
-+ break;
-+ }
-+ restore_record(table, s->default_values);
-+ table->field[0]->store(name_buffer, strlen(name_buffer),
-+ system_charset_info);
-+ table->field[1]->store(pos, (uint32) (end - pos), system_charset_info);
-+ if (schema_table_store_record(thd, table))
-+ DBUG_RETURN(TRUE);
-+ }
-+ }
-+ }
-+
-+ DBUG_RETURN(FALSE);
-+}
-+
-+
-+/* collect status for all running threads */
-+
-+void calc_sum_of_all_status(STATUS_VAR *to)
-+{
-+ DBUG_ENTER("calc_sum_of_all_status");
-+
-+ /* Ensure that thread id not killed during loop */
-+ VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
-+
-+ I_List_iterator<THD> it(threads);
-+ THD *tmp;
-+
-+ /* Get global values as base */
-+ *to= global_status_var;
-+
-+ /* Add to this status from existing threads */
-+ while ((tmp= it++))
-+ add_to_status(to, &tmp->status_var);
-+
-+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
-+ DBUG_VOID_RETURN;
-+}
-+
-+
-+LEX_STRING *make_lex_string(THD *thd, LEX_STRING *lex_str,
-+ const char* str, uint length,
-+ bool allocate_lex_string)
-+{
-+ MEM_ROOT *mem= thd->mem_root;
-+ if (allocate_lex_string)
-+ if (!(lex_str= (LEX_STRING *)thd->alloc(sizeof(LEX_STRING))))
-+ return 0;
-+ lex_str->str= strmake_root(mem, str, length);
-+ lex_str->length= length;
-+ return lex_str;
-+}
-+
-+
-+/* INFORMATION_SCHEMA name */
-+LEX_STRING information_schema_name= {(char*)"information_schema", 18};
-+
-+/* This is only used internally, but we need it here as a forward reference */
-+extern ST_SCHEMA_TABLE schema_tables[];
-+
-+typedef struct st_index_field_values
-+{
-+ const char *db_value, *table_value;
-+} INDEX_FIELD_VALUES;
-+
-+
-+/*
-+ Store record to I_S table, convert HEAP table
-+ to MyISAM if necessary
-+
-+ SYNOPSIS
-+ schema_table_store_record()
-+ thd thread handler
-+ table Information schema table to be updated
-+
-+ RETURN
-+ 0 success
-+ 1 error
-+*/
-+
-+static bool schema_table_store_record(THD *thd, TABLE *table)
-+{
-+ int error;
-+ if ((error= table->file->write_row(table->record[0])))
-+ {
-+ if (create_myisam_from_heap(thd, table,
-+ table->pos_in_table_list->schema_table_param,
-+ error, 0))
-+ return 1;
-+ }
-+ return 0;
-+}
-+
-+
-+void get_index_field_values(LEX *lex, INDEX_FIELD_VALUES *index_field_values)
-+{
-+ const char *wild= lex->wild ? lex->wild->ptr() : NullS;
-+ switch (lex->orig_sql_command) {
-+ case SQLCOM_SHOW_DATABASES:
-+ index_field_values->db_value= wild;
-+ break;
-+ case SQLCOM_SHOW_TABLES:
-+ case SQLCOM_SHOW_TABLE_STATUS:
-+ case SQLCOM_SHOW_TRIGGERS:
-+ index_field_values->db_value= lex->select_lex.db;
-+ index_field_values->table_value= wild;
-+ break;
-+ default:
-+ index_field_values->db_value= NullS;
-+ index_field_values->table_value= NullS;
-+ break;
-+ }
-+}
-+
-+
-+int make_table_list(THD *thd, SELECT_LEX *sel,
-+ char *db, char *table)
-+{
-+ Table_ident *table_ident;
-+ LEX_STRING ident_db, ident_table;
-+ ident_db.str= db;
-+ ident_db.length= strlen(db);
-+ ident_table.str= table;
-+ ident_table.length= strlen(table);
-+ table_ident= new Table_ident(thd, ident_db, ident_table, 1);
-+ sel->init_query();
-+ if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ,
-+ (List<String> *) 0, (List<String> *) 0))
-+ return 1;
-+ return 0;
-+}
-+
-+
-+bool uses_only_table_name_fields(Item *item, TABLE_LIST *table)
-+{
-+ if (item->type() == Item::FUNC_ITEM)
-+ {
-+ Item_func *item_func= (Item_func*)item;
-+ Item **child;
-+ Item **item_end= (item_func->arguments()) + item_func->argument_count();
-+ for (child= item_func->arguments(); child != item_end; child++)
-+ {
-+ if (!uses_only_table_name_fields(*child, table))
-+ return 0;
-+ }
-+ }
-+ else if (item->type() == Item::FIELD_ITEM)
-+ {
-+ Item_field *item_field= (Item_field*)item;
-+ CHARSET_INFO *cs= system_charset_info;
-+ ST_SCHEMA_TABLE *schema_table= table->schema_table;
-+ ST_FIELD_INFO *field_info= schema_table->fields_info;
-+ const char *field_name1= schema_table->idx_field1 >= 0 ? field_info[schema_table->idx_field1].field_name : "";
-+ const char *field_name2= schema_table->idx_field2 >= 0 ? field_info[schema_table->idx_field2].field_name : "";
-+ if (table->table != item_field->field->table ||
-+ (cs->coll->strnncollsp(cs, (uchar *) field_name1, strlen(field_name1),
-+ (uchar *) item_field->field_name,
-+ strlen(item_field->field_name), 0) &&
-+ cs->coll->strnncollsp(cs, (uchar *) field_name2, strlen(field_name2),
-+ (uchar *) item_field->field_name,
-+ strlen(item_field->field_name), 0)))
-+ return 0;
-+ }
-+ else if (item->type() == Item::REF_ITEM)
-+ return uses_only_table_name_fields(item->real_item(), table);
-+ if (item->type() == Item::SUBSELECT_ITEM &&
-+ !item->const_item())
-+ return 0;
-+
-+ return 1;
-+}
-+
-+
-+static COND * make_cond_for_info_schema(COND *cond, TABLE_LIST *table)
-+{
-+ if (!cond)
-+ return (COND*) 0;
-+ if (cond->type() == Item::COND_ITEM)
-+ {
-+ if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
-+ {
-+ /* Create new top level AND item */
-+ Item_cond_and *new_cond=new Item_cond_and;
-+ if (!new_cond)
-+ return (COND*) 0;
-+ List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
-+ Item *item;
-+ while ((item=li++))
-+ {
-+ Item *fix= make_cond_for_info_schema(item, table);
-+ if (fix)
-+ new_cond->argument_list()->push_back(fix);
-+ }
-+ switch (new_cond->argument_list()->elements) {
-+ case 0:
-+ return (COND*) 0;
-+ case 1:
-+ return new_cond->argument_list()->head();
-+ default:
-+ new_cond->quick_fix_field();
-+ return new_cond;
-+ }
-+ }
-+ else
-+ { // Or list
-+ Item_cond_or *new_cond=new Item_cond_or;
-+ if (!new_cond)
-+ return (COND*) 0;
-+ List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
-+ Item *item;
-+ while ((item=li++))
-+ {
-+ Item *fix=make_cond_for_info_schema(item, table);
-+ if (!fix)
-+ return (COND*) 0;
-+ new_cond->argument_list()->push_back(fix);
-+ }
-+ new_cond->quick_fix_field();
-+ new_cond->top_level_item();
-+ return new_cond;
-+ }
-+ }
-+
-+ if (!uses_only_table_name_fields(cond, table))
-+ return (COND*) 0;
-+ return cond;
-+}
-+
-+
-+enum enum_schema_tables get_schema_table_idx(ST_SCHEMA_TABLE *schema_table)
-+{
-+ return (enum enum_schema_tables) (schema_table - &schema_tables[0]);
-+}
-+
-+
-+/*
-+ Create db names list. Information schema name always is first in list
-+
-+ SYNOPSIS
-+ make_db_list()
-+ thd thread handler
-+ files list of db names
-+ wild wild string
-+ idx_field_vals idx_field_vals->db_name contains db name or
-+ wild string
-+ with_i_schema returns 1 if we added 'IS' name to list
-+ otherwise returns 0
-+ is_wild_value if value is 1 then idx_field_vals->db_name is
-+ wild string otherwise it's db name;
-+
-+ RETURN
-+ zero success
-+ non-zero error
-+*/
-+
-+int make_db_list(THD *thd, List<char> *files,
-+ INDEX_FIELD_VALUES *idx_field_vals,
-+ bool *with_i_schema, bool is_wild_value)
-+{
-+ LEX *lex= thd->lex;
-+ *with_i_schema= 0;
-+ get_index_field_values(lex, idx_field_vals);
-+ if (is_wild_value)
-+ {
-+ /*
-+ This part of code is only for SHOW DATABASES command.
-+ idx_field_vals->db_value can be 0 when we don't use
-+ LIKE clause (see also get_index_field_values() function)
-+ */
-+ if (!idx_field_vals->db_value ||
-+ !wild_case_compare(system_charset_info,
-+ information_schema_name.str,
-+ idx_field_vals->db_value))
-+ {
-+ *with_i_schema= 1;
-+ if (files->push_back(thd->strdup(information_schema_name.str)))
-+ return 1;
-+ }
-+ return (find_files(thd, files, NullS, mysql_data_home,
-+ idx_field_vals->db_value, 1) != FIND_FILES_OK);
-+ }
-+
-+ /*
-+ This part of code is for SHOW TABLES, SHOW TABLE STATUS commands.
-+ idx_field_vals->db_value can't be 0 (see get_index_field_values()
-+ function). lex->orig_sql_command can be not equal to SQLCOM_END
-+ only in case of executing of SHOW commands.
-+ */
-+ if (lex->orig_sql_command != SQLCOM_END)
-+ {
-+ if (!my_strcasecmp(system_charset_info, information_schema_name.str,
-+ idx_field_vals->db_value))
-+ {
-+ *with_i_schema= 1;
-+ return files->push_back(thd->strdup(information_schema_name.str));
-+ }
-+ return files->push_back(thd->strdup(idx_field_vals->db_value));
-+ }
-+
-+ /*
-+ Create list of existing databases. It is used in case
-+ of select from information schema table
-+ */
-+ if (files->push_back(thd->strdup(information_schema_name.str)))
-+ return 1;
-+ *with_i_schema= 1;
-+ return (find_files(thd, files, NullS,
-+ mysql_data_home, NullS, 1) != FIND_FILES_OK);
-+}
-+
-+
-+int schema_tables_add(THD *thd, List<char> *files, const char *wild)
-+{
-+ ST_SCHEMA_TABLE *tmp_schema_table= schema_tables;
-+ for (; tmp_schema_table->table_name; tmp_schema_table++)
-+ {
-+ if (tmp_schema_table->hidden)
-+ continue;
-+ if (wild)
-+ {
-+ if (lower_case_table_names)
-+ {
-+ if (wild_case_compare(files_charset_info,
-+ tmp_schema_table->table_name,
-+ wild))
-+ continue;
-+ }
-+ else if (wild_compare(tmp_schema_table->table_name, wild, 0))
-+ continue;
-+ }
-+ if (files->push_back(thd->strdup(tmp_schema_table->table_name)))
-+ return 1;
-+ }
-+ return 0;
-+}
-+
-+
-+int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
-+{
-+ LEX *lex= thd->lex;
-+ TABLE *table= tables->table;
-+ SELECT_LEX *select_lex= &lex->select_lex;
-+ SELECT_LEX *old_all_select_lex= lex->all_selects_list;
-+ enum_sql_command save_sql_command= lex->sql_command;
-+ SELECT_LEX *lsel= tables->schema_select_lex;
-+ ST_SCHEMA_TABLE *schema_table= tables->schema_table;
-+ SELECT_LEX sel;
-+ INDEX_FIELD_VALUES idx_field_vals;
-+ char path[FN_REFLEN], *end, *base_name, *orig_base_name, *file_name;
-+ uint len;
-+ bool with_i_schema;
-+ enum enum_schema_tables schema_table_idx;
-+ List<char> bases;
-+ List_iterator_fast<char> it(bases);
-+ COND *partial_cond;
-+ Security_context *sctx= thd->security_ctx;
-+ uint derived_tables= lex->derived_tables;
-+ int error= 1;
-+ db_type not_used;
-+ Open_tables_state open_tables_state_backup;
-+ bool save_view_prepare_mode= lex->view_prepare_mode;
-+ Query_tables_list query_tables_list_backup;
-+ lex->view_prepare_mode= TRUE;
-+ DBUG_ENTER("get_all_tables");
-+
-+ LINT_INIT(end);
-+ LINT_INIT(len);
-+
-+ lex->reset_n_backup_query_tables_list(&query_tables_list_backup);
-+
-+ /*
-+ We should not introduce deadlocks even if we already have some
-+ tables open and locked, since we won't lock tables which we will
-+ open and will ignore possible name-locks for these tables.
-+ */
-+ thd->reset_n_backup_open_tables_state(&open_tables_state_backup);
-+
-+ if (lsel)
-+ {
-+ TABLE_LIST *show_table_list= (TABLE_LIST*) lsel->table_list.first;
-+ bool res;
-+
-+ lex->all_selects_list= lsel;
-+ /*
-+ Restore thd->temporary_tables to be able to process
-+ temporary tables(only for 'show index' & 'show columns').
-+ This should be changed when processing of temporary tables for
-+ I_S tables will be done.
-+ */
-+ thd->temporary_tables= open_tables_state_backup.temporary_tables;
-+ /*
-+ Let us set fake sql_command so views won't try to merge
-+ themselves into main statement. If we don't do this,
-+ SELECT * from information_schema.xxxx will cause problems.
-+ SQLCOM_SHOW_FIELDS is used because it satisfies 'only_view_structure()'
-+ */
-+ lex->sql_command= SQLCOM_SHOW_FIELDS;
-+ res= open_normal_and_derived_tables(thd, show_table_list,
-+ MYSQL_LOCK_IGNORE_FLUSH);
-+ lex->sql_command= save_sql_command;
-+ /*
-+ get_all_tables() returns 1 on failure and 0 on success thus
-+ return only these and not the result code of ::process_table()
-+
-+ We should use show_table_list->alias instead of
-+ show_table_list->table_name because table_name
-+ could be changed during opening of I_S tables. It's safe
-+ to use alias because alias contains original table name
-+ in this case(this part of code is used only for
-+ 'show columns' & 'show statistics' commands).
-+ */
-+ error= test(schema_table->process_table(thd, show_table_list,
-+ table, res,
-+ (show_table_list->view ?
-+ show_table_list->view_db.str :
-+ show_table_list->db),
-+ show_table_list->alias));
-+ thd->temporary_tables= 0;
-+ close_tables_for_reopen(thd, &show_table_list);
-+ goto err;
-+ }
-+
-+ schema_table_idx= get_schema_table_idx(schema_table);
-+
-+ if (make_db_list(thd, &bases, &idx_field_vals,
-+ &with_i_schema, 0))
-+ goto err;
-+
-+ partial_cond= make_cond_for_info_schema(cond, tables);
-+ it.rewind(); /* To get access to new elements in basis list */
-+ while ((orig_base_name= base_name= it++) ||
-+ /*
-+ generate error for non existing database.
-+ (to save old behaviour for SHOW TABLES FROM db)
-+ */
-+ ((lex->orig_sql_command == SQLCOM_SHOW_TABLES ||
-+ lex->orig_sql_command == SQLCOM_SHOW_TABLE_STATUS) &&
-+ (base_name= select_lex->db) && !bases.elements))
-+ {
-+#ifndef NO_EMBEDDED_ACCESS_CHECKS
-+ if (!check_access(thd,SELECT_ACL, base_name,
-+ &thd->col_access, 0, 1, with_i_schema) ||
-+ sctx->master_access & (DB_ACLS | SHOW_DB_ACL) ||
-+ acl_get(sctx->host, sctx->ip, sctx->priv_user, base_name,0) ||
-+ (grant_option && !check_grant_db(thd, base_name)))
-+#endif
-+ {
-+ List<char> files;
-+ if (with_i_schema) // information schema table names
-+ {
-+ if (schema_tables_add(thd, &files, idx_field_vals.table_value))
-+ goto err;
-+ }
-+ else
-+ {
-+ strxmov(path, mysql_data_home, "/", base_name, NullS);
-+ end= path + (len= unpack_dirname(path,path));
-+ len= FN_LEN - len;
-+ find_files_result res= find_files(thd, &files, base_name,
-+ path, idx_field_vals.table_value, 0);
-+ if (res != FIND_FILES_OK)
-+ {
-+ /*
-+ Downgrade errors about problems with database directory to
-+ warnings if this is not a 'SHOW' command. Another thread
-+ may have dropped database, and we may still have a name
-+ for that directory.
-+ */
-+ if (res == FIND_FILES_DIR && lex->orig_sql_command == SQLCOM_END)
-+ {
-+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
-+ thd->net.last_errno, thd->net.last_error);
-+ thd->clear_error();
-+ continue;
-+ }
-+ else
-+ {
-+ goto err;
-+ }
-+ }
-+ if (lower_case_table_names)
-+ orig_base_name= thd->strdup(base_name);
-+ }
-+
-+ List_iterator_fast<char> it_files(files);
-+ while ((file_name= it_files++))
-+ {
-+ restore_record(table, s->default_values);
-+ table->field[schema_table->idx_field1]->
-+ store(base_name, strlen(base_name), system_charset_info);
-+ table->field[schema_table->idx_field2]->
-+ store(file_name, strlen(file_name),system_charset_info);
-+ if (!partial_cond || partial_cond->val_int())
-+ {
-+ if (schema_table_idx == SCH_TABLE_NAMES)
-+ {
-+ if (lex->verbose || lex->orig_sql_command == SQLCOM_END)
-+ {
-+ if (with_i_schema)
-+ {
-+ table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"),
-+ system_charset_info);
-+ }
-+ else
-+ {
-+ my_snprintf(end, len, "/%s%s", file_name, reg_ext);
-+ switch (mysql_frm_type(thd, path, ¬_used)) {
-+ case FRMTYPE_ERROR:
-+ table->field[3]->store(STRING_WITH_LEN("ERROR"),
-+ system_charset_info);
-+ break;
-+ case FRMTYPE_TABLE:
-+ table->field[3]->store(STRING_WITH_LEN("BASE TABLE"),
-+ system_charset_info);
-+ break;
-+ case FRMTYPE_VIEW:
-+ table->field[3]->store(STRING_WITH_LEN("VIEW"),
-+ system_charset_info);
-+ break;
-+ default:
-+ DBUG_ASSERT(0);
-+ }
-+ }
-+ }
-+ if (schema_table_store_record(thd, table))
-+ goto err;
-+ }
-+ else
-+ {
-+ int res;
-+ /*
-+ Set the parent lex of 'sel' because it is needed by sel.init_query()
-+ which is called inside make_table_list.
-+ */
-+ sel.parent_lex= lex;
-+ if (make_table_list(thd, &sel, base_name, file_name))
-+ goto err;
-+ TABLE_LIST *show_table_list= (TABLE_LIST*) sel.table_list.first;
-+ lex->all_selects_list= &sel;
-+ lex->derived_tables= 0;
-+ lex->sql_command= SQLCOM_SHOW_FIELDS;
-+ res= open_normal_and_derived_tables(thd, show_table_list,
-+ MYSQL_LOCK_IGNORE_FLUSH);
-+ lex->sql_command= save_sql_command;
-+ /*
-+ We should use show_table_list->alias instead of
-+ show_table_list->table_name because table_name
-+ could be changed during opening of I_S tables. It's safe
-+ to use alias because alias contains original table name
-+ in this case.
-+ */
-+ res= schema_table->process_table(thd, show_table_list, table,
-+ res, orig_base_name,
-+ show_table_list->alias);
-+ close_tables_for_reopen(thd, &show_table_list);
-+ DBUG_ASSERT(!lex->query_tables_own_last);
-+ if (res)
-+ goto err;
-+ }
-+ }
-+ }
-+ /*
-+ If we have information schema its always the first table and only
-+ the first table. Reset for other tables.
-+ */
-+ with_i_schema= 0;
-+ }
-+ }
-+
-+ error= 0;
-+err:
-+ thd->restore_backup_open_tables_state(&open_tables_state_backup);
-+ lex->restore_backup_query_tables_list(&query_tables_list_backup);
-+ lex->derived_tables= derived_tables;
-+ lex->all_selects_list= old_all_select_lex;
-+ lex->view_prepare_mode= save_view_prepare_mode;
-+ lex->sql_command= save_sql_command;
-+ DBUG_RETURN(error);
-+}
-+
-+
-+bool store_schema_shemata(THD* thd, TABLE *table, const char *db_name,
-+ CHARSET_INFO *cs)
-+{
-+ restore_record(table, s->default_values);
-+ table->field[1]->store(db_name, strlen(db_name), system_charset_info);
-+ table->field[2]->store(cs->csname, strlen(cs->csname), system_charset_info);
-+ table->field[3]->store(cs->name, strlen(cs->name), system_charset_info);
-+ return schema_table_store_record(thd, table);
-+}
-+
-+
-+int fill_schema_shemata(THD *thd, TABLE_LIST *tables, COND *cond)
-+{
-+ /*
-+ TODO: fill_schema_shemata() is called when new client is connected.
-+ Returning error status in this case leads to client hangup.
-+ */
-+
-+ INDEX_FIELD_VALUES idx_field_vals;
-+ List<char> files;
-+ char *file_name;
-+ bool with_i_schema;
-+ HA_CREATE_INFO create;
-+ TABLE *table= tables->table;
-+ Security_context *sctx= thd->security_ctx;
-+ DBUG_ENTER("fill_schema_shemata");
-+
-+ if (make_db_list(thd, &files, &idx_field_vals,
-+ &with_i_schema, 1))
-+ DBUG_RETURN(1);
-+
-+ List_iterator_fast<char> it(files);
-+ while ((file_name=it++))
-+ {
-+ if (with_i_schema) // information schema name is always first in list
-+ {
-+ if (store_schema_shemata(thd, table, file_name,
-+ system_charset_info))
-+ DBUG_RETURN(1);
-+ with_i_schema= 0;
-+ continue;
-+ }
-+#ifndef NO_EMBEDDED_ACCESS_CHECKS
-+ if (sctx->master_access & (DB_ACLS | SHOW_DB_ACL) ||
-+ acl_get(sctx->host, sctx->ip, sctx->priv_user, file_name,0) ||
-+ (grant_option && !check_grant_db(thd, file_name)))
-+#endif
-+ {
-+ load_db_opt_by_name(thd, file_name, &create);
-+
-+ if (store_schema_shemata(thd, table, file_name,
-+ create.default_table_charset))
-+ DBUG_RETURN(1);
-+ }
-+ }
-+ DBUG_RETURN(0);
-+}
-+
-+
-+static int get_schema_tables_record(THD *thd, struct st_table_list *tables,
-+ TABLE *table, bool res,
-+ const char *base_name,
-+ const char *file_name)
-+{
-+ const char *tmp_buff;
-+ TIME time;
-+ CHARSET_INFO *cs= system_charset_info;
-+ DBUG_ENTER("get_schema_tables_record");
-+
-+ restore_record(table, s->default_values);
-+ table->field[1]->store(base_name, strlen(base_name), cs);
-+ table->field[2]->store(file_name, strlen(file_name), cs);
-+ if (res)
-+ {
-+ /*
-+ there was errors during opening tables
-+ */
-+ const char *error= thd->net.last_error;
-+ if (tables->view)
-+ table->field[3]->store(STRING_WITH_LEN("VIEW"), cs);
-+ else if (tables->schema_table)
-+ table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"), cs);
-+ else
-+ table->field[3]->store(STRING_WITH_LEN("BASE TABLE"), cs);
-+ table->field[20]->store(error, strlen(error), cs);
-+ thd->clear_error();
-+ }
-+ else if (tables->view)
-+ {
-+ table->field[3]->store(STRING_WITH_LEN("VIEW"), cs);
-+ table->field[20]->store(STRING_WITH_LEN("VIEW"), cs);
-+ }
-+ else
-+ {
-+ TABLE *show_table= tables->table;
-+ TABLE_SHARE *share= show_table->s;
-+ handler *file= show_table->file;
-+
-+ file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_AUTO |
-+ HA_STATUS_NO_LOCK);
-+ if (share->tmp_table == SYSTEM_TMP_TABLE)
-+ table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"), cs);
-+ else if (share->tmp_table)
-+ table->field[3]->store(STRING_WITH_LEN("LOCAL TEMPORARY"), cs);
-+ else
-+ table->field[3]->store(STRING_WITH_LEN("BASE TABLE"), cs);
-+
-+ for (int i= 4; i < 20; i++)
-+ {
-+ if (i == 7 || (i > 12 && i < 17) || i == 18)
-+ continue;
-+ table->field[i]->set_notnull();
-+ }
-+ tmp_buff= file->table_type();
-+ table->field[4]->store(tmp_buff, strlen(tmp_buff), cs);
-+ table->field[5]->store((longlong) share->frm_version, TRUE);
-+ enum row_type row_type = file->get_row_type();
-+ switch (row_type) {
-+ case ROW_TYPE_NOT_USED:
-+ case ROW_TYPE_DEFAULT:
-+ tmp_buff= ((share->db_options_in_use &
-+ HA_OPTION_COMPRESS_RECORD) ? "Compressed" :
-+ (share->db_options_in_use & HA_OPTION_PACK_RECORD) ?
-+ "Dynamic" : "Fixed");
-+ break;
-+ case ROW_TYPE_FIXED:
-+ tmp_buff= "Fixed";
-+ break;
-+ case ROW_TYPE_DYNAMIC:
-+ tmp_buff= "Dynamic";
-+ break;
-+ case ROW_TYPE_COMPRESSED:
-+ tmp_buff= "Compressed";
-+ break;
-+ case ROW_TYPE_REDUNDANT:
-+ tmp_buff= "Redundant";
-+ break;
-+ case ROW_TYPE_COMPACT:
-+ tmp_buff= "Compact";
-+ break;
-+ }
-+ table->field[6]->store(tmp_buff, strlen(tmp_buff), cs);
-+ if (!tables->schema_table)
-+ {
-+ table->field[7]->store((longlong) file->records, TRUE);
-+ table->field[7]->set_notnull();
-+ }
-+ table->field[8]->store((longlong) file->mean_rec_length, TRUE);
-+ table->field[9]->store((longlong) file->data_file_length, TRUE);
-+ if (file->max_data_file_length)
-+ {
-+ table->field[10]->store((longlong) file->max_data_file_length, TRUE);
-+ }
-+ table->field[11]->store((longlong) file->index_file_length, TRUE);
-+ table->field[12]->store((longlong) file->delete_length, TRUE);
-+ if (show_table->found_next_number_field)
-+ {
-+ table->field[13]->store((longlong) file->auto_increment_value, TRUE);
-+ table->field[13]->set_notnull();
-+ }
-+ if (file->create_time)
-+ {
-+ thd->variables.time_zone->gmt_sec_to_TIME(&time,
-+ file->create_time);
-+ table->field[14]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
-+ table->field[14]->set_notnull();
-+ }
-+ if (file->update_time)
-+ {
-+ thd->variables.time_zone->gmt_sec_to_TIME(&time,
-+ file->update_time);
-+ table->field[15]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
-+ table->field[15]->set_notnull();
-+ }
-+ if (file->check_time)
-+ {
-+ thd->variables.time_zone->gmt_sec_to_TIME(&time, file->check_time);
-+ table->field[16]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
-+ table->field[16]->set_notnull();
-+ }
-+ tmp_buff= (share->table_charset ?
-+ share->table_charset->name : "default");
-+ table->field[17]->store(tmp_buff, strlen(tmp_buff), cs);
-+ if (file->table_flags() & (ulong) HA_HAS_CHECKSUM)
-+ {
-+ table->field[18]->store((longlong) file->checksum(), TRUE);
-+ table->field[18]->set_notnull();
-+ }
-+
-+ char option_buff[350],*ptr;
-+ ptr=option_buff;
-+ if (share->min_rows)
-+ {
-+ ptr=strmov(ptr," min_rows=");
-+ ptr=longlong10_to_str(share->min_rows,ptr,10);
-+ }
-+ if (share->max_rows)
-+ {
-+ ptr=strmov(ptr," max_rows=");
-+ ptr=longlong10_to_str(share->max_rows,ptr,10);
-+ }
-+ if (share->avg_row_length)
-+ {
-+ ptr=strmov(ptr," avg_row_length=");
-+ ptr=longlong10_to_str(share->avg_row_length,ptr,10);
-+ }
-+ if (share->db_create_options & HA_OPTION_PACK_KEYS)
-+ ptr=strmov(ptr," pack_keys=1");
-+ if (share->db_create_options & HA_OPTION_NO_PACK_KEYS)
-+ ptr=strmov(ptr," pack_keys=0");
-+ if (share->db_create_options & HA_OPTION_CHECKSUM)
-+ ptr=strmov(ptr," checksum=1");
-+ if (share->db_create_options & HA_OPTION_DELAY_KEY_WRITE)
-+ ptr=strmov(ptr," delay_key_write=1");
-+ if (share->row_type != ROW_TYPE_DEFAULT)
-+ ptr=strxmov(ptr, " row_format=",
-+ ha_row_type[(uint) share->row_type],
-+ NullS);
-+ if (file->raid_type)
-+ {
-+ char buff[100];
-+ my_snprintf(buff,sizeof(buff),
-+ " raid_type=%s raid_chunks=%d raid_chunksize=%ld",
-+ my_raid_type(file->raid_type), file->raid_chunks,
-+ file->raid_chunksize/RAID_BLOCK_SIZE);
-+ ptr=strmov(ptr,buff);
-+ }
-+ table->field[19]->store(option_buff+1,
-+ (ptr == option_buff ? 0 :
-+ (uint) (ptr-option_buff)-1), cs);
-+ {
-+ char *comment;
-+ comment= show_table->file->update_table_comment(share->comment.str);
-+ if (comment)
-+ {
-+ table->field[20]->store(comment,
-+ (comment == share->comment.str ?
-+ share->comment.length :
-+ strlen(comment)), cs);
-+ if (comment != share->comment.str)
-+ my_free(comment, MYF(0));
-+ }
-+ }
-+ }
-+ DBUG_RETURN(schema_table_store_record(thd, table));
-+}
-+
-+
-+static int get_schema_column_record(THD *thd, struct st_table_list *tables,
-+ TABLE *table, bool res,
-+ const char *base_name,
-+ const char *file_name)
-+{
-+ LEX *lex= thd->lex;
-+ const char *wild= lex->wild ? lex->wild->ptr() : NullS;
-+ CHARSET_INFO *cs= system_charset_info;
-+ TABLE *show_table;
-+ handler *file;
-+ Field **ptr,*field;
-+ int count;
-+ uint base_name_length, file_name_length;
-+ DBUG_ENTER("get_schema_column_record");
-+
-+ if (res)
-+ {
-+ if (lex->orig_sql_command != SQLCOM_SHOW_FIELDS)
-+ {
-+ /*
-+ I.e. we are in SELECT FROM INFORMATION_SCHEMA.COLUMS
-+ rather than in SHOW COLUMNS
-+ */
-+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
-+ thd->net.last_errno, thd->net.last_error);
-+ thd->clear_error();
-+ res= 0;
-+ }
-+ DBUG_RETURN(res);
-+ }
-+
-+ show_table= tables->table;
-+ file= show_table->file;
-+ count= 0;
-+ file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
-+ restore_record(show_table, s->default_values);
-+ base_name_length= strlen(base_name);
-+ file_name_length= strlen(file_name);
-+
-+ for (ptr=show_table->field; (field= *ptr) ; ptr++)
-+ {
-+ const char *tmp_buff;
-+ byte *pos;
-+ bool is_blob;
-+ uint flags=field->flags;
-+ char tmp[MAX_FIELD_WIDTH];
-+ char tmp1[MAX_FIELD_WIDTH];
-+ String type(tmp,sizeof(tmp), system_charset_info);
-+ char *end;
-+ int decimals, field_length;
-+
-+ if (wild && wild[0] &&
-+ wild_case_compare(system_charset_info, field->field_name,wild))
-+ continue;
-+
-+ flags= field->flags;
-+ count++;
-+ /* Get default row, with all NULL fields set to NULL */
-+ restore_record(table, s->default_values);
-+
-+#ifndef NO_EMBEDDED_ACCESS_CHECKS
-+ uint col_access;
-+ check_access(thd,SELECT_ACL | EXTRA_ACL, base_name,
-+ &tables->grant.privilege, 0, 0, test(tables->schema_table));
-+ col_access= get_column_grant(thd, &tables->grant,
-+ base_name, file_name,
-+ field->field_name) & COL_ACLS;
-+ if (lex->orig_sql_command != SQLCOM_SHOW_FIELDS &&
-+ !tables->schema_table && !col_access)
-+ continue;
-+ end= tmp;
-+ for (uint bitnr=0; col_access ; col_access>>=1,bitnr++)
-+ {
-+ if (col_access & 1)
-+ {
-+ *end++=',';
-+ end=strmov(end,grant_types.type_names[bitnr]);
-+ }
-+ }
-+ table->field[17]->store(tmp+1,end == tmp ? 0 : (uint) (end-tmp-1), cs);
-+
-+#endif
-+ table->field[1]->store(base_name, base_name_length, cs);
-+ table->field[2]->store(file_name, file_name_length, cs);
-+ table->field[3]->store(field->field_name, strlen(field->field_name),
-+ cs);
-+ table->field[4]->store((longlong) count, TRUE);
-+ field->sql_type(type);
-+ table->field[14]->store(type.ptr(), type.length(), cs);
-+ tmp_buff= strchr(type.ptr(), '(');
-+ table->field[7]->store(type.ptr(),
-+ (tmp_buff ? tmp_buff - type.ptr() :
-+ type.length()), cs);
-+ if (show_table->timestamp_field == field &&
-+ field->unireg_check != Field::TIMESTAMP_UN_FIELD)
-+ {
-+ table->field[5]->store(STRING_WITH_LEN("CURRENT_TIMESTAMP"), cs);
-+ table->field[5]->set_notnull();
-+ }
-+ else if (field->unireg_check != Field::NEXT_NUMBER &&
-+ !field->is_null() &&
-+ !(field->flags & NO_DEFAULT_VALUE_FLAG))
-+ {
-+ String def(tmp1,sizeof(tmp1), cs);
-+ type.set(tmp, sizeof(tmp), field->charset());
-+ field->val_str(&type);
-+ uint dummy_errors;
-+ def.copy(type.ptr(), type.length(), type.charset(), cs, &dummy_errors);
-+ table->field[5]->store(def.ptr(), def.length(), def.charset());
-+ table->field[5]->set_notnull();
-+ }
-+ else if (field->unireg_check == Field::NEXT_NUMBER ||
-+ lex->orig_sql_command != SQLCOM_SHOW_FIELDS ||
-+ field->maybe_null())
-+ table->field[5]->set_null(); // Null as default
-+ else
-+ {
-+ table->field[5]->store("",0, cs);
-+ table->field[5]->set_notnull();
-+ }
-+ pos=(byte*) ((flags & NOT_NULL_FLAG) ? "NO" : "YES");
-+ table->field[6]->store((const char*) pos,
-+ strlen((const char*) pos), cs);
-+ is_blob= (field->type() == FIELD_TYPE_BLOB);
-+ if (field->has_charset() || is_blob ||
-+ field->real_type() == MYSQL_TYPE_VARCHAR || // For varbinary type
-+ field->real_type() == MYSQL_TYPE_STRING) // For binary type
-+ {
-+ uint32 octet_max_length= field->max_length();
-+ if (is_blob && octet_max_length != (uint32) 4294967295U)
-+ octet_max_length /= field->charset()->mbmaxlen;
-+ longlong char_max_len= is_blob ?
-+ (longlong) octet_max_length / field->charset()->mbminlen :
-+ (longlong) octet_max_length / field->charset()->mbmaxlen;
-+ table->field[8]->store(char_max_len, TRUE);
-+ table->field[8]->set_notnull();
-+ table->field[9]->store((longlong) octet_max_length, TRUE);
-+ table->field[9]->set_notnull();
-+ }
-+
-+ /*
-+ Calculate field_length and decimals.
-+ They are set to -1 if they should not be set (we should return NULL)
-+ */
-+
-+ decimals= field->decimals();
-+ switch (field->type()) {
-+ case FIELD_TYPE_NEWDECIMAL:
-+ field_length= ((Field_new_decimal*) field)->precision;
-+ break;
-+ case FIELD_TYPE_DECIMAL:
-+ field_length= field->field_length - (decimals ? 2 : 1);
-+ break;
-+ case FIELD_TYPE_TINY:
-+ case FIELD_TYPE_SHORT:
-+ case FIELD_TYPE_LONG:
-+ case FIELD_TYPE_LONGLONG:
-+ case FIELD_TYPE_INT24:
-+ field_length= field->max_length() - 1;
-+ break;
-+ case FIELD_TYPE_BIT:
-+ field_length= field->max_length();
-+ decimals= -1; // return NULL
-+ break;
-+ case FIELD_TYPE_FLOAT:
-+ case FIELD_TYPE_DOUBLE:
-+ field_length= field->field_length;
-+ if (decimals == NOT_FIXED_DEC)
-+ decimals= -1; // return NULL
-+ break;
-+ default:
-+ field_length= decimals= -1;
-+ break;
-+ }
-+
-+ if (field_length >= 0)
-+ {
-+ table->field[10]->store((longlong) field_length, TRUE);
-+ table->field[10]->set_notnull();
-+ }
-+ if (decimals >= 0)
-+ {
-+ table->field[11]->store((longlong) decimals, TRUE);
-+ table->field[11]->set_notnull();
-+ }
-+
-+ if (field->has_charset())
-+ {
-+ pos=(byte*) field->charset()->csname;
-+ table->field[12]->store((const char*) pos,
-+ strlen((const char*) pos), cs);
-+ table->field[12]->set_notnull();
-+ pos=(byte*) field->charset()->name;
-+ table->field[13]->store((const char*) pos,
-+ strlen((const char*) pos), cs);
-+ table->field[13]->set_notnull();
-+ }
-+ pos=(byte*) ((field->flags & PRI_KEY_FLAG) ? "PRI" :
-+ (field->flags & UNIQUE_KEY_FLAG) ? "UNI" :
-+ (field->flags & MULTIPLE_KEY_FLAG) ? "MUL":"");
-+ table->field[15]->store((const char*) pos,
-+ strlen((const char*) pos), cs);
-+
-+ end= tmp;
-+ if (field->unireg_check == Field::NEXT_NUMBER)
-+ end=strmov(tmp,"auto_increment");
-+ table->field[16]->store(tmp, (uint) (end-tmp), cs);
-+
-+ table->field[18]->store(field->comment.str, field->comment.length, cs);
-+ if (schema_table_store_record(thd, table))
-+ DBUG_RETURN(1);
-+ }
-+ DBUG_RETURN(0);
-+}
-+
-+
-+
-+int fill_schema_charsets(THD *thd, TABLE_LIST *tables, COND *cond)
-+{
-+ CHARSET_INFO **cs;
-+ const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
-+ TABLE *table= tables->table;
-+ CHARSET_INFO *scs= system_charset_info;
-+
-+ for (cs= all_charsets ; cs < all_charsets+255 ; cs++)
-+ {
-+ CHARSET_INFO *tmp_cs= cs[0];
-+ if (tmp_cs && (tmp_cs->state & MY_CS_PRIMARY) &&
-+ (tmp_cs->state & MY_CS_AVAILABLE) &&
-+ !(wild && wild[0] &&
-+ wild_case_compare(scs, tmp_cs->csname,wild)))
-+ {
-+ const char *comment;
-+ restore_record(table, s->default_values);
-+ table->field[0]->store(tmp_cs->csname, strlen(tmp_cs->csname), scs);
-+ table->field[1]->store(tmp_cs->name, strlen(tmp_cs->name), scs);
-+ comment= tmp_cs->comment ? tmp_cs->comment : "";
-+ table->field[2]->store(comment, strlen(comment), scs);
-+ table->field[3]->store((longlong) tmp_cs->mbmaxlen, TRUE);
-+ if (schema_table_store_record(thd, table))
-+ return 1;
-+ }
-+ }
-+ return 0;
-+}
-+
-+
-+int fill_schema_collation(THD *thd, TABLE_LIST *tables, COND *cond)
-+{
-+ CHARSET_INFO **cs;
-+ const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
-+ TABLE *table= tables->table;
-+ CHARSET_INFO *scs= system_charset_info;
-+ for (cs= all_charsets ; cs < all_charsets+255 ; cs++ )
-+ {
-+ CHARSET_INFO **cl;
-+ CHARSET_INFO *tmp_cs= cs[0];
-+ if (!tmp_cs || !(tmp_cs->state & MY_CS_AVAILABLE) ||
-+ !(tmp_cs->state & MY_CS_PRIMARY))
-+ continue;
-+ for (cl= all_charsets; cl < all_charsets+255 ;cl ++)
-+ {
-+ CHARSET_INFO *tmp_cl= cl[0];
-+ if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) ||
-+ !my_charset_same(tmp_cs, tmp_cl))
-+ continue;
-+ if (!(wild && wild[0] &&
-+ wild_case_compare(scs, tmp_cl->name,wild)))
-+ {
-+ const char *tmp_buff;
-+ restore_record(table, s->default_values);
-+ table->field[0]->store(tmp_cl->name, strlen(tmp_cl->name), scs);
-+ table->field[1]->store(tmp_cl->csname , strlen(tmp_cl->csname), scs);
-+ table->field[2]->store((longlong) tmp_cl->number, TRUE);
-+ tmp_buff= (tmp_cl->state & MY_CS_PRIMARY) ? "Yes" : "";
-+ table->field[3]->store(tmp_buff, strlen(tmp_buff), scs);
-+ tmp_buff= (tmp_cl->state & MY_CS_COMPILED)? "Yes" : "";
-+ table->field[4]->store(tmp_buff, strlen(tmp_buff), scs);
-+ table->field[5]->store((longlong) tmp_cl->strxfrm_multiply, TRUE);
-+ if (schema_table_store_record(thd, table))
-+ return 1;
-+ }
-+ }
-+ }
-+ return 0;
-+}
-+
-+
-+int fill_schema_coll_charset_app(THD *thd, TABLE_LIST *tables, COND *cond)
-+{
-+ CHARSET_INFO **cs;
-+ TABLE *table= tables->table;
-+ CHARSET_INFO *scs= system_charset_info;
-+ for (cs= all_charsets ; cs < all_charsets+255 ; cs++ )
-+ {
-+ CHARSET_INFO **cl;
-+ CHARSET_INFO *tmp_cs= cs[0];
-+ if (!tmp_cs || !(tmp_cs->state & MY_CS_AVAILABLE) ||
-+ !(tmp_cs->state & MY_CS_PRIMARY))
-+ continue;
-+ for (cl= all_charsets; cl < all_charsets+255 ;cl ++)
-+ {
-+ CHARSET_INFO *tmp_cl= cl[0];
-+ if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) ||
-+ !my_charset_same(tmp_cs,tmp_cl))
-+ continue;
-+ restore_record(table, s->default_values);
-+ table->field[0]->store(tmp_cl->name, strlen(tmp_cl->name), scs);
-+ table->field[1]->store(tmp_cl->csname , strlen(tmp_cl->csname), scs);
-+ if (schema_table_store_record(thd, table))
-+ return 1;
-+ }
-+ }
-+ return 0;
-+}
-+
-+
-+bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table,
-+ const char *wild, bool full_access, const char *sp_user)
-+{
-+ String tmp_string;
-+ String sp_db, sp_name, definer;
-+ TIME time;
-+ LEX *lex= thd->lex;
-+ CHARSET_INFO *cs= system_charset_info;
-+ get_field(thd->mem_root, proc_table->field[0], &sp_db);
-+ get_field(thd->mem_root, proc_table->field[1], &sp_name);
-+ get_field(thd->mem_root, proc_table->field[11], &definer);
-+ if (!full_access)
-+ full_access= !strcmp(sp_user, definer.ptr());
-+ if (!full_access && check_some_routine_access(thd, sp_db.ptr(), sp_name.ptr(),
-+ proc_table->field[2]->val_int() ==
-+ TYPE_ENUM_PROCEDURE))
-+ return 0;
-+
-+ 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)
-+ {
-+ restore_record(table, s->default_values);
-+ if (!wild || !wild[0] || !wild_compare(sp_name.ptr(), wild, 0))
-+ {
-+ int enum_idx= (int) proc_table->field[5]->val_int();
-+ table->field[3]->store(sp_name.ptr(), sp_name.length(), cs);
-+ get_field(thd->mem_root, proc_table->field[3], &tmp_string);
-+ table->field[0]->store(tmp_string.ptr(), tmp_string.length(), cs);
-+ table->field[2]->store(sp_db.ptr(), sp_db.length(), cs);
-+ get_field(thd->mem_root, proc_table->field[2], &tmp_string);
-+ table->field[4]->store(tmp_string.ptr(), tmp_string.length(), cs);
-+ if (proc_table->field[2]->val_int() == TYPE_ENUM_FUNCTION)
-+ {
-+ get_field(thd->mem_root, proc_table->field[9], &tmp_string);
-+ table->field[5]->store(tmp_string.ptr(), tmp_string.length(), cs);
-+ table->field[5]->set_notnull();
-+ }
-+ if (full_access)
-+ {
-+ get_field(thd->mem_root, proc_table->field[10], &tmp_string);
-+ table->field[7]->store(tmp_string.ptr(), tmp_string.length(), cs);
-+ table->field[7]->set_notnull();
-+ }
-+ table->field[6]->store(STRING_WITH_LEN("SQL"), cs);
-+ table->field[10]->store(STRING_WITH_LEN("SQL"), cs);
-+ get_field(thd->mem_root, proc_table->field[6], &tmp_string);
-+ table->field[11]->store(tmp_string.ptr(), tmp_string.length(), cs);
-+ table->field[12]->store(sp_data_access_name[enum_idx].str,
-+ sp_data_access_name[enum_idx].length , cs);
-+ get_field(thd->mem_root, proc_table->field[7], &tmp_string);
-+ table->field[14]->store(tmp_string.ptr(), tmp_string.length(), cs);
-+ bzero((char *)&time, sizeof(time));
-+ ((Field_timestamp *) proc_table->field[12])->get_time(&time);
-+ table->field[15]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
-+ bzero((char *)&time, sizeof(time));
-+ ((Field_timestamp *) proc_table->field[13])->get_time(&time);
-+ table->field[16]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
-+ get_field(thd->mem_root, proc_table->field[14], &tmp_string);
-+ table->field[17]->store(tmp_string.ptr(), tmp_string.length(), cs);
-+ get_field(thd->mem_root, proc_table->field[15], &tmp_string);
-+ table->field[18]->store(tmp_string.ptr(), tmp_string.length(), cs);
-+ table->field[19]->store(definer.ptr(), definer.length(), cs);
-+ return schema_table_store_record(thd, table);
-+ }
-+ }
-+ return 0;
-+}
-+
-+
-+int fill_schema_proc(THD *thd, TABLE_LIST *tables, COND *cond)
-+{
-+ TABLE *proc_table;
-+ TABLE_LIST proc_tables;
-+ const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
-+ int res= 0;
-+ TABLE *table= tables->table;
-+ bool full_access;
-+ char definer[USER_HOST_BUFF_SIZE];
-+ Open_tables_state open_tables_state_backup;
-+ DBUG_ENTER("fill_schema_proc");
-+
-+ strxmov(definer, thd->security_ctx->priv_user, "@",
-+ thd->security_ctx->priv_host, NullS);
-+ /* We use this TABLE_LIST instance only for checking of privileges. */
-+ 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_proc_table_for_read(thd, &open_tables_state_backup)))
-+ {
-+ DBUG_RETURN(1);
-+ }
-+ proc_table->file->ha_index_init(0);
-+ if ((res= proc_table->file->index_first(proc_table->record[0])))
-+ {
-+ res= (res == HA_ERR_END_OF_FILE) ? 0 : 1;
-+ goto err;
-+ }
-+ if (store_schema_proc(thd, table, proc_table, wild, full_access, definer))
-+ {
-+ res= 1;
-+ goto err;
-+ }
-+ while (!proc_table->file->index_next(proc_table->record[0]))
-+ {
-+ if (store_schema_proc(thd, table, proc_table, wild, full_access, definer))
-+ {
-+ res= 1;
-+ goto err;
-+ }
-+ }
-+
-+err:
-+ proc_table->file->ha_index_end();
-+ close_proc_table(thd, &open_tables_state_backup);
-+ DBUG_RETURN(res);
-+}
-+
-+
-+static int get_schema_stat_record(THD *thd, struct st_table_list *tables,
-+ TABLE *table, bool res,
-+ const char *base_name,
-+ const char *file_name)
-+{
-+ CHARSET_INFO *cs= system_charset_info;
-+ DBUG_ENTER("get_schema_stat_record");
-+ if (res)
-+ {
-+ if (thd->lex->orig_sql_command != SQLCOM_SHOW_KEYS)
-+ {
-+ /*
-+ I.e. we are in SELECT FROM INFORMATION_SCHEMA.STATISTICS
-+ rather than in SHOW KEYS
-+ */
-+ if (!tables->view)
-+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
-+ thd->net.last_errno, thd->net.last_error);
-+ thd->clear_error();
-+ res= 0;
-+ }
-+ DBUG_RETURN(res);
-+ }
-+ else if (!tables->view)
-+ {
-+ TABLE *show_table= tables->table;
-+ KEY *key_info=show_table->key_info;
-+ show_table->file->info(HA_STATUS_VARIABLE |
-+ HA_STATUS_NO_LOCK |
-+ HA_STATUS_TIME);
-+ for (uint i=0 ; i < show_table->s->keys ; i++,key_info++)
-+ {
-+ KEY_PART_INFO *key_part= key_info->key_part;
-+ const char *str;
-+ for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
-+ {
-+ restore_record(table, s->default_values);
-+ table->field[1]->store(base_name, strlen(base_name), cs);
-+ table->field[2]->store(file_name, strlen(file_name), cs);
-+ table->field[3]->store((longlong) ((key_info->flags &
-+ HA_NOSAME) ? 0 : 1), TRUE);
-+ table->field[4]->store(base_name, strlen(base_name), cs);
-+ table->field[5]->store(key_info->name, strlen(key_info->name), cs);
-+ table->field[6]->store((longlong) (j+1), TRUE);
-+ str=(key_part->field ? key_part->field->field_name :
-+ "?unknown field?");
-+ table->field[7]->store(str, strlen(str), cs);
-+ if (show_table->file->index_flags(i, j, 0) & HA_READ_ORDER)
-+ {
-+ table->field[8]->store(((key_part->key_part_flag &
-+ HA_REVERSE_SORT) ?
-+ "D" : "A"), 1, cs);
-+ table->field[8]->set_notnull();
-+ }
-+ KEY *key=show_table->key_info+i;
-+ if (key->rec_per_key[j])
-+ {
-+ ha_rows records=(show_table->file->records /
-+ key->rec_per_key[j]);
-+ table->field[9]->store((longlong) records, TRUE);
-+ table->field[9]->set_notnull();
-+ }
-+ if (!(key_info->flags & HA_FULLTEXT) &&
-+ (key_part->field &&
-+ key_part->length !=
-+ show_table->field[key_part->fieldnr-1]->key_length()))
-+ {
-+ table->field[10]->store((longlong) key_part->length /
-+ key_part->field->charset()->mbmaxlen, 1);
-+ table->field[10]->set_notnull();
-+ }
-+ uint flags= key_part->field ? key_part->field->flags : 0;
-+ const char *pos=(char*) ((flags & NOT_NULL_FLAG) ? "" : "YES");
-+ table->field[12]->store(pos, strlen(pos), cs);
-+ pos= show_table->file->index_type(i);
-+ table->field[13]->store(pos, strlen(pos), cs);
-+ if (!show_table->s->keys_in_use.is_set(i))
-+ table->field[14]->store(STRING_WITH_LEN("disabled"), cs);
-+ else
-+ table->field[14]->store("", 0, cs);
-+ table->field[14]->set_notnull();
-+ if (schema_table_store_record(thd, table))
-+ DBUG_RETURN(1);
-+ }
-+ }
-+ }
-+ DBUG_RETURN(res);
-+}
-+
-+
-+static int get_schema_views_record(THD *thd, struct st_table_list *tables,
-+ TABLE *table, bool res,
-+ const char *base_name,
-+ const char *file_name)
-+{
-+ CHARSET_INFO *cs= system_charset_info;
-+ DBUG_ENTER("get_schema_views_record");
-+ char definer[USER_HOST_BUFF_SIZE];
-+ uint definer_len;
-+
-+ if (tables->view)
-+ {
-+ Security_context *sctx= thd->security_ctx;
-+ if (!tables->allowed_show)
-+ {
-+ if (!my_strcasecmp(system_charset_info, tables->definer.user.str,
-+ sctx->priv_user) &&
-+ !my_strcasecmp(system_charset_info, tables->definer.host.str,
-+ sctx->priv_host))
-+ tables->allowed_show= TRUE;
-+ }
-+ restore_record(table, s->default_values);
-+ table->field[1]->store(tables->view_db.str, tables->view_db.length, cs);
-+ table->field[2]->store(tables->view_name.str, tables->view_name.length, cs);
-+ if (tables->allowed_show)
-+ {
-+ char buff[2048];
-+ String qwe_str(buff, sizeof(buff), cs);
-+ qwe_str.length(0);
-+ qwe_str.append(STRING_WITH_LEN("/* "));
-+ append_algorithm(tables, &qwe_str);
-+ qwe_str.append(STRING_WITH_LEN("*/ "));
-+ qwe_str.append(tables->query.str, tables->query.length);
-+ table->field[3]->store(qwe_str.ptr(), qwe_str.length(), cs);
-+ }
-+
-+ if (tables->with_check != VIEW_CHECK_NONE)
-+ {
-+ if (tables->with_check == VIEW_CHECK_LOCAL)
-+ table->field[4]->store(STRING_WITH_LEN("LOCAL"), cs);
-+ else
-+ table->field[4]->store(STRING_WITH_LEN("CASCADED"), cs);
-+ }
-+ else
-+ table->field[4]->store(STRING_WITH_LEN("NONE"), cs);
-+
-+ if (tables->updatable_view)
-+ table->field[5]->store(STRING_WITH_LEN("YES"), cs);
-+ else
-+ table->field[5]->store(STRING_WITH_LEN("NO"), cs);
-+ definer_len= (strxmov(definer, tables->definer.user.str, "@",
-+ tables->definer.host.str, NullS) - definer);
-+ table->field[6]->store(definer, definer_len, cs);
-+ if (tables->view_suid)
-+ table->field[7]->store(STRING_WITH_LEN("DEFINER"), cs);
-+ else
-+ table->field[7]->store(STRING_WITH_LEN("INVOKER"), cs);
-+ if (schema_table_store_record(thd, table))
-+ DBUG_RETURN(1);
-+ if (res)
-+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
-+ thd->net.last_errno, thd->net.last_error);
-+ }
-+ if (res)
-+ thd->clear_error();
-+ DBUG_RETURN(0);
-+}
-+
-+
-+bool store_constraints(THD *thd, TABLE *table, const char *db,
-+ const char *tname, const char *key_name,
-+ uint key_len, const char *con_type, uint con_len)
-+{
-+ CHARSET_INFO *cs= system_charset_info;
-+ restore_record(table, s->default_values);
-+ table->field[1]->store(db, strlen(db), cs);
-+ table->field[2]->store(key_name, key_len, cs);
-+ table->field[3]->store(db, strlen(db), cs);
-+ table->field[4]->store(tname, strlen(tname), cs);
-+ table->field[5]->store(con_type, con_len, cs);
-+ return schema_table_store_record(thd, table);
-+}
-+
-+
-+static int get_schema_constraints_record(THD *thd, struct st_table_list *tables,
-+ TABLE *table, bool res,
-+ const char *base_name,
-+ const char *file_name)
-+{
-+ DBUG_ENTER("get_schema_constraints_record");
-+ if (res)
-+ {
-+ if (!tables->view)
-+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
-+ thd->net.last_errno, thd->net.last_error);
-+ thd->clear_error();
-+ DBUG_RETURN(0);
-+ }
-+ else if (!tables->view)
-+ {
-+ List<FOREIGN_KEY_INFO> f_key_list;
-+ TABLE *show_table= tables->table;
-+ KEY *key_info=show_table->key_info;
-+ uint primary_key= show_table->s->primary_key;
-+ show_table->file->info(HA_STATUS_VARIABLE |
-+ HA_STATUS_NO_LOCK |
-+ HA_STATUS_TIME);
-+ for (uint i=0 ; i < show_table->s->keys ; i++, key_info++)
-+ {
-+ if (i != primary_key && !(key_info->flags & HA_NOSAME))
-+ continue;
-+
-+ if (i == primary_key && !strcmp(key_info->name, primary_key_name))
-+ {
-+ if (store_constraints(thd, table, base_name, file_name, key_info->name,
-+ strlen(key_info->name),
-+ STRING_WITH_LEN("PRIMARY KEY")))
-+ DBUG_RETURN(1);
-+ }
-+ else if (key_info->flags & HA_NOSAME)
-+ {
-+ if (store_constraints(thd, table, base_name, file_name, key_info->name,
-+ strlen(key_info->name),
-+ STRING_WITH_LEN("UNIQUE")))
-+ DBUG_RETURN(1);
-+ }
-+ }
-+
-+ show_table->file->get_foreign_key_list(thd, &f_key_list);
-+ FOREIGN_KEY_INFO *f_key_info;
-+ List_iterator_fast<FOREIGN_KEY_INFO> it(f_key_list);
-+ while ((f_key_info=it++))
-+ {
-+ if (store_constraints(thd, table, base_name, file_name,
-+ f_key_info->forein_id->str,
-+ strlen(f_key_info->forein_id->str),
-+ "FOREIGN KEY", 11))
-+ DBUG_RETURN(1);
-+ }
-+ }
-+ DBUG_RETURN(res);
-+}
-+
-+
-+static bool store_trigger(THD *thd, TABLE *table, const char *db,
-+ const char *tname, LEX_STRING *trigger_name,
-+ enum trg_event_type event,
-+ enum trg_action_time_type timing,
-+ LEX_STRING *trigger_stmt,
-+ ulong sql_mode,
-+ LEX_STRING *definer_buffer)
-+{
-+ CHARSET_INFO *cs= system_charset_info;
-+ byte *sql_mode_str;
-+ ulong sql_mode_len;
-+
-+ restore_record(table, s->default_values);
-+ table->field[1]->store(db, strlen(db), cs);
-+ table->field[2]->store(trigger_name->str, trigger_name->length, cs);
-+ table->field[3]->store(trg_event_type_names[event].str,
-+ trg_event_type_names[event].length, cs);
-+ table->field[5]->store(db, strlen(db), cs);
-+ table->field[6]->store(tname, strlen(tname), cs);
-+ table->field[9]->store(trigger_stmt->str, trigger_stmt->length, cs);
-+ table->field[10]->store(STRING_WITH_LEN("ROW"), cs);
-+ table->field[11]->store(trg_action_time_type_names[timing].str,
-+ trg_action_time_type_names[timing].length, cs);
-+ table->field[14]->store(STRING_WITH_LEN("OLD"), cs);
-+ table->field[15]->store(STRING_WITH_LEN("NEW"), cs);
-+
-+ sql_mode_str=
-+ sys_var_thd_sql_mode::symbolic_mode_representation(thd,
-+ sql_mode,
-+ &sql_mode_len);
-+ table->field[17]->store((const char*)sql_mode_str, sql_mode_len, cs);
-+ table->field[18]->store((const char *)definer_buffer->str, definer_buffer->length, cs);
-+ return schema_table_store_record(thd, table);
-+}
-+
-+
-+static int get_schema_triggers_record(THD *thd, struct st_table_list *tables,
-+ TABLE *table, bool res,
-+ const char *base_name,
-+ const char *file_name)
-+{
-+ DBUG_ENTER("get_schema_triggers_record");
-+ /*
-+ res can be non zero value when processed table is a view or
-+ error happened during opening of processed table.
-+ */
-+ if (res)
-+ {
-+ if (!tables->view)
-+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
-+ thd->net.last_errno, thd->net.last_error);
-+ thd->clear_error();
-+ DBUG_RETURN(0);
-+ }
-+ if (!tables->view && tables->table->triggers)
-+ {
-+ Table_triggers_list *triggers= tables->table->triggers;
-+ int event, timing;
-+ for (event= 0; event < (int)TRG_EVENT_MAX; event++)
-+ {
-+ for (timing= 0; timing < (int)TRG_ACTION_MAX; timing++)
-+ {
-+ LEX_STRING trigger_name;
-+ LEX_STRING trigger_stmt;
-+ ulong sql_mode;
-+ char definer_holder[USER_HOST_BUFF_SIZE];
-+ LEX_STRING definer_buffer;
-+ definer_buffer.str= definer_holder;
-+ if (triggers->get_trigger_info(thd, (enum trg_event_type) event,
-+ (enum trg_action_time_type)timing,
-+ &trigger_name, &trigger_stmt,
-+ &sql_mode,
-+ &definer_buffer))
-+ continue;
-+
-+ if (store_trigger(thd, table, base_name, file_name, &trigger_name,
-+ (enum trg_event_type) event,
-+ (enum trg_action_time_type) timing, &trigger_stmt,
-+ sql_mode,
-+ &definer_buffer))
-+ DBUG_RETURN(1);
-+ }
-+ }
-+ }
-+ DBUG_RETURN(0);
-+}
-+
-+
-+void store_key_column_usage(TABLE *table, const char*db, const char *tname,
-+ const char *key_name, uint key_len,
-+ const char *con_type, uint con_len, longlong idx)
-+{
-+ CHARSET_INFO *cs= system_charset_info;
-+ table->field[1]->store(db, strlen(db), cs);
-+ table->field[2]->store(key_name, key_len, cs);
-+ table->field[4]->store(db, strlen(db), cs);
-+ table->field[5]->store(tname, strlen(tname), cs);
-+ table->field[6]->store(con_type, con_len, cs);
-+ table->field[7]->store((longlong) idx, TRUE);
-+}
-+
-+
-+static int get_schema_key_column_usage_record(THD *thd,
-+ struct st_table_list *tables,
-+ TABLE *table, bool res,
-+ const char *base_name,
-+ const char *file_name)
-+{
-+ DBUG_ENTER("get_schema_key_column_usage_record");
-+ if (res)
-+ {
-+ if (!tables->view)
-+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
-+ thd->net.last_errno, thd->net.last_error);
-+ thd->clear_error();
-+ DBUG_RETURN(0);
-+ }
-+ else if (!tables->view)
-+ {
-+ List<FOREIGN_KEY_INFO> f_key_list;
-+ TABLE *show_table= tables->table;
-+ KEY *key_info=show_table->key_info;
-+ uint primary_key= show_table->s->primary_key;
-+ show_table->file->info(HA_STATUS_VARIABLE |
-+ HA_STATUS_NO_LOCK |
-+ HA_STATUS_TIME);
-+ for (uint i=0 ; i < show_table->s->keys ; i++, key_info++)
-+ {
-+ if (i != primary_key && !(key_info->flags & HA_NOSAME))
-+ continue;
-+ uint f_idx= 0;
-+ KEY_PART_INFO *key_part= key_info->key_part;
-+ for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
-+ {
-+ if (key_part->field)
-+ {
-+ f_idx++;
-+ restore_record(table, s->default_values);
-+ store_key_column_usage(table, base_name, file_name,
-+ key_info->name,
-+ strlen(key_info->name),
-+ key_part->field->field_name,
-+ strlen(key_part->field->field_name),
-+ (longlong) f_idx);
-+ if (schema_table_store_record(thd, table))
-+ DBUG_RETURN(1);
-+ }
-+ }
-+ }
-+
-+ show_table->file->get_foreign_key_list(thd, &f_key_list);
-+ FOREIGN_KEY_INFO *f_key_info;
-+ List_iterator_fast<FOREIGN_KEY_INFO> it(f_key_list);
-+ while ((f_key_info= it++))
-+ {
-+ LEX_STRING *f_info;
-+ LEX_STRING *r_info;
-+ List_iterator_fast<LEX_STRING> it(f_key_info->foreign_fields),
-+ it1(f_key_info->referenced_fields);
-+ uint f_idx= 0;
-+ while ((f_info= it++))
-+ {
-+ r_info= it1++;
-+ f_idx++;
-+ restore_record(table, s->default_values);
-+ store_key_column_usage(table, base_name, file_name,
-+ f_key_info->forein_id->str,
-+ f_key_info->forein_id->length,
-+ f_info->str, f_info->length,
-+ (longlong) f_idx);
-+ table->field[8]->store((longlong) f_idx, TRUE);
-+ table->field[8]->set_notnull();
-+ table->field[9]->store(f_key_info->referenced_db->str,
-+ f_key_info->referenced_db->length,
-+ system_charset_info);
-+ table->field[9]->set_notnull();
-+ table->field[10]->store(f_key_info->referenced_table->str,
-+ f_key_info->referenced_table->length,
-+ system_charset_info);
-+ table->field[10]->set_notnull();
-+ table->field[11]->store(r_info->str, r_info->length,
-+ system_charset_info);
-+ table->field[11]->set_notnull();
-+ if (schema_table_store_record(thd, table))
-+ DBUG_RETURN(1);
-+ }
-+ }
-+ }
-+ DBUG_RETURN(res);
-+}
-+
-+
-+int fill_open_tables(THD *thd, TABLE_LIST *tables, COND *cond)
-+{
-+ DBUG_ENTER("fill_open_tables");
-+ const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
-+ TABLE *table= tables->table;
-+ CHARSET_INFO *cs= system_charset_info;
-+ OPEN_TABLE_LIST *open_list;
-+ if (!(open_list=list_open_tables(thd,thd->lex->select_lex.db, wild))
-+ && thd->is_fatal_error)
-+ DBUG_RETURN(1);
-+
-+ for (; open_list ; open_list=open_list->next)
-+ {
-+ restore_record(table, s->default_values);
-+ table->field[0]->store(open_list->db, strlen(open_list->db), cs);
-+ table->field[1]->store(open_list->table, strlen(open_list->table), cs);
-+ table->field[2]->store((longlong) open_list->in_use, TRUE);
-+ table->field[3]->store((longlong) open_list->locked, TRUE);
-+ if (schema_table_store_record(thd, table))
-+ DBUG_RETURN(1);
-+ }
-+ DBUG_RETURN(0);
-+}
-+
-+
-+int fill_variables(THD *thd, TABLE_LIST *tables, COND *cond)
-+{
-+ DBUG_ENTER("fill_variables");
-+ int res= 0;
-+ LEX *lex= thd->lex;
-+ const char *wild= lex->wild ? lex->wild->ptr() : NullS;
-+ pthread_mutex_lock(&LOCK_global_system_variables);
-+ res= show_status_array(thd, wild, init_vars,
-+ lex->option_type, 0, "", tables->table);
-+ pthread_mutex_unlock(&LOCK_global_system_variables);
-+ DBUG_RETURN(res);
-+}
-+
-+
-+int fill_status(THD *thd, TABLE_LIST *tables, COND *cond)
-+{
-+ DBUG_ENTER("fill_status");
-+ LEX *lex= thd->lex;
-+ const char *wild= lex->wild ? lex->wild->ptr() : NullS;
-+ int res= 0;
-+ STATUS_VAR tmp;
-+ ha_update_statistics(); /* Export engines statistics */
-+ pthread_mutex_lock(&LOCK_status);
-+ if (lex->option_type == OPT_GLOBAL)
-+ calc_sum_of_all_status(&tmp);
-+ res= show_status_array(thd, wild, status_vars, OPT_GLOBAL,
-+ (lex->option_type == OPT_GLOBAL ?
-+ &tmp: &thd->status_var), "",tables->table);
-+ pthread_mutex_unlock(&LOCK_status);
-+ DBUG_RETURN(res);
-+}
-+
-+
-+/*
-+ Find schema_tables elment by name
-+
-+ SYNOPSIS
-+ find_schema_table()
-+ thd thread handler
-+ table_name table name
-+
-+ RETURN
-+ 0 table not found
-+ # pointer to 'shema_tables' element
-+*/
-+
-+ST_SCHEMA_TABLE *find_schema_table(THD *thd, const char* table_name)
-+{
-+ ST_SCHEMA_TABLE *schema_table= schema_tables;
-+ for (; schema_table->table_name; schema_table++)
-+ {
-+ if (!my_strcasecmp(system_charset_info,
-+ schema_table->table_name,
-+ table_name))
-+ return schema_table;
-+ }
-+ return 0;
-+}
-+
-+
-+ST_SCHEMA_TABLE *get_schema_table(enum enum_schema_tables schema_table_idx)
-+{
-+ return &schema_tables[schema_table_idx];
-+}
-+
-+
-+/*
-+ Create information_schema table using schema_table data
-+
-+ SYNOPSIS
-+ create_schema_table()
-+ thd thread handler
-+ schema_table pointer to 'shema_tables' element
-+
-+ RETURN
-+ # Pointer to created table
-+ 0 Can't create table
-+*/
-+
-+TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list)
-+{
-+ int field_count= 0;
-+ Item *item;
-+ TABLE *table;
-+ List<Item> field_list;
-+ ST_SCHEMA_TABLE *schema_table= table_list->schema_table;
-+ ST_FIELD_INFO *fields_info= schema_table->fields_info;
-+ CHARSET_INFO *cs= system_charset_info;
-+ DBUG_ENTER("create_schema_table");
-+
-+ for (; fields_info->field_name; fields_info++)
-+ {
-+ switch (fields_info->field_type) {
-+ case MYSQL_TYPE_LONG:
-+ if (!(item= new Item_int(fields_info->field_name,
-+ fields_info->value,
-+ fields_info->field_length)))
-+ {
-+ DBUG_RETURN(0);
-+ }
-+ break;
-+ case MYSQL_TYPE_TIMESTAMP:
-+ if (!(item=new Item_datetime(fields_info->field_name)))
-+ {
-+ DBUG_RETURN(0);
-+ }
-+ break;
-+ default:
-+ /* this should be changed when Item_empty_string is fixed(in 4.1) */
-+ if (!(item= new Item_empty_string("", 0, cs)))
-+ {
-+ DBUG_RETURN(0);
-+ }
-+ item->max_length= fields_info->field_length * cs->mbmaxlen;
-+ item->set_name(fields_info->field_name,
-+ strlen(fields_info->field_name), cs);
-+ break;
-+ }
-+ field_list.push_back(item);
-+ item->maybe_null= fields_info->maybe_null;
-+ field_count++;
-+ }
-+ TMP_TABLE_PARAM *tmp_table_param =
-+ (TMP_TABLE_PARAM*) (thd->calloc(sizeof(TMP_TABLE_PARAM)));
-+ tmp_table_param->init();
-+ tmp_table_param->table_charset= cs;
-+ tmp_table_param->field_count= field_count;
-+ tmp_table_param->schema_table= 1;
-+ SELECT_LEX *select_lex= thd->lex->current_select;
-+ if (!(table= create_tmp_table(thd, tmp_table_param,
-+ field_list, (ORDER*) 0, 0, 0,
-+ (select_lex->options | thd->options |
-+ TMP_TABLE_ALL_COLUMNS),
-+ HA_POS_ERROR, table_list->alias)))
-+ DBUG_RETURN(0);
-+ table_list->schema_table_param= tmp_table_param;
-+ DBUG_RETURN(table);
-+}
-+
-+
-+/*
-+ For old SHOW compatibility. It is used when
-+ old SHOW doesn't have generated column names
-+ Make list of fields for SHOW
-+
-+ SYNOPSIS
-+ make_old_format()
-+ thd thread handler
-+ schema_table pointer to 'schema_tables' element
-+
-+ RETURN
-+ -1 errror
-+ 0 success
-+*/
-+
-+int make_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
-+{
-+ ST_FIELD_INFO *field_info= schema_table->fields_info;
-+ Name_resolution_context *context= &thd->lex->select_lex.context;
-+ for (; field_info->field_name; field_info++)
-+ {
-+ if (field_info->old_name)
-+ {
-+ Item_field *field= new Item_field(context,
-+ NullS, NullS, field_info->field_name);
-+ if (field)
-+ {
-+ field->set_name(field_info->old_name,
-+ strlen(field_info->old_name),
-+ system_charset_info);
-+ if (add_item_to_list(thd, field))
-+ return 1;
-+ }
-+ }
-+ }
-+ return 0;
-+}
-+
-+
-+int make_schemata_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
-+{
-+ char tmp[128];
-+ LEX *lex= thd->lex;
-+ SELECT_LEX *sel= lex->current_select;
-+ Name_resolution_context *context= &sel->context;
-+
-+ if (!sel->item_list.elements)
-+ {
-+ ST_FIELD_INFO *field_info= &schema_table->fields_info[1];
-+ String buffer(tmp,sizeof(tmp), system_charset_info);
-+ Item_field *field= new Item_field(context,
-+ NullS, NullS, field_info->field_name);
-+ if (!field || add_item_to_list(thd, field))
-+ return 1;
-+ buffer.length(0);
-+ buffer.append(field_info->old_name);
-+ if (lex->wild && lex->wild->ptr())
-+ {
-+ buffer.append(STRING_WITH_LEN(" ("));
-+ buffer.append(lex->wild->ptr());
-+ buffer.append(')');
-+ }
-+ field->set_name(buffer.ptr(), buffer.length(), system_charset_info);
-+ }
-+ return 0;
-+}
-+
-+
-+int make_table_names_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
-+{
-+ char tmp[128];
-+ String buffer(tmp,sizeof(tmp), thd->charset());
-+ LEX *lex= thd->lex;
-+ Name_resolution_context *context= &lex->select_lex.context;
-+
-+ ST_FIELD_INFO *field_info= &schema_table->fields_info[2];
-+ buffer.length(0);
-+ buffer.append(field_info->old_name);
-+ buffer.append(lex->select_lex.db);
-+ if (lex->wild && lex->wild->ptr())
-+ {
-+ buffer.append(STRING_WITH_LEN(" ("));
-+ buffer.append(lex->wild->ptr());
-+ buffer.append(')');
-+ }
-+ Item_field *field= new Item_field(context,
-+ NullS, NullS, field_info->field_name);
-+ if (add_item_to_list(thd, field))
-+ return 1;
-+ field->set_name(buffer.ptr(), buffer.length(), system_charset_info);
-+ if (thd->lex->verbose)
-+ {
-+ field->set_name(buffer.ptr(), buffer.length(), system_charset_info);
-+ field_info= &schema_table->fields_info[3];
-+ field= new Item_field(context, NullS, NullS, field_info->field_name);
-+ if (add_item_to_list(thd, field))
-+ return 1;
-+ field->set_name(field_info->old_name, strlen(field_info->old_name),
-+ system_charset_info);
-+ }
-+ return 0;
-+}
-+
-+
-+int make_columns_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
-+{
-+ int fields_arr[]= {3, 14, 13, 6, 15, 5, 16, 17, 18, -1};
-+ int *field_num= fields_arr;
-+ ST_FIELD_INFO *field_info;
-+ Name_resolution_context *context= &thd->lex->select_lex.context;
-+
-+ for (; *field_num >= 0; field_num++)
-+ {
-+ field_info= &schema_table->fields_info[*field_num];
-+ if (!thd->lex->verbose && (*field_num == 13 ||
-+ *field_num == 17 ||
-+ *field_num == 18))
-+ continue;
-+ Item_field *field= new Item_field(context,
-+ NullS, NullS, field_info->field_name);
-+ if (field)
-+ {
-+ field->set_name(field_info->old_name,
-+ strlen(field_info->old_name),
-+ system_charset_info);
-+ if (add_item_to_list(thd, field))
-+ return 1;
-+ }
-+ }
-+ return 0;
-+}
-+
-+
-+int make_character_sets_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
-+{
-+ int fields_arr[]= {0, 2, 1, 3, -1};
-+ int *field_num= fields_arr;
-+ ST_FIELD_INFO *field_info;
-+ Name_resolution_context *context= &thd->lex->select_lex.context;
-+
-+ for (; *field_num >= 0; field_num++)
-+ {
-+ field_info= &schema_table->fields_info[*field_num];
-+ Item_field *field= new Item_field(context,
-+ NullS, NullS, field_info->field_name);
-+ if (field)
-+ {
-+ field->set_name(field_info->old_name,
-+ strlen(field_info->old_name),
-+ system_charset_info);
-+ if (add_item_to_list(thd, field))
-+ return 1;
-+ }
-+ }
-+ return 0;
-+}
-+
-+
-+int make_proc_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
-+{
-+ int fields_arr[]= {2, 3, 4, 19, 16, 15, 14, 18, -1};
-+ int *field_num= fields_arr;
-+ ST_FIELD_INFO *field_info;
-+ Name_resolution_context *context= &thd->lex->select_lex.context;
-+
-+ for (; *field_num >= 0; field_num++)
-+ {
-+ field_info= &schema_table->fields_info[*field_num];
-+ Item_field *field= new Item_field(context,
-+ NullS, NullS, field_info->field_name);
-+ if (field)
-+ {
-+ field->set_name(field_info->old_name,
-+ strlen(field_info->old_name),
-+ system_charset_info);
-+ if (add_item_to_list(thd, field))
-+ return 1;
-+ }
-+ }
-+ return 0;
-+}
-+
-+
-+/*
-+ Create information_schema table
-+
-+ SYNOPSIS
-+ mysql_schema_table()
-+ thd thread handler
-+ lex pointer to LEX
-+ table_list pointer to table_list
-+
-+ RETURN
-+ 0 success
-+ 1 error
-+*/
-+
-+int mysql_schema_table(THD *thd, LEX *lex, TABLE_LIST *table_list)
-+{
-+ TABLE *table;
-+ DBUG_ENTER("mysql_schema_table");
-+ if (!(table= table_list->schema_table->create_table(thd, table_list)))
-+ {
-+ DBUG_RETURN(1);
-+ }
-+ table->s->tmp_table= SYSTEM_TMP_TABLE;
-+ table->grant.privilege= SELECT_ACL;
-+ /*
-+ This test is necessary to make
-+ case insensitive file systems +
-+ upper case table names(information schema tables) +
-+ views
-+ working correctly
-+ */
-+ if (table_list->schema_table_name)
-+ table->alias_name_used= my_strcasecmp(table_alias_charset,
-+ table_list->schema_table_name,
-+ table_list->alias);
-+ table_list->table_name= (char*) table->s->table_name;
-+ table_list->table_name_length= strlen(table->s->table_name);
-+ table_list->table= table;
-+ table->next= thd->derived_tables;
-+ thd->derived_tables= table;
-+ table_list->select_lex->options |= OPTION_SCHEMA_TABLE;
-+ lex->safe_to_cache_query= 0;
-+
-+ if (table_list->schema_table_reformed) // show command
-+ {
-+ SELECT_LEX *sel= lex->current_select;
-+ Item *item;
-+ Field_translator *transl, *org_transl;
-+
-+ if (table_list->field_translation)
-+ {
-+ Field_translator *end= table_list->field_translation_end;
-+ for (transl= table_list->field_translation; transl < end; transl++)
-+ {
-+ if (!transl->item->fixed &&
-+ transl->item->fix_fields(thd, &transl->item))
-+ DBUG_RETURN(1);
-+ }
-+ DBUG_RETURN(0);
-+ }
-+ List_iterator_fast<Item> it(sel->item_list);
-+ if (!(transl=
-+ (Field_translator*)(thd->stmt_arena->
-+ alloc(sel->item_list.elements *
-+ sizeof(Field_translator)))))
-+ {
-+ DBUG_RETURN(1);
-+ }
-+ for (org_transl= transl; (item= it++); transl++)
-+ {
-+ transl->item= item;
-+ transl->name= item->name;
-+ if (!item->fixed && item->fix_fields(thd, &transl->item))
-+ {
-+ DBUG_RETURN(1);
-+ }
-+ }
-+ table_list->field_translation= org_transl;
-+ table_list->field_translation_end= transl;
-+ }
-+
-+ DBUG_RETURN(0);
-+}
-+
-+
-+/*
-+ Generate select from information_schema table
-+
-+ SYNOPSIS
-+ make_schema_select()
-+ thd thread handler
-+ sel pointer to SELECT_LEX
-+ schema_table_idx index of 'schema_tables' element
-+
-+ RETURN
-+ 0 success
-+ 1 error
-+*/
-+
-+int make_schema_select(THD *thd, SELECT_LEX *sel,
-+ enum enum_schema_tables schema_table_idx)
-+{
-+ ST_SCHEMA_TABLE *schema_table= get_schema_table(schema_table_idx);
-+ LEX_STRING db, table;
-+ DBUG_ENTER("mysql_schema_select");
-+ /*
-+ We have to make non const db_name & table_name
-+ because of lower_case_table_names
-+ */
-+ make_lex_string(thd, &db, information_schema_name.str,
-+ information_schema_name.length, 0);
-+ make_lex_string(thd, &table, schema_table->table_name,
-+ strlen(schema_table->table_name), 0);
-+ if (schema_table->old_format(thd, schema_table) || /* Handle old syntax */
-+ !sel->add_table_to_list(thd, new Table_ident(thd, db, table, 0),
-+ 0, 0, TL_READ, (List<String> *) 0,
-+ (List<String> *) 0))
-+ {
-+ DBUG_RETURN(1);
-+ }
-+ DBUG_RETURN(0);
-+}
-+
-+
-+/*
-+ Fill temporary schema tables before SELECT
-+
-+ SYNOPSIS
-+ get_schema_tables_result()
-+ join join which use schema tables
-+ executed_place place where I_S table processed
-+
-+ RETURN
-+ FALSE success
-+ TRUE error
-+*/
-+
-+bool get_schema_tables_result(JOIN *join,
-+ enum enum_schema_table_state executed_place)
-+{
-+ JOIN_TAB *tmp_join_tab= join->join_tab+join->tables;
-+ THD *thd= join->thd;
-+ LEX *lex= thd->lex;
-+ bool result= 0;
-+ DBUG_ENTER("get_schema_tables_result");
-+
-+ thd->no_warnings_for_error= 1;
-+ for (JOIN_TAB *tab= join->join_tab; tab < tmp_join_tab; tab++)
-+ {
-+ if (!tab->table || !tab->table->pos_in_table_list)
-+ break;
-+
-+ TABLE_LIST *table_list= tab->table->pos_in_table_list;
-+ if (table_list->schema_table && thd->fill_derived_tables())
-+ {
-+ bool is_subselect= (&lex->unit != lex->current_select->master_unit() &&
-+ lex->current_select->master_unit()->item);
-+ /*
-+ If schema table is already processed and
-+ the statement is not a subselect then
-+ we don't need to fill this table again.
-+ If schema table is already processed and
-+ schema_table_state != executed_place then
-+ table is already processed and
-+ we should skip second data processing.
-+ */
-+ if (table_list->schema_table_state &&
-+ (!is_subselect || table_list->schema_table_state != executed_place))
-+ continue;
-+
-+ /*
-+ if table is used in a subselect and
-+ table has been processed earlier with the same
-+ 'executed_place' value then we should refresh the table.
-+ */
-+ if (table_list->schema_table_state && is_subselect)
-+ {
-+ table_list->table->file->extra(HA_EXTRA_RESET_STATE);
-+ table_list->table->file->delete_all_rows();
-+ free_io_cache(table_list->table);
-+ filesort_free_buffers(table_list->table,1);
-+ table_list->table->null_row= 0;
-+ }
-+ else
-+ table_list->table->file->records= 0;
-+
-+ if (table_list->schema_table->fill_table(thd, table_list,
-+ tab->select_cond))
-+ {
-+ result= 1;
-+ join->error= 1;
-+ table_list->schema_table_state= executed_place;
-+ break;
-+ }
-+ table_list->schema_table_state= executed_place;
-+ }
-+ }
-+ thd->no_warnings_for_error= 0;
-+ DBUG_RETURN(result);
-+}
-+
-+
-+ST_FIELD_INFO schema_fields_info[]=
-+{
-+ {"CATALOG_NAME", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
-+ {"SCHEMA_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Database"},
-+ {"DEFAULT_CHARACTER_SET_NAME", 64, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"DEFAULT_COLLATION_NAME", 64, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"SQL_PATH", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
-+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
-+};
-+
-+
-+ST_FIELD_INFO tables_fields_info[]=
-+{
-+ {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
-+ {"TABLE_SCHEMA",NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Name"},
-+ {"TABLE_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"ENGINE", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, "Engine"},
-+ {"VERSION", 21 , MYSQL_TYPE_LONG, 0, 1, "Version"},
-+ {"ROW_FORMAT", 10, MYSQL_TYPE_STRING, 0, 1, "Row_format"},
-+ {"TABLE_ROWS", 21 , MYSQL_TYPE_LONG, 0, 1, "Rows"},
-+ {"AVG_ROW_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, "Avg_row_length"},
-+ {"DATA_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, "Data_length"},
-+ {"MAX_DATA_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, "Max_data_length"},
-+ {"INDEX_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, "Index_length"},
-+ {"DATA_FREE", 21 , MYSQL_TYPE_LONG, 0, 1, "Data_free"},
-+ {"AUTO_INCREMENT", 21 , MYSQL_TYPE_LONG, 0, 1, "Auto_increment"},
-+ {"CREATE_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Create_time"},
-+ {"UPDATE_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Update_time"},
-+ {"CHECK_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Check_time"},
-+ {"TABLE_COLLATION", 64, MYSQL_TYPE_STRING, 0, 1, "Collation"},
-+ {"CHECKSUM", 21 , MYSQL_TYPE_LONG, 0, 1, "Checksum"},
-+ {"CREATE_OPTIONS", 255, MYSQL_TYPE_STRING, 0, 1, "Create_options"},
-+ {"TABLE_COMMENT", 80, MYSQL_TYPE_STRING, 0, 0, "Comment"},
-+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
-+};
-+
-+
-+ST_FIELD_INFO columns_fields_info[]=
-+{
-+ {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
-+ {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"COLUMN_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Field"},
-+ {"ORDINAL_POSITION", 21 , MYSQL_TYPE_LONG, 0, 0, 0},
-+ {"COLUMN_DEFAULT", MAX_FIELD_VARCHARLENGTH, MYSQL_TYPE_STRING, 0, 1, "Default"},
-+ {"IS_NULLABLE", 3, MYSQL_TYPE_STRING, 0, 0, "Null"},
-+ {"DATA_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"CHARACTER_MAXIMUM_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0},
-+ {"CHARACTER_OCTET_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0},
-+ {"NUMERIC_PRECISION", 21 , MYSQL_TYPE_LONG, 0, 1, 0},
-+ {"NUMERIC_SCALE", 21 , MYSQL_TYPE_LONG, 0, 1, 0},
-+ {"CHARACTER_SET_NAME", 64, MYSQL_TYPE_STRING, 0, 1, 0},
-+ {"COLLATION_NAME", 64, MYSQL_TYPE_STRING, 0, 1, "Collation"},
-+ {"COLUMN_TYPE", 65535, MYSQL_TYPE_STRING, 0, 0, "Type"},
-+ {"COLUMN_KEY", 3, MYSQL_TYPE_STRING, 0, 0, "Key"},
-+ {"EXTRA", 20, MYSQL_TYPE_STRING, 0, 0, "Extra"},
-+ {"PRIVILEGES", 80, MYSQL_TYPE_STRING, 0, 0, "Privileges"},
-+ {"COLUMN_COMMENT", 255, MYSQL_TYPE_STRING, 0, 0, "Comment"},
-+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
-+};
-+
-+
-+ST_FIELD_INFO charsets_fields_info[]=
-+{
-+ {"CHARACTER_SET_NAME", 64, MYSQL_TYPE_STRING, 0, 0, "Charset"},
-+ {"DEFAULT_COLLATE_NAME", 64, MYSQL_TYPE_STRING, 0, 0, "Default collation"},
-+ {"DESCRIPTION", 60, MYSQL_TYPE_STRING, 0, 0, "Description"},
-+ {"MAXLEN", 3 ,MYSQL_TYPE_LONG, 0, 0, "Maxlen"},
-+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
-+};
-+
-+
-+ST_FIELD_INFO collation_fields_info[]=
-+{
-+ {"COLLATION_NAME", 64, MYSQL_TYPE_STRING, 0, 0, "Collation"},
-+ {"CHARACTER_SET_NAME", 64, MYSQL_TYPE_STRING, 0, 0, "Charset"},
-+ {"ID", 11, MYSQL_TYPE_LONG, 0, 0, "Id"},
-+ {"IS_DEFAULT", 3, MYSQL_TYPE_STRING, 0, 0, "Default"},
-+ {"IS_COMPILED", 3, MYSQL_TYPE_STRING, 0, 0, "Compiled"},
-+ {"SORTLEN", 3 ,MYSQL_TYPE_LONG, 0, 0, "Sortlen"},
-+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
-+};
-+
-+
-+ST_FIELD_INFO coll_charset_app_fields_info[]=
-+{
-+ {"COLLATION_NAME", 64, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"CHARACTER_SET_NAME", 64, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
-+};
-+
-+
-+ST_FIELD_INFO proc_fields_info[]=
-+{
-+ {"SPECIFIC_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"ROUTINE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
-+ {"ROUTINE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Db"},
-+ {"ROUTINE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Name"},
-+ {"ROUTINE_TYPE", 9, MYSQL_TYPE_STRING, 0, 0, "Type"},
-+ {"DTD_IDENTIFIER", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
-+ {"ROUTINE_BODY", 8, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"ROUTINE_DEFINITION", 65535, MYSQL_TYPE_STRING, 0, 1, 0},
-+ {"EXTERNAL_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
-+ {"EXTERNAL_LANGUAGE", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
-+ {"PARAMETER_STYLE", 8, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"IS_DETERMINISTIC", 3, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"SQL_DATA_ACCESS", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"SQL_PATH", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
-+ {"SECURITY_TYPE", 7, MYSQL_TYPE_STRING, 0, 0, "Security_type"},
-+ {"CREATED", 0, MYSQL_TYPE_TIMESTAMP, 0, 0, "Created"},
-+ {"LAST_ALTERED", 0, MYSQL_TYPE_TIMESTAMP, 0, 0, "Modified"},
-+ {"SQL_MODE", 65535, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"ROUTINE_COMMENT", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Comment"},
-+ {"DEFINER", 77, MYSQL_TYPE_STRING, 0, 0, "Definer"},
-+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
-+};
-+
-+
-+ST_FIELD_INFO stat_fields_info[]=
-+{
-+ {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
-+ {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table"},
-+ {"NON_UNIQUE", 1, MYSQL_TYPE_LONG, 0, 0, "Non_unique"},
-+ {"INDEX_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"INDEX_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Key_name"},
-+ {"SEQ_IN_INDEX", 2, MYSQL_TYPE_LONG, 0, 0, "Seq_in_index"},
-+ {"COLUMN_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Column_name"},
-+ {"COLLATION", 1, MYSQL_TYPE_STRING, 0, 1, "Collation"},
-+ {"CARDINALITY", 21, MYSQL_TYPE_LONG, 0, 1, "Cardinality"},
-+ {"SUB_PART", 3, MYSQL_TYPE_LONG, 0, 1, "Sub_part"},
-+ {"PACKED", 10, MYSQL_TYPE_STRING, 0, 1, "Packed"},
-+ {"NULLABLE", 3, MYSQL_TYPE_STRING, 0, 0, "Null"},
-+ {"INDEX_TYPE", 16, MYSQL_TYPE_STRING, 0, 0, "Index_type"},
-+ {"COMMENT", 16, MYSQL_TYPE_STRING, 0, 1, "Comment"},
-+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
-+};
-+
-+
-+ST_FIELD_INFO view_fields_info[]=
-+{
-+ {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
-+ {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"VIEW_DEFINITION", 65535, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"CHECK_OPTION", 8, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"IS_UPDATABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"DEFINER", 77, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"SECURITY_TYPE", 7, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
-+};
-+
-+
-+ST_FIELD_INFO user_privileges_fields_info[]=
-+{
-+ {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
-+ {"PRIVILEGE_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
-+};
-+
-+
-+ST_FIELD_INFO schema_privileges_fields_info[]=
-+{
-+ {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
-+ {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"PRIVILEGE_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
-+};
-+
-+
-+ST_FIELD_INFO table_privileges_fields_info[]=
-+{
-+ {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
-+ {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"PRIVILEGE_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
-+};
-+
-+
-+ST_FIELD_INFO column_privileges_fields_info[]=
-+{
-+ {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
-+ {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"COLUMN_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"PRIVILEGE_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
-+};
-+
-+
-+ST_FIELD_INFO table_constraints_fields_info[]=
-+{
-+ {"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
-+ {"CONSTRAINT_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"CONSTRAINT_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"CONSTRAINT_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
-+};
-+
-+
-+ST_FIELD_INFO key_column_usage_fields_info[]=
-+{
-+ {"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
-+ {"CONSTRAINT_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"CONSTRAINT_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
-+ {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"COLUMN_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"ORDINAL_POSITION", 10 ,MYSQL_TYPE_LONG, 0, 0, 0},
-+ {"POSITION_IN_UNIQUE_CONSTRAINT", 10 ,MYSQL_TYPE_LONG, 0, 1, 0},
-+ {"REFERENCED_TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
-+ {"REFERENCED_TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
-+ {"REFERENCED_COLUMN_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
-+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
-+};
-+
-+
-+ST_FIELD_INFO table_names_fields_info[]=
-+{
-+ {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
-+ {"TABLE_SCHEMA",NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Tables_in_"},
-+ {"TABLE_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table_type"},
-+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
-+};
-+
-+
-+ST_FIELD_INFO open_tables_fields_info[]=
-+{
-+ {"Database", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Database"},
-+ {"Table",NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table"},
-+ {"In_use", 1, MYSQL_TYPE_LONG, 0, 0, "In_use"},
-+ {"Name_locked", 4, MYSQL_TYPE_LONG, 0, 0, "Name_locked"},
-+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
-+};
-+
-+
-+ST_FIELD_INFO triggers_fields_info[]=
-+{
-+ {"TRIGGER_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
-+ {"TRIGGER_SCHEMA",NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"TRIGGER_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Trigger"},
-+ {"EVENT_MANIPULATION", 6, MYSQL_TYPE_STRING, 0, 0, "Event"},
-+ {"EVENT_OBJECT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
-+ {"EVENT_OBJECT_SCHEMA",NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"EVENT_OBJECT_TABLE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table"},
-+ {"ACTION_ORDER", 4, MYSQL_TYPE_LONG, 0, 0, 0},
-+ {"ACTION_CONDITION", 65535, MYSQL_TYPE_STRING, 0, 1, 0},
-+ {"ACTION_STATEMENT", 65535, MYSQL_TYPE_STRING, 0, 0, "Statement"},
-+ {"ACTION_ORIENTATION", 9, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"ACTION_TIMING", 6, MYSQL_TYPE_STRING, 0, 0, "Timing"},
-+ {"ACTION_REFERENCE_OLD_TABLE", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
-+ {"ACTION_REFERENCE_NEW_TABLE", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
-+ {"ACTION_REFERENCE_OLD_ROW", 3, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"ACTION_REFERENCE_NEW_ROW", 3, MYSQL_TYPE_STRING, 0, 0, 0},
-+ {"CREATED", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Created"},
-+ {"SQL_MODE", 65535, MYSQL_TYPE_STRING, 0, 0, "sql_mode"},
-+ {"DEFINER", 65535, MYSQL_TYPE_STRING, 0, 0, "Definer"},
-+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
-+};
-+
-+
-+ST_FIELD_INFO variables_fields_info[]=
-+{
-+ {"Variable_name", 80, MYSQL_TYPE_STRING, 0, 0, "Variable_name"},
-+ {"Value", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, "Value"},
-+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
-+};
-+
-+
-+/*
-+ Description of ST_FIELD_INFO in table.h
-+*/
-+
-+ST_SCHEMA_TABLE schema_tables[]=
-+{
-+ {"CHARACTER_SETS", charsets_fields_info, create_schema_table,
-+ fill_schema_charsets, make_character_sets_old_format, 0, -1, -1, 0},
-+ {"COLLATIONS", collation_fields_info, create_schema_table,
-+ fill_schema_collation, make_old_format, 0, -1, -1, 0},
-+ {"COLLATION_CHARACTER_SET_APPLICABILITY", coll_charset_app_fields_info,
-+ create_schema_table, fill_schema_coll_charset_app, 0, 0, -1, -1, 0},
-+ {"COLUMNS", columns_fields_info, create_schema_table,
-+ get_all_tables, make_columns_old_format, get_schema_column_record, 1, 2, 0},
-+ {"COLUMN_PRIVILEGES", column_privileges_fields_info, create_schema_table,
-+ fill_schema_column_privileges, 0, 0, -1, -1, 0},
-+ {"KEY_COLUMN_USAGE", key_column_usage_fields_info, create_schema_table,
-+ get_all_tables, 0, get_schema_key_column_usage_record, 4, 5, 0},
-+ {"OPEN_TABLES", open_tables_fields_info, create_schema_table,
-+ fill_open_tables, make_old_format, 0, -1, -1, 1},
-+ {"ROUTINES", proc_fields_info, create_schema_table,
-+ fill_schema_proc, make_proc_old_format, 0, -1, -1, 0},
-+ {"SCHEMATA", schema_fields_info, create_schema_table,
-+ fill_schema_shemata, make_schemata_old_format, 0, 1, -1, 0},
-+ {"SCHEMA_PRIVILEGES", schema_privileges_fields_info, create_schema_table,
-+ fill_schema_schema_privileges, 0, 0, -1, -1, 0},
-+ {"STATISTICS", stat_fields_info, create_schema_table,
-+ get_all_tables, make_old_format, get_schema_stat_record, 1, 2, 0},
-+ {"STATUS", variables_fields_info, create_schema_table, fill_status,
-+ make_old_format, 0, -1, -1, 1},
-+ {"TABLES", tables_fields_info, create_schema_table,
-+ get_all_tables, make_old_format, get_schema_tables_record, 1, 2, 0},
-+ {"TABLE_CONSTRAINTS", table_constraints_fields_info, create_schema_table,
-+ get_all_tables, 0, get_schema_constraints_record, 3, 4, 0},
-+ {"TABLE_NAMES", table_names_fields_info, create_schema_table,
-+ get_all_tables, make_table_names_old_format, 0, 1, 2, 1},
-+ {"TABLE_PRIVILEGES", table_privileges_fields_info, create_schema_table,
-+ fill_schema_table_privileges, 0, 0, -1, -1, 0},
-+ {"TRIGGERS", triggers_fields_info, create_schema_table,
-+ get_all_tables, make_old_format, get_schema_triggers_record, 5, 6, 0},
-+ {"USER_PRIVILEGES", user_privileges_fields_info, create_schema_table,
-+ fill_schema_user_privileges, 0, 0, -1, -1, 0},
-+ {"VARIABLES", variables_fields_info, create_schema_table, fill_variables,
-+ make_old_format, 0, -1, -1, 1},
-+ {"VIEWS", view_fields_info, create_schema_table,
-+ get_all_tables, 0, get_schema_views_record, 1, 2, 0},
-+ {0, 0, 0, 0, 0, 0, 0, 0, 0}
-+};
-+
-+
-+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
-+template class List_iterator_fast<char>;
-+template class List<char>;
-+#endif
Copied: branches/etch-5.0/debian/patches/92_SECURITY_CVE-2007-2692_thd_privs.dpatch (from rev 967, branches/etch-5.0/debian/patches/92_SECURITY_CVE-2007-2691_thd_privs.dpatch)
===================================================================
--- branches/etch-5.0/debian/patches/92_SECURITY_CVE-2007-2692_thd_privs.dpatch (rev 0)
+++ branches/etch-5.0/debian/patches/92_SECURITY_CVE-2007-2692_thd_privs.dpatch 2007-11-06 21:06:03 UTC (rev 968)
@@ -0,0 +1,13878 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## 92_SECURITY_CVE-2007-2692_thd_privs.dpatch by <seanius at debian.org>
+##
+## DP: taken from http://lists.mysql.com/commits/23293
+## DP: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2007-2692
+
+ at DPATCH@
+diff -urNad mysql-5.0-etch~/sql/mysql_priv.h mysql-5.0-etch/sql/mysql_priv.h
+--- mysql-5.0-etch~/sql/mysql_priv.h 2007-05-28 18:56:15.000000000 +0200
++++ mysql-5.0-etch/sql/mysql_priv.h 2007-05-28 19:12:52.000000000 +0200
+@@ -930,6 +930,8 @@
+ int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
+ bool get_schema_tables_result(JOIN *join,
+ enum enum_schema_table_state executed_place);
++enum enum_schema_tables get_schema_table_idx(ST_SCHEMA_TABLE *schema_table);
++
+ #define is_schema_db(X) \
+ !my_strcasecmp(system_charset_info, information_schema_name.str, (X))
+
+diff -urNad mysql-5.0-etch~/sql/mysql_priv.h.orig mysql-5.0-etch/sql/mysql_priv.h.orig
+--- mysql-5.0-etch~/sql/mysql_priv.h.orig 1970-01-01 01:00:00.000000000 +0100
++++ mysql-5.0-etch/sql/mysql_priv.h.orig 2007-05-28 18:56:15.000000000 +0200
+@@ -0,0 +1,1685 @@
++/* Copyright (C) 2000-2003 MySQL AB
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
++
++/*
++ Mostly this file is used in the server. But a little part of it is used in
++ mysqlbinlog too (definition of SELECT_DISTINCT and others).
++ The consequence is that 90% of the file is wrapped in #ifndef MYSQL_CLIENT,
++ except the part which must be in the server and in the client.
++*/
++
++#ifndef MYSQL_CLIENT
++
++#include <my_global.h>
++#include <mysql_version.h>
++#include <mysql_embed.h>
++#include <my_sys.h>
++#include <my_time.h>
++#include <m_string.h>
++#include <hash.h>
++#include <signal.h>
++#include <thr_lock.h>
++#include <my_base.h> /* Needed by field.h */
++#include "sql_bitmap.h"
++#include "sql_array.h"
++
++#ifdef __EMX__
++#undef write /* remove pthread.h macro definition for EMX */
++#endif
++
++/* TODO convert all these three maps to Bitmap classes */
++typedef ulonglong table_map; /* Used for table bits in join */
++#if MAX_INDEXES <= 64
++typedef Bitmap<64> key_map; /* Used for finding keys */
++#else
++typedef Bitmap<((MAX_INDEXES+7)/8*8)> key_map; /* Used for finding keys */
++#endif
++typedef ulong key_part_map; /* Used for finding key parts */
++typedef ulong nesting_map; /* Used for flags of nesting constructs */
++/*
++ Used to identify NESTED_JOIN structures within a join (applicable only to
++ structures that have not been simplified away and embed more the one
++ element)
++*/
++typedef ulonglong nested_join_map;
++
++/* query_id */
++typedef ulonglong query_id_t;
++extern query_id_t query_id;
++
++/* increment query_id and return it. */
++inline query_id_t next_query_id() { return query_id++; }
++
++/* useful constants */
++extern const key_map key_map_empty;
++extern key_map key_map_full; /* Should be threaded as const */
++extern const char *primary_key_name;
++
++#include "mysql_com.h"
++#include <violite.h>
++#include "unireg.h"
++
++void init_sql_alloc(MEM_ROOT *root, uint block_size, uint pre_alloc_size);
++gptr sql_alloc(unsigned size);
++gptr sql_calloc(unsigned size);
++char *sql_strdup(const char *str);
++char *sql_strmake(const char *str,uint len);
++gptr sql_memdup(const void * ptr,unsigned size);
++void sql_element_free(void *ptr);
++char *sql_strmake_with_convert(const char *str, uint32 arg_length,
++ CHARSET_INFO *from_cs,
++ uint32 max_res_length,
++ CHARSET_INFO *to_cs, uint32 *result_length);
++void kill_one_thread(THD *thd, ulong id, bool only_kill_query);
++bool net_request_file(NET* net, const char* fname);
++char* query_table_status(THD *thd,const char *db,const char *table_name);
++
++#define x_free(A) { my_free((gptr) (A),MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR)); }
++#define safeFree(x) { if(x) { my_free((gptr) x,MYF(0)); x = NULL; } }
++#define PREV_BITS(type,A) ((type) (((type) 1 << (A)) -1))
++#define all_bits_set(A,B) ((A) & (B) != (B))
++
++extern CHARSET_INFO *system_charset_info, *files_charset_info ;
++extern CHARSET_INFO *national_charset_info, *table_alias_charset;
++
++
++enum Derivation
++{
++ DERIVATION_IGNORABLE= 5,
++ DERIVATION_COERCIBLE= 4,
++ DERIVATION_SYSCONST= 3,
++ DERIVATION_IMPLICIT= 2,
++ DERIVATION_NONE= 1,
++ DERIVATION_EXPLICIT= 0
++};
++
++
++typedef struct my_locale_st
++{
++ const char *name;
++ const char *description;
++ const bool is_ascii;
++ TYPELIB *month_names;
++ TYPELIB *ab_month_names;
++ TYPELIB *day_names;
++ TYPELIB *ab_day_names;
++#ifdef __cplusplus
++ my_locale_st(const char *name_par, const char *descr_par, bool is_ascii_par,
++ TYPELIB *month_names_par, TYPELIB *ab_month_names_par,
++ TYPELIB *day_names_par, TYPELIB *ab_day_names_par) :
++ name(name_par), description(descr_par), is_ascii(is_ascii_par),
++ month_names(month_names_par), ab_month_names(ab_month_names_par),
++ day_names(day_names_par), ab_day_names(ab_day_names_par)
++ {}
++#endif
++} MY_LOCALE;
++
++extern MY_LOCALE my_locale_en_US;
++extern MY_LOCALE *my_locales[];
++
++MY_LOCALE *my_locale_by_name(const char *name);
++
++/***************************************************************************
++ Configuration parameters
++****************************************************************************/
++
++#define ACL_CACHE_SIZE 256
++#define MAX_PASSWORD_LENGTH 32
++#define HOST_CACHE_SIZE 128
++#define MAX_ACCEPT_RETRY 10 // Test accept this many times
++#define MAX_FIELDS_BEFORE_HASH 32
++#define USER_VARS_HASH_SIZE 16
++#define TABLE_OPEN_CACHE_MIN 64
++#define TABLE_OPEN_CACHE_DEFAULT 64
++
++/*
++ Value of 9236 discovered through binary search 2006-09-26 on Ubuntu Dapper
++ Drake, libc6 2.3.6-0ubuntu2, Linux kernel 2.6.15-27-686, on x86. (Added
++ 100 bytes as reasonable buffer against growth and other environments'
++ requirements.)
++
++ Feel free to raise this by the smallest amount you can to get the
++ "execution_constants" test to pass.
++ */
++#define STACK_MIN_SIZE 10788 // Abort if less stack during eval.
++
++#define STACK_MIN_SIZE_FOR_OPEN 1024*80
++#define STACK_BUFF_ALLOC 256 // For stack overrun checks
++#ifndef MYSQLD_NET_RETRY_COUNT
++#define MYSQLD_NET_RETRY_COUNT 10 // Abort read after this many int.
++#endif
++#define TEMP_POOL_SIZE 128
++
++#define QUERY_ALLOC_BLOCK_SIZE 8192
++#define QUERY_ALLOC_PREALLOC_SIZE 8192
++#define TRANS_ALLOC_BLOCK_SIZE 4096
++#define TRANS_ALLOC_PREALLOC_SIZE 4096
++#define RANGE_ALLOC_BLOCK_SIZE 2048
++#define ACL_ALLOC_BLOCK_SIZE 1024
++#define UDF_ALLOC_BLOCK_SIZE 1024
++#define TABLE_ALLOC_BLOCK_SIZE 1024
++#define BDB_LOG_ALLOC_BLOCK_SIZE 1024
++#define WARN_ALLOC_BLOCK_SIZE 2048
++#define WARN_ALLOC_PREALLOC_SIZE 1024
++
++/*
++ The following parameters is to decide when to use an extra cache to
++ optimise seeks when reading a big table in sorted order
++*/
++#define MIN_FILE_LENGTH_TO_USE_ROW_CACHE (10L*1024*1024)
++#define MIN_ROWS_TO_USE_TABLE_CACHE 100
++#define MIN_ROWS_TO_USE_BULK_INSERT 100
++
++/*
++ The following is used to decide if MySQL should use table scanning
++ instead of reading with keys. The number says how many evaluation of the
++ WHERE clause is comparable to reading one extra row from a table.
++*/
++#define TIME_FOR_COMPARE 5 // 5 compares == one read
++
++/*
++ Number of comparisons of table rowids equivalent to reading one row from a
++ table.
++*/
++#define TIME_FOR_COMPARE_ROWID (TIME_FOR_COMPARE*2)
++
++/*
++ For sequential disk seeks the cost formula is:
++ DISK_SEEK_BASE_COST + DISK_SEEK_PROP_COST * #blocks_to_skip
++
++ The cost of average seek
++ DISK_SEEK_BASE_COST + DISK_SEEK_PROP_COST*BLOCKS_IN_AVG_SEEK =1.0.
++*/
++#define DISK_SEEK_BASE_COST ((double)0.5)
++
++#define BLOCKS_IN_AVG_SEEK 128
++
++#define DISK_SEEK_PROP_COST ((double)0.5/BLOCKS_IN_AVG_SEEK)
++
++
++/*
++ Number of rows in a reference table when refereed through a not unique key.
++ This value is only used when we don't know anything about the key
++ distribution.
++*/
++#define MATCHING_ROWS_IN_OTHER_TABLE 10
++
++/* Don't pack string keys shorter than this (if PACK_KEYS=1 isn't used) */
++#define KEY_DEFAULT_PACK_LENGTH 8
++
++/* Characters shown for the command in 'show processlist' */
++#define PROCESS_LIST_WIDTH 100
++
++#define PRECISION_FOR_DOUBLE 53
++#define PRECISION_FOR_FLOAT 24
++
++/* The following can also be changed from the command line */
++#define CONNECT_TIMEOUT 5 // Do not wait long for connect
++#define DEFAULT_CONCURRENCY 10
++#define DELAYED_LIMIT 100 /* pause after xxx inserts */
++#define DELAYED_QUEUE_SIZE 1000
++#define DELAYED_WAIT_TIMEOUT 5*60 /* Wait for delayed insert */
++#define FLUSH_TIME 0 /* Don't flush tables */
++#define MAX_CONNECT_ERRORS 10 // errors before disabling host
++
++#ifdef HAVE_INNOBASE_DB
++#define IF_INNOBASE_DB(A, B) (A)
++#else
++#define IF_INNOBASE_DB(A, B) (B)
++#endif
++#ifdef __NETWARE__
++#define IF_NETWARE(A,B) (A)
++#else
++#define IF_NETWARE(A,B) (B)
++#endif
++
++#if defined(__WIN__) || defined(OS2)
++#define IF_WIN(A,B) (A)
++#undef FLUSH_TIME
++#define FLUSH_TIME 1800 /* Flush every half hour */
++
++#define INTERRUPT_PRIOR -2
++#define CONNECT_PRIOR -1
++#define WAIT_PRIOR 0
++#define QUERY_PRIOR 2
++#else
++#define IF_WIN(A,B) (B)
++#define INTERRUPT_PRIOR 10
++#define CONNECT_PRIOR 9
++#define WAIT_PRIOR 8
++#define QUERY_PRIOR 6
++#endif /* __WIN92__ */
++
++ /* Bits from testflag */
++#define TEST_PRINT_CACHED_TABLES 1
++#define TEST_NO_KEY_GROUP 2
++#define TEST_MIT_THREAD 4
++#define TEST_BLOCKING 8
++#define TEST_KEEP_TMP_TABLES 16
++#define TEST_NO_THREADS 32 /* For debugging under Linux */
++#define TEST_READCHECK 64 /* Force use of readcheck */
++#define TEST_NO_EXTRA 128
++#define TEST_CORE_ON_SIGNAL 256 /* Give core if signal */
++#define TEST_NO_STACKTRACE 512
++#define TEST_SIGINT 1024 /* Allow sigint on threads */
++#define TEST_SYNCHRONIZATION 2048 /* get server to do sleep in
++ some places */
++#endif
++
++/*
++ This is included in the server and in the client.
++ Options for select set by the yacc parser (stored in lex->options).
++
++ XXX:
++ log_event.h defines OPTIONS_WRITTEN_TO_BIN_LOG to specify what THD
++ options list are written into binlog. These options can NOT change their
++ values, or it will break replication between version.
++
++ context is encoded as following:
++ SELECT - SELECT_LEX_NODE::options
++ THD - THD::options
++ intern - neither. used only as
++ func(..., select_node->options | thd->options | OPTION_XXX, ...)
++
++ TODO: separate three contexts above, move them to separate bitfields.
++*/
++
++#define SELECT_DISTINCT (1L << 0) // SELECT, user
++#define SELECT_STRAIGHT_JOIN (1L << 1) // SELECT, user
++#define SELECT_DESCRIBE (1L << 2) // SELECT, user
++#define SELECT_SMALL_RESULT (1L << 3) // SELECT, user
++#define SELECT_BIG_RESULT (1L << 4) // SELECT, user
++#define OPTION_FOUND_ROWS (1L << 5) // SELECT, user
++#define OPTION_TO_QUERY_CACHE (1L << 6) // SELECT, user
++#define SELECT_NO_JOIN_CACHE (1L << 7) // intern
++#define OPTION_BIG_TABLES (1L << 8) // THD, user
++#define OPTION_BIG_SELECTS (1L << 9) // THD, user
++#define OPTION_LOG_OFF (1L << 10) // THD, user
++#define OPTION_UPDATE_LOG (1L << 11) // THD, user, unused
++#define TMP_TABLE_ALL_COLUMNS (1L << 12) // SELECT, intern
++#define OPTION_WARNINGS (1L << 13) // THD, user
++#define OPTION_AUTO_IS_NULL (1L << 14) // THD, user, binlog
++#define OPTION_FOUND_COMMENT (1L << 15) // SELECT, intern, parser
++#define OPTION_SAFE_UPDATES (1L << 16) // THD, user
++#define OPTION_BUFFER_RESULT (1L << 17) // SELECT, user
++#define OPTION_BIN_LOG (1L << 18) // THD, user
++#define OPTION_NOT_AUTOCOMMIT (1L << 19) // THD, user
++#define OPTION_BEGIN (1L << 20) // THD, intern
++#define OPTION_TABLE_LOCK (1L << 21) // THD, intern
++#define OPTION_QUICK (1L << 22) // SELECT (for DELETE)
++#define OPTION_QUOTE_SHOW_CREATE (1L << 23) // THD, user
++
++/* Thr following is used to detect a conflict with DISTINCT
++ in the user query has requested */
++#define SELECT_ALL (1L << 24) // SELECT, user, parser
++
++/* Set if we are updating a non-transaction safe table */
++#define OPTION_STATUS_NO_TRANS_UPDATE (1L << 25) // THD, intern
++
++/* The following can be set when importing tables in a 'wrong order'
++ to suppress foreign key checks */
++#define OPTION_NO_FOREIGN_KEY_CHECKS (1L << 26) // THD, user, binlog
++/* The following speeds up inserts to InnoDB tables by suppressing unique
++ key checks in some cases */
++#define OPTION_RELAXED_UNIQUE_CHECKS (1L << 27) // THD, user, binlog
++#define SELECT_NO_UNLOCK (1L << 28) // SELECT, intern
++#define OPTION_SCHEMA_TABLE (1L << 29) // SELECT, intern
++/* Flag set if setup_tables already done */
++#define OPTION_SETUP_TABLES_DONE (1L << 30) // intern
++/* If not set then the thread will ignore all warnings with level notes. */
++#define OPTION_SQL_NOTES (1UL << 31) // THD, user
++/*
++ Force the used temporary table to be a MyISAM table (because we will use
++ fulltext functions when reading from it.
++*/
++#define TMP_TABLE_FORCE_MYISAM (LL(1) << 32)
++
++/*
++ Maximum length of time zone name that we support
++ (Time zone name is char(64) in db). mysqlbinlog needs it.
++*/
++#define MAX_TIME_ZONE_NAME_LENGTH 72
++
++/* The rest of the file is included in the server only */
++#ifndef MYSQL_CLIENT
++
++/* Bits for different SQL modes modes (including ANSI mode) */
++#define MODE_REAL_AS_FLOAT 1
++#define MODE_PIPES_AS_CONCAT 2
++#define MODE_ANSI_QUOTES 4
++#define MODE_IGNORE_SPACE 8
++#define MODE_NOT_USED 16
++#define MODE_ONLY_FULL_GROUP_BY 32
++#define MODE_NO_UNSIGNED_SUBTRACTION 64
++#define MODE_NO_DIR_IN_CREATE 128
++#define MODE_POSTGRESQL 256
++#define MODE_ORACLE 512
++#define MODE_MSSQL 1024
++#define MODE_DB2 2048
++#define MODE_MAXDB 4096
++#define MODE_NO_KEY_OPTIONS 8192
++#define MODE_NO_TABLE_OPTIONS 16384
++#define MODE_NO_FIELD_OPTIONS 32768
++#define MODE_MYSQL323 65536
++#define MODE_MYSQL40 (MODE_MYSQL323*2)
++#define MODE_ANSI (MODE_MYSQL40*2)
++#define MODE_NO_AUTO_VALUE_ON_ZERO (MODE_ANSI*2)
++#define MODE_NO_BACKSLASH_ESCAPES (MODE_NO_AUTO_VALUE_ON_ZERO*2)
++#define MODE_STRICT_TRANS_TABLES (MODE_NO_BACKSLASH_ESCAPES*2)
++#define MODE_STRICT_ALL_TABLES (MODE_STRICT_TRANS_TABLES*2)
++#define MODE_NO_ZERO_IN_DATE (MODE_STRICT_ALL_TABLES*2)
++#define MODE_NO_ZERO_DATE (MODE_NO_ZERO_IN_DATE*2)
++#define MODE_INVALID_DATES (MODE_NO_ZERO_DATE*2)
++#define MODE_ERROR_FOR_DIVISION_BY_ZERO (MODE_INVALID_DATES*2)
++#define MODE_TRADITIONAL (MODE_ERROR_FOR_DIVISION_BY_ZERO*2)
++#define MODE_NO_AUTO_CREATE_USER (MODE_TRADITIONAL*2)
++#define MODE_HIGH_NOT_PRECEDENCE (MODE_NO_AUTO_CREATE_USER*2)
++#define MODE_NO_ENGINE_SUBSTITUTION (MODE_HIGH_NOT_PRECEDENCE*2)
++/*
++ Replication uses 8 bytes to store SQL_MODE in the binary log. The day you
++ use strictly more than 64 bits by adding one more define above, you should
++ contact the replication team because the replication code should then be
++ updated (to store more bytes on disk).
++
++ NOTE: When adding new SQL_MODE types, make sure to also add them to
++ ../scripts/mysql_create_system_tables.sh and
++ ../scripts/mysql_fix_privilege_tables.sql
++*/
++
++#define RAID_BLOCK_SIZE 1024
++
++#define MY_CHARSET_BIN_MB_MAXLEN 1
++
++// uncachable cause
++#define UNCACHEABLE_DEPENDENT 1
++#define UNCACHEABLE_RAND 2
++#define UNCACHEABLE_SIDEEFFECT 4
++// forcing to save JOIN for explain
++#define UNCACHEABLE_EXPLAIN 8
++/* Don't evaluate subqueries in prepare even if they're not correlated */
++#define UNCACHEABLE_PREPARE 16
++
++#ifdef EXTRA_DEBUG
++/*
++ Sync points allow us to force the server to reach a certain line of code
++ and block there until the client tells the server it is ok to go on.
++ The client tells the server to block with SELECT GET_LOCK()
++ and unblocks it with SELECT RELEASE_LOCK(). Used for debugging difficult
++ concurrency problems
++*/
++#define DBUG_SYNC_POINT(lock_name,lock_timeout) \
++ debug_sync_point(lock_name,lock_timeout)
++void debug_sync_point(const char* lock_name, uint lock_timeout);
++#else
++#define DBUG_SYNC_POINT(lock_name,lock_timeout)
++#endif /* EXTRA_DEBUG */
++
++/* BINLOG_DUMP options */
++
++#define BINLOG_DUMP_NON_BLOCK 1
++
++/* sql_show.cc:show_log_files() */
++#define SHOW_LOG_STATUS_FREE "FREE"
++#define SHOW_LOG_STATUS_INUSE "IN USE"
++
++struct st_table_list;
++class String;
++void view_store_options(THD *thd, st_table_list *table, String *buff);
++
++/* Options to add_table_to_list() */
++#define TL_OPTION_UPDATING 1
++#define TL_OPTION_FORCE_INDEX 2
++#define TL_OPTION_IGNORE_LEAVES 4
++#define TL_OPTION_ALIAS 8
++
++/* Some portable defines */
++
++#define portable_sizeof_char_ptr 8
++
++#define tmp_file_prefix "#sql" /* Prefix for tmp tables */
++#define tmp_file_prefix_length 4
++
++/* Flags for calc_week() function. */
++#define WEEK_MONDAY_FIRST 1
++#define WEEK_YEAR 2
++#define WEEK_FIRST_WEEKDAY 4
++
++#define STRING_BUFFER_USUAL_SIZE 80
++
++enum enum_parsing_place
++{
++ NO_MATTER,
++ IN_HAVING,
++ SELECT_LIST,
++ IN_WHERE,
++ IN_ON
++};
++
++struct st_table;
++class THD;
++
++/* Struct to handle simple linked lists */
++
++typedef struct st_sql_list {
++ uint elements;
++ byte *first;
++ byte **next;
++
++ st_sql_list() {} /* Remove gcc warning */
++ inline void empty()
++ {
++ elements=0;
++ first=0;
++ next= &first;
++ }
++ inline void link_in_list(byte *element,byte **next_ptr)
++ {
++ elements++;
++ (*next)=element;
++ next= next_ptr;
++ *next=0;
++ }
++ inline void save_and_clear(struct st_sql_list *save)
++ {
++ *save= *this;
++ empty();
++ }
++ inline void push_front(struct st_sql_list *save)
++ {
++ *save->next= first; /* link current list last */
++ first= save->first;
++ elements+= save->elements;
++ }
++ inline void push_back(struct st_sql_list *save)
++ {
++ if (save->first)
++ {
++ *next= save->first;
++ next= save->next;
++ elements+= save->elements;
++ }
++ }
++} SQL_LIST;
++
++
++extern pthread_key(THD*, THR_THD);
++inline THD *_current_thd(void)
++{
++ return my_pthread_getspecific_ptr(THD*,THR_THD);
++}
++#define current_thd _current_thd()
++
++/*
++ External variables
++*/
++extern ulong server_id, concurrency;
++
++
++typedef my_bool (*qc_engine_callback)(THD *thd, char *table_key,
++ uint key_length,
++ ulonglong *engine_data);
++#include "sql_string.h"
++#include "sql_list.h"
++#include "sql_map.h"
++#include "my_decimal.h"
++#include "handler.h"
++#include "parse_file.h"
++#include "table.h"
++#include "sql_error.h"
++#include "field.h" /* Field definitions */
++#include "protocol.h"
++#include "sql_udf.h"
++class user_var_entry;
++class Security_context;
++enum enum_var_type
++{
++ OPT_DEFAULT= 0, OPT_SESSION, OPT_GLOBAL
++};
++class sys_var;
++class Comp_creator;
++typedef Comp_creator* (*chooser_compare_func_creator)(bool invert);
++#include "item.h"
++extern my_decimal decimal_zero;
++
++/* sql_parse.cc */
++void free_items(Item *item);
++void cleanup_items(Item *item);
++class THD;
++void close_thread_tables(THD *thd, bool locked=0, bool skip_derived=0);
++bool check_one_table_access(THD *thd, ulong privilege,
++ TABLE_LIST *tables);
++bool check_single_table_access(THD *thd, ulong privilege,
++ TABLE_LIST *tables);
++bool check_routine_access(THD *thd,ulong want_access,char *db,char *name,
++ bool is_proc, bool no_errors);
++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, const char *db, const char *name, bool is_proc);
++bool multi_update_precheck(THD *thd, TABLE_LIST *tables);
++bool multi_delete_precheck(THD *thd, TABLE_LIST *tables);
++bool mysql_multi_update_prepare(THD *thd);
++bool mysql_multi_delete_prepare(THD *thd);
++bool mysql_insert_select_prepare(THD *thd);
++bool update_precheck(THD *thd, TABLE_LIST *tables);
++bool delete_precheck(THD *thd, TABLE_LIST *tables);
++bool insert_precheck(THD *thd, TABLE_LIST *tables);
++bool create_table_precheck(THD *thd, TABLE_LIST *tables,
++ TABLE_LIST *create_table);
++int append_query_string(CHARSET_INFO *csinfo,
++ String const *from, String *to);
++
++void get_default_definer(THD *thd, LEX_USER *definer);
++LEX_USER *create_default_definer(THD *thd);
++LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name);
++LEX_USER *get_current_user(THD *thd, LEX_USER *user);
++bool check_string_length(LEX_STRING *str,
++ const char *err_msg, uint max_length);
++
++enum enum_mysql_completiontype {
++ ROLLBACK_RELEASE=-2, ROLLBACK=1, ROLLBACK_AND_CHAIN=7,
++ COMMIT_RELEASE=-1, COMMIT=0, COMMIT_AND_CHAIN=6
++};
++
++int end_trans(THD *thd, enum enum_mysql_completiontype completion);
++
++Item *negate_expression(THD *thd, Item *expr);
++#include "sql_class.h"
++#include "sql_acl.h"
++#include "tztime.h"
++#include "opt_range.h"
++
++#ifdef HAVE_QUERY_CACHE
++struct Query_cache_query_flags
++{
++ unsigned int client_long_flag:1;
++ unsigned int client_protocol_41:1;
++ unsigned int more_results_exists:1;
++ unsigned int pkt_nr;
++ uint character_set_client_num;
++ uint character_set_results_num;
++ uint collation_connection_num;
++ ha_rows limit;
++ Time_zone *time_zone;
++ ulong sql_mode;
++ ulong max_sort_length;
++ ulong group_concat_max_len;
++ MY_LOCALE *lc_time_names;
++};
++#define QUERY_CACHE_FLAGS_SIZE sizeof(Query_cache_query_flags)
++#include "sql_cache.h"
++#define query_cache_store_query(A, B) query_cache.store_query(A, B)
++#define query_cache_destroy() query_cache.destroy()
++#define query_cache_result_size_limit(A) query_cache.result_size_limit(A)
++#define query_cache_init() query_cache.init()
++#define query_cache_resize(A) query_cache.resize(A)
++#define query_cache_set_min_res_unit(A) query_cache.set_min_res_unit(A)
++#define query_cache_invalidate3(A, B, C) query_cache.invalidate(A, B, C)
++#define query_cache_invalidate1(A) query_cache.invalidate(A)
++#define query_cache_send_result_to_client(A, B, C) \
++ query_cache.send_result_to_client(A, B, C)
++#define query_cache_invalidate_by_MyISAM_filename_ref \
++ &query_cache_invalidate_by_MyISAM_filename
++#else
++#define QUERY_CACHE_FLAGS_SIZE 0
++#define query_cache_store_query(A, B)
++#define query_cache_destroy()
++#define query_cache_result_size_limit(A)
++#define query_cache_init()
++#define query_cache_resize(A)
++#define query_cache_set_min_res_unit(A)
++#define query_cache_invalidate3(A, B, C)
++#define query_cache_invalidate1(A)
++#define query_cache_send_result_to_client(A, B, C) 0
++#define query_cache_invalidate_by_MyISAM_filename_ref NULL
++
++#define query_cache_abort(A)
++#define query_cache_end_of_result(A)
++#define query_cache_invalidate_by_MyISAM_filename_ref NULL
++#endif /*HAVE_QUERY_CACHE*/
++
++bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create, bool silent);
++bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create);
++bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent);
++void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, ushort flags);
++bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
++ my_bool drop_temporary);
++int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
++ bool drop_temporary, bool drop_view, bool log_query);
++int mysql_rm_table_part2_with_lock(THD *thd, TABLE_LIST *tables,
++ bool if_exists, bool drop_temporary,
++ bool log_query);
++int quick_rm_table(enum db_type base,const char *db,
++ const char *table_name);
++void close_cached_table(THD *thd, TABLE *table);
++bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list);
++bool do_rename(THD *thd, TABLE_LIST *ren_table, char *new_db,
++ char *new_table_name, char *new_table_alias,
++ bool skip_error);
++bool mysql_change_db(THD *thd,const char *name,bool no_access_check);
++void mysql_parse(THD *thd,char *inBuf,uint length);
++bool mysql_test_parse_for_slave(THD *thd,char *inBuf,uint length);
++bool is_update_query(enum enum_sql_command command);
++bool alloc_query(THD *thd, const char *packet, uint packet_length);
++void mysql_init_select(LEX *lex);
++void mysql_reset_thd_for_next_command(THD *thd);
++void mysql_init_query(THD *thd, uchar *buf, uint length);
++bool mysql_new_select(LEX *lex, bool move_down);
++void create_select_for_variable(const char *var_name);
++void mysql_init_multi_delete(LEX *lex);
++bool multi_delete_set_locks_and_link_aux_tables(LEX *lex);
++void init_max_user_conn(void);
++void init_update_queries(void);
++void free_max_user_conn(void);
++pthread_handler_t handle_one_connection(void *arg);
++pthread_handler_t handle_bootstrap(void *arg);
++void end_thread(THD *thd,bool put_in_cache);
++void flush_thread_cache();
++bool mysql_execute_command(THD *thd);
++bool do_command(THD *thd);
++bool dispatch_command(enum enum_server_command command, THD *thd,
++ char* packet, uint packet_length);
++void log_slow_statement(THD *thd);
++bool check_dup(const char *db, const char *name, TABLE_LIST *tables);
++
++bool table_cache_init(void);
++void table_cache_free(void);
++uint cached_tables(void);
++void kill_mysql(void);
++void close_connection(THD *thd, uint errcode, bool lock);
++bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
++ bool *write_to_binlog);
++bool check_access(THD *thd, ulong access, const char *db, ulong *save_priv,
++ bool no_grant, bool no_errors, bool schema_db);
++bool check_table_access(THD *thd, ulong want_access, TABLE_LIST *tables,
++ bool no_errors);
++bool check_global_access(THD *thd, ulong want_access);
++
++bool mysql_backup_table(THD* thd, TABLE_LIST* table_list);
++bool mysql_restore_table(THD* thd, TABLE_LIST* table_list);
++
++bool mysql_checksum_table(THD* thd, TABLE_LIST* table_list,
++ HA_CHECK_OPT* check_opt);
++bool mysql_check_table(THD* thd, TABLE_LIST* table_list,
++ HA_CHECK_OPT* check_opt);
++bool mysql_repair_table(THD* thd, TABLE_LIST* table_list,
++ HA_CHECK_OPT* check_opt);
++bool mysql_analyze_table(THD* thd, TABLE_LIST* table_list,
++ HA_CHECK_OPT* check_opt);
++bool mysql_optimize_table(THD* thd, TABLE_LIST* table_list,
++ HA_CHECK_OPT* check_opt);
++bool mysql_assign_to_keycache(THD* thd, TABLE_LIST* table_list,
++ LEX_STRING *key_cache_name);
++bool mysql_preload_keys(THD* thd, TABLE_LIST* table_list);
++int reassign_keycache_tables(THD* thd, KEY_CACHE *src_cache,
++ KEY_CACHE *dst_cache);
++TABLE *create_virtual_tmp_table(THD *thd, List<create_field> &field_list);
++
++bool mysql_xa_recover(THD *thd);
++
++bool check_simple_select();
++
++SORT_FIELD * make_unireg_sortorder(ORDER *order, uint *length,
++ SORT_FIELD *sortorder);
++int setup_order(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
++ List<Item> &fields, List <Item> &all_fields, ORDER *order);
++int setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
++ List<Item> &fields, List<Item> &all_fields, ORDER *order,
++ bool *hidden_group_fields);
++
++bool handle_select(THD *thd, LEX *lex, select_result *result,
++ ulong setup_tables_done_option);
++bool mysql_select(THD *thd, Item ***rref_pointer_array,
++ TABLE_LIST *tables, uint wild_num, List<Item> &list,
++ COND *conds, uint og_num, ORDER *order, ORDER *group,
++ Item *having, ORDER *proc_param, ulonglong select_type,
++ select_result *result, SELECT_LEX_UNIT *unit,
++ SELECT_LEX *select_lex);
++void free_underlaid_joins(THD *thd, SELECT_LEX *select);
++bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit,
++ select_result *result);
++int mysql_explain_select(THD *thd, SELECT_LEX *sl, char const *type,
++ select_result *result);
++bool mysql_union(THD *thd, LEX *lex, select_result *result,
++ SELECT_LEX_UNIT *unit, ulong setup_tables_done_option);
++bool mysql_handle_derived(LEX *lex, bool (*processor)(THD *thd,
++ LEX *lex,
++ TABLE_LIST *table));
++bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *t);
++bool mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *t);
++Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
++ Item ***copy_func, Field **from_field,
++ Field **def_field,
++ bool group, bool modify_item,
++ bool table_cant_handle_bit_fields,
++ bool make_copy_field,
++ uint convert_blob_length);
++void sp_prepare_create_field(THD *thd, create_field *sql_field);
++int prepare_create_field(create_field *sql_field,
++ uint *blob_columns,
++ int *timestamps, int *timestamps_with_niladic,
++ uint table_flags);
++bool mysql_create_table(THD *thd,const char *db, const char *table_name,
++ HA_CREATE_INFO *create_info,
++ List<create_field> &fields, List<Key> &keys,
++ bool tmp_table, uint select_field_count);
++
++bool mysql_alter_table(THD *thd, char *new_db, char *new_name,
++ HA_CREATE_INFO *create_info,
++ TABLE_LIST *table_list,
++ List<create_field> &fields,
++ List<Key> &keys,
++ uint order_num, ORDER *order, bool ignore,
++ ALTER_INFO *alter_info, bool do_send_ok);
++bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list, bool do_send_ok);
++bool mysql_create_like_table(THD *thd, TABLE_LIST *table,
++ HA_CREATE_INFO *create_info,
++ Table_ident *src_table);
++bool mysql_rename_table(enum db_type base,
++ const char *old_db,
++ const char * old_name,
++ const char *new_db,
++ const char * new_name);
++bool mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys);
++bool mysql_drop_index(THD *thd, TABLE_LIST *table_list,
++ ALTER_INFO *alter_info);
++bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
++ Item **conds, uint order_num, ORDER *order);
++int mysql_update(THD *thd,TABLE_LIST *tables,List<Item> &fields,
++ List<Item> &values,COND *conds,
++ uint order_num, ORDER *order, ha_rows limit,
++ enum enum_duplicates handle_duplicates, bool ignore);
++bool mysql_multi_update(THD *thd, TABLE_LIST *table_list,
++ List<Item> *fields, List<Item> *values,
++ COND *conds, ulonglong options,
++ enum enum_duplicates handle_duplicates, bool ignore,
++ SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex);
++bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
++ List<Item> &fields, List_item *values,
++ List<Item> &update_fields,
++ List<Item> &update_values, enum_duplicates duplic,
++ COND **where, bool select_insert);
++bool mysql_insert(THD *thd,TABLE_LIST *table,List<Item> &fields,
++ List<List_item> &values, List<Item> &update_fields,
++ List<Item> &update_values, enum_duplicates flag,
++ bool ignore);
++int check_that_all_fields_are_given_values(THD *thd, TABLE *entry,
++ TABLE_LIST *table_list);
++void mark_fields_used_by_triggers_for_insert_stmt(THD *thd, TABLE *table,
++ enum_duplicates duplic);
++bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds);
++bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
++ SQL_LIST *order, ha_rows rows, ulonglong options,
++ bool reset_auto_increment);
++bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok);
++bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create);
++TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update);
++TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT* mem,
++ bool *refresh, uint flags);
++bool reopen_name_locked_table(THD* thd, TABLE_LIST* table);
++TABLE *find_locked_table(THD *thd, const char *db,const char *table_name);
++bool reopen_table(TABLE *table,bool locked);
++bool reopen_tables(THD *thd,bool get_locks,bool in_refresh);
++void close_old_data_files(THD *thd, TABLE *table, bool abort_locks,
++ bool send_refresh);
++bool close_data_tables(THD *thd,const char *db, const char *table_name);
++bool wait_for_tables(THD *thd);
++bool table_is_used(TABLE *table, bool wait_for_name_lock);
++bool drop_locked_tables(THD *thd,const char *db, const char *table_name);
++void abort_locked_tables(THD *thd,const char *db, const char *table_name);
++void execute_init_command(THD *thd, sys_var_str *init_command_var,
++ rw_lock_t *var_mutex);
++extern Field *not_found_field;
++extern Field *view_ref_found;
++
++enum find_item_error_report_type {REPORT_ALL_ERRORS, REPORT_EXCEPT_NOT_FOUND,
++ IGNORE_ERRORS, REPORT_EXCEPT_NON_UNIQUE,
++ IGNORE_EXCEPT_NON_UNIQUE};
++Field *
++find_field_in_tables(THD *thd, Item_ident *item,
++ TABLE_LIST *first_table, TABLE_LIST *last_table,
++ Item **ref, find_item_error_report_type report_error,
++ bool check_privileges, bool register_tree_change);
++Field *
++find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
++ const char *name, uint length,
++ const char *item_name, const char *db_name,
++ const char *table_name, Item **ref,
++ bool check_privileges, bool allow_rowid,
++ uint *cached_field_index_ptr,
++ bool register_tree_change, TABLE_LIST **actual_table);
++Field *
++find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
++ bool allow_rowid, uint *cached_field_index_ptr);
++
++#ifdef HAVE_OPENSSL
++#include <openssl/des.h>
++struct st_des_keyblock
++{
++ DES_cblock key1, key2, key3;
++};
++struct st_des_keyschedule
++{
++ DES_key_schedule ks1, ks2, ks3;
++};
++extern char *des_key_file;
++extern struct st_des_keyschedule des_keyschedule[10];
++extern uint des_default_key;
++extern pthread_mutex_t LOCK_des_key_file;
++bool load_des_key_file(const char *file_name);
++#endif /* HAVE_OPENSSL */
++
++/* sql_do.cc */
++bool mysql_do(THD *thd, List<Item> &values);
++
++/* sql_analyse.h */
++bool append_escaped(String *to_str, String *from_str);
++
++/* sql_show.cc */
++bool mysqld_show_open_tables(THD *thd,const char *wild);
++bool mysqld_show_logs(THD *thd);
++void append_identifier(THD *thd, String *packet, const char *name,
++ uint length);
++int get_quote_char_for_identifier(THD *thd, const char *name, uint length);
++void mysqld_list_fields(THD *thd,TABLE_LIST *table, const char *wild);
++int mysqld_dump_create_info(THD *thd, TABLE_LIST *table_list, int fd);
++bool mysqld_show_create(THD *thd, TABLE_LIST *table_list);
++bool mysqld_show_create_db(THD *thd, char *dbname, HA_CREATE_INFO *create);
++
++void mysqld_list_processes(THD *thd,const char *user,bool verbose);
++int mysqld_show_status(THD *thd);
++int mysqld_show_variables(THD *thd,const char *wild);
++bool mysqld_show_storage_engines(THD *thd);
++bool mysqld_show_privileges(THD *thd);
++bool mysqld_show_column_types(THD *thd);
++bool mysqld_help (THD *thd, const char *text);
++void calc_sum_of_all_status(STATUS_VAR *to);
++
++void append_definer(THD *thd, String *buffer, const LEX_STRING *definer_user,
++ const LEX_STRING *definer_host);
++
++
++/* information schema */
++extern LEX_STRING information_schema_name;
++LEX_STRING *make_lex_string(THD *thd, LEX_STRING *lex_str,
++ const char* str, uint length,
++ bool allocate_lex_string);
++ST_SCHEMA_TABLE *find_schema_table(THD *thd, const char* table_name);
++ST_SCHEMA_TABLE *get_schema_table(enum enum_schema_tables schema_table_idx);
++int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
++ enum enum_schema_tables schema_table_idx);
++int make_schema_select(THD *thd, SELECT_LEX *sel,
++ enum enum_schema_tables schema_table_idx);
++int mysql_schema_table(THD *thd, LEX *lex, TABLE_LIST *table_list);
++int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
++int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
++int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
++int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
++bool get_schema_tables_result(JOIN *join,
++ enum enum_schema_table_state executed_place);
++#define is_schema_db(X) \
++ !my_strcasecmp(system_charset_info, information_schema_name.str, (X))
++
++/* sql_prepare.cc */
++
++void mysql_stmt_prepare(THD *thd, const char *packet, uint packet_length);
++void mysql_stmt_execute(THD *thd, char *packet, uint packet_length);
++void mysql_stmt_close(THD *thd, char *packet);
++void mysql_sql_stmt_prepare(THD *thd);
++void mysql_sql_stmt_execute(THD *thd);
++void mysql_sql_stmt_close(THD *thd);
++void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length);
++void mysql_stmt_reset(THD *thd, char *packet);
++void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length);
++void reinit_stmt_before_use(THD *thd, LEX *lex);
++
++/* sql_handler.cc */
++bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen);
++bool mysql_ha_close(THD *thd, TABLE_LIST *tables);
++bool mysql_ha_read(THD *, TABLE_LIST *,enum enum_ha_read_modes,char *,
++ List<Item> *,enum ha_rkey_function,Item *,ha_rows,ha_rows);
++int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags,
++ bool is_locked);
++void mysql_ha_mark_tables_for_reopen(THD *thd, TABLE *table);
++/* mysql_ha_flush mode_flags bits */
++#define MYSQL_HA_CLOSE_FINAL 0x00
++#define MYSQL_HA_REOPEN_ON_USAGE 0x01
++#define MYSQL_HA_FLUSH_ALL 0x02
++
++/* sql_base.cc */
++#define TMP_TABLE_KEY_EXTRA 8
++void set_item_name(Item *item,char *pos,uint length);
++bool add_field_to_list(THD *thd, char *field_name, enum enum_field_types type,
++ char *length, char *decimal,
++ uint type_modifier,
++ Item *default_value, Item *on_update_value,
++ LEX_STRING *comment,
++ char *change, List<String> *interval_list,
++ CHARSET_INFO *cs,
++ uint uint_geom_type);
++create_field * new_create_field(THD *thd, char *field_name, enum_field_types type,
++ char *length, char *decimals,
++ uint type_modifier,
++ Item *default_value, Item *on_update_value,
++ LEX_STRING *comment, char *change,
++ List<String> *interval_list, CHARSET_INFO *cs,
++ uint uint_geom_type);
++void store_position_for_column(const char *name);
++bool add_to_list(THD *thd, SQL_LIST &list,Item *group,bool asc);
++bool push_new_name_resolution_context(THD *thd,
++ TABLE_LIST *left_op,
++ TABLE_LIST *right_op);
++void add_join_on(TABLE_LIST *b,Item *expr);
++void add_join_natural(TABLE_LIST *a,TABLE_LIST *b,List<String> *using_fields);
++bool add_proc_to_list(THD *thd, Item *item);
++TABLE *unlink_open_table(THD *thd,TABLE *list,TABLE *find);
++void update_non_unique_table_error(TABLE_LIST *update,
++ const char *operation,
++ TABLE_LIST *duplicate);
++
++SQL_SELECT *make_select(TABLE *head, table_map const_tables,
++ table_map read_tables, COND *conds,
++ bool allow_null_cond, int *error);
++extern Item **not_found_item;
++Item ** find_item_in_list(Item *item, List<Item> &items, uint *counter,
++ find_item_error_report_type report_error,
++ bool *unaliased);
++bool get_key_map_from_key_list(key_map *map, TABLE *table,
++ List<String> *index_list);
++bool insert_fields(THD *thd, Name_resolution_context *context,
++ const char *db_name, const char *table_name,
++ List_iterator<Item> *it, bool any_privileges);
++bool setup_tables(THD *thd, Name_resolution_context *context,
++ List<TABLE_LIST> *from_clause, TABLE_LIST *tables,
++ Item **conds, TABLE_LIST **leaves, bool select_insert);
++bool setup_tables_and_check_access (THD *thd,
++ Name_resolution_context *context,
++ List<TABLE_LIST> *from_clause,
++ TABLE_LIST *tables, Item **conds,
++ TABLE_LIST **leaves,
++ bool select_insert,
++ ulong want_access_first,
++ ulong want_access);
++int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
++ List<Item> *sum_func_list, uint wild_num);
++bool setup_fields(THD *thd, Item** ref_pointer_array,
++ List<Item> &item, bool set_query_id,
++ List<Item> *sum_func_list, bool allow_sum_func);
++inline bool setup_fields_with_no_wrap(THD *thd, Item **ref_pointer_array,
++ List<Item> &item, bool set_query_id,
++ List<Item> *sum_func_list,
++ bool allow_sum_func)
++{
++ bool res;
++ thd->lex->select_lex.no_wrap_view_item= TRUE;
++ res= setup_fields(thd, ref_pointer_array, item, set_query_id, sum_func_list,
++ allow_sum_func);
++ thd->lex->select_lex.no_wrap_view_item= FALSE;
++ return res;
++}
++int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
++ COND **conds);
++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, uint flags);
++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, uint flags);
++int lock_tables(THD *thd, TABLE_LIST *tables, uint counter, bool *need_reopen);
++TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
++ const char *table_name, bool link_in_list);
++bool rm_temporary_table(enum db_type base, char *path);
++void free_io_cache(TABLE *entry);
++void intern_close_table(TABLE *entry);
++bool close_thread_table(THD *thd, TABLE **table_ptr);
++void close_temporary_tables(THD *thd);
++void close_tables_for_reopen(THD *thd, TABLE_LIST **tables);
++TABLE_LIST *find_table_in_list(TABLE_LIST *table,
++ st_table_list *TABLE_LIST::*link,
++ const char *db_name,
++ const char *table_name);
++TABLE_LIST *unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list);
++TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name);
++bool close_temporary_table(THD *thd, const char *db, const char *table_name);
++void close_temporary(TABLE *table, bool delete_table);
++bool rename_temporary_table(THD* thd, TABLE *table, const char *new_db,
++ const char *table_name);
++void remove_db_from_cache(const char *db);
++void flush_tables();
++bool is_equal(const LEX_STRING *a, const LEX_STRING *b);
++
++/* bits for last argument to remove_table_from_cache() */
++#define RTFC_NO_FLAG 0x0000
++#define RTFC_OWNED_BY_THD_FLAG 0x0001
++#define RTFC_WAIT_OTHER_THREAD_FLAG 0x0002
++#define RTFC_CHECK_KILLED_FLAG 0x0004
++bool remove_table_from_cache(THD *thd, const char *db, const char *table,
++ uint flags);
++
++bool close_cached_tables(THD *thd, bool wait_for_refresh, TABLE_LIST *tables);
++void copy_field_from_tmp_record(Field *field,int offset);
++bool fill_record(THD *thd, Field **field, List<Item> &values,
++ bool ignore_errors);
++bool fill_record_n_invoke_before_triggers(THD *thd, List<Item> &fields,
++ List<Item> &values,
++ bool ignore_errors,
++ Table_triggers_list *triggers,
++ enum trg_event_type event);
++bool fill_record_n_invoke_before_triggers(THD *thd, Field **field,
++ List<Item> &values,
++ bool ignore_errors,
++ Table_triggers_list *triggers,
++ enum trg_event_type event);
++OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *db, const char *wild);
++
++inline TABLE_LIST *find_table_in_global_list(TABLE_LIST *table,
++ const char *db_name,
++ const char *table_name)
++{
++ return find_table_in_list(table, &TABLE_LIST::next_global,
++ db_name, table_name);
++}
++
++inline TABLE_LIST *find_table_in_local_list(TABLE_LIST *table,
++ const char *db_name,
++ const char *table_name)
++{
++ return find_table_in_list(table, &TABLE_LIST::next_local,
++ db_name, table_name);
++}
++
++
++/* sql_calc.cc */
++bool eval_const_cond(COND *cond);
++
++/* sql_load.cc */
++bool mysql_load(THD *thd, sql_exchange *ex, TABLE_LIST *table_list,
++ List<Item> &fields_vars, List<Item> &set_fields,
++ List<Item> &set_values_list,
++ enum enum_duplicates handle_duplicates, bool ignore,
++ bool local_file);
++int write_record(THD *thd, TABLE *table, COPY_INFO *info);
++
++/* sql_manager.cc */
++/* bits set in manager_status */
++#define MANAGER_BERKELEY_LOG_CLEANUP (1L << 0)
++extern ulong volatile manager_status;
++extern bool volatile manager_thread_in_use, mqh_used;
++extern pthread_t manager_thread;
++pthread_handler_t handle_manager(void *arg);
++
++/* sql_test.cc */
++#ifndef DBUG_OFF
++void print_where(COND *cond,const char *info);
++void print_cached_tables(void);
++void TEST_filesort(SORT_FIELD *sortorder,uint s_length);
++void print_plan(JOIN* join,uint idx, double record_count, double read_time,
++ double current_read_time, const char *info);
++#endif
++void mysql_print_status();
++/* key.cc */
++int find_ref_key(TABLE *form,Field *field, uint *offset);
++void key_copy(byte *to_key, byte *from_record, KEY *key_info, uint key_length);
++void key_restore(byte *to_record, byte *from_key, KEY *key_info,
++ uint key_length);
++bool key_cmp_if_same(TABLE *form,const byte *key,uint index,uint key_length);
++void key_unpack(String *to,TABLE *form,uint index);
++bool is_key_used(TABLE *table, uint idx, List<Item> &fields);
++int key_cmp(KEY_PART_INFO *key_part, const byte *key, uint key_length);
++
++bool init_errmessage(void);
++void sql_perror(const char *message);
++
++void vprint_msg_to_log(enum loglevel level, const char *format, va_list args);
++void sql_print_error(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2);
++void sql_print_warning(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2);
++void sql_print_information(const char *format, ...)
++ ATTRIBUTE_FORMAT(printf, 1, 2);
++
++
++bool fn_format_relative_to_data_home(my_string to, const char *name,
++ const char *dir, const char *extension);
++File open_binlog(IO_CACHE *log, const char *log_file_name,
++ const char **errmsg);
++
++/* mysqld.cc */
++extern void MYSQLerror(const char*);
++void refresh_status(THD *thd);
++
++/* item_func.cc */
++extern bool check_reserved_words(LEX_STRING *name);
++
++/* strfunc.cc */
++ulonglong find_set(TYPELIB *lib, const char *x, uint length, CHARSET_INFO *cs,
++ char **err_pos, uint *err_len, bool *set_warning);
++uint find_type(TYPELIB *lib, const char *find, uint length, bool part_match);
++uint find_type2(TYPELIB *lib, const char *find, uint length, CHARSET_INFO *cs);
++void unhex_type2(TYPELIB *lib);
++uint check_word(TYPELIB *lib, const char *val, const char *end,
++ const char **end_of_word);
++
++
++bool is_keyword(const char *name, uint len);
++
++#define MY_DB_OPT_FILE "db.opt"
++bool check_db_dir_existence(const char *db_name);
++bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create);
++bool load_db_opt_by_name(THD *thd, const char *db_name,
++ HA_CREATE_INFO *db_create_info);
++bool my_dbopt_init(void);
++void my_dbopt_cleanup(void);
++void my_dbopt_free(void);
++
++/*
++ External variables
++*/
++
++extern time_t start_time;
++extern char *mysql_data_home,server_version[SERVER_VERSION_LENGTH],
++ mysql_real_data_home[], *opt_mysql_tmpdir, mysql_charsets_dir[],
++ def_ft_boolean_syntax[sizeof(ft_boolean_syntax)];
++#define mysql_tmpdir (my_tmpdir(&mysql_tmpdir_list))
++extern MY_TMPDIR mysql_tmpdir_list;
++extern const char *command_name[];
++extern const char *first_keyword, *my_localhost, *delayed_user, *binary_keyword;
++extern const char **errmesg; /* Error messages */
++extern const char *myisam_recover_options_str;
++extern const char *in_left_expr_name, *in_additional_cond;
++extern const char * const triggers_file_ext;
++extern const char * const trigname_file_ext;
++extern Eq_creator eq_creator;
++extern Ne_creator ne_creator;
++extern Gt_creator gt_creator;
++extern Lt_creator lt_creator;
++extern Ge_creator ge_creator;
++extern Le_creator le_creator;
++extern char language[FN_REFLEN], reg_ext[FN_EXTLEN];
++extern char glob_hostname[FN_REFLEN], mysql_home[FN_REFLEN];
++extern char pidfile_name[FN_REFLEN], system_time_zone[30], *opt_init_file;
++extern char log_error_file[FN_REFLEN], *opt_tc_log_file;
++extern double log_10[32];
++extern ulonglong log_10_int[20];
++extern ulonglong keybuff_size;
++extern ulonglong thd_startup_options;
++extern ulong refresh_version,flush_version, thread_id;
++extern ulong binlog_cache_use, binlog_cache_disk_use;
++extern ulong aborted_threads,aborted_connects;
++extern ulong delayed_insert_timeout;
++extern ulong delayed_insert_limit, delayed_queue_size;
++extern ulong delayed_insert_threads, delayed_insert_writes;
++extern ulong delayed_rows_in_use,delayed_insert_errors;
++extern ulong slave_open_temp_tables;
++extern ulong query_cache_size, query_cache_min_res_unit;
++extern ulong slow_launch_threads, slow_launch_time;
++extern ulong table_cache_size;
++extern ulong max_connections,max_connect_errors, connect_timeout;
++extern ulong slave_net_timeout, slave_trans_retries;
++extern uint max_user_connections;
++extern ulong what_to_log,flush_time;
++extern ulong query_buff_size, thread_stack;
++extern ulong max_prepared_stmt_count, prepared_stmt_count;
++extern ulong binlog_cache_size, max_binlog_cache_size, open_files_limit;
++extern ulong max_binlog_size, max_relay_log_size;
++extern ulong rpl_recovery_rank, thread_cache_size;
++extern ulong back_log;
++extern ulong specialflag, current_pid;
++extern ulong expire_logs_days, sync_binlog_period, sync_binlog_counter;
++extern ulong opt_tc_log_size, tc_log_max_pages_used, tc_log_page_size;
++extern ulong tc_log_page_waits;
++extern my_bool relay_log_purge, opt_innodb_safe_binlog, opt_innodb;
++extern uint test_flags,select_errors,ha_open_options;
++extern uint protocol_version, mysqld_port, dropping_tables;
++extern uint delay_key_write_options, lower_case_table_names;
++extern bool opt_endinfo, using_udf_functions;
++extern my_bool locked_in_memory;
++extern bool opt_using_transactions, mysqld_embedded;
++extern bool using_update_log, opt_large_files, server_id_supplied;
++extern bool opt_log, opt_update_log, opt_bin_log, opt_slow_log, opt_error_log;
++extern my_bool opt_log_queries_not_using_indexes;
++extern bool opt_disable_networking, opt_skip_show_db;
++extern my_bool opt_character_set_client_handshake;
++extern bool volatile abort_loop, shutdown_in_progress, grant_option;
++extern uint volatile thread_count, thread_running, global_read_lock;
++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, opt_allow_suspicious_udfs;
++extern my_bool opt_secure_auth;
++extern my_bool opt_log_slow_admin_statements;
++extern my_bool sp_automatic_privileges, opt_noacl;
++extern my_bool opt_old_style_user_limits, trust_function_creators;
++extern uint opt_crash_binlog_innodb;
++extern char *shared_memory_base_name, *mysqld_unix_port;
++extern my_bool opt_enable_shared_memory;
++extern char *default_tz_name;
++extern my_bool opt_large_pages;
++extern uint opt_large_page_size;
++
++extern MYSQL_LOG mysql_log,mysql_slow_log,mysql_bin_log;
++extern FILE *bootstrap_file;
++extern int bootstrap_error;
++extern FILE *stderror_file;
++extern pthread_key(MEM_ROOT**,THR_MALLOC);
++extern pthread_mutex_t LOCK_mysql_create_db,LOCK_Acl,LOCK_open,
++ LOCK_thread_count,LOCK_mapped_file,LOCK_user_locks, LOCK_status,
++ LOCK_error_log, LOCK_delayed_insert, LOCK_uuid_generator,
++ LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_timezone,
++ LOCK_slave_list, LOCK_active_mi, LOCK_manager, LOCK_global_read_lock,
++ LOCK_global_system_variables, LOCK_user_conn,
++ LOCK_prepared_stmt_count,
++ LOCK_bytes_sent, LOCK_bytes_received;
++#ifdef HAVE_OPENSSL
++extern pthread_mutex_t LOCK_des_key_file;
++#endif
++extern rw_lock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave;
++extern pthread_cond_t COND_refresh, COND_thread_count, COND_manager;
++extern pthread_cond_t COND_global_read_lock;
++extern pthread_attr_t connection_attrib;
++extern I_List<THD> threads;
++extern I_List<NAMED_LIST> key_caches;
++extern MY_BITMAP temp_pool;
++extern String my_empty_string;
++extern const String my_null_string;
++extern SHOW_VAR init_vars[],status_vars[], internal_vars[];
++extern struct system_variables global_system_variables;
++extern struct system_variables max_system_variables;
++extern struct system_status_var global_status_var;
++extern struct rand_struct sql_rand;
++
++extern const char *opt_date_time_formats[];
++extern KNOWN_DATE_TIME_FORMAT known_date_time_formats[];
++
++extern String null_string;
++extern HASH open_cache;
++extern TABLE *unused_tables;
++extern I_List<i_string> binlog_do_db, binlog_ignore_db;
++extern const char* any_db;
++extern struct my_option my_long_options[];
++extern const LEX_STRING view_type;
++
++/* optional things, have_* variables */
++
++#ifdef HAVE_INNOBASE_DB
++extern handlerton innobase_hton;
++#define have_innodb innobase_hton.state
++#else
++extern SHOW_COMP_OPTION have_innodb;
++#endif
++#ifdef HAVE_BERKELEY_DB
++extern handlerton berkeley_hton;
++#define have_berkeley_db berkeley_hton.state
++#else
++extern SHOW_COMP_OPTION have_berkeley_db;
++#endif
++#ifdef HAVE_EXAMPLE_DB
++extern handlerton example_hton;
++#define have_example_db example_hton.state
++#else
++extern SHOW_COMP_OPTION have_example_db;
++#endif
++#ifdef HAVE_ARCHIVE_DB
++extern handlerton archive_hton;
++#define have_archive_db archive_hton.state
++#else
++extern SHOW_COMP_OPTION have_archive_db;
++#endif
++#ifdef HAVE_CSV_DB
++extern handlerton tina_hton;
++#define have_csv_db tina_hton.state
++#else
++extern SHOW_COMP_OPTION have_csv_db;
++#endif
++#ifdef HAVE_FEDERATED_DB
++extern handlerton federated_hton;
++#define have_federated_db federated_hton.state
++#else
++extern SHOW_COMP_OPTION have_federated_db;
++#endif
++#ifdef HAVE_BLACKHOLE_DB
++extern handlerton blackhole_hton;
++#define have_blackhole_db blackhole_hton.state
++#else
++extern SHOW_COMP_OPTION have_blackhole_db;
++#endif
++#ifdef HAVE_NDBCLUSTER_DB
++extern handlerton ndbcluster_hton;
++#define have_ndbcluster ndbcluster_hton.state
++#else
++extern SHOW_COMP_OPTION have_ndbcluster;
++#endif
++
++/* MRG_MYISAM handler is always built, but may be skipped */
++extern handlerton myisammrg_hton;
++#define have_merge_db myisammrg_hton.state
++
++extern SHOW_COMP_OPTION have_isam;
++extern SHOW_COMP_OPTION have_raid, have_openssl, have_symlink, have_dlopen;
++extern SHOW_COMP_OPTION have_query_cache;
++extern SHOW_COMP_OPTION have_geometry, have_rtree_keys;
++extern SHOW_COMP_OPTION have_crypt;
++extern SHOW_COMP_OPTION have_compress;
++
++#ifndef __WIN__
++extern pthread_t signal_thread;
++#endif
++
++#ifdef HAVE_OPENSSL
++extern struct st_VioSSLFd * ssl_acceptor_fd;
++#endif /* HAVE_OPENSSL */
++
++MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **table, uint count,
++ uint flags, bool *need_reopen);
++/* mysql_lock_tables() and open_table() flags bits */
++#define MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK 0x0001
++#define MYSQL_LOCK_IGNORE_FLUSH 0x0002
++#define MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN 0x0004
++#define MYSQL_OPEN_IGNORE_LOCKED_TABLES 0x0008
++
++void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock);
++void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock);
++void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count);
++void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table);
++void mysql_lock_abort(THD *thd, TABLE *table);
++bool mysql_lock_abort_for_thread(THD *thd, TABLE *table);
++MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b);
++TABLE_LIST *mysql_lock_have_duplicate(THD *thd, TABLE_LIST *needle,
++ TABLE_LIST *haystack);
++bool lock_global_read_lock(THD *thd);
++void unlock_global_read_lock(THD *thd);
++bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh,
++ bool is_not_commit);
++void start_waiting_global_read_lock(THD *thd);
++bool make_global_read_lock_block_commit(THD *thd);
++bool set_protect_against_global_read_lock(void);
++void unset_protect_against_global_read_lock(void);
++void broadcast_refresh(void);
++
++/* Lock based on name */
++int lock_and_wait_for_table_name(THD *thd, TABLE_LIST *table_list);
++int lock_table_name(THD *thd, TABLE_LIST *table_list);
++void unlock_table_name(THD *thd, TABLE_LIST *table_list);
++bool wait_for_locked_table_names(THD *thd, TABLE_LIST *table_list);
++bool lock_table_names(THD *thd, TABLE_LIST *table_list);
++void unlock_table_names(THD *thd, TABLE_LIST *table_list,
++ TABLE_LIST *last_table);
++
++
++/* old unireg functions */
++
++void unireg_init(ulong options);
++void unireg_end(void);
++bool mysql_create_frm(THD *thd, my_string file_name,
++ const char *db, const char *table,
++ HA_CREATE_INFO *create_info,
++ List<create_field> &create_field,
++ uint key_count,KEY *key_info,handler *db_type);
++int rea_create_table(THD *thd, my_string file_name,
++ const char *db, const char *table,
++ HA_CREATE_INFO *create_info,
++ List<create_field> &create_field,
++ uint key_count,KEY *key_info);
++int format_number(uint inputflag,uint max_length,my_string pos,uint length,
++ my_string *errpos);
++int openfrm(THD *thd, const char *name,const char *alias,uint filestat,
++ uint prgflag, uint ha_open_flags, TABLE *outparam);
++int readfrm(const char *name, const void** data, uint* length);
++int writefrm(const char* name, const void* data, uint len);
++int closefrm(TABLE *table);
++int read_string(File file, gptr *to, uint length);
++void free_blobs(TABLE *table);
++int set_zone(int nr,int min_zone,int max_zone);
++ulong convert_period_to_month(ulong period);
++ulong convert_month_to_period(ulong month);
++void get_date_from_daynr(long daynr,uint *year, uint *month,
++ uint *day);
++my_time_t TIME_to_timestamp(THD *thd, const TIME *t, my_bool *not_exist);
++bool str_to_time_with_warn(const char *str,uint length,TIME *l_time);
++timestamp_type str_to_datetime_with_warn(const char *str, uint length,
++ TIME *l_time, uint flags);
++void localtime_to_TIME(TIME *to, struct tm *from);
++void calc_time_from_sec(TIME *to, long seconds, long microseconds);
++
++void make_truncated_value_warning(THD *thd, const char *str_val,
++ uint str_length, timestamp_type time_type,
++ const char *field_name);
++extern DATE_TIME_FORMAT *date_time_format_make(timestamp_type format_type,
++ const char *format_str,
++ uint format_length);
++extern DATE_TIME_FORMAT *date_time_format_copy(THD *thd,
++ DATE_TIME_FORMAT *format);
++const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format,
++ timestamp_type type);
++extern bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time,
++ timestamp_type type, String *str);
++void make_datetime(const DATE_TIME_FORMAT *format, const TIME *l_time,
++ String *str);
++void make_date(const DATE_TIME_FORMAT *format, const TIME *l_time,
++ String *str);
++void make_time(const DATE_TIME_FORMAT *format, const TIME *l_time,
++ String *str);
++
++int test_if_number(char *str,int *res,bool allow_wildcards);
++void change_byte(byte *,uint,char,char);
++void init_read_record(READ_RECORD *info, THD *thd, TABLE *reg_form,
++ SQL_SELECT *select,
++ int use_record_cache, bool print_errors);
++void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table,
++ bool print_error, uint idx);
++void end_read_record(READ_RECORD *info);
++ha_rows filesort(THD *thd, TABLE *form,struct st_sort_field *sortorder,
++ uint s_length, SQL_SELECT *select,
++ ha_rows max_rows, ha_rows *examined_rows);
++void filesort_free_buffers(TABLE *table, bool full);
++void change_double_for_sort(double nr,byte *to);
++double my_double_round(double value, int dec, bool truncate);
++int get_quick_record(SQL_SELECT *select);
++int calc_weekday(long daynr,bool sunday_first_day_of_week);
++uint calc_week(TIME *l_time, uint week_behaviour, uint *year);
++void find_date(char *pos,uint *vek,uint flag);
++TYPELIB *convert_strings_to_array_type(my_string *typelibs, my_string *end);
++TYPELIB *typelib(MEM_ROOT *mem_root, List<String> &strings);
++ulong get_form_pos(File file, uchar *head, TYPELIB *save_names);
++ulong make_new_entry(File file,uchar *fileinfo,TYPELIB *formnames,
++ const char *newname);
++ulong next_io_size(ulong pos);
++void append_unescaped(String *res, const char *pos, uint length);
++int create_frm(THD *thd, char *name, const char *db, const char *table,
++ uint reclength,uchar *fileinfo,
++ HA_CREATE_INFO *create_info, uint keys);
++void update_create_info_from_table(HA_CREATE_INFO *info, TABLE *form);
++int rename_file_ext(const char * from,const char * to,const char * ext);
++bool check_db_name(char *db);
++bool check_column_name(const char *name);
++bool check_table_name(const char *name, uint length);
++char *get_field(MEM_ROOT *mem, Field *field);
++bool get_field(MEM_ROOT *mem, Field *field, class String *res);
++int wild_case_compare(CHARSET_INFO *cs, const char *str,const char *wildstr);
++
++/* from hostname.cc */
++struct in_addr;
++my_string ip_to_hostname(struct in_addr *in,uint *errors);
++void inc_host_errors(struct in_addr *in);
++void reset_host_errors(struct in_addr *in);
++bool hostname_cache_init();
++void hostname_cache_free();
++void hostname_cache_refresh(void);
++
++/* sql_cache.cc */
++extern bool sql_cache_init();
++extern void sql_cache_free();
++extern int sql_cache_hit(THD *thd, char *inBuf, uint length);
++
++/* item_func.cc */
++Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name,
++ LEX_STRING component);
++int get_var_with_binlog(THD *thd, enum_sql_command sql_command,
++ LEX_STRING &name, user_var_entry **out_entry);
++/* log.cc */
++bool flush_error_log(void);
++
++/* sql_list.cc */
++void free_list(I_List <i_string_pair> *list);
++void free_list(I_List <i_string> *list);
++
++/* sql_yacc.cc */
++extern int MYSQLparse(void *thd);
++#ifndef DBUG_OFF
++extern void turn_parser_debug_on();
++#endif
++
++/* frm_crypt.cc */
++#ifdef HAVE_CRYPTED_FRM
++SQL_CRYPT *get_crypt_for_frm(void);
++#endif
++
++#include "sql_view.h"
++
++/* Some inline functions for more speed */
++
++inline bool add_item_to_list(THD *thd, Item *item)
++{
++ return thd->lex->current_select->add_item_to_list(thd, item);
++}
++
++inline bool add_value_to_list(THD *thd, Item *value)
++{
++ return thd->lex->value_list.push_back(value);
++}
++
++inline bool add_order_to_list(THD *thd, Item *item, bool asc)
++{
++ return thd->lex->current_select->add_order_to_list(thd, item, asc);
++}
++
++inline bool add_group_to_list(THD *thd, Item *item, bool asc)
++{
++ return thd->lex->current_select->add_group_to_list(thd, item, asc);
++}
++
++inline void mark_as_null_row(TABLE *table)
++{
++ table->null_row=1;
++ table->status|=STATUS_NULL_ROW;
++ bfill(table->null_flags,table->s->null_bytes,255);
++}
++
++inline void table_case_convert(char * name, uint length)
++{
++ if (lower_case_table_names)
++ files_charset_info->cset->casedn(files_charset_info,
++ name, length, name, length);
++}
++
++inline const char *table_case_name(HA_CREATE_INFO *info, const char *name)
++{
++ return ((lower_case_table_names == 2 && info->alias) ? info->alias : name);
++}
++
++inline ulong sql_rnd_with_mutex()
++{
++ pthread_mutex_lock(&LOCK_thread_count);
++ ulong tmp=(ulong) (my_rnd(&sql_rand) * 0xffffffff); /* make all bits random */
++ pthread_mutex_unlock(&LOCK_thread_count);
++ return tmp;
++}
++
++Comp_creator *comp_eq_creator(bool invert);
++Comp_creator *comp_ge_creator(bool invert);
++Comp_creator *comp_gt_creator(bool invert);
++Comp_creator *comp_le_creator(bool invert);
++Comp_creator *comp_lt_creator(bool invert);
++Comp_creator *comp_ne_creator(bool invert);
++
++Item * all_any_subquery_creator(Item *left_expr,
++ chooser_compare_func_creator cmp,
++ bool all,
++ SELECT_LEX *select_lex);
++
++/*
++ clean/setup table fields and map
++
++ SYNOPSYS
++ setup_table_map()
++ table - TABLE structure pointer (which should be setup)
++ table_list TABLE_LIST structure pointer (owner of TABLE)
++ tablenr - table number
++*/
++
++inline void setup_table_map(TABLE *table, TABLE_LIST *table_list, uint tablenr)
++{
++ table->used_fields= 0;
++ table->const_table= 0;
++ table->null_row= 0;
++ table->status= STATUS_NO_RECORD;
++ table->keys_in_use_for_query= table->s->keys_in_use;
++ table->maybe_null= table_list->outer_join;
++ TABLE_LIST *embedding= table_list->embedding;
++ while (!table->maybe_null && embedding)
++ {
++ table->maybe_null= embedding->outer_join;
++ embedding= embedding->embedding;
++ }
++ table->tablenr= tablenr;
++ table->map= (table_map) 1 << tablenr;
++ table->force_index= table_list->force_index;
++}
++
++
++/*
++ SYNOPSYS
++ hexchar_to_int()
++ convert a hex digit into number
++*/
++
++inline int hexchar_to_int(char c)
++{
++ if (c <= '9' && c >= '0')
++ return c-'0';
++ c|=32;
++ if (c <= 'f' && c >= 'a')
++ return c-'a'+10;
++ return -1;
++}
++
++/*
++ is_user_table()
++ return true if the table was created explicitly
++*/
++
++inline bool is_user_table(TABLE * table)
++{
++ const char *name= table->s->table_name;
++ return strncmp(name, tmp_file_prefix, tmp_file_prefix_length);
++}
++
++/*
++ Some functions that are different in the embedded library and the normal
++ server
++*/
++
++#ifndef EMBEDDED_LIBRARY
++extern "C" void unireg_abort(int exit_code);
++void kill_delayed_threads(void);
++bool check_stack_overrun(THD *thd, long margin, char *dummy);
++#else
++#define unireg_abort(exit_code) DBUG_RETURN(exit_code)
++inline void kill_delayed_threads(void) {}
++#define check_stack_overrun(A, B, C) 0
++#endif
++
++#endif /* MYSQL_CLIENT */
+diff -urNad mysql-5.0-etch~/sql/sql_parse.cc mysql-5.0-etch/sql/sql_parse.cc
+--- mysql-5.0-etch~/sql/sql_parse.cc 2007-05-28 18:56:15.000000000 +0200
++++ mysql-5.0-etch/sql/sql_parse.cc 2007-05-28 19:12:52.000000000 +0200
+@@ -2213,7 +2213,8 @@
+ enum enum_schema_tables schema_table_idx)
+ {
+ DBUG_ENTER("prepare_schema_table");
+- SELECT_LEX *sel= 0;
++ SELECT_LEX *schema_select_lex= NULL;
++
+ switch (schema_table_idx) {
+ case SCH_SCHEMATA:
+ #if defined(DONT_ALLOW_SHOW_COMMANDS)
+@@ -2221,11 +2222,9 @@
+ ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
+ DBUG_RETURN(1);
+ #else
+- if ((specialflag & SPECIAL_SKIP_SHOW_DB) &&
+- check_global_access(thd, SHOW_DB_ACL))
+- DBUG_RETURN(1);
+ break;
+ #endif
++
+ case SCH_TABLE_NAMES:
+ case SCH_TABLES:
+ case SCH_VIEWS:
+@@ -2235,32 +2234,25 @@
+ ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
+ DBUG_RETURN(1);
+ #else
++ if (lex->select_lex.db == NULL &&
++ thd->copy_db_to(&lex->select_lex.db, NULL))
+ {
+- char *db;
+- if (lex->select_lex.db == NULL &&
+- thd->copy_db_to(&lex->select_lex.db, 0))
+- {
+- DBUG_RETURN(1);
+- }
+- db= lex->select_lex.db;
+- remove_escape(db); // Fix escaped '_'
+- if (check_db_name(db))
+- {
+- my_error(ER_WRONG_DB_NAME, MYF(0), db);
+- DBUG_RETURN(1);
+- }
+- if (check_access(thd, SELECT_ACL, db, &thd->col_access, 0, 0,
+- is_schema_db(db)))
+- DBUG_RETURN(1); /* purecov: inspected */
+- if (!thd->col_access && check_grant_db(thd,db))
+- {
+- my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
+- thd->security_ctx->priv_user, thd->security_ctx->priv_host,
+- db);
+- DBUG_RETURN(1);
+- }
+- break;
++ DBUG_RETURN(1);
++ }
++
++ schema_select_lex= new SELECT_LEX();
++ schema_select_lex->db= lex->select_lex.db;
++ schema_select_lex->table_list.first= NULL;
++ remove_escape(schema_select_lex->db); // Fix escaped '_'
++
++ if (check_db_name(schema_select_lex->db))
++ {
++ my_error(ER_WRONG_DB_NAME, MYF(0), schema_select_lex->db);
++ DBUG_RETURN(1);
+ }
++
++
++ break;
+ #endif
+ case SCH_COLUMNS:
+ case SCH_STATISTICS:
+@@ -2269,28 +2261,23 @@
+ ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
+ DBUG_RETURN(1);
+ #else
+- if (table_ident)
+ {
++ DBUG_ASSERT(table_ident);
++
+ TABLE_LIST **query_tables_last= lex->query_tables_last;
+- sel= new SELECT_LEX();
++ schema_select_lex= new SELECT_LEX();
+ /* 'parent_lex' is used in init_query() so it must be before it. */
+- sel->parent_lex= lex;
+- sel->init_query();
+- if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ,
+- (List<String> *) 0, (List<String> *) 0))
++ schema_select_lex->parent_lex= lex;
++ schema_select_lex->init_query();
++ if (!schema_select_lex->add_table_to_list(thd, table_ident, 0, 0, TL_READ,
++ (List<String> *) 0, (List<String> *) 0))
+ DBUG_RETURN(1);
+ lex->query_tables_last= query_tables_last;
+- TABLE_LIST *table_list= (TABLE_LIST*) sel->table_list.first;
+- char *db= table_list->db;
+- remove_escape(db); // Fix escaped '_'
+- remove_escape(table_list->table_name);
+- if (check_access(thd,SELECT_ACL | EXTRA_ACL,db,
+- &table_list->grant.privilege, 0, 0,
+- test(table_list->schema_table)))
+- DBUG_RETURN(1); /* purecov: inspected */
+- if (grant_option && check_grant(thd, SELECT_ACL, table_list, 2,
+- UINT_MAX, 0))
+- DBUG_RETURN(1);
++
++ TABLE_LIST *dst_table= (TABLE_LIST*) schema_select_lex->table_list.first;
++ remove_escape(dst_table->db); // Fix escaped '_'
++ remove_escape(dst_table->table_name);
++
+ break;
+ }
+ #endif
+@@ -2317,7 +2304,7 @@
+ DBUG_RETURN(1);
+ }
+ TABLE_LIST *table_list= (TABLE_LIST*) select_lex->table_list.first;
+- table_list->schema_select_lex= sel;
++ table_list->schema_select_lex= schema_select_lex;
+ table_list->schema_table_reformed= 1;
+ statistic_increment(thd->status_var.com_stat[lex->orig_sql_command],
+ &LOCK_status);
+@@ -5272,6 +5259,83 @@
+ }
+
+
++static bool check_show_access(THD *thd, TABLE_LIST *table)
++{
++ switch (get_schema_table_idx(table->schema_table))
++ {
++ case SCH_SCHEMATA:
++ return (specialflag & SPECIAL_SKIP_SHOW_DB) &&
++ check_global_access(thd, SHOW_DB_ACL);
++
++ case SCH_TABLE_NAMES:
++ case SCH_TABLES:
++ case SCH_VIEWS:
++ case SCH_TRIGGERS:
++ {
++ const char *dst_db_name= table->schema_select_lex->db;
++
++ DBUG_ASSERT(dst_db_name);
++
++ if (check_access(thd, SELECT_ACL, dst_db_name,
++ &thd->col_access, FALSE, FALSE,
++ is_schema_db(dst_db_name)))
++ {
++ return TRUE;
++ }
++
++ if (!thd->col_access && check_grant_db(thd, dst_db_name))
++ {
++ my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
++ thd->security_ctx->priv_user,
++ thd->security_ctx->priv_host,
++ dst_db_name);
++ return TRUE;
++ }
++
++ return FALSE;
++ }
++
++ case SCH_COLUMNS:
++ case SCH_STATISTICS:
++ {
++ TABLE_LIST *dst_table=
++ (TABLE_LIST *) table->schema_select_lex->table_list.first;
++
++ DBUG_ASSERT(dst_table);
++
++ if (check_access(thd, SELECT_ACL | EXTRA_ACL,
++ dst_table->db,
++ &dst_table->grant.privilege,
++ FALSE, FALSE,
++ test(dst_table->schema_table)))
++ {
++ return FALSE;
++ }
++
++ return grant_option &&
++ check_grant(thd, SELECT_ACL, dst_table, 2, UINT_MAX, FALSE);
++ }
++
++ case SCH_OPEN_TABLES:
++ case SCH_VARIABLES:
++ case SCH_STATUS:
++ case SCH_PROCEDURES:
++ case SCH_CHARSETS:
++ case SCH_COLLATIONS:
++ case SCH_COLLATION_CHARACTER_SET_APPLICABILITY:
++ case SCH_USER_PRIVILEGES:
++ case SCH_SCHEMA_PRIVILEGES:
++ case SCH_TABLE_PRIVILEGES:
++ case SCH_COLUMN_PRIVILEGES:
++ case SCH_TABLE_CONSTRAINTS:
++ case SCH_KEY_COLUMN_USAGE:
++ break;
++ }
++
++ return FALSE;
++}
++
++
+ /*
+ Check the privilege for all used tables.
+
+@@ -5330,7 +5394,16 @@
+ Remove SHOW_VIEW_ACL, because it will be checked during making view
+ */
+ tables->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL);
+- if (tables->derived || tables->schema_table ||
++
++ if (tables->schema_table_reformed)
++ {
++ if (check_show_access(thd, tables))
++ goto deny;
++
++ continue;
++ }
++
++ if (tables->derived ||
+ (tables->table && (int)tables->table->s->tmp_table) ||
+ my_tz_check_n_skip_implicit_tables(&tables,
+ thd->lex->time_zone_tables_used))
+diff -urNad mysql-5.0-etch~/sql/sql_parse.cc.orig mysql-5.0-etch/sql/sql_parse.cc.orig
+--- mysql-5.0-etch~/sql/sql_parse.cc.orig 1970-01-01 01:00:00.000000000 +0100
++++ mysql-5.0-etch/sql/sql_parse.cc.orig 2007-05-28 18:56:15.000000000 +0200
+@@ -0,0 +1,7572 @@
++/* Copyright (C) 2000-2003 MySQL AB
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
++
++#define MYSQL_LEX 1
++#include "mysql_priv.h"
++#include "sql_repl.h"
++#include "repl_failsafe.h"
++#include <m_ctype.h>
++#include <myisam.h>
++#include <my_dir.h>
++
++#ifdef HAVE_INNOBASE_DB
++#include "ha_innodb.h"
++#endif
++
++#ifdef HAVE_NDBCLUSTER_DB
++#include "ha_ndbcluster.h"
++#endif
++
++#include "sp_head.h"
++#include "sp.h"
++#include "sp_cache.h"
++
++#ifdef HAVE_OPENSSL
++/*
++ Without SSL the handshake consists of one packet. This packet
++ has both client capabilites and scrambled password.
++ With SSL the handshake might consist of two packets. If the first
++ packet (client capabilities) has CLIENT_SSL flag set, we have to
++ switch to SSL and read the second packet. The scrambled password
++ is in the second packet and client_capabilites field will be ignored.
++ Maybe it is better to accept flags other than CLIENT_SSL from the
++ second packet?
++*/
++#define SSL_HANDSHAKE_SIZE 2
++#define NORMAL_HANDSHAKE_SIZE 6
++#define MIN_HANDSHAKE_SIZE 2
++#else
++#define MIN_HANDSHAKE_SIZE 6
++#endif /* HAVE_OPENSSL */
++
++/* Used in error handling only */
++#define SP_TYPE_STRING(LP) \
++ ((LP)->sphead->m_type == TYPE_ENUM_FUNCTION ? "FUNCTION" : "PROCEDURE")
++#define SP_COM_STRING(LP) \
++ ((LP)->sql_command == SQLCOM_CREATE_SPFUNCTION || \
++ (LP)->sql_command == SQLCOM_ALTER_FUNCTION || \
++ (LP)->sql_command == SQLCOM_SHOW_CREATE_FUNC || \
++ (LP)->sql_command == SQLCOM_DROP_FUNCTION ? \
++ "FUNCTION" : "PROCEDURE")
++
++#ifdef SOLARIS
++extern "C" int gethostname(char *name, int namelen);
++#endif
++
++static void time_out_user_resource_limits(THD *thd, USER_CONN *uc);
++#ifndef NO_EMBEDDED_ACCESS_CHECKS
++static int check_for_max_user_connections(THD *thd, USER_CONN *uc);
++static void decrease_user_connections(USER_CONN *uc);
++#endif /* NO_EMBEDDED_ACCESS_CHECKS */
++static bool check_db_used(THD *thd,TABLE_LIST *tables);
++static bool check_multi_update_lock(THD *thd);
++static void remove_escape(char *name);
++static bool append_file_to_dir(THD *thd, const char **filename_ptr,
++ const char *table_name);
++
++const char *any_db="*any*"; // Special symbol for check_access
++
++const char *command_name[]={
++ "Sleep", "Quit", "Init DB", "Query", "Field List", "Create DB",
++ "Drop DB", "Refresh", "Shutdown", "Statistics", "Processlist",
++ "Connect","Kill","Debug","Ping","Time","Delayed insert","Change user",
++ "Binlog Dump","Table Dump", "Connect Out", "Register Slave",
++ "Prepare", "Execute", "Long Data", "Close stmt",
++ "Reset stmt", "Set option", "Fetch",
++ "Error" // Last command number
++};
++
++const char *xa_state_names[]={
++ "NON-EXISTING", "ACTIVE", "IDLE", "PREPARED"
++};
++
++#ifdef __WIN__
++static void test_signal(int sig_ptr)
++{
++#if !defined( DBUG_OFF)
++ MessageBox(NULL,"Test signal","DBUG",MB_OK);
++#endif
++#if defined(OS2)
++ fprintf(stderr, "Test signal %d\n", sig_ptr);
++ fflush(stderr);
++#endif
++}
++static void init_signals(void)
++{
++ int signals[7] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGBREAK,SIGABRT } ;
++ for (int i=0 ; i < 7 ; i++)
++ signal( signals[i], test_signal) ;
++}
++#endif
++
++static void unlock_locked_tables(THD *thd)
++{
++ if (thd->locked_tables)
++ {
++ thd->lock=thd->locked_tables;
++ thd->locked_tables=0; // Will be automatically closed
++ close_thread_tables(thd); // Free tables
++ }
++}
++
++
++static bool end_active_trans(THD *thd)
++{
++ int error=0;
++ DBUG_ENTER("end_active_trans");
++ if (unlikely(thd->in_sub_stmt))
++ {
++ my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
++ DBUG_RETURN(1);
++ }
++ if (thd->transaction.xid_state.xa_state != XA_NOTR)
++ {
++ my_error(ER_XAER_RMFAIL, MYF(0),
++ xa_state_names[thd->transaction.xid_state.xa_state]);
++ DBUG_RETURN(1);
++ }
++ if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN |
++ OPTION_TABLE_LOCK))
++ {
++ DBUG_PRINT("info",("options: 0x%lx", (ulong) thd->options));
++ /* Safety if one did "drop table" on locked tables */
++ if (!thd->locked_tables)
++ thd->options&= ~OPTION_TABLE_LOCK;
++ thd->server_status&= ~SERVER_STATUS_IN_TRANS;
++ if (ha_commit(thd))
++ error=1;
++ thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
++ }
++ DBUG_RETURN(error);
++}
++
++static bool begin_trans(THD *thd)
++{
++ int error=0;
++ if (unlikely(thd->in_sub_stmt))
++ {
++ my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
++ return 1;
++ }
++ if (thd->locked_tables)
++ {
++ thd->lock=thd->locked_tables;
++ thd->locked_tables=0; // Will be automatically closed
++ close_thread_tables(thd); // Free tables
++ }
++ if (end_active_trans(thd))
++ error= -1;
++ else
++ {
++ LEX *lex= thd->lex;
++ thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) |
++ OPTION_BEGIN);
++ thd->server_status|= SERVER_STATUS_IN_TRANS;
++ if (lex->start_transaction_opt & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT)
++ error= ha_start_consistent_snapshot(thd);
++ }
++ return error;
++}
++
++#ifdef HAVE_REPLICATION
++/*
++ Returns true if all tables should be ignored
++*/
++inline bool all_tables_not_ok(THD *thd, TABLE_LIST *tables)
++{
++ return table_rules_on && tables && !tables_ok(thd,tables);
++}
++#endif
++
++
++static bool some_non_temp_table_to_be_updated(THD *thd, TABLE_LIST *tables)
++{
++ for (TABLE_LIST *table= tables; table; table= table->next_global)
++ {
++ DBUG_ASSERT(table->db && table->table_name);
++ if (table->updating &&
++ !find_temporary_table(thd, table->db, table->table_name))
++ return 1;
++ }
++ return 0;
++}
++
++#ifndef NO_EMBEDDED_ACCESS_CHECKS
++static HASH hash_user_connections;
++
++static int get_or_create_user_conn(THD *thd, const char *user,
++ const char *host,
++ USER_RESOURCES *mqh)
++{
++ int return_val= 0;
++ uint temp_len, user_len;
++ char temp_user[USER_HOST_BUFF_SIZE];
++ struct user_conn *uc;
++
++ DBUG_ASSERT(user != 0);
++ DBUG_ASSERT(host != 0);
++
++ user_len= strlen(user);
++ temp_len= (strmov(strmov(temp_user, user)+1, host) - temp_user)+1;
++ (void) pthread_mutex_lock(&LOCK_user_conn);
++ if (!(uc = (struct user_conn *) hash_search(&hash_user_connections,
++ (byte*) temp_user, temp_len)))
++ {
++ /* First connection for user; Create a user connection object */
++ if (!(uc= ((struct user_conn*)
++ my_malloc(sizeof(struct user_conn) + temp_len+1,
++ MYF(MY_WME)))))
++ {
++ net_send_error(thd, 0, NullS); // Out of memory
++ return_val= 1;
++ goto end;
++ }
++ uc->user=(char*) (uc+1);
++ memcpy(uc->user,temp_user,temp_len+1);
++ uc->host= uc->user + user_len + 1;
++ uc->len= temp_len;
++ uc->connections= uc->questions= uc->updates= uc->conn_per_hour= 0;
++ uc->user_resources= *mqh;
++ uc->intime= thd->thr_create_time;
++ if (my_hash_insert(&hash_user_connections, (byte*) uc))
++ {
++ my_free((char*) uc,0);
++ net_send_error(thd, 0, NullS); // Out of memory
++ return_val= 1;
++ goto end;
++ }
++ }
++ thd->user_connect=uc;
++ uc->connections++;
++end:
++ (void) pthread_mutex_unlock(&LOCK_user_conn);
++ return return_val;
++
++}
++#endif /* !NO_EMBEDDED_ACCESS_CHECKS */
++
++
++/*
++ Check if user exist and password supplied is correct.
++
++ SYNOPSIS
++ check_user()
++ thd thread handle, thd->security_ctx->{host,user,ip} are used
++ command originator of the check: now check_user is called
++ during connect and change user procedures; used for
++ logging.
++ passwd scrambled password received from client
++ passwd_len length of scrambled password
++ db database name to connect to, may be NULL
++ check_count dont know exactly
++
++ Note, that host, user and passwd may point to communication buffer.
++ Current implementation does not depend on that, but future changes
++ should be done with this in mind; 'thd' is INOUT, all other params
++ are 'IN'.
++
++ RETURN VALUE
++ 0 OK; thd->security_ctx->user/master_access/priv_user/db_access and
++ thd->db are updated; OK is sent to client;
++ -1 access denied or handshake error; error is sent to client;
++ >0 error, not sent to client
++*/
++
++int check_user(THD *thd, enum enum_server_command command,
++ const char *passwd, uint passwd_len, const char *db,
++ bool check_count)
++{
++ DBUG_ENTER("check_user");
++
++#ifdef NO_EMBEDDED_ACCESS_CHECKS
++ thd->main_security_ctx.master_access= GLOBAL_ACLS; // Full rights
++ /* Change database if necessary */
++ if (db && db[0])
++ {
++ /*
++ thd->db is saved in caller and needs to be freed by caller if this
++ function returns 0
++ */
++ thd->reset_db(NULL, 0);
++ if (mysql_change_db(thd, db, FALSE))
++ {
++ /* Send the error to the client */
++ net_send_error(thd);
++ DBUG_RETURN(-1);
++ }
++ }
++ send_ok(thd);
++ DBUG_RETURN(0);
++#else
++
++ my_bool opt_secure_auth_local;
++ pthread_mutex_lock(&LOCK_global_system_variables);
++ opt_secure_auth_local= opt_secure_auth;
++ pthread_mutex_unlock(&LOCK_global_system_variables);
++
++ /*
++ If the server is running in secure auth mode, short scrambles are
++ forbidden.
++ */
++ if (opt_secure_auth_local && passwd_len == SCRAMBLE_LENGTH_323)
++ {
++ net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE);
++ mysql_log.write(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
++ DBUG_RETURN(-1);
++ }
++ if (passwd_len != 0 &&
++ passwd_len != SCRAMBLE_LENGTH &&
++ passwd_len != SCRAMBLE_LENGTH_323)
++ DBUG_RETURN(ER_HANDSHAKE_ERROR);
++
++ /*
++ Clear thd->db as it points to something, that will be freed when
++ connection is closed. We don't want to accidentally free a wrong pointer
++ if connect failed. Also in case of 'CHANGE USER' failure, current
++ database will be switched to 'no database selected'.
++ */
++ thd->reset_db(NULL, 0);
++
++ USER_RESOURCES ur;
++ int res= acl_getroot(thd, &ur, passwd, passwd_len);
++#ifndef EMBEDDED_LIBRARY
++ if (res == -1)
++ {
++ /*
++ This happens when client (new) sends password scrambled with
++ scramble(), but database holds old value (scrambled with
++ scramble_323()). Here we please client to send scrambled_password
++ in old format.
++ */
++ NET *net= &thd->net;
++ if (opt_secure_auth_local)
++ {
++ net_printf_error(thd, ER_SERVER_IS_IN_SECURE_AUTH_MODE,
++ thd->main_security_ctx.user,
++ thd->main_security_ctx.host_or_ip);
++ mysql_log.write(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE),
++ thd->main_security_ctx.user,
++ thd->main_security_ctx.host_or_ip);
++ DBUG_RETURN(-1);
++ }
++ /* We have to read very specific packet size */
++ if (send_old_password_request(thd) ||
++ my_net_read(net) != SCRAMBLE_LENGTH_323 + 1)
++ {
++ inc_host_errors(&thd->remote.sin_addr);
++ DBUG_RETURN(ER_HANDSHAKE_ERROR);
++ }
++ /* Final attempt to check the user based on reply */
++ /* So as passwd is short, errcode is always >= 0 */
++ res= acl_getroot(thd, &ur, (char *) net->read_pos, SCRAMBLE_LENGTH_323);
++ }
++#endif /*EMBEDDED_LIBRARY*/
++ /* here res is always >= 0 */
++ if (res == 0)
++ {
++ if (!(thd->main_security_ctx.master_access &
++ NO_ACCESS)) // authentication is OK
++ {
++ DBUG_PRINT("info",
++ ("Capabilities: %lu packet_length: %ld Host: '%s' "
++ "Login user: '%s' Priv_user: '%s' Using password: %s "
++ "Access: %lu db: '%s'",
++ thd->client_capabilities,
++ thd->max_client_packet_length,
++ thd->main_security_ctx.host_or_ip,
++ thd->main_security_ctx.user,
++ thd->main_security_ctx.priv_user,
++ passwd_len ? "yes": "no",
++ thd->main_security_ctx.master_access,
++ (thd->db ? thd->db : "*none*")));
++
++ if (check_count)
++ {
++ VOID(pthread_mutex_lock(&LOCK_thread_count));
++ bool count_ok= thread_count <= max_connections + delayed_insert_threads
++ || (thd->main_security_ctx.master_access & SUPER_ACL);
++ VOID(pthread_mutex_unlock(&LOCK_thread_count));
++ if (!count_ok)
++ { // too many connections
++ net_send_error(thd, ER_CON_COUNT_ERROR);
++ DBUG_RETURN(-1);
++ }
++ }
++
++ /* Why logging is performed before all checks've passed? */
++ mysql_log.write(thd, command,
++ (thd->main_security_ctx.priv_user ==
++ thd->main_security_ctx.user ?
++ (char*) "%s@%s on %s" :
++ (char*) "%s@%s as anonymous on %s"),
++ thd->main_security_ctx.user,
++ thd->main_security_ctx.host_or_ip,
++ db ? db : (char*) "");
++
++ /*
++ This is the default access rights for the current database. It's
++ set to 0 here because we don't have an active database yet (and we
++ may not have an active database to set.
++ */
++ thd->main_security_ctx.db_access=0;
++
++ /* Don't allow user to connect if he has done too many queries */
++ if ((ur.questions || ur.updates || ur.conn_per_hour || ur.user_conn ||
++ max_user_connections) &&
++ get_or_create_user_conn(thd,
++ (opt_old_style_user_limits ? thd->main_security_ctx.user :
++ thd->main_security_ctx.priv_user),
++ (opt_old_style_user_limits ? thd->main_security_ctx.host_or_ip :
++ thd->main_security_ctx.priv_host),
++ &ur))
++ DBUG_RETURN(-1);
++ if (thd->user_connect &&
++ (thd->user_connect->user_resources.conn_per_hour ||
++ thd->user_connect->user_resources.user_conn ||
++ max_user_connections) &&
++ check_for_max_user_connections(thd, thd->user_connect))
++ DBUG_RETURN(-1);
++
++ /* Change database if necessary */
++ if (db && db[0])
++ {
++ if (mysql_change_db(thd, db, FALSE))
++ {
++ /* Send error to the client */
++ net_send_error(thd);
++ if (thd->user_connect)
++ decrease_user_connections(thd->user_connect);
++ DBUG_RETURN(-1);
++ }
++ }
++ send_ok(thd);
++ thd->password= test(passwd_len); // remember for error messages
++ /* Ready to handle queries */
++ DBUG_RETURN(0);
++ }
++ }
++ else if (res == 2) // client gave short hash, server has long hash
++ {
++ net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE);
++ mysql_log.write(thd,COM_CONNECT,ER(ER_NOT_SUPPORTED_AUTH_MODE));
++ DBUG_RETURN(-1);
++ }
++ net_printf_error(thd, ER_ACCESS_DENIED_ERROR,
++ thd->main_security_ctx.user,
++ thd->main_security_ctx.host_or_ip,
++ passwd_len ? ER(ER_YES) : ER(ER_NO));
++ mysql_log.write(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR),
++ thd->main_security_ctx.user,
++ thd->main_security_ctx.host_or_ip,
++ passwd_len ? ER(ER_YES) : ER(ER_NO));
++ DBUG_RETURN(-1);
++#endif /* NO_EMBEDDED_ACCESS_CHECKS */
++}
++
++/*
++ Check for maximum allowable user connections, if the mysqld server is
++ started with corresponding variable that is greater then 0.
++*/
++
++extern "C" byte *get_key_conn(user_conn *buff, uint *length,
++ my_bool not_used __attribute__((unused)))
++{
++ *length=buff->len;
++ return (byte*) buff->user;
++}
++
++extern "C" void free_user(struct user_conn *uc)
++{
++ my_free((char*) uc,MYF(0));
++}
++
++void init_max_user_conn(void)
++{
++#ifndef NO_EMBEDDED_ACCESS_CHECKS
++ (void) hash_init(&hash_user_connections,system_charset_info,max_connections,
++ 0,0,
++ (hash_get_key) get_key_conn, (hash_free_key) free_user,
++ 0);
++#endif
++}
++
++
++/*
++ check if user has already too many connections
++
++ SYNOPSIS
++ check_for_max_user_connections()
++ thd Thread handle
++ uc User connect object
++
++ NOTES
++ If check fails, we decrease user connection count, which means one
++ shouldn't call decrease_user_connections() after this function.
++
++ RETURN
++ 0 ok
++ 1 error
++*/
++
++#ifndef NO_EMBEDDED_ACCESS_CHECKS
++
++static int check_for_max_user_connections(THD *thd, USER_CONN *uc)
++{
++ int error=0;
++ DBUG_ENTER("check_for_max_user_connections");
++
++ (void) pthread_mutex_lock(&LOCK_user_conn);
++ if (max_user_connections && !uc->user_resources.user_conn &&
++ max_user_connections < (uint) uc->connections)
++ {
++ net_printf_error(thd, ER_TOO_MANY_USER_CONNECTIONS, uc->user);
++ error=1;
++ goto end;
++ }
++ time_out_user_resource_limits(thd, uc);
++ if (uc->user_resources.user_conn &&
++ uc->user_resources.user_conn < uc->connections)
++ {
++ net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user,
++ "max_user_connections",
++ (long) uc->user_resources.user_conn);
++ error= 1;
++ goto end;
++ }
++ if (uc->user_resources.conn_per_hour &&
++ uc->user_resources.conn_per_hour <= uc->conn_per_hour)
++ {
++ net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user,
++ "max_connections_per_hour",
++ (long) uc->user_resources.conn_per_hour);
++ error=1;
++ goto end;
++ }
++ uc->conn_per_hour++;
++
++ end:
++ if (error)
++ uc->connections--; // no need for decrease_user_connections() here
++ (void) pthread_mutex_unlock(&LOCK_user_conn);
++ DBUG_RETURN(error);
++}
++
++/*
++ Decrease user connection count
++
++ SYNOPSIS
++ decrease_user_connections()
++ uc User connection object
++
++ NOTES
++ If there is a n user connection object for a connection
++ (which only happens if 'max_user_connections' is defined or
++ if someone has created a resource grant for a user), then
++ the connection count is always incremented on connect.
++
++ The user connect object is not freed if some users has
++ 'max connections per hour' defined as we need to be able to hold
++ count over the lifetime of the connection.
++*/
++
++static void decrease_user_connections(USER_CONN *uc)
++{
++ DBUG_ENTER("decrease_user_connections");
++ (void) pthread_mutex_lock(&LOCK_user_conn);
++ DBUG_ASSERT(uc->connections);
++ if (!--uc->connections && !mqh_used)
++ {
++ /* Last connection for user; Delete it */
++ (void) hash_delete(&hash_user_connections,(byte*) uc);
++ }
++ (void) pthread_mutex_unlock(&LOCK_user_conn);
++ DBUG_VOID_RETURN;
++}
++
++#endif /* NO_EMBEDDED_ACCESS_CHECKS */
++
++
++void free_max_user_conn(void)
++{
++#ifndef NO_EMBEDDED_ACCESS_CHECKS
++ hash_free(&hash_user_connections);
++#endif /* NO_EMBEDDED_ACCESS_CHECKS */
++}
++
++
++
++/*
++ Mark all commands that somehow changes a table
++ This is used to check number of updates / hour
++
++ sql_command is actually set to SQLCOM_END sometimes
++ so we need the +1 to include it in the array.
++
++ numbers are:
++ 0 - read-only query
++ != 0 - query that may change a table
++ 2 - query that returns meaningful ROW_COUNT() -
++ a number of modified rows
++*/
++
++char uc_update_queries[SQLCOM_END+1];
++
++void init_update_queries(void)
++{
++ bzero((gptr) &uc_update_queries, sizeof(uc_update_queries));
++
++ uc_update_queries[SQLCOM_CREATE_TABLE]=1;
++ uc_update_queries[SQLCOM_CREATE_INDEX]=1;
++ uc_update_queries[SQLCOM_ALTER_TABLE]=1;
++ uc_update_queries[SQLCOM_UPDATE]=2;
++ uc_update_queries[SQLCOM_UPDATE_MULTI]=2;
++ uc_update_queries[SQLCOM_INSERT]=2;
++ uc_update_queries[SQLCOM_INSERT_SELECT]=2;
++ uc_update_queries[SQLCOM_DELETE]=2;
++ uc_update_queries[SQLCOM_DELETE_MULTI]=2;
++ uc_update_queries[SQLCOM_TRUNCATE]=1;
++ uc_update_queries[SQLCOM_DROP_TABLE]=1;
++ uc_update_queries[SQLCOM_LOAD]=1;
++ uc_update_queries[SQLCOM_CREATE_DB]=1;
++ uc_update_queries[SQLCOM_DROP_DB]=1;
++ uc_update_queries[SQLCOM_REPLACE]=2;
++ uc_update_queries[SQLCOM_REPLACE_SELECT]=2;
++ uc_update_queries[SQLCOM_RENAME_TABLE]=1;
++ uc_update_queries[SQLCOM_BACKUP_TABLE]=1;
++ uc_update_queries[SQLCOM_RESTORE_TABLE]=1;
++ uc_update_queries[SQLCOM_DROP_INDEX]=1;
++ uc_update_queries[SQLCOM_CREATE_VIEW]=1;
++ uc_update_queries[SQLCOM_DROP_VIEW]=1;
++}
++
++bool is_update_query(enum enum_sql_command command)
++{
++ DBUG_ASSERT(command >= 0 && command <= SQLCOM_END);
++ return uc_update_queries[command] != 0;
++}
++
++/*
++ Reset per-hour user resource limits when it has been more than
++ an hour since they were last checked
++
++ SYNOPSIS:
++ time_out_user_resource_limits()
++ thd Thread handler
++ uc User connection details
++
++ NOTE:
++ This assumes that the LOCK_user_conn mutex has been acquired, so it is
++ safe to test and modify members of the USER_CONN structure.
++*/
++
++static void time_out_user_resource_limits(THD *thd, USER_CONN *uc)
++{
++ time_t check_time = thd->start_time ? thd->start_time : time(NULL);
++ DBUG_ENTER("time_out_user_resource_limits");
++
++ /* If more than a hour since last check, reset resource checking */
++ if (check_time - uc->intime >= 3600)
++ {
++ uc->questions=1;
++ uc->updates=0;
++ uc->conn_per_hour=0;
++ uc->intime=check_time;
++ }
++
++ DBUG_VOID_RETURN;
++}
++
++
++/*
++ Check if maximum queries per hour limit has been reached
++ returns 0 if OK.
++*/
++
++static bool check_mqh(THD *thd, uint check_command)
++{
++#ifndef NO_EMBEDDED_ACCESS_CHECKS
++ bool error= 0;
++ USER_CONN *uc=thd->user_connect;
++ DBUG_ENTER("check_mqh");
++ DBUG_ASSERT(uc != 0);
++
++ (void) pthread_mutex_lock(&LOCK_user_conn);
++
++ time_out_user_resource_limits(thd, uc);
++
++ /* Check that we have not done too many questions / hour */
++ if (uc->user_resources.questions &&
++ uc->questions++ >= uc->user_resources.questions)
++ {
++ net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_questions",
++ (long) uc->user_resources.questions);
++ error=1;
++ goto end;
++ }
++ if (check_command < (uint) SQLCOM_END)
++ {
++ /* Check that we have not done too many updates / hour */
++ if (uc->user_resources.updates && uc_update_queries[check_command] &&
++ uc->updates++ >= uc->user_resources.updates)
++ {
++ net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_updates",
++ (long) uc->user_resources.updates);
++ error=1;
++ goto end;
++ }
++ }
++end:
++ (void) pthread_mutex_unlock(&LOCK_user_conn);
++ DBUG_RETURN(error);
++#else
++ return (0);
++#endif /* NO_EMBEDDED_ACCESS_CHECKS */
++}
++
++
++static void reset_mqh(LEX_USER *lu, bool get_them= 0)
++{
++#ifndef NO_EMBEDDED_ACCESS_CHECKS
++ (void) pthread_mutex_lock(&LOCK_user_conn);
++ if (lu) // for GRANT
++ {
++ USER_CONN *uc;
++ uint temp_len=lu->user.length+lu->host.length+2;
++ char temp_user[USER_HOST_BUFF_SIZE];
++
++ memcpy(temp_user,lu->user.str,lu->user.length);
++ memcpy(temp_user+lu->user.length+1,lu->host.str,lu->host.length);
++ temp_user[lu->user.length]='\0'; temp_user[temp_len-1]=0;
++ if ((uc = (struct user_conn *) hash_search(&hash_user_connections,
++ (byte*) temp_user, temp_len)))
++ {
++ uc->questions=0;
++ get_mqh(temp_user,&temp_user[lu->user.length+1],uc);
++ uc->updates=0;
++ uc->conn_per_hour=0;
++ }
++ }
++ else
++ {
++ /* for FLUSH PRIVILEGES and FLUSH USER_RESOURCES */
++ for (uint idx=0;idx < hash_user_connections.records; idx++)
++ {
++ USER_CONN *uc=(struct user_conn *) hash_element(&hash_user_connections,
++ idx);
++ if (get_them)
++ get_mqh(uc->user,uc->host,uc);
++ uc->questions=0;
++ uc->updates=0;
++ uc->conn_per_hour=0;
++ }
++ }
++ (void) pthread_mutex_unlock(&LOCK_user_conn);
++#endif /* NO_EMBEDDED_ACCESS_CHECKS */
++}
++
++void thd_init_client_charset(THD *thd, uint cs_number)
++{
++ /*
++ Use server character set and collation if
++ - opt_character_set_client_handshake is not set
++ - client has not specified a character set
++ - client character set is the same as the servers
++ - client character set doesn't exists in server
++ */
++ if (!opt_character_set_client_handshake ||
++ !(thd->variables.character_set_client= get_charset(cs_number, MYF(0))) ||
++ !my_strcasecmp(&my_charset_latin1,
++ global_system_variables.character_set_client->name,
++ thd->variables.character_set_client->name))
++ {
++ thd->variables.character_set_client=
++ global_system_variables.character_set_client;
++ thd->variables.collation_connection=
++ global_system_variables.collation_connection;
++ thd->variables.character_set_results=
++ global_system_variables.character_set_results;
++ }
++ else
++ {
++ thd->variables.character_set_results=
++ thd->variables.collation_connection=
++ thd->variables.character_set_client;
++ }
++}
++
++
++/*
++ Perform handshake, authorize client and update thd ACL variables.
++ SYNOPSIS
++ check_connection()
++ thd thread handle
++
++ RETURN
++ 0 success, OK is sent to user, thd is updated.
++ -1 error, which is sent to user
++ > 0 error code (not sent to user)
++*/
++
++#ifndef EMBEDDED_LIBRARY
++static int check_connection(THD *thd)
++{
++ uint connect_errors= 0;
++ NET *net= &thd->net;
++ ulong pkt_len= 0;
++ char *end;
++
++ DBUG_PRINT("info",
++ ("New connection received on %s", vio_description(net->vio)));
++#ifdef SIGNAL_WITH_VIO_CLOSE
++ thd->set_active_vio(net->vio);
++#endif
++
++ if (!thd->main_security_ctx.host) // If TCP/IP connection
++ {
++ char ip[30];
++
++ if (vio_peer_addr(net->vio, ip, &thd->peer_port))
++ return (ER_BAD_HOST_ERROR);
++ if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(0))))
++ return (ER_OUT_OF_RESOURCES);
++ thd->main_security_ctx.host_or_ip= thd->main_security_ctx.ip;
++ vio_in_addr(net->vio,&thd->remote.sin_addr);
++ if (!(specialflag & SPECIAL_NO_RESOLVE))
++ {
++ vio_in_addr(net->vio,&thd->remote.sin_addr);
++ thd->main_security_ctx.host=
++ ip_to_hostname(&thd->remote.sin_addr, &connect_errors);
++ /* Cut very long hostnames to avoid possible overflows */
++ if (thd->main_security_ctx.host)
++ {
++ if (thd->main_security_ctx.host != my_localhost)
++ thd->main_security_ctx.host[min(strlen(thd->main_security_ctx.host),
++ HOSTNAME_LENGTH)]= 0;
++ thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host;
++ }
++ if (connect_errors > max_connect_errors)
++ return(ER_HOST_IS_BLOCKED);
++ }
++ DBUG_PRINT("info",("Host: %s ip: %s",
++ (thd->main_security_ctx.host ?
++ thd->main_security_ctx.host : "unknown host"),
++ (thd->main_security_ctx.ip ?
++ thd->main_security_ctx.ip : "unknown ip")));
++ if (acl_check_host(thd->main_security_ctx.host, thd->main_security_ctx.ip))
++ return(ER_HOST_NOT_PRIVILEGED);
++ }
++ else /* Hostname given means that the connection was on a socket */
++ {
++ DBUG_PRINT("info",("Host: %s", thd->main_security_ctx.host));
++ thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host;
++ thd->main_security_ctx.ip= 0;
++ /* Reset sin_addr */
++ bzero((char*) &thd->remote, sizeof(thd->remote));
++ }
++ vio_keepalive(net->vio, TRUE);
++ {
++ /* buff[] needs to big enough to hold the server_version variable */
++ char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64];
++ ulong client_flags = (CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB |
++ CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION);
++
++ if (opt_using_transactions)
++ client_flags|=CLIENT_TRANSACTIONS;
++#ifdef HAVE_COMPRESS
++ client_flags |= CLIENT_COMPRESS;
++#endif /* HAVE_COMPRESS */
++#ifdef HAVE_OPENSSL
++ if (ssl_acceptor_fd)
++ client_flags |= CLIENT_SSL; /* Wow, SSL is available! */
++#endif /* HAVE_OPENSSL */
++
++ end= strnmov(buff, server_version, SERVER_VERSION_LENGTH) + 1;
++ int4store((uchar*) end, thd->thread_id);
++ end+= 4;
++ /*
++ So as check_connection is the only entry point to authorization
++ procedure, scramble is set here. This gives us new scramble for
++ each handshake.
++ */
++ create_random_string(thd->scramble, SCRAMBLE_LENGTH, &thd->rand);
++ /*
++ Old clients does not understand long scrambles, but can ignore packet
++ tail: that's why first part of the scramble is placed here, and second
++ part at the end of packet.
++ */
++ end= strmake(end, thd->scramble, SCRAMBLE_LENGTH_323) + 1;
++
++ int2store(end, client_flags);
++ /* write server characteristics: up to 16 bytes allowed */
++ end[2]=(char) default_charset_info->number;
++ int2store(end+3, thd->server_status);
++ bzero(end+5, 13);
++ end+= 18;
++ /* write scramble tail */
++ end= strmake(end, thd->scramble + SCRAMBLE_LENGTH_323,
++ SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323) + 1;
++
++ /* At this point we write connection message and read reply */
++ if (net_write_command(net, (uchar) protocol_version, "", 0, buff,
++ (uint) (end-buff)) ||
++ (pkt_len= my_net_read(net)) == packet_error ||
++ pkt_len < MIN_HANDSHAKE_SIZE)
++ {
++ inc_host_errors(&thd->remote.sin_addr);
++ return(ER_HANDSHAKE_ERROR);
++ }
++ }
++#ifdef _CUSTOMCONFIG_
++#include "_cust_sql_parse.h"
++#endif
++ if (connect_errors)
++ reset_host_errors(&thd->remote.sin_addr);
++ if (thd->packet.alloc(thd->variables.net_buffer_length))
++ return(ER_OUT_OF_RESOURCES);
++
++ thd->client_capabilities=uint2korr(net->read_pos);
++ if (thd->client_capabilities & CLIENT_PROTOCOL_41)
++ {
++ thd->client_capabilities|= ((ulong) uint2korr(net->read_pos+2)) << 16;
++ thd->max_client_packet_length= uint4korr(net->read_pos+4);
++ DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8]));
++ thd_init_client_charset(thd, (uint) net->read_pos[8]);
++ thd->update_charset();
++ end= (char*) net->read_pos+32;
++ }
++ else
++ {
++ thd->max_client_packet_length= uint3korr(net->read_pos+2);
++ end= (char*) net->read_pos+5;
++ }
++
++ if (thd->client_capabilities & CLIENT_IGNORE_SPACE)
++ thd->variables.sql_mode|= MODE_IGNORE_SPACE;
++#ifdef HAVE_OPENSSL
++ DBUG_PRINT("info", ("client capabilities: %lu", thd->client_capabilities));
++ if (thd->client_capabilities & CLIENT_SSL)
++ {
++ /* Do the SSL layering. */
++ if (!ssl_acceptor_fd)
++ {
++ inc_host_errors(&thd->remote.sin_addr);
++ return(ER_HANDSHAKE_ERROR);
++ }
++ DBUG_PRINT("info", ("IO layer change in progress..."));
++ if (sslaccept(ssl_acceptor_fd, net->vio, thd->variables.net_wait_timeout))
++ {
++ DBUG_PRINT("error", ("Failed to accept new SSL connection"));
++ inc_host_errors(&thd->remote.sin_addr);
++ return(ER_HANDSHAKE_ERROR);
++ }
++ DBUG_PRINT("info", ("Reading user information over SSL layer"));
++ if ((pkt_len= my_net_read(net)) == packet_error ||
++ pkt_len < NORMAL_HANDSHAKE_SIZE)
++ {
++ DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
++ pkt_len));
++ inc_host_errors(&thd->remote.sin_addr);
++ return(ER_HANDSHAKE_ERROR);
++ }
++ }
++#endif
++
++ if (end >= (char*) net->read_pos+ pkt_len +2)
++ {
++ inc_host_errors(&thd->remote.sin_addr);
++ return(ER_HANDSHAKE_ERROR);
++ }
++
++ if (thd->client_capabilities & CLIENT_INTERACTIVE)
++ thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
++ if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
++ opt_using_transactions)
++ net->return_status= &thd->server_status;
++ net->read_timeout=(uint) thd->variables.net_read_timeout;
++
++ char *user= end;
++ char *passwd= strend(user)+1;
++ uint user_len= passwd - user - 1;
++ char *db= passwd;
++ char db_buff[NAME_LEN + 1]; // buffer to store db in utf8
++ char user_buff[USERNAME_LENGTH + 1]; // buffer to store user in utf8
++ uint dummy_errors;
++
++ /*
++ Old clients send null-terminated string as password; new clients send
++ the size (1 byte) + string (not null-terminated). Hence in case of empty
++ password both send '\0'.
++ */
++ uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
++ *passwd++ : strlen(passwd);
++ db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ?
++ db + passwd_len + 1 : 0;
++ uint db_len= db ? strlen(db) : 0;
++
++ if (passwd + passwd_len + db_len > (char *)net->read_pos + pkt_len)
++ {
++ inc_host_errors(&thd->remote.sin_addr);
++ return ER_HANDSHAKE_ERROR;
++ }
++
++ /* Since 4.1 all database names are stored in utf8 */
++ if (db)
++ {
++ db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
++ system_charset_info,
++ db, db_len,
++ thd->charset(), &dummy_errors)]= 0;
++ db= db_buff;
++ }
++
++ user_buff[user_len= copy_and_convert(user_buff, sizeof(user_buff)-1,
++ system_charset_info, user, user_len,
++ thd->charset(), &dummy_errors)]= '\0';
++ user= user_buff;
++
++ /* If username starts and ends in "'", chop them off */
++ if (user_len > 1 && user[0] == '\'' && user[user_len - 1] == '\'')
++ {
++ user[user_len-1]= 0;
++ user++;
++ user_len-= 2;
++ }
++
++ if (thd->main_security_ctx.user)
++ x_free(thd->main_security_ctx.user);
++ if (!(thd->main_security_ctx.user= my_strdup(user, MYF(0))))
++ return (ER_OUT_OF_RESOURCES);
++ return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE);
++}
++
++
++void execute_init_command(THD *thd, sys_var_str *init_command_var,
++ rw_lock_t *var_mutex)
++{
++ Vio* save_vio;
++ ulong save_client_capabilities;
++
++ thd->proc_info= "Execution of init_command";
++ /*
++ We need to lock init_command_var because
++ during execution of init_command_var query
++ values of init_command_var can't be changed
++ */
++ rw_rdlock(var_mutex);
++ thd->query= init_command_var->value;
++ thd->query_length= init_command_var->value_length;
++ save_client_capabilities= thd->client_capabilities;
++ thd->client_capabilities|= CLIENT_MULTI_QUERIES;
++ /*
++ We don't need return result of execution to client side.
++ To forbid this we should set thd->net.vio to 0.
++ */
++ save_vio= thd->net.vio;
++ thd->net.vio= 0;
++ thd->net.no_send_error= 0;
++ dispatch_command(COM_QUERY, thd, thd->query, thd->query_length+1);
++ rw_unlock(var_mutex);
++ thd->client_capabilities= save_client_capabilities;
++ thd->net.vio= save_vio;
++}
++
++
++pthread_handler_t handle_one_connection(void *arg)
++{
++ THD *thd=(THD*) arg;
++ uint launch_time =
++ (uint) ((thd->thr_create_time = time(NULL)) - thd->connect_time);
++ if (launch_time >= slow_launch_time)
++ statistic_increment(slow_launch_threads,&LOCK_status );
++
++ pthread_detach_this_thread();
++
++#if !defined( __WIN__) && !defined(OS2) // Win32 calls this in pthread_create
++ /* The following calls needs to be done before we call DBUG_ macros */
++ if (!(test_flags & TEST_NO_THREADS) & my_thread_init())
++ {
++ close_connection(thd, ER_OUT_OF_RESOURCES, 1);
++ statistic_increment(aborted_connects,&LOCK_status);
++ end_thread(thd,0);
++ return 0;
++ }
++#endif
++
++ /*
++ handle_one_connection() is the only way a thread would start
++ and would always be on top of the stack, therefore, the thread
++ stack always starts at the address of the first local variable
++ of handle_one_connection, which is thd. We need to know the
++ start of the stack so that we could check for stack overruns.
++ */
++ DBUG_PRINT("info", ("handle_one_connection called by thread %lu\n",
++ thd->thread_id));
++ /* now that we've called my_thread_init(), it is safe to call DBUG_* */
++
++#if defined(__WIN__)
++ init_signals();
++#elif !defined(OS2) && !defined(__NETWARE__)
++ sigset_t set;
++ VOID(sigemptyset(&set)); // Get mask in use
++ VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
++#endif
++ thd->thread_stack= (char*) &thd;
++ if (thd->store_globals())
++ {
++ close_connection(thd, ER_OUT_OF_RESOURCES, 1);
++ statistic_increment(aborted_connects,&LOCK_status);
++ end_thread(thd,0);
++ return 0;
++ }
++
++ do
++ {
++ int error;
++ NET *net= &thd->net;
++ Security_context *sctx= thd->security_ctx;
++ net->no_send_error= 0;
++
++ if ((error=check_connection(thd)))
++ { // Wrong permissions
++ if (error > 0)
++ net_printf_error(thd, error, sctx->host_or_ip);
++#ifdef __NT__
++ if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE)
++ my_sleep(1000); /* must wait after eof() */
++#endif
++ statistic_increment(aborted_connects,&LOCK_status);
++ goto end_thread;
++ }
++#ifdef __NETWARE__
++ netware_reg_user(sctx->ip, sctx->user, "MySQL");
++#endif
++ if (thd->variables.max_join_size == HA_POS_ERROR)
++ thd->options |= OPTION_BIG_SELECTS;
++ if (thd->client_capabilities & CLIENT_COMPRESS)
++ net->compress=1; // Use compression
++
++ thd->version= refresh_version;
++ thd->proc_info= 0;
++ thd->command= COM_SLEEP;
++ thd->set_time();
++ thd->init_for_queries();
++
++ if (sys_init_connect.value_length && !(sctx->master_access & SUPER_ACL))
++ {
++ execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect);
++ if (thd->query_error)
++ {
++ thd->killed= THD::KILL_CONNECTION;
++ sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
++ thd->thread_id,(thd->db ? thd->db : "unconnected"),
++ sctx->user ? sctx->user : "unauthenticated",
++ sctx->host_or_ip, "init_connect command failed");
++ sql_print_warning("%s", net->last_error);
++ }
++ thd->proc_info=0;
++ thd->set_time();
++ thd->init_for_queries();
++ }
++
++ while (!net->error && net->vio != 0 &&
++ !(thd->killed == THD::KILL_CONNECTION))
++ {
++ net->no_send_error= 0;
++ if (do_command(thd))
++ break;
++ }
++ if (thd->user_connect)
++ decrease_user_connections(thd->user_connect);
++ if (net->error && net->vio != 0 && net->report_error)
++ {
++ if (!thd->killed && thd->variables.log_warnings > 1)
++ sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
++ thd->thread_id,(thd->db ? thd->db : "unconnected"),
++ sctx->user ? sctx->user : "unauthenticated",
++ sctx->host_or_ip,
++ (net->last_errno ? ER(net->last_errno) :
++ ER(ER_UNKNOWN_ERROR)));
++ net_send_error(thd, net->last_errno, NullS);
++ statistic_increment(aborted_threads,&LOCK_status);
++ }
++ else if (thd->killed)
++ {
++ statistic_increment(aborted_threads,&LOCK_status);
++ }
++
++end_thread:
++ close_connection(thd, 0, 1);
++ end_thread(thd,1);
++ /*
++ If end_thread returns, we are either running with --one-thread
++ or this thread has been schedule to handle the next query
++ */
++ thd= current_thd;
++ thd->thread_stack= (char*) &thd;
++ } while (!(test_flags & TEST_NO_THREADS));
++ /* The following is only executed if we are not using --one-thread */
++ return(0); /* purecov: deadcode */
++}
++
++#endif /* EMBEDDED_LIBRARY */
++
++/*
++ Execute commands from bootstrap_file.
++ Used when creating the initial grant tables
++*/
++
++pthread_handler_t handle_bootstrap(void *arg)
++{
++ THD *thd=(THD*) arg;
++ FILE *file=bootstrap_file;
++ char *buff;
++
++ /* The following must be called before DBUG_ENTER */
++ thd->thread_stack= (char*) &thd;
++ if (my_thread_init() || thd->store_globals())
++ {
++#ifndef EMBEDDED_LIBRARY
++ close_connection(thd, ER_OUT_OF_RESOURCES, 1);
++#endif
++ thd->fatal_error();
++ goto end;
++ }
++ DBUG_ENTER("handle_bootstrap");
++
++#ifndef EMBEDDED_LIBRARY
++ pthread_detach_this_thread();
++ thd->thread_stack= (char*) &thd;
++#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
++ sigset_t set;
++ VOID(sigemptyset(&set)); // Get mask in use
++ VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
++#endif
++#endif /* EMBEDDED_LIBRARY */
++
++ if (thd->variables.max_join_size == HA_POS_ERROR)
++ thd->options |= OPTION_BIG_SELECTS;
++
++ thd->proc_info=0;
++ thd->version=refresh_version;
++ thd->security_ctx->priv_user=
++ thd->security_ctx->user= (char*) my_strdup("boot", MYF(MY_WME));
++ /*
++ Make the "client" handle multiple results. This is necessary
++ to enable stored procedures with SELECTs and Dynamic SQL
++ in init-file.
++ */
++ thd->client_capabilities|= CLIENT_MULTI_RESULTS;
++
++ buff= (char*) thd->net.buff;
++ thd->init_for_queries();
++ while (fgets(buff, thd->net.max_packet, file))
++ {
++ ulong length= (ulong) strlen(buff);
++ while (buff[length-1] != '\n' && !feof(file))
++ {
++ /*
++ We got only a part of the current string. Will try to increase
++ net buffer then read the rest of the current string.
++ */
++ if (net_realloc(&(thd->net), 2 * thd->net.max_packet))
++ {
++ net_send_error(thd, ER_NET_PACKET_TOO_LARGE, NullS);
++ thd->fatal_error();
++ break;
++ }
++ buff= (char*) thd->net.buff;
++ fgets(buff + length, thd->net.max_packet - length, file);
++ length+= (ulong) strlen(buff + length);
++ }
++ if (thd->is_fatal_error)
++ break;
++
++ while (length && (my_isspace(thd->charset(), buff[length-1]) ||
++ buff[length-1] == ';'))
++ length--;
++ buff[length]=0;
++ thd->query_length=length;
++ thd->query= thd->memdup_w_gap(buff, length+1,
++ thd->db_length+1+QUERY_CACHE_FLAGS_SIZE);
++ thd->query[length] = '\0';
++ /*
++ We don't need to obtain LOCK_thread_count here because in bootstrap
++ mode we have only one thread.
++ */
++ thd->query_id=next_query_id();
++ mysql_parse(thd,thd->query,length);
++ close_thread_tables(thd); // Free tables
++ if (thd->is_fatal_error)
++ break;
++ free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
++#ifdef USING_TRANSACTIONS
++ free_root(&thd->transaction.mem_root,MYF(MY_KEEP_PREALLOC));
++#endif
++ }
++
++ /* thd->fatal_error should be set in case something went wrong */
++end:
++ bootstrap_error= thd->is_fatal_error;
++
++ net_end(&thd->net);
++ thd->cleanup();
++ delete thd;
++
++#ifndef EMBEDDED_LIBRARY
++ (void) pthread_mutex_lock(&LOCK_thread_count);
++ thread_count--;
++ (void) pthread_mutex_unlock(&LOCK_thread_count);
++ (void) pthread_cond_broadcast(&COND_thread_count);
++ my_thread_end();
++ pthread_exit(0);
++#endif
++ DBUG_RETURN(0);
++}
++
++
++ /* This works because items are allocated with sql_alloc() */
++
++void cleanup_items(Item *item)
++{
++ DBUG_ENTER("cleanup_items");
++ for (; item ; item=item->next)
++ item->cleanup();
++ DBUG_VOID_RETURN;
++}
++
++/*
++ Handle COM_TABLE_DUMP command
++
++ SYNOPSIS
++ mysql_table_dump
++ thd thread handle
++ db database name or an empty string. If empty,
++ the current database of the connection is used
++ tbl_name name of the table to dump
++
++ NOTES
++ This function is written to handle one specific command only.
++
++ RETURN VALUE
++ 0 success
++ 1 error, the error message is set in THD
++*/
++
++static
++int mysql_table_dump(THD* thd, char* db, char* tbl_name)
++{
++ TABLE* table;
++ TABLE_LIST* table_list;
++ int error = 0;
++ DBUG_ENTER("mysql_table_dump");
++ db = (db && db[0]) ? db : thd->db;
++ if (!(table_list = (TABLE_LIST*) thd->calloc(sizeof(TABLE_LIST))))
++ DBUG_RETURN(1); // out of memory
++ table_list->db= db;
++ table_list->table_name= table_list->alias= tbl_name;
++ table_list->lock_type= TL_READ_NO_INSERT;
++ table_list->prev_global= &table_list; // can be removed after merge with 4.1
++
++ if (!db || check_db_name(db))
++ {
++ my_error(ER_WRONG_DB_NAME ,MYF(0), db ? db : "NULL");
++ goto err;
++ }
++ if (lower_case_table_names)
++ my_casedn_str(files_charset_info, tbl_name);
++ remove_escape(table_list->table_name);
++
++ if (!(table=open_ltable(thd, table_list, TL_READ_NO_INSERT)))
++ DBUG_RETURN(1);
++
++ if (check_one_table_access(thd, SELECT_ACL, table_list))
++ goto err;
++ thd->free_list = 0;
++ thd->query_length=(uint) strlen(tbl_name);
++ thd->query = tbl_name;
++ if ((error = mysqld_dump_create_info(thd, table_list, -1)))
++ {
++ my_error(ER_GET_ERRNO, MYF(0), my_errno);
++ goto err;
++ }
++ net_flush(&thd->net);
++ if ((error= table->file->dump(thd,-1)))
++ my_error(ER_GET_ERRNO, MYF(0), error);
++
++err:
++ DBUG_RETURN(error);
++}
++
++/*
++ Ends the current transaction and (maybe) begin the next
++
++ SYNOPSIS
++ end_trans()
++ thd Current thread
++ completion Completion type
++
++ RETURN
++ 0 - OK
++*/
++
++int end_trans(THD *thd, enum enum_mysql_completiontype completion)
++{
++ bool do_release= 0;
++ int res= 0;
++ DBUG_ENTER("end_trans");
++
++ if (unlikely(thd->in_sub_stmt))
++ {
++ my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
++ DBUG_RETURN(1);
++ }
++ if (thd->transaction.xid_state.xa_state != XA_NOTR)
++ {
++ my_error(ER_XAER_RMFAIL, MYF(0),
++ xa_state_names[thd->transaction.xid_state.xa_state]);
++ DBUG_RETURN(1);
++ }
++ switch (completion) {
++ case COMMIT:
++ /*
++ We don't use end_active_trans() here to ensure that this works
++ even if there is a problem with the OPTION_AUTO_COMMIT flag
++ (Which of course should never happen...)
++ */
++ thd->server_status&= ~SERVER_STATUS_IN_TRANS;
++ res= ha_commit(thd);
++ thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
++ break;
++ case COMMIT_RELEASE:
++ do_release= 1; /* fall through */
++ case COMMIT_AND_CHAIN:
++ res= end_active_trans(thd);
++ if (!res && completion == COMMIT_AND_CHAIN)
++ res= begin_trans(thd);
++ break;
++ case ROLLBACK_RELEASE:
++ do_release= 1; /* fall through */
++ case ROLLBACK:
++ case ROLLBACK_AND_CHAIN:
++ {
++ thd->server_status&= ~SERVER_STATUS_IN_TRANS;
++ if (ha_rollback(thd))
++ res= -1;
++ thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
++ if (!res && (completion == ROLLBACK_AND_CHAIN))
++ res= begin_trans(thd);
++ break;
++ }
++ default:
++ res= -1;
++ my_error(ER_UNKNOWN_COM_ERROR, MYF(0));
++ DBUG_RETURN(-1);
++ }
++
++ if (res < 0)
++ my_error(thd->killed_errno(), MYF(0));
++ else if ((res == 0) && do_release)
++ thd->killed= THD::KILL_CONNECTION;
++
++ DBUG_RETURN(res);
++}
++
++#ifndef EMBEDDED_LIBRARY
++
++/*
++ Read one command from socket and execute it (query or simple command).
++ This function is called in loop from thread function.
++ SYNOPSIS
++ do_command()
++ RETURN VALUE
++ 0 success
++ 1 request of thread shutdown (see dispatch_command() description)
++*/
++
++bool do_command(THD *thd)
++{
++ char *packet;
++ uint old_timeout;
++ ulong packet_length;
++ NET *net;
++ enum enum_server_command command;
++ DBUG_ENTER("do_command");
++
++ net= &thd->net;
++ /*
++ indicator of uninitialized lex => normal flow of errors handling
++ (see my_message_sql)
++ */
++ thd->lex->current_select= 0;
++
++ packet=0;
++ old_timeout=net->read_timeout;
++ /* Wait max for 8 hours */
++ net->read_timeout=(uint) thd->variables.net_wait_timeout;
++ thd->clear_error(); // Clear error message
++
++ net_new_transaction(net);
++ if ((packet_length=my_net_read(net)) == packet_error)
++ {
++ DBUG_PRINT("info",("Got error %d reading command from socket %s",
++ net->error,
++ vio_description(net->vio)));
++ /* Check if we can continue without closing the connection */
++ if (net->error != 3)
++ {
++ statistic_increment(aborted_threads,&LOCK_status);
++ DBUG_RETURN(TRUE); // We have to close it.
++ }
++ net_send_error(thd, net->last_errno, NullS);
++ net->error= 0;
++ DBUG_RETURN(FALSE);
++ }
++ else
++ {
++ packet=(char*) net->read_pos;
++ command = (enum enum_server_command) (uchar) packet[0];
++ if (command >= COM_END)
++ command= COM_END; // Wrong command
++ DBUG_PRINT("info",("Command on %s = %d (%s)",
++ vio_description(net->vio), command,
++ command_name[command]));
++ }
++ net->read_timeout=old_timeout; // restore it
++ /*
++ packet_length contains length of data, as it was stored in packet
++ header. In case of malformed header, packet_length can be zero.
++ If packet_length is not zero, my_net_read ensures that this number
++ of bytes was actually read from network. Additionally my_net_read
++ sets packet[packet_length]= 0 (thus if packet_length == 0,
++ command == packet[0] == COM_SLEEP).
++ In dispatch_command packet[packet_length] points beyond the end of packet.
++ */
++ DBUG_RETURN(dispatch_command(command,thd, packet+1, (uint) packet_length));
++}
++#endif /* EMBEDDED_LIBRARY */
++
++
++/*
++ Perform one connection-level (COM_XXXX) command.
++
++ SYNOPSIS
++ dispatch_command()
++ thd connection handle
++ command type of command to perform
++ packet data for the command, packet is always null-terminated
++ packet_length length of packet + 1 (to show that data is
++ null-terminated) except for COM_SLEEP, where it
++ can be zero.
++ RETURN VALUE
++ 0 ok
++ 1 request of thread shutdown, i. e. if command is
++ COM_QUIT/COM_SHUTDOWN
++*/
++
++bool dispatch_command(enum enum_server_command command, THD *thd,
++ char* packet, uint packet_length)
++{
++ NET *net= &thd->net;
++ bool error= 0;
++ DBUG_ENTER("dispatch_command");
++
++ if (thd->killed == THD::KILL_QUERY || thd->killed == THD::KILL_BAD_DATA)
++ thd->killed= THD::NOT_KILLED;
++
++ thd->command=command;
++ /*
++ Commands which always take a long time are logged into
++ the slow log only if opt_log_slow_admin_statements is set.
++ */
++ thd->enable_slow_log= TRUE;
++ thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */
++ thd->set_time();
++ VOID(pthread_mutex_lock(&LOCK_thread_count));
++ thd->query_id=query_id;
++ if (command != COM_STATISTICS && command != COM_PING)
++ next_query_id();
++ thread_running++;
++ /* TODO: set thd->lex->sql_command to SQLCOM_END here */
++ VOID(pthread_mutex_unlock(&LOCK_thread_count));
++
++ thd->server_status&=
++ ~(SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED);
++ switch (command) {
++ case COM_INIT_DB:
++ {
++ LEX_STRING tmp;
++ statistic_increment(thd->status_var.com_stat[SQLCOM_CHANGE_DB],
++ &LOCK_status);
++ thd->convert_string(&tmp, system_charset_info,
++ packet, strlen(packet), thd->charset());
++ if (!mysql_change_db(thd, tmp.str, FALSE))
++ {
++ mysql_log.write(thd,command,"%s",thd->db);
++ send_ok(thd);
++ }
++ break;
++ }
++#ifdef HAVE_REPLICATION
++ case COM_REGISTER_SLAVE:
++ {
++ if (!register_slave(thd, (uchar*)packet, packet_length))
++ send_ok(thd);
++ break;
++ }
++#endif
++ case COM_TABLE_DUMP:
++ {
++ char *db, *tbl_name;
++ uint db_len= *(uchar*) packet;
++ if (db_len >= packet_length || db_len > NAME_LEN)
++ {
++ my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
++ break;
++ }
++ uint tbl_len= *(uchar*) (packet + db_len + 1);
++ if (db_len+tbl_len+2 > packet_length || tbl_len > NAME_LEN)
++ {
++ my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
++ break;
++ }
++
++ statistic_increment(thd->status_var.com_other, &LOCK_status);
++ thd->enable_slow_log= opt_log_slow_admin_statements;
++ db= thd->alloc(db_len + tbl_len + 2);
++ if (!db)
++ {
++ my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
++ break;
++ }
++ tbl_name= strmake(db, packet + 1, db_len)+1;
++ strmake(tbl_name, packet + db_len + 2, tbl_len);
++ mysql_table_dump(thd, db, tbl_name);
++ break;
++ }
++ case COM_CHANGE_USER:
++ {
++ thd->change_user();
++ thd->clear_error(); // if errors from rollback
++
++ statistic_increment(thd->status_var.com_other, &LOCK_status);
++ char *user= (char*) packet;
++ char *passwd= strend(user)+1;
++ /*
++ Old clients send null-terminated string ('\0' for empty string) for
++ password. New clients send the size (1 byte) + string (not null
++ terminated, so also '\0' for empty string).
++ */
++ char db_buff[NAME_LEN+1]; // buffer to store db in utf8
++ char *db= passwd;
++ uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
++ *passwd++ : strlen(passwd);
++ db+= passwd_len + 1;
++#ifndef EMBEDDED_LIBRARY
++ /* Small check for incoming packet */
++ if ((uint) ((uchar*) db - net->read_pos) > packet_length)
++ {
++ my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
++ break;
++ }
++#endif
++ /* Convert database name to utf8 */
++ uint dummy_errors;
++ db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
++ system_charset_info, db, strlen(db),
++ thd->charset(), &dummy_errors)]= 0;
++ db= db_buff;
++
++ /* Save user and privileges */
++ uint save_db_length= thd->db_length;
++ char *save_db= thd->db;
++ Security_context save_security_ctx= *thd->security_ctx;
++ USER_CONN *save_user_connect= thd->user_connect;
++
++ if (!(thd->security_ctx->user= my_strdup(user, MYF(0))))
++ {
++ thd->security_ctx->user= save_security_ctx.user;
++ my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
++ break;
++ }
++
++ /* Clear variables that are allocated */
++ thd->user_connect= 0;
++ int res= check_user(thd, COM_CHANGE_USER, passwd, passwd_len, db, FALSE);
++
++ if (res)
++ {
++ /* authentication failure, we shall restore old user */
++ if (res > 0)
++ my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
++ x_free(thd->security_ctx->user);
++ *thd->security_ctx= save_security_ctx;
++ thd->user_connect= save_user_connect;
++ thd->db= save_db;
++ thd->db_length= save_db_length;
++ }
++ else
++ {
++#ifndef NO_EMBEDDED_ACCESS_CHECKS
++ /* we've authenticated new user */
++ if (save_user_connect)
++ decrease_user_connections(save_user_connect);
++#endif /* NO_EMBEDDED_ACCESS_CHECKS */
++ x_free((gptr) save_db);
++ x_free((gptr) save_security_ctx.user);
++ }
++ break;
++ }
++ case COM_STMT_EXECUTE:
++ {
++ mysql_stmt_execute(thd, packet, packet_length);
++ break;
++ }
++ case COM_STMT_FETCH:
++ {
++ mysql_stmt_fetch(thd, packet, packet_length);
++ break;
++ }
++ case COM_STMT_SEND_LONG_DATA:
++ {
++ mysql_stmt_get_longdata(thd, packet, packet_length);
++ break;
++ }
++ case COM_STMT_PREPARE:
++ {
++ mysql_stmt_prepare(thd, packet, packet_length);
++ break;
++ }
++ case COM_STMT_CLOSE:
++ {
++ mysql_stmt_close(thd, packet);
++ break;
++ }
++ case COM_STMT_RESET:
++ {
++ mysql_stmt_reset(thd, packet);
++ break;
++ }
++ case COM_QUERY:
++ {
++ if (alloc_query(thd, packet, packet_length))
++ break; // fatal error is set
++ char *packet_end= thd->query + thd->query_length;
++ /* 'b' stands for 'buffer' parameter', special for 'my_snprintf' */
++ const char *format= "%.*b";
++ mysql_log.write(thd,command, format, thd->query_length, thd->query);
++ DBUG_PRINT("query",("%-.4096s",thd->query));
++
++ if (!(specialflag & SPECIAL_NO_PRIOR))
++ my_pthread_setprio(pthread_self(),QUERY_PRIOR);
++
++ mysql_parse(thd,thd->query, thd->query_length);
++
++ while (!thd->killed && thd->lex->found_semicolon && !thd->net.report_error)
++ {
++ char *packet= thd->lex->found_semicolon;
++ net->no_send_error= 0;
++ /*
++ Multiple queries exits, execute them individually
++ */
++ if (thd->lock || thd->open_tables || thd->derived_tables ||
++ thd->prelocked_mode)
++ close_thread_tables(thd);
++ ulong length= (ulong)(packet_end-packet);
++
++ log_slow_statement(thd);
++
++ /* Remove garbage at start of query */
++ while (my_isspace(thd->charset(), *packet) && length > 0)
++ {
++ packet++;
++ length--;
++ }
++ VOID(pthread_mutex_lock(&LOCK_thread_count));
++ thd->query_length= length;
++ thd->query= packet;
++ thd->query_id= next_query_id();
++ thd->set_time(); /* Reset the query start time. */
++ /* TODO: set thd->lex->sql_command to SQLCOM_END here */
++ VOID(pthread_mutex_unlock(&LOCK_thread_count));
++ mysql_parse(thd, packet, length);
++ }
++
++ if (!(specialflag & SPECIAL_NO_PRIOR))
++ my_pthread_setprio(pthread_self(),WAIT_PRIOR);
++ DBUG_PRINT("info",("query ready"));
++ break;
++ }
++ case COM_FIELD_LIST: // This isn't actually needed
++#ifdef DONT_ALLOW_SHOW_COMMANDS
++ my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
++ MYF(0)); /* purecov: inspected */
++ break;
++#else
++ {
++ char *fields, *pend;
++ /* Locked closure of all tables */
++ TABLE_LIST *locked_tables= NULL;
++ TABLE_LIST table_list;
++ LEX_STRING conv_name;
++ /* Saved variable value */
++ my_bool old_innodb_table_locks=
++ IF_INNOBASE_DB(thd->variables.innodb_table_locks, FALSE);
++ /* used as fields initializator */
++ lex_start(thd, 0, 0);
++
++
++ statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_FIELDS],
++ &LOCK_status);
++ bzero((char*) &table_list,sizeof(table_list));
++ if (thd->copy_db_to(&table_list.db, 0))
++ break;
++ pend= strend(packet);
++ thd->convert_string(&conv_name, system_charset_info,
++ packet, (uint) (pend-packet), thd->charset());
++ table_list.alias= table_list.table_name= conv_name.str;
++ packet= pend+1;
++
++ if (!my_strcasecmp(system_charset_info, table_list.db,
++ information_schema_name.str))
++ {
++ ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, table_list.alias);
++ if (schema_table)
++ table_list.schema_table= schema_table;
++ }
++
++ thd->query_length= strlen(packet); // for simplicity: don't optimize
++ if (!(thd->query=fields=thd->memdup(packet,thd->query_length+1)))
++ break;
++ mysql_log.write(thd,command,"%s %s",table_list.table_name, fields);
++ if (lower_case_table_names)
++ my_casedn_str(files_charset_info, table_list.table_name);
++ remove_escape(table_list.table_name); // This can't have wildcards
++
++ if (check_access(thd,SELECT_ACL,table_list.db,&table_list.grant.privilege,
++ 0, 0, test(table_list.schema_table)))
++ break;
++ if (grant_option &&
++ check_grant(thd, SELECT_ACL, &table_list, 2, UINT_MAX, 0))
++ break;
++ /* init structures for VIEW processing */
++ table_list.select_lex= &(thd->lex->select_lex);
++ mysql_init_query(thd, (uchar*)"", 0);
++ thd->lex->
++ select_lex.table_list.link_in_list((byte*) &table_list,
++ (byte**) &table_list.next_local);
++ thd->lex->add_to_query_tables(&table_list);
++
++ /* 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();
++ break;
++ }
++#endif
++ case COM_QUIT:
++ /* We don't calculate statistics for this command */
++ mysql_log.write(thd,command,NullS);
++ net->error=0; // Don't give 'abort' message
++ error=TRUE; // End server
++ break;
++
++ case COM_CREATE_DB: // QQ: To be removed
++ {
++ char *db=thd->strdup(packet), *alias;
++ HA_CREATE_INFO create_info;
++
++ statistic_increment(thd->status_var.com_stat[SQLCOM_CREATE_DB],
++ &LOCK_status);
++ // null test to handle EOM
++ if (!db || !(alias= thd->strdup(db)) || check_db_name(db))
++ {
++ my_error(ER_WRONG_DB_NAME, MYF(0), db ? db : "NULL");
++ break;
++ }
++ if (check_access(thd,CREATE_ACL,db,0,1,0,is_schema_db(db)))
++ break;
++ mysql_log.write(thd,command,packet);
++ bzero(&create_info, sizeof(create_info));
++ mysql_create_db(thd, (lower_case_table_names == 2 ? alias : db),
++ &create_info, 0);
++ break;
++ }
++ case COM_DROP_DB: // QQ: To be removed
++ {
++ statistic_increment(thd->status_var.com_stat[SQLCOM_DROP_DB],
++ &LOCK_status);
++ char *db=thd->strdup(packet);
++ /* null test to handle EOM */
++ if (!db || check_db_name(db))
++ {
++ my_error(ER_WRONG_DB_NAME, MYF(0), db ? db : "NULL");
++ break;
++ }
++ if (check_access(thd,DROP_ACL,db,0,1,0,is_schema_db(db)))
++ break;
++ if (thd->locked_tables || thd->active_transaction())
++ {
++ my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
++ ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
++ break;
++ }
++ mysql_log.write(thd,command,db);
++ mysql_rm_db(thd, db, 0, 0);
++ break;
++ }
++#ifndef EMBEDDED_LIBRARY
++ case COM_BINLOG_DUMP:
++ {
++ ulong pos;
++ ushort flags;
++ uint32 slave_server_id;
++
++ statistic_increment(thd->status_var.com_other,&LOCK_status);
++ thd->enable_slow_log= opt_log_slow_admin_statements;
++ if (check_global_access(thd, REPL_SLAVE_ACL))
++ break;
++
++ /* TODO: The following has to be changed to an 8 byte integer */
++ pos = uint4korr(packet);
++ flags = uint2korr(packet + 4);
++ thd->server_id=0; /* avoid suicide */
++ if ((slave_server_id= uint4korr(packet+6))) // mysqlbinlog.server_id==0
++ kill_zombie_dump_threads(slave_server_id);
++ thd->server_id = slave_server_id;
++
++ mysql_log.write(thd, command, "Log: '%s' Pos: %ld", packet+10,
++ (long) pos);
++ mysql_binlog_send(thd, thd->strdup(packet + 10), (my_off_t) pos, flags);
++ unregister_slave(thd,1,1);
++ /* fake COM_QUIT -- if we get here, the thread needs to terminate */
++ error = TRUE;
++ net->error = 0;
++ break;
++ }
++#endif
++ case COM_REFRESH:
++ {
++ bool not_used;
++ statistic_increment(thd->status_var.com_stat[SQLCOM_FLUSH],
++ &LOCK_status);
++ ulong options= (ulong) (uchar) packet[0];
++ if (check_global_access(thd,RELOAD_ACL))
++ break;
++ mysql_log.write(thd,command,NullS);
++ if (!reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, ¬_used))
++ send_ok(thd);
++ break;
++ }
++#ifndef EMBEDDED_LIBRARY
++ case COM_SHUTDOWN:
++ {
++ statistic_increment(thd->status_var.com_other, &LOCK_status);
++ if (check_global_access(thd,SHUTDOWN_ACL))
++ break; /* purecov: inspected */
++ /*
++ If the client is < 4.1.3, it is going to send us no argument; then
++ packet_length is 1, packet[0] is the end 0 of the packet. Note that
++ SHUTDOWN_DEFAULT is 0. If client is >= 4.1.3, the shutdown level is in
++ packet[0].
++ */
++ enum mysql_enum_shutdown_level level=
++ (enum mysql_enum_shutdown_level) (uchar) packet[0];
++ DBUG_PRINT("quit",("Got shutdown command for level %u", level));
++ if (level == SHUTDOWN_DEFAULT)
++ level= SHUTDOWN_WAIT_ALL_BUFFERS; // soon default will be configurable
++ else if (level != SHUTDOWN_WAIT_ALL_BUFFERS)
++ {
++ my_error(ER_NOT_SUPPORTED_YET, MYF(0), "this shutdown level");
++ break;
++ }
++ DBUG_PRINT("quit",("Got shutdown command for level %u", level));
++ mysql_log.write(thd,command,NullS);
++ send_eof(thd);
++#ifdef __WIN__
++ sleep(1); // must wait after eof()
++#endif
++#ifndef OS2
++ send_eof(thd); // This is for 'quit request'
++#endif
++ close_connection(thd, 0, 1);
++ close_thread_tables(thd); // Free before kill
++ kill_mysql();
++ error=TRUE;
++ break;
++ }
++#endif
++ case COM_STATISTICS:
++ {
++ mysql_log.write(thd,command,NullS);
++ statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_STATUS],
++ &LOCK_status);
++#ifndef EMBEDDED_LIBRARY
++ char buff[200];
++#else
++ char *buff= thd->net.last_error;
++#endif
++
++ STATUS_VAR current_global_status_var;
++ calc_sum_of_all_status(¤t_global_status_var);
++
++ ulong uptime = (ulong) (thd->start_time - start_time);
++ sprintf((char*) buff,
++ "Uptime: %lu Threads: %d Questions: %lu Slow queries: %lu Opens: %lu Flush tables: %lu Open tables: %u Queries per second avg: %.3f",
++ uptime,
++ (int) thread_count, (ulong) thd->query_id,
++ current_global_status_var.long_query_count,
++ current_global_status_var.opened_tables, refresh_version, cached_tables(),
++ (uptime ? (ulonglong2double(thd->query_id) / (double) uptime) :
++ (double) 0));
++#ifdef SAFEMALLOC
++ if (sf_malloc_cur_memory) // Using SAFEMALLOC
++ sprintf(strend(buff), " Memory in use: %ldK Max memory used: %ldK",
++ (sf_malloc_cur_memory+1023L)/1024L,
++ (sf_malloc_max_memory+1023L)/1024L);
++#endif
++#ifndef EMBEDDED_LIBRARY
++ VOID(my_net_write(net, buff,(uint) strlen(buff)));
++ VOID(net_flush(net));
++#endif
++ break;
++ }
++ case COM_PING:
++ statistic_increment(thd->status_var.com_other, &LOCK_status);
++ send_ok(thd); // Tell client we are alive
++ break;
++ case COM_PROCESS_INFO:
++ statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_PROCESSLIST],
++ &LOCK_status);
++ if (!thd->security_ctx->priv_user[0] &&
++ check_global_access(thd, PROCESS_ACL))
++ break;
++ mysql_log.write(thd,command,NullS);
++ mysqld_list_processes(thd,
++ thd->security_ctx->master_access & PROCESS_ACL ?
++ NullS : thd->security_ctx->priv_user, 0);
++ break;
++ case COM_PROCESS_KILL:
++ {
++ statistic_increment(thd->status_var.com_stat[SQLCOM_KILL], &LOCK_status);
++ ulong id=(ulong) uint4korr(packet);
++ kill_one_thread(thd,id,false);
++ break;
++ }
++ case COM_SET_OPTION:
++ {
++ statistic_increment(thd->status_var.com_stat[SQLCOM_SET_OPTION],
++ &LOCK_status);
++ enum_mysql_set_option command= (enum_mysql_set_option) uint2korr(packet);
++ switch (command) {
++ case MYSQL_OPTION_MULTI_STATEMENTS_ON:
++ thd->client_capabilities|= CLIENT_MULTI_STATEMENTS;
++ send_eof(thd);
++ break;
++ case MYSQL_OPTION_MULTI_STATEMENTS_OFF:
++ thd->client_capabilities&= ~CLIENT_MULTI_STATEMENTS;
++ send_eof(thd);
++ break;
++ default:
++ my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
++ break;
++ }
++ break;
++ }
++ case COM_DEBUG:
++ statistic_increment(thd->status_var.com_other, &LOCK_status);
++ if (check_global_access(thd, SUPER_ACL))
++ break; /* purecov: inspected */
++ mysql_print_status();
++ mysql_log.write(thd,command,NullS);
++ send_eof(thd);
++ break;
++ case COM_SLEEP:
++ case COM_CONNECT: // Impossible here
++ case COM_TIME: // Impossible from client
++ case COM_DELAYED_INSERT:
++ case COM_END:
++ default:
++ my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
++ break;
++ }
++ if (thd->lock || thd->open_tables || thd->derived_tables ||
++ thd->prelocked_mode)
++ {
++ thd->proc_info="closing tables";
++ close_thread_tables(thd); /* Free tables */
++ }
++ /*
++ assume handlers auto-commit (if some doesn't - transaction handling
++ in MySQL should be redesigned to support it; it's a big change,
++ and it's not worth it - better to commit explicitly only writing
++ transactions, read-only ones should better take care of themselves.
++ saves some work in 2pc too)
++ see also sql_base.cc - close_thread_tables()
++ */
++ bzero(&thd->transaction.stmt, sizeof(thd->transaction.stmt));
++ if (!thd->active_transaction())
++ thd->transaction.xid_state.xid.null();
++
++ /* report error issued during command execution */
++ if (thd->killed_errno() && !thd->net.report_error)
++ thd->send_kill_message();
++ if (thd->net.report_error)
++ net_send_error(thd);
++
++ log_slow_statement(thd);
++
++ thd->proc_info="cleaning up";
++ VOID(pthread_mutex_lock(&LOCK_thread_count)); // For process list
++ thd->proc_info=0;
++ thd->command=COM_SLEEP;
++ thd->query=0;
++ thd->query_length=0;
++ thread_running--;
++ VOID(pthread_mutex_unlock(&LOCK_thread_count));
++ thd->packet.shrink(thd->variables.net_buffer_length); // Reclaim some memory
++ free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
++ DBUG_RETURN(error);
++}
++
++
++void log_slow_statement(THD *thd)
++{
++ time_t start_of_query;
++
++ /*
++ The following should never be true with our current code base,
++ but better to keep this here so we don't accidently try to log a
++ statement in a trigger or stored function
++ */
++ if (unlikely(thd->in_sub_stmt))
++ return; // Don't set time for sub stmt
++
++ start_of_query= thd->start_time;
++ thd->end_time(); // Set start time
++
++ /*
++ Do not log administrative statements unless the appropriate option is
++ set; do not log into slow log if reading from backup.
++ */
++ if (thd->enable_slow_log && !thd->user_time)
++ {
++ thd->proc_info="logging slow query";
++
++ if ((ulong) (thd->start_time - thd->time_after_lock) >
++ thd->variables.long_query_time ||
++ (thd->server_status &
++ (SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) &&
++ (specialflag & SPECIAL_LOG_QUERIES_NOT_USING_INDEXES) &&
++ /* == SQLCOM_END unless this is a SHOW command */
++ thd->lex->orig_sql_command == SQLCOM_END)
++ {
++ thd->status_var.long_query_count++;
++ mysql_slow_log.write(thd, thd->query, thd->query_length, start_of_query);
++ }
++ }
++}
++
++
++/*
++ Create a TABLE_LIST object for an INFORMATION_SCHEMA table.
++
++ SYNOPSIS
++ prepare_schema_table()
++ thd thread handle
++ lex current lex
++ table_ident table alias if it's used
++ schema_table_idx the type of the INFORMATION_SCHEMA table to be
++ created
++
++ DESCRIPTION
++ This function is used in the parser to convert a SHOW or DESCRIBE
++ table_name command to a SELECT from INFORMATION_SCHEMA.
++ It prepares a SELECT_LEX and a TABLE_LIST object to represent the
++ given command as a SELECT parse tree.
++
++ NOTES
++ Due to the way this function works with memory and LEX it cannot
++ be used outside the parser (parse tree transformations outside
++ the parser break PS and SP).
++
++ RETURN VALUE
++ 0 success
++ 1 out of memory or SHOW commands are not allowed
++ in this version of the server.
++*/
++
++int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
++ enum enum_schema_tables schema_table_idx)
++{
++ DBUG_ENTER("prepare_schema_table");
++ SELECT_LEX *sel= 0;
++ switch (schema_table_idx) {
++ case SCH_SCHEMATA:
++#if defined(DONT_ALLOW_SHOW_COMMANDS)
++ my_message(ER_NOT_ALLOWED_COMMAND,
++ ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
++ DBUG_RETURN(1);
++#else
++ if ((specialflag & SPECIAL_SKIP_SHOW_DB) &&
++ check_global_access(thd, SHOW_DB_ACL))
++ DBUG_RETURN(1);
++ break;
++#endif
++ case SCH_TABLE_NAMES:
++ case SCH_TABLES:
++ case SCH_VIEWS:
++ case SCH_TRIGGERS:
++#ifdef DONT_ALLOW_SHOW_COMMANDS
++ my_message(ER_NOT_ALLOWED_COMMAND,
++ ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
++ DBUG_RETURN(1);
++#else
++ {
++ char *db;
++ if (lex->select_lex.db == NULL &&
++ thd->copy_db_to(&lex->select_lex.db, 0))
++ {
++ DBUG_RETURN(1);
++ }
++ db= lex->select_lex.db;
++ remove_escape(db); // Fix escaped '_'
++ if (check_db_name(db))
++ {
++ my_error(ER_WRONG_DB_NAME, MYF(0), db);
++ DBUG_RETURN(1);
++ }
++ if (check_access(thd, SELECT_ACL, db, &thd->col_access, 0, 0,
++ is_schema_db(db)))
++ DBUG_RETURN(1); /* purecov: inspected */
++ if (!thd->col_access && check_grant_db(thd,db))
++ {
++ my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
++ thd->security_ctx->priv_user, thd->security_ctx->priv_host,
++ db);
++ DBUG_RETURN(1);
++ }
++ break;
++ }
++#endif
++ case SCH_COLUMNS:
++ case SCH_STATISTICS:
++#ifdef DONT_ALLOW_SHOW_COMMANDS
++ my_message(ER_NOT_ALLOWED_COMMAND,
++ ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
++ DBUG_RETURN(1);
++#else
++ if (table_ident)
++ {
++ TABLE_LIST **query_tables_last= lex->query_tables_last;
++ sel= new SELECT_LEX();
++ /* 'parent_lex' is used in init_query() so it must be before it. */
++ sel->parent_lex= lex;
++ sel->init_query();
++ if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ,
++ (List<String> *) 0, (List<String> *) 0))
++ DBUG_RETURN(1);
++ lex->query_tables_last= query_tables_last;
++ TABLE_LIST *table_list= (TABLE_LIST*) sel->table_list.first;
++ char *db= table_list->db;
++ remove_escape(db); // Fix escaped '_'
++ remove_escape(table_list->table_name);
++ if (check_access(thd,SELECT_ACL | EXTRA_ACL,db,
++ &table_list->grant.privilege, 0, 0,
++ test(table_list->schema_table)))
++ DBUG_RETURN(1); /* purecov: inspected */
++ if (grant_option && check_grant(thd, SELECT_ACL, table_list, 2,
++ UINT_MAX, 0))
++ DBUG_RETURN(1);
++ break;
++ }
++#endif
++ case SCH_OPEN_TABLES:
++ case SCH_VARIABLES:
++ case SCH_STATUS:
++ case SCH_PROCEDURES:
++ case SCH_CHARSETS:
++ case SCH_COLLATIONS:
++ case SCH_COLLATION_CHARACTER_SET_APPLICABILITY:
++ case SCH_USER_PRIVILEGES:
++ case SCH_SCHEMA_PRIVILEGES:
++ case SCH_TABLE_PRIVILEGES:
++ case SCH_COLUMN_PRIVILEGES:
++ case SCH_TABLE_CONSTRAINTS:
++ case SCH_KEY_COLUMN_USAGE:
++ default:
++ break;
++ }
++
++ SELECT_LEX *select_lex= lex->current_select;
++ if (make_schema_select(thd, select_lex, schema_table_idx))
++ {
++ DBUG_RETURN(1);
++ }
++ TABLE_LIST *table_list= (TABLE_LIST*) select_lex->table_list.first;
++ table_list->schema_select_lex= sel;
++ table_list->schema_table_reformed= 1;
++ statistic_increment(thd->status_var.com_stat[lex->orig_sql_command],
++ &LOCK_status);
++ DBUG_RETURN(0);
++}
++
++
++/*
++ Read query from packet and store in thd->query
++ Used in COM_QUERY and COM_STMT_PREPARE
++
++ DESCRIPTION
++ Sets the following THD variables:
++ query
++ query_length
++
++ RETURN VALUES
++ FALSE ok
++ TRUE error; In this case thd->fatal_error is set
++*/
++
++bool alloc_query(THD *thd, const char *packet, uint packet_length)
++{
++ packet_length--; // Remove end null
++ /* Remove garbage at start and end of query */
++ while (my_isspace(thd->charset(),packet[0]) && packet_length > 0)
++ {
++ packet++;
++ packet_length--;
++ }
++ const char *pos= packet + packet_length; // Point at end null
++ while (packet_length > 0 &&
++ (pos[-1] == ';' || my_isspace(thd->charset() ,pos[-1])))
++ {
++ pos--;
++ packet_length--;
++ }
++ /* We must allocate some extra memory for query cache */
++ thd->query_length= 0; // Extra safety: Avoid races
++ if (!(thd->query= (char*) thd->memdup_w_gap((gptr) (packet),
++ packet_length,
++ thd->db_length+ 1 +
++ QUERY_CACHE_FLAGS_SIZE)))
++ return TRUE;
++ thd->query[packet_length]=0;
++ thd->query_length= packet_length;
++
++ /* Reclaim some memory */
++ thd->packet.shrink(thd->variables.net_buffer_length);
++ thd->convert_buffer.shrink(thd->variables.net_buffer_length);
++
++ return FALSE;
++}
++
++static void reset_one_shot_variables(THD *thd)
++{
++ thd->variables.character_set_client=
++ global_system_variables.character_set_client;
++ thd->variables.collation_connection=
++ global_system_variables.collation_connection;
++ thd->variables.collation_database=
++ global_system_variables.collation_database;
++ thd->variables.collation_server=
++ global_system_variables.collation_server;
++ thd->update_charset();
++ thd->variables.time_zone=
++ global_system_variables.time_zone;
++ thd->one_shot_set= 0;
++}
++
++
++/*
++ Execute command saved in thd and lex->sql_command
++
++ SYNOPSIS
++ mysql_execute_command()
++ thd Thread handle
++
++ IMPLEMENTATION
++
++ Before every operation that can request a write lock for a table
++ wait if a global read lock exists. However do not wait if this
++ thread has locked tables already. No new locks can be requested
++ until the other locks are released. The thread that requests the
++ global read lock waits for write locked tables to become unlocked.
++
++ Note that wait_if_global_read_lock() sets a protection against a new
++ global read lock when it succeeds. This needs to be released by
++ start_waiting_global_read_lock() after the operation.
++
++ RETURN
++ FALSE OK
++ TRUE Error
++*/
++
++bool
++mysql_execute_command(THD *thd)
++{
++ bool res= FALSE;
++ bool need_start_waiting= FALSE; // have protection against global read lock
++ int result= 0;
++ LEX *lex= thd->lex;
++ /* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */
++ SELECT_LEX *select_lex= &lex->select_lex;
++ /* first table of first SELECT_LEX */
++ TABLE_LIST *first_table= (TABLE_LIST*) select_lex->table_list.first;
++ /* list of all tables in query */
++ TABLE_LIST *all_tables;
++ /* most outer SELECT_LEX_UNIT of query */
++ SELECT_LEX_UNIT *unit= &lex->unit;
++ /* Saved variable value */
++ DBUG_ENTER("mysql_execute_command");
++ thd->net.no_send_error= 0;
++
++ /*
++ Remember first generated insert id value of the previous
++ statement. We remember it here at the beginning of the statement,
++ and also in Item_func_last_insert_id::fix_fields() and
++ sys_var_last_insert_id::value_ptr(). Last two places are required
++ because LAST_INSERT_ID() and @@LAST_INSERT_ID may also be used in
++ expression that is not executed with mysql_execute_command().
++
++ And we remember it here because some statements read
++ @@LAST_INSERT_ID indirectly, like "SELECT * FROM t1 WHERE id IS
++ NULL", that may replace "id IS NULL" with "id = <LAST_INSERT_ID>".
++ */
++ thd->current_insert_id= thd->last_insert_id;
++
++ /*
++ In many cases first table of main SELECT_LEX have special meaning =>
++ check that it is first table in global list and relink it first in
++ queries_tables list if it is necessary (we need such relinking only
++ for queries with subqueries in select list, in this case tables of
++ subqueries will go to global list first)
++
++ all_tables will differ from first_table only if most upper SELECT_LEX
++ do not contain tables.
++
++ Because of above in place where should be at least one table in most
++ outer SELECT_LEX we have following check:
++ DBUG_ASSERT(first_table == all_tables);
++ DBUG_ASSERT(first_table == all_tables && first_table != 0);
++ */
++ lex->first_lists_tables_same();
++ /* should be assigned after making first tables same */
++ all_tables= lex->query_tables;
++ /* set context for commands which do not use setup_tables */
++ select_lex->
++ context.resolve_in_table_list_only((TABLE_LIST*)select_lex->
++ table_list.first);
++
++ /*
++ 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.
++ Don't reset warnings when executing a stored routine.
++ */
++ if ((all_tables || &lex->select_lex != lex->all_selects_list ||
++ lex->sroutines.records) && !thd->spcont ||
++ lex->time_zone_tables_used)
++ mysql_reset_errors(thd, 0);
++
++#ifdef HAVE_REPLICATION
++ if (unlikely(thd->slave_thread))
++ {
++ /*
++ Check if statment should be skipped because of slave filtering
++ rules
++
++ Exceptions are:
++ - UPDATE MULTI: For this statement, we want to check the filtering
++ rules later in the code
++ - SET: we always execute it (Not that many SET commands exists in
++ the binary log anyway -- only 4.1 masters write SET statements,
++ in 5.0 there are no SET statements in the binary log)
++ - DROP TEMPORARY TABLE IF EXISTS: we always execute it (otherwise we
++ have stale files on slave caused by exclusion of one tmp table).
++ */
++ if (!(lex->sql_command == SQLCOM_UPDATE_MULTI) &&
++ !(lex->sql_command == SQLCOM_SET_OPTION) &&
++ !(lex->sql_command == SQLCOM_DROP_TABLE &&
++ lex->drop_temporary && lex->drop_if_exists) &&
++ all_tables_not_ok(thd, all_tables))
++ {
++ /* we warn the slave SQL thread */
++ my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
++ if (thd->one_shot_set)
++ {
++ /*
++ It's ok to check thd->one_shot_set here:
++
++ The charsets in a MySQL 5.0 slave can change by both a binlogged
++ SET ONE_SHOT statement and the event-internal charset setting,
++ and these two ways to change charsets do not seems to work
++ together.
++
++ At least there seems to be problems in the rli cache for
++ charsets if we are using ONE_SHOT. Note that this is normally no
++ problem because either the >= 5.0 slave reads a 4.1 binlog (with
++ ONE_SHOT) *or* or 5.0 binlog (without ONE_SHOT) but never both."
++ */
++ reset_one_shot_variables(thd);
++ }
++ DBUG_RETURN(0);
++ }
++ }
++ else
++ {
++#endif /* HAVE_REPLICATION */
++ /*
++ When option readonly is set deny operations which change non-temporary
++ tables. Except for the replication thread and the 'super' users.
++ */
++ if (opt_readonly &&
++ !(thd->security_ctx->master_access & SUPER_ACL) &&
++ uc_update_queries[lex->sql_command] &&
++ !((lex->sql_command == SQLCOM_CREATE_TABLE) &&
++ (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)) &&
++ !((lex->sql_command == SQLCOM_DROP_TABLE) && lex->drop_temporary) &&
++ ((lex->sql_command != SQLCOM_UPDATE_MULTI) &&
++ some_non_temp_table_to_be_updated(thd, all_tables)))
++ {
++ my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
++ DBUG_RETURN(-1);
++ }
++#ifdef HAVE_REPLICATION
++ } /* endif unlikely slave */
++#endif
++ if(lex->orig_sql_command == SQLCOM_END)
++ statistic_increment(thd->status_var.com_stat[lex->sql_command],
++ &LOCK_status);
++
++ switch (lex->sql_command) {
++ case SQLCOM_SELECT:
++ {
++ /* assign global limit variable if limit is not given */
++ {
++ SELECT_LEX *param= lex->unit.global_parameters;
++ if (!param->explicit_limit)
++ param->select_limit=
++ new Item_int((ulonglong)thd->variables.select_limit);
++ }
++
++ select_result *result=lex->result;
++ if (all_tables)
++ {
++ if (lex->orig_sql_command != SQLCOM_SHOW_STATUS_PROC &&
++ lex->orig_sql_command != SQLCOM_SHOW_STATUS_FUNC)
++ res= check_table_access(thd,
++ lex->exchange ? SELECT_ACL | FILE_ACL :
++ SELECT_ACL,
++ all_tables, 0);
++ }
++ else
++ res= check_access(thd,
++ lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL,
++ any_db, 0, 0, 0, 0);
++ if (res)
++ goto error;
++
++ if (!(res= open_and_lock_tables(thd, all_tables)))
++ {
++ if (lex->describe)
++ {
++ /*
++ We always use select_send for EXPLAIN, even if it's an EXPLAIN
++ for SELECT ... INTO OUTFILE: a user application should be able
++ to prepend EXPLAIN to any query and receive output for it,
++ even if the query itself redirects the output.
++ */
++ if (!(result= new select_send()))
++ goto error;
++ else
++ thd->send_explain_fields(result);
++ res= mysql_explain_union(thd, &thd->lex->unit, result);
++ if (lex->describe & DESCRIBE_EXTENDED)
++ {
++ char buff[1024];
++ String str(buff,(uint32) sizeof(buff), system_charset_info);
++ str.length(0);
++ thd->lex->unit.print(&str);
++ str.append('\0');
++ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
++ ER_YES, str.ptr());
++ }
++ result->send_eof();
++ delete result;
++ }
++ else
++ {
++ if (!result && !(result= new select_send()))
++ goto error;
++ query_cache_store_query(thd, all_tables);
++ res= handle_select(thd, lex, result, 0);
++ if (result != lex->result)
++ delete result;
++ }
++ }
++ break;
++ }
++ case SQLCOM_PREPARE:
++ {
++ mysql_sql_stmt_prepare(thd);
++ break;
++ }
++ case SQLCOM_EXECUTE:
++ {
++ mysql_sql_stmt_execute(thd);
++ break;
++ }
++ case SQLCOM_DEALLOCATE_PREPARE:
++ {
++ mysql_sql_stmt_close(thd);
++ break;
++ }
++ case SQLCOM_DO:
++ 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);
++ break;
++
++ case SQLCOM_EMPTY_QUERY:
++ send_ok(thd);
++ break;
++
++ case SQLCOM_HELP:
++ res= mysqld_help(thd,lex->help_arg);
++ break;
++
++#ifndef EMBEDDED_LIBRARY
++ case SQLCOM_PURGE:
++ {
++ if (check_global_access(thd, SUPER_ACL))
++ goto error;
++ /* PURGE MASTER LOGS TO 'file' */
++ res = purge_master_logs(thd, lex->to_log);
++ break;
++ }
++ case SQLCOM_PURGE_BEFORE:
++ {
++ Item *it;
++
++ if (check_global_access(thd, SUPER_ACL))
++ goto error;
++ /* PURGE MASTER LOGS BEFORE 'data' */
++ it= (Item *)lex->value_list.head();
++ if ((!it->fixed && it->fix_fields(lex->thd, &it)) ||
++ it->check_cols(1))
++ {
++ my_error(ER_WRONG_ARGUMENTS, MYF(0), "PURGE LOGS BEFORE");
++ goto error;
++ }
++ it= new Item_func_unix_timestamp(it);
++ /*
++ it is OK only emulate fix_fieds, because we need only
++ value of constant
++ */
++ it->quick_fix_field();
++ res = purge_master_logs_before_date(thd, (ulong)it->val_int());
++ break;
++ }
++#endif
++ case SQLCOM_SHOW_WARNS:
++ {
++ res= mysqld_show_warnings(thd, (ulong)
++ ((1L << (uint) MYSQL_ERROR::WARN_LEVEL_NOTE) |
++ (1L << (uint) MYSQL_ERROR::WARN_LEVEL_WARN) |
++ (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR)
++ ));
++ break;
++ }
++ case SQLCOM_SHOW_ERRORS:
++ {
++ res= mysqld_show_warnings(thd, (ulong)
++ (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR));
++ break;
++ }
++ case SQLCOM_SHOW_NEW_MASTER:
++ {
++ if (check_global_access(thd, REPL_SLAVE_ACL))
++ goto error;
++ /* This query don't work now. See comment in repl_failsafe.cc */
++#ifndef WORKING_NEW_MASTER
++ my_error(ER_NOT_SUPPORTED_YET, MYF(0), "SHOW NEW MASTER");
++ goto error;
++#else
++ res = show_new_master(thd);
++ break;
++#endif
++ }
++
++#ifdef HAVE_REPLICATION
++ case SQLCOM_SHOW_SLAVE_HOSTS:
++ {
++ if (check_global_access(thd, REPL_SLAVE_ACL))
++ goto error;
++ res = show_slave_hosts(thd);
++ break;
++ }
++ case SQLCOM_SHOW_BINLOG_EVENTS:
++ {
++ if (check_global_access(thd, REPL_SLAVE_ACL))
++ goto error;
++ res = mysql_show_binlog_events(thd);
++ break;
++ }
++#endif
++
++ case SQLCOM_BACKUP_TABLE:
++ {
++ DBUG_ASSERT(first_table == all_tables && first_table != 0);
++ if (check_db_used(thd, all_tables) ||
++ check_table_access(thd, SELECT_ACL, all_tables, 0) ||
++ check_global_access(thd, FILE_ACL))
++ goto error; /* purecov: inspected */
++ thd->enable_slow_log= opt_log_slow_admin_statements;
++ res = mysql_backup_table(thd, first_table);
++ select_lex->table_list.first= (byte*) first_table;
++ lex->query_tables=all_tables;
++ break;
++ }
++ case SQLCOM_RESTORE_TABLE:
++ {
++ DBUG_ASSERT(first_table == all_tables && first_table != 0);
++ if (check_db_used(thd, all_tables) ||
++ check_table_access(thd, INSERT_ACL, all_tables, 0) ||
++ check_global_access(thd, FILE_ACL))
++ goto error; /* purecov: inspected */
++ thd->enable_slow_log= opt_log_slow_admin_statements;
++ res = mysql_restore_table(thd, first_table);
++ select_lex->table_list.first= (byte*) first_table;
++ lex->query_tables=all_tables;
++ break;
++ }
++ case SQLCOM_ASSIGN_TO_KEYCACHE:
++ {
++ DBUG_ASSERT(first_table == all_tables && first_table != 0);
++ if (check_db_used(thd, all_tables) ||
++ check_access(thd, INDEX_ACL, first_table->db,
++ &first_table->grant.privilege, 0, 0,
++ test(first_table->schema_table)))
++ goto error;
++ res= mysql_assign_to_keycache(thd, first_table, &lex->ident);
++ break;
++ }
++ case SQLCOM_PRELOAD_KEYS:
++ {
++ DBUG_ASSERT(first_table == all_tables && first_table != 0);
++ if (check_db_used(thd, all_tables) ||
++ check_access(thd, INDEX_ACL, first_table->db,
++ &first_table->grant.privilege, 0, 0,
++ test(first_table->schema_table)))
++ goto error;
++ res = mysql_preload_keys(thd, first_table);
++ break;
++ }
++#ifdef HAVE_REPLICATION
++ case SQLCOM_CHANGE_MASTER:
++ {
++ if (check_global_access(thd, SUPER_ACL))
++ goto error;
++ pthread_mutex_lock(&LOCK_active_mi);
++ res = change_master(thd,active_mi);
++ pthread_mutex_unlock(&LOCK_active_mi);
++ break;
++ }
++ case SQLCOM_SHOW_SLAVE_STAT:
++ {
++ /* Accept one of two privileges */
++ if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
++ goto error;
++ pthread_mutex_lock(&LOCK_active_mi);
++ res = show_master_info(thd,active_mi);
++ pthread_mutex_unlock(&LOCK_active_mi);
++ break;
++ }
++ case SQLCOM_SHOW_MASTER_STAT:
++ {
++ /* Accept one of two privileges */
++ if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
++ goto error;
++ res = show_binlog_info(thd);
++ break;
++ }
++
++ case SQLCOM_LOAD_MASTER_DATA: // sync with master
++ if (check_global_access(thd, SUPER_ACL))
++ goto error;
++ if (end_active_trans(thd))
++ goto error;
++ else
++ res = load_master_data(thd);
++ break;
++#endif /* HAVE_REPLICATION */
++#ifdef HAVE_NDBCLUSTER_DB
++ case SQLCOM_SHOW_NDBCLUSTER_STATUS:
++ {
++ res = ndbcluster_show_status(thd);
++ break;
++ }
++#endif
++#ifdef HAVE_INNOBASE_DB
++ case SQLCOM_SHOW_INNODB_STATUS:
++ {
++ if (check_global_access(thd, SUPER_ACL))
++ goto error;
++ res = innodb_show_status(thd);
++ break;
++ }
++ case SQLCOM_SHOW_MUTEX_STATUS:
++ {
++ if (check_global_access(thd, SUPER_ACL))
++ goto error;
++ res = innodb_mutex_show_status(thd);
++ break;
++ }
++#endif
++#ifdef HAVE_REPLICATION
++ case SQLCOM_LOAD_MASTER_TABLE:
++ {
++ DBUG_ASSERT(first_table == all_tables && first_table != 0);
++ DBUG_ASSERT(first_table->db); /* Must be set in the parser */
++
++ if (check_access(thd, CREATE_ACL, first_table->db,
++ &first_table->grant.privilege, 0, 0,
++ test(first_table->schema_table)))
++ goto error; /* purecov: inspected */
++ if (grant_option)
++ {
++ /* Check that the first table has CREATE privilege */
++ if (check_grant(thd, CREATE_ACL, all_tables, 0, 1, 0))
++ goto error;
++ }
++ if (strlen(first_table->table_name) > NAME_LEN)
++ {
++ my_error(ER_WRONG_TABLE_NAME, MYF(0), first_table->table_name);
++ break;
++ }
++ pthread_mutex_lock(&LOCK_active_mi);
++ /*
++ fetch_master_table will send the error to the client on failure.
++ Give error if the table already exists.
++ */
++ if (!fetch_master_table(thd, first_table->db, first_table->table_name,
++ active_mi, 0, 0))
++ {
++ send_ok(thd);
++ }
++ pthread_mutex_unlock(&LOCK_active_mi);
++ break;
++ }
++#endif /* HAVE_REPLICATION */
++
++ case SQLCOM_CREATE_TABLE:
++ {
++ /* If CREATE TABLE of non-temporary table, do implicit commit */
++ if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
++ {
++ if (end_active_trans(thd))
++ {
++ res= -1;
++ break;
++ }
++ }
++ else
++ {
++ /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
++ thd->options|= OPTION_STATUS_NO_TRANS_UPDATE;
++ }
++ DBUG_ASSERT(first_table == all_tables && first_table != 0);
++ bool link_to_local;
++ // Skip first table, which is the table we are creating
++ TABLE_LIST *create_table= lex->unlink_first_table(&link_to_local);
++ TABLE_LIST *select_tables= lex->query_tables;
++
++ if ((res= create_table_precheck(thd, select_tables, create_table)))
++ goto end_with_restore_list;
++
++#ifndef HAVE_READLINK
++ lex->create_info.data_file_name=lex->create_info.index_file_name=0;
++#else
++ /* Fix names if symlinked tables */
++ if (append_file_to_dir(thd, &lex->create_info.data_file_name,
++ create_table->table_name) ||
++ append_file_to_dir(thd, &lex->create_info.index_file_name,
++ create_table->table_name))
++ goto end_with_restore_list;
++#endif
++ /*
++ If we are using SET CHARSET without DEFAULT, add an implicit
++ DEFAULT to not confuse old users. (This may change).
++ */
++ if ((lex->create_info.used_fields &
++ (HA_CREATE_USED_DEFAULT_CHARSET | HA_CREATE_USED_CHARSET)) ==
++ HA_CREATE_USED_CHARSET)
++ {
++ lex->create_info.used_fields&= ~HA_CREATE_USED_CHARSET;
++ lex->create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
++ lex->create_info.default_table_charset= lex->create_info.table_charset;
++ lex->create_info.table_charset= 0;
++ }
++ /*
++ The create-select command will open and read-lock the select table
++ and then create, open and write-lock the new table. If a global
++ read lock steps in, we get a deadlock. The write lock waits for
++ the global read lock, while the global read lock waits for the
++ select table to be closed. So we wait until the global readlock is
++ gone before starting both steps. Note that
++ wait_if_global_read_lock() sets a protection against a new global
++ read lock when it succeeds. This needs to be released by
++ start_waiting_global_read_lock(). We protect the normal CREATE
++ TABLE in the same way. That way we avoid that a new table is
++ created during a gobal read lock.
++ */
++ if (!thd->locked_tables &&
++ !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
++ {
++ res= 1;
++ goto end_with_restore_list;
++ }
++ if (select_lex->item_list.elements) // With select
++ {
++ select_result *result;
++
++ select_lex->options|= SELECT_NO_UNLOCK;
++ unit->set_limit(select_lex);
++
++ if (!(res= open_and_lock_tables(thd, select_tables)))
++ {
++ /*
++ Is table which we are changing used somewhere in other parts
++ of query
++ */
++ if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
++ {
++ TABLE_LIST *duplicate;
++ if ((duplicate= unique_table(thd, create_table, select_tables)))
++ {
++ update_non_unique_table_error(create_table, "CREATE", duplicate);
++ res= 1;
++ goto end_with_restore_list;
++ }
++ }
++ /* If we create merge table, we have to test tables in merge, too */
++ if (lex->create_info.used_fields & HA_CREATE_USED_UNION)
++ {
++ TABLE_LIST *tab;
++ for (tab= (TABLE_LIST*) lex->create_info.merge_list.first;
++ tab;
++ tab= tab->next_local)
++ {
++ TABLE_LIST *duplicate;
++ if ((duplicate= unique_table(thd, tab, select_tables)))
++ {
++ update_non_unique_table_error(tab, "CREATE", duplicate);
++ res= 1;
++ goto end_with_restore_list;
++ }
++ }
++ }
++
++ if ((result= new select_create(create_table,
++ &lex->create_info,
++ lex->create_list,
++ lex->key_list,
++ select_lex->item_list,
++ lex->duplicates,
++ lex->ignore)))
++ {
++ /*
++ CREATE from SELECT give its SELECT_LEX for SELECT,
++ and item_list belong to SELECT
++ */
++ res= handle_select(thd, lex, result, 0);
++ delete result;
++ }
++ /* reset for PS */
++ lex->create_list.empty();
++ lex->key_list.empty();
++ }
++ }
++ else
++ {
++ /* regular create */
++ if (lex->name)
++ res= mysql_create_like_table(thd, create_table, &lex->create_info,
++ (Table_ident *)lex->name);
++ else
++ {
++ res= mysql_create_table(thd, create_table->db,
++ create_table->table_name, &lex->create_info,
++ lex->create_list,
++ lex->key_list, 0, 0);
++ }
++ if (!res)
++ send_ok(thd);
++ }
++
++ /* put tables back for PS rexecuting */
++end_with_restore_list:
++ lex->link_first_table_back(create_table, link_to_local);
++ break;
++ }
++ case SQLCOM_CREATE_INDEX:
++ DBUG_ASSERT(first_table == all_tables && first_table != 0);
++ if (check_one_table_access(thd, INDEX_ACL, all_tables))
++ goto error; /* purecov: inspected */
++ thd->enable_slow_log= opt_log_slow_admin_statements;
++ if (end_active_trans(thd))
++ goto error;
++ else
++ res = mysql_create_index(thd, first_table, lex->key_list);
++ break;
++
++#ifdef HAVE_REPLICATION
++ case SQLCOM_SLAVE_START:
++ {
++ pthread_mutex_lock(&LOCK_active_mi);
++ start_slave(thd,active_mi,1 /* net report*/);
++ pthread_mutex_unlock(&LOCK_active_mi);
++ break;
++ }
++ case SQLCOM_SLAVE_STOP:
++ /*
++ If the client thread has locked tables, a deadlock is possible.
++ Assume that
++ - the client thread does LOCK TABLE t READ.
++ - then the master updates t.
++ - then the SQL slave thread wants to update t,
++ so it waits for the client thread because t is locked by it.
++ - then the client thread does SLAVE STOP.
++ SLAVE STOP waits for the SQL slave thread to terminate its
++ update t, which waits for the client thread because t is locked by it.
++ To prevent that, refuse SLAVE STOP if the
++ client thread has locked tables
++ */
++ if (thd->locked_tables || thd->active_transaction() || thd->global_read_lock)
++ {
++ my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
++ ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
++ goto error;
++ }
++ {
++ pthread_mutex_lock(&LOCK_active_mi);
++ stop_slave(thd,active_mi,1/* net report*/);
++ pthread_mutex_unlock(&LOCK_active_mi);
++ break;
++ }
++#endif /* HAVE_REPLICATION */
++
++ case SQLCOM_ALTER_TABLE:
++ DBUG_ASSERT(first_table == all_tables && first_table != 0);
++ {
++ ulong priv=0;
++ if (lex->name && (!lex->name[0] || strlen(lex->name) > NAME_LEN))
++ {
++ my_error(ER_WRONG_TABLE_NAME, MYF(0), lex->name);
++ goto error;
++ }
++ /* Must be set in the parser */
++ DBUG_ASSERT(select_lex->db);
++ if (check_access(thd, ALTER_ACL, first_table->db,
++ &first_table->grant.privilege, 0, 0,
++ test(first_table->schema_table)) ||
++ check_access(thd,INSERT_ACL | CREATE_ACL,select_lex->db,&priv,0,0,
++ is_schema_db(select_lex->db))||
++ check_merge_table_access(thd, first_table->db,
++ (TABLE_LIST *)
++ lex->create_info.merge_list.first))
++ goto error; /* purecov: inspected */
++ if (grant_option)
++ {
++ if (check_grant(thd, ALTER_ACL, all_tables, 0, UINT_MAX, 0))
++ goto error;
++ if (lex->name && !test_all_bits(priv,INSERT_ACL | CREATE_ACL))
++ { // Rename of table
++ TABLE_LIST tmp_table;
++ bzero((char*) &tmp_table,sizeof(tmp_table));
++ tmp_table.table_name=lex->name;
++ tmp_table.db=select_lex->db;
++ tmp_table.grant.privilege=priv;
++ if (check_grant(thd, INSERT_ACL | CREATE_ACL, &tmp_table, 0,
++ UINT_MAX, 0))
++ goto error;
++ }
++ }
++ /* Don't yet allow changing of symlinks with ALTER TABLE */
++ if (lex->create_info.data_file_name)
++ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
++ "DATA DIRECTORY option ignored");
++ if (lex->create_info.index_file_name)
++ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
++ "INDEX DIRECTORY option ignored");
++ lex->create_info.data_file_name=lex->create_info.index_file_name=0;
++ /* ALTER TABLE ends previous transaction */
++ if (end_active_trans(thd))
++ goto error;
++ else
++ {
++ if (!thd->locked_tables &&
++ !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
++ {
++ res= 1;
++ break;
++ }
++
++ thd->enable_slow_log= opt_log_slow_admin_statements;
++ res= mysql_alter_table(thd, select_lex->db, lex->name,
++ &lex->create_info,
++ first_table, lex->create_list,
++ lex->key_list,
++ select_lex->order_list.elements,
++ (ORDER *) select_lex->order_list.first,
++ lex->ignore, &lex->alter_info, 1);
++ }
++ break;
++ }
++ case SQLCOM_RENAME_TABLE:
++ {
++ DBUG_ASSERT(first_table == all_tables && first_table != 0);
++ TABLE_LIST *table;
++ if (check_db_used(thd, all_tables))
++ goto error;
++ for (table= first_table; table; table= table->next_local->next_local)
++ {
++ if (check_access(thd, ALTER_ACL | DROP_ACL, table->db,
++ &table->grant.privilege,0,0, test(table->schema_table)) ||
++ check_access(thd, INSERT_ACL | CREATE_ACL, table->next_local->db,
++ &table->next_local->grant.privilege, 0, 0,
++ test(table->next_local->schema_table)))
++ goto error;
++ if (grant_option)
++ {
++ TABLE_LIST old_list, new_list;
++ /*
++ we do not need initialize old_list and new_list because we will
++ come table[0] and table->next[0] there
++ */
++ old_list= table[0];
++ new_list= table->next_local[0];
++ if (check_grant(thd, ALTER_ACL | DROP_ACL, &old_list, 0, 1, 0) ||
++ (!test_all_bits(table->next_local->grant.privilege,
++ INSERT_ACL | CREATE_ACL) &&
++ check_grant(thd, INSERT_ACL | CREATE_ACL, &new_list, 0, 1, 0)))
++ goto error;
++ }
++ }
++ query_cache_invalidate3(thd, first_table, 0);
++ if (end_active_trans(thd) || mysql_rename_tables(thd, first_table))
++ goto error;
++ break;
++ }
++#ifndef EMBEDDED_LIBRARY
++ case SQLCOM_SHOW_BINLOGS:
++#ifdef DONT_ALLOW_SHOW_COMMANDS
++ my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
++ MYF(0)); /* purecov: inspected */
++ goto error;
++#else
++ {
++ if (check_global_access(thd, SUPER_ACL))
++ goto error;
++ res = show_binlogs(thd);
++ break;
++ }
++#endif
++#endif /* EMBEDDED_LIBRARY */
++ case SQLCOM_SHOW_CREATE:
++ DBUG_ASSERT(first_table == all_tables && first_table != 0);
++#ifdef DONT_ALLOW_SHOW_COMMANDS
++ my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
++ MYF(0)); /* purecov: inspected */
++ goto error;
++#else
++ {
++ /* Ignore temporary tables if this is "SHOW CREATE VIEW" */
++ if (lex->only_view)
++ first_table->skip_temporary= 1;
++
++ if (check_db_used(thd, all_tables) ||
++ check_access(thd, SELECT_ACL | EXTRA_ACL, first_table->db,
++ &first_table->grant.privilege, 0, 0,
++ test(first_table->schema_table)))
++ goto error;
++ if (grant_option && check_grant(thd, SELECT_ACL, all_tables, 2, UINT_MAX, 0))
++ goto error;
++ res= mysqld_show_create(thd, first_table);
++ break;
++ }
++#endif
++ case SQLCOM_CHECKSUM:
++ {
++ DBUG_ASSERT(first_table == all_tables && first_table != 0);
++ if (check_db_used(thd, all_tables) ||
++ check_table_access(thd, SELECT_ACL | EXTRA_ACL, all_tables, 0))
++ goto error; /* purecov: inspected */
++ res = mysql_checksum_table(thd, first_table, &lex->check_opt);
++ break;
++ }
++ case SQLCOM_REPAIR:
++ {
++ DBUG_ASSERT(first_table == all_tables && first_table != 0);
++ if (check_db_used(thd, all_tables) ||
++ check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0))
++ goto error; /* purecov: inspected */
++ thd->enable_slow_log= opt_log_slow_admin_statements;
++ res= mysql_repair_table(thd, first_table, &lex->check_opt);
++ /* ! we write after unlocking the table */
++ if (!res && !lex->no_write_to_binlog)
++ {
++ /* Presumably, REPAIR and binlog writing doesn't require synchronization */
++ if (mysql_bin_log.is_open())
++ {
++ thd->clear_error(); // No binlog error generated
++ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
++ mysql_bin_log.write(&qinfo);
++ }
++ }
++ select_lex->table_list.first= (byte*) first_table;
++ lex->query_tables=all_tables;
++ break;
++ }
++ case SQLCOM_CHECK:
++ {
++ DBUG_ASSERT(first_table == all_tables && first_table != 0);
++ if (check_db_used(thd, all_tables) ||
++ check_table_access(thd, SELECT_ACL | EXTRA_ACL , all_tables, 0))
++ goto error; /* purecov: inspected */
++ thd->enable_slow_log= opt_log_slow_admin_statements;
++ res = mysql_check_table(thd, first_table, &lex->check_opt);
++ select_lex->table_list.first= (byte*) first_table;
++ lex->query_tables=all_tables;
++ break;
++ }
++ case SQLCOM_ANALYZE:
++ {
++ DBUG_ASSERT(first_table == all_tables && first_table != 0);
++ if (check_db_used(thd, all_tables) ||
++ check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0))
++ goto error; /* purecov: inspected */
++ thd->enable_slow_log= opt_log_slow_admin_statements;
++ res = mysql_analyze_table(thd, first_table, &lex->check_opt);
++ /* ! we write after unlocking the table */
++ if (!res && !lex->no_write_to_binlog)
++ {
++ /* Presumably, ANALYZE and binlog writing doesn't require synchronization */
++ if (mysql_bin_log.is_open())
++ {
++ thd->clear_error(); // No binlog error generated
++ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
++ mysql_bin_log.write(&qinfo);
++ }
++ }
++ select_lex->table_list.first= (byte*) first_table;
++ lex->query_tables=all_tables;
++ break;
++ }
++
++ case SQLCOM_OPTIMIZE:
++ {
++ DBUG_ASSERT(first_table == all_tables && first_table != 0);
++ if (check_db_used(thd, all_tables) ||
++ check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0))
++ goto error; /* purecov: inspected */
++ thd->enable_slow_log= opt_log_slow_admin_statements;
++ res= (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC)) ?
++ mysql_recreate_table(thd, first_table, 1) :
++ mysql_optimize_table(thd, first_table, &lex->check_opt);
++ /* ! we write after unlocking the table */
++ if (!res && !lex->no_write_to_binlog)
++ {
++ /* Presumably, OPTIMIZE and binlog writing doesn't require synchronization */
++ if (mysql_bin_log.is_open())
++ {
++ thd->clear_error(); // No binlog error generated
++ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
++ mysql_bin_log.write(&qinfo);
++ }
++ }
++ select_lex->table_list.first= (byte*) first_table;
++ lex->query_tables=all_tables;
++ break;
++ }
++ case SQLCOM_UPDATE:
++ DBUG_ASSERT(first_table == all_tables && first_table != 0);
++ if (update_precheck(thd, all_tables))
++ break;
++ DBUG_ASSERT(select_lex->offset_limit == 0);
++ unit->set_limit(select_lex);
++ res= (result= mysql_update(thd, all_tables,
++ select_lex->item_list,
++ lex->value_list,
++ select_lex->where,
++ select_lex->order_list.elements,
++ (ORDER *) select_lex->order_list.first,
++ unit->select_limit_cnt,
++ lex->duplicates, lex->ignore));
++ /* mysql_update return 2 if we need to switch to multi-update */
++ if (result != 2)
++ break;
++ case SQLCOM_UPDATE_MULTI:
++ {
++ DBUG_ASSERT(first_table == all_tables && first_table != 0);
++ /* if we switched from normal update, rights are checked */
++ if (result != 2)
++ {
++ if ((res= multi_update_precheck(thd, all_tables)))
++ break;
++ }
++ else
++ res= 0;
++
++ res= mysql_multi_update_prepare(thd);
++
++#ifdef HAVE_REPLICATION
++ /* Check slave filtering rules */
++ if (unlikely(thd->slave_thread))
++ {
++ if (all_tables_not_ok(thd, all_tables))
++ {
++ if (res!= 0)
++ {
++ res= 0; /* don't care of prev failure */
++ thd->clear_error(); /* filters are of highest prior */
++ }
++ /* we warn the slave SQL thread */
++ my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
++ break;
++ }
++ if (res)
++ break;
++ }
++ else
++ {
++#endif /* HAVE_REPLICATION */
++ if (res)
++ break;
++ if (opt_readonly &&
++ !(thd->security_ctx->master_access & SUPER_ACL) &&
++ some_non_temp_table_to_be_updated(thd, all_tables))
++ {
++ my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
++ break;
++ }
++#ifdef HAVE_REPLICATION
++ } /* unlikely */
++#endif
++
++ res= mysql_multi_update(thd, all_tables,
++ &select_lex->item_list,
++ &lex->value_list,
++ select_lex->where,
++ select_lex->options,
++ lex->duplicates, lex->ignore, unit, select_lex);
++ break;
++ }
++ case SQLCOM_REPLACE:
++ case SQLCOM_INSERT:
++ {
++ DBUG_ASSERT(first_table == all_tables && first_table != 0);
++ if ((res= insert_precheck(thd, all_tables)))
++ break;
++
++ if (!thd->locked_tables &&
++ !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
++ {
++ res= 1;
++ break;
++ }
++
++ res= mysql_insert(thd, all_tables, lex->field_list, lex->many_values,
++ lex->update_list, lex->value_list,
++ lex->duplicates, lex->ignore);
++
++ /*
++ If we have inserted into a VIEW, and the base table has
++ AUTO_INCREMENT column, but this column is not accessible through
++ a view, then we should restore LAST_INSERT_ID to the value it
++ had before the statement.
++ */
++ if (first_table->view && !first_table->contain_auto_increment)
++ thd->last_insert_id= thd->current_insert_id;
++
++ break;
++ }
++ case SQLCOM_REPLACE_SELECT:
++ case SQLCOM_INSERT_SELECT:
++ {
++ select_result *result;
++ DBUG_ASSERT(first_table == all_tables && first_table != 0);
++ if ((res= insert_precheck(thd, all_tables)))
++ break;
++
++ /* Fix lock for first table */
++ if (first_table->lock_type == TL_WRITE_DELAYED)
++ first_table->lock_type= TL_WRITE;
++
++ /* Don't unlock tables until command is written to binary log */
++ select_lex->options|= SELECT_NO_UNLOCK;
++
++ unit->set_limit(select_lex);
++
++ if (! thd->locked_tables &&
++ ! (need_start_waiting= ! wait_if_global_read_lock(thd, 0, 1)))
++ {
++ res= 1;
++ break;
++ }
++
++ if (!(res= open_and_lock_tables(thd, all_tables)))
++ {
++ /* Skip first table, which is the table we are inserting in */
++ TABLE_LIST *second_table= first_table->next_local;
++ select_lex->table_list.first= (byte*) second_table;
++ select_lex->context.table_list=
++ select_lex->context.first_name_resolution_table= second_table;
++ res= mysql_insert_select_prepare(thd);
++ if (!res && (result= new select_insert(first_table, first_table->table,
++ &lex->field_list,
++ &lex->update_list,
++ &lex->value_list,
++ lex->duplicates, lex->ignore)))
++ {
++ res= handle_select(thd, lex, result, OPTION_SETUP_TABLES_DONE);
++ /*
++ Invalidate the table in the query cache if something changed
++ after unlocking when changes become visible.
++ TODO: this is workaround. right way will be move invalidating in
++ the unlock procedure.
++ */
++ if (first_table->lock_type == TL_WRITE_CONCURRENT_INSERT &&
++ thd->lock)
++ {
++ /* INSERT ... SELECT should invalidate only the very first table */
++ TABLE_LIST *save_table= first_table->next_local;
++ first_table->next_local= 0;
++ mysql_unlock_tables(thd, thd->lock);
++ query_cache_invalidate3(thd, first_table, 1);
++ first_table->next_local= save_table;
++ thd->lock=0;
++ }
++ delete result;
++ }
++ /* revert changes for SP */
++ select_lex->table_list.first= (byte*) first_table;
++ }
++
++ /*
++ If we have inserted into a VIEW, and the base table has
++ AUTO_INCREMENT column, but this column is not accessible through
++ a view, then we should restore LAST_INSERT_ID to the value it
++ had before the statement.
++ */
++ if (first_table->view && !first_table->contain_auto_increment)
++ thd->last_insert_id= thd->current_insert_id;
++
++ break;
++ }
++ case SQLCOM_TRUNCATE:
++ if (end_active_trans(thd))
++ {
++ res= -1;
++ break;
++ }
++ DBUG_ASSERT(first_table == all_tables && first_table != 0);
++ if (check_one_table_access(thd, DELETE_ACL, all_tables))
++ goto error;
++ /*
++ Don't allow this within a transaction because we want to use
++ re-generate table
++ */
++ if (thd->locked_tables || thd->active_transaction())
++ {
++ my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
++ ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
++ goto error;
++ }
++
++ res= mysql_truncate(thd, first_table, 0);
++ break;
++ case SQLCOM_DELETE:
++ {
++ DBUG_ASSERT(first_table == all_tables && first_table != 0);
++ if ((res= delete_precheck(thd, all_tables)))
++ break;
++ DBUG_ASSERT(select_lex->offset_limit == 0);
++ unit->set_limit(select_lex);
++
++ if (!thd->locked_tables &&
++ !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
++ {
++ res= 1;
++ break;
++ }
++
++ res = mysql_delete(thd, all_tables, select_lex->where,
++ &select_lex->order_list,
++ unit->select_limit_cnt, select_lex->options,
++ FALSE);
++ break;
++ }
++ case SQLCOM_DELETE_MULTI:
++ {
++ DBUG_ASSERT(first_table == all_tables && first_table != 0);
++ TABLE_LIST *aux_tables=
++ (TABLE_LIST *)thd->lex->auxiliary_table_list.first;
++ multi_delete *result;
++
++ if (!thd->locked_tables &&
++ !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
++ {
++ res= 1;
++ break;
++ }
++
++ if ((res= multi_delete_precheck(thd, all_tables)))
++ break;
++
++ /* condition will be TRUE on SP re-excuting */
++ if (select_lex->item_list.elements != 0)
++ select_lex->item_list.empty();
++ if (add_item_to_list(thd, new Item_null()))
++ goto error;
++
++ thd->proc_info="init";
++ if ((res= open_and_lock_tables(thd, all_tables)))
++ break;
++
++ if ((res= mysql_multi_delete_prepare(thd)))
++ goto error;
++
++ if (!thd->is_fatal_error && (result= new multi_delete(aux_tables,
++ lex->table_count)))
++ {
++ res= mysql_select(thd, &select_lex->ref_pointer_array,
++ select_lex->get_table_list(),
++ select_lex->with_wild,
++ select_lex->item_list,
++ select_lex->where,
++ 0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL,
++ (ORDER *)NULL,
++ select_lex->options | thd->options |
++ SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK |
++ OPTION_SETUP_TABLES_DONE,
++ result, unit, select_lex);
++ delete result;
++ }
++ else
++ res= TRUE; // Error
++ break;
++ }
++ case SQLCOM_DROP_TABLE:
++ {
++ DBUG_ASSERT(first_table == all_tables && first_table != 0);
++ if (!lex->drop_temporary)
++ {
++ if (check_table_access(thd, DROP_ACL, all_tables, 0))
++ goto error; /* purecov: inspected */
++ if (end_active_trans(thd))
++ goto error;
++ }
++ else
++ {
++ /*
++ If this is a slave thread, we may sometimes execute some
++ DROP / * 40005 TEMPORARY * / TABLE
++ that come from parts of binlogs (likely if we use RESET SLAVE or CHANGE
++ MASTER TO), while the temporary table has already been dropped.
++ To not generate such irrelevant "table does not exist errors",
++ we silently add IF EXISTS if TEMPORARY was used.
++ */
++ if (thd->slave_thread)
++ lex->drop_if_exists= 1;
++
++ /* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */
++ thd->options|= OPTION_STATUS_NO_TRANS_UPDATE;
++ }
++ /* DDL and binlog write order protected by LOCK_open */
++ res= mysql_rm_table(thd, first_table, lex->drop_if_exists,
++ lex->drop_temporary);
++ }
++ break;
++ case SQLCOM_DROP_INDEX:
++ DBUG_ASSERT(first_table == all_tables && first_table != 0);
++ if (check_one_table_access(thd, INDEX_ACL, all_tables))
++ goto error; /* purecov: inspected */
++ if (end_active_trans(thd))
++ goto error;
++ else
++ res = mysql_drop_index(thd, first_table, &lex->alter_info);
++ break;
++ case SQLCOM_SHOW_PROCESSLIST:
++ if (!thd->security_ctx->priv_user[0] &&
++ check_global_access(thd,PROCESS_ACL))
++ break;
++ mysqld_list_processes(thd,
++ (thd->security_ctx->master_access & PROCESS_ACL ?
++ NullS :
++ thd->security_ctx->priv_user),
++ lex->verbose);
++ break;
++ case SQLCOM_SHOW_STORAGE_ENGINES:
++ res= mysqld_show_storage_engines(thd);
++ break;
++ case SQLCOM_SHOW_PRIVILEGES:
++ res= mysqld_show_privileges(thd);
++ break;
++ case SQLCOM_SHOW_COLUMN_TYPES:
++ res= mysqld_show_column_types(thd);
++ break;
++ case SQLCOM_SHOW_LOGS:
++#ifdef DONT_ALLOW_SHOW_COMMANDS
++ my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
++ MYF(0)); /* purecov: inspected */
++ goto error;
++#else
++ {
++ if (grant_option && check_access(thd, FILE_ACL, any_db,0,0,0,0))
++ goto error;
++ res= mysqld_show_logs(thd);
++ break;
++ }
++#endif
++ case SQLCOM_CHANGE_DB:
++ if (!mysql_change_db(thd,select_lex->db,FALSE))
++ send_ok(thd);
++ break;
++
++ case SQLCOM_LOAD:
++ {
++ DBUG_ASSERT(first_table == all_tables && first_table != 0);
++ uint privilege= (lex->duplicates == DUP_REPLACE ?
++ INSERT_ACL | DELETE_ACL : INSERT_ACL) |
++ (lex->local_file ? 0 : FILE_ACL);
++
++ if (lex->local_file)
++ {
++ if (!(thd->client_capabilities & CLIENT_LOCAL_FILES) ||
++ !opt_local_infile)
++ {
++ my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND), MYF(0));
++ goto error;
++ }
++ }
++
++ if (check_one_table_access(thd, privilege, all_tables))
++ goto error;
++
++ res= mysql_load(thd, lex->exchange, first_table, lex->field_list,
++ lex->update_list, lex->value_list, lex->duplicates,
++ lex->ignore, (bool) lex->local_file);
++ break;
++ }
++
++ case SQLCOM_SET_OPTION:
++ {
++ List<set_var_base> *lex_var_list= &lex->var_list;
++ 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))
++ {
++ my_error(ER_RESERVED_SYNTAX, MYF(0), "SET ONE_SHOT");
++ goto error;
++ }
++ if (!(res= sql_set_variables(thd, lex_var_list)))
++ {
++ /*
++ If the previous command was a SET ONE_SHOT, we don't want to forget
++ about the ONE_SHOT property of that SET. So we use a |= instead of = .
++ */
++ thd->one_shot_set|= lex->one_shot_set;
++ send_ok(thd);
++ }
++ break;
++ }
++
++ case SQLCOM_UNLOCK_TABLES:
++ /*
++ It is critical for mysqldump --single-transaction --master-data that
++ UNLOCK TABLES does not implicitely commit a connection which has only
++ done FLUSH TABLES WITH READ LOCK + BEGIN. If this assumption becomes
++ false, mysqldump will not work.
++ */
++ unlock_locked_tables(thd);
++ if (thd->options & OPTION_TABLE_LOCK)
++ {
++ end_active_trans(thd);
++ thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
++ }
++ if (thd->global_read_lock)
++ unlock_global_read_lock(thd);
++ send_ok(thd);
++ break;
++ case SQLCOM_LOCK_TABLES:
++ unlock_locked_tables(thd);
++ if (check_db_used(thd, all_tables) || end_active_trans(thd))
++ goto error;
++ if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables, 0))
++ goto error;
++ thd->in_lock_tables=1;
++ thd->options|= OPTION_TABLE_LOCK;
++
++ if (!(res= simple_open_n_lock_tables(thd, all_tables)))
++ {
++#ifdef HAVE_QUERY_CACHE
++ if (thd->variables.query_cache_wlock_invalidate)
++ query_cache.invalidate_locked_for_write(first_table);
++#endif /*HAVE_QUERY_CACHE*/
++ thd->locked_tables=thd->lock;
++ thd->lock=0;
++ send_ok(thd);
++ }
++ else
++ thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
++ thd->in_lock_tables=0;
++ break;
++ case SQLCOM_CREATE_DB:
++ {
++ if (end_active_trans(thd))
++ {
++ res= -1;
++ break;
++ }
++ char *alias;
++ if (!(alias=thd->strdup(lex->name)) || check_db_name(lex->name))
++ {
++ my_error(ER_WRONG_DB_NAME, MYF(0), lex->name);
++ break;
++ }
++ /*
++ If in a slave thread :
++ CREATE DATABASE DB was certainly not preceded by USE DB.
++ For that reason, db_ok() in sql/slave.cc did not check the
++ do_db/ignore_db. And as this query involves no tables, tables_ok()
++ above was not called. So we have to check rules again here.
++ */
++#ifdef HAVE_REPLICATION
++ if (thd->slave_thread &&
++ (!db_ok(lex->name, replicate_do_db, replicate_ignore_db) ||
++ !db_ok_with_wild_table(lex->name)))
++ {
++ my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
++ break;
++ }
++#endif
++ if (check_access(thd,CREATE_ACL,lex->name,0,1,0,is_schema_db(lex->name)))
++ break;
++ res= mysql_create_db(thd,(lower_case_table_names == 2 ? alias : lex->name),
++ &lex->create_info, 0);
++ break;
++ }
++ case SQLCOM_DROP_DB:
++ {
++ if (end_active_trans(thd))
++ {
++ res= -1;
++ break;
++ }
++ if (check_db_name(lex->name))
++ {
++ my_error(ER_WRONG_DB_NAME, MYF(0), lex->name);
++ break;
++ }
++ /*
++ If in a slave thread :
++ DROP DATABASE DB may not be preceded by USE DB.
++ For that reason, maybe db_ok() in sql/slave.cc did not check the
++ do_db/ignore_db. And as this query involves no tables, tables_ok()
++ above was not called. So we have to check rules again here.
++ */
++#ifdef HAVE_REPLICATION
++ if (thd->slave_thread &&
++ (!db_ok(lex->name, replicate_do_db, replicate_ignore_db) ||
++ !db_ok_with_wild_table(lex->name)))
++ {
++ my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
++ break;
++ }
++#endif
++ if (check_access(thd,DROP_ACL,lex->name,0,1,0,is_schema_db(lex->name)))
++ break;
++ if (thd->locked_tables || thd->active_transaction())
++ {
++ my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
++ ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
++ goto error;
++ }
++ res= mysql_rm_db(thd, lex->name, lex->drop_if_exists, 0);
++ break;
++ }
++ case SQLCOM_ALTER_DB:
++ {
++ char *db= lex->name;
++ DBUG_ASSERT(db); /* Must be set in the parser */
++ if (!strip_sp(db) || check_db_name(db))
++ {
++ my_error(ER_WRONG_DB_NAME, MYF(0), lex->name);
++ break;
++ }
++ /*
++ If in a slave thread :
++ ALTER DATABASE DB may not be preceded by USE DB.
++ For that reason, maybe db_ok() in sql/slave.cc did not check the
++ do_db/ignore_db. And as this query involves no tables, tables_ok()
++ above was not called. So we have to check rules again here.
++ */
++#ifdef HAVE_REPLICATION
++ if (thd->slave_thread &&
++ (!db_ok(db, replicate_do_db, replicate_ignore_db) ||
++ !db_ok_with_wild_table(db)))
++ {
++ my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
++ break;
++ }
++#endif
++ if (check_access(thd, ALTER_ACL, db, 0, 1, 0, is_schema_db(db)))
++ break;
++ if (thd->locked_tables || thd->active_transaction())
++ {
++ my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
++ ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
++ goto error;
++ }
++ res= mysql_alter_db(thd, db, &lex->create_info);
++ break;
++ }
++ case SQLCOM_SHOW_CREATE_DB:
++ {
++ if (!strip_sp(lex->name) || check_db_name(lex->name))
++ {
++ my_error(ER_WRONG_DB_NAME, MYF(0), lex->name);
++ break;
++ }
++ if (check_access(thd,SELECT_ACL,lex->name,0,1,0,is_schema_db(lex->name)))
++ break;
++ res=mysqld_show_create_db(thd,lex->name,&lex->create_info);
++ break;
++ }
++ case SQLCOM_CREATE_FUNCTION: // UDF function
++ {
++ if (check_access(thd,INSERT_ACL,"mysql",0,1,0,0))
++ break;
++#ifdef HAVE_DLOPEN
++ if (sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname,
++ &thd->sp_func_cache, FALSE))
++ {
++ my_error(ER_UDF_EXISTS, MYF(0), lex->spname->m_name.str);
++ goto error;
++ }
++ if (!(res = mysql_create_function(thd, &lex->udf)))
++ send_ok(thd);
++#else
++ my_error(ER_CANT_OPEN_LIBRARY, MYF(0), lex->udf.dl, 0, "feature disabled");
++ res= TRUE;
++#endif
++ break;
++ }
++#ifndef NO_EMBEDDED_ACCESS_CHECKS
++ case SQLCOM_CREATE_USER:
++ {
++ if (check_access(thd, INSERT_ACL, "mysql", 0, 1, 1, 0) &&
++ check_global_access(thd,CREATE_USER_ACL))
++ break;
++ if (end_active_trans(thd))
++ goto error;
++ /* Conditionally writes to binlog */
++ if (!(res= mysql_create_user(thd, lex->users_list)))
++ send_ok(thd);
++ break;
++ }
++ case SQLCOM_DROP_USER:
++ {
++ if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 1, 0) &&
++ check_global_access(thd,CREATE_USER_ACL))
++ break;
++ if (end_active_trans(thd))
++ goto error;
++ /* Conditionally writes to binlog */
++ if (!(res= mysql_drop_user(thd, lex->users_list)))
++ send_ok(thd);
++ break;
++ }
++ case SQLCOM_RENAME_USER:
++ {
++ if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1, 0) &&
++ check_global_access(thd,CREATE_USER_ACL))
++ break;
++ if (end_active_trans(thd))
++ goto error;
++ /* Conditionally writes to binlog */
++ if (!(res= mysql_rename_user(thd, lex->users_list)))
++ send_ok(thd);
++ break;
++ }
++ case SQLCOM_REVOKE_ALL:
++ {
++ if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1, 0) &&
++ check_global_access(thd,CREATE_USER_ACL))
++ break;
++ /* Conditionally writes to binlog */
++ if (!(res = mysql_revoke_all(thd, lex->users_list)))
++ send_ok(thd);
++ break;
++ }
++ case SQLCOM_REVOKE:
++ case SQLCOM_GRANT:
++ {
++ if (check_access(thd, lex->grant | lex->grant_tot_col | GRANT_ACL,
++ first_table ? first_table->db : select_lex->db,
++ first_table ? &first_table->grant.privilege : 0,
++ first_table ? 0 : 1, 0,
++ first_table ? (bool) first_table->schema_table :
++ select_lex->db ? is_schema_db(select_lex->db) : 0))
++ goto error;
++
++ if (thd->security_ctx->user) // If not replication
++ {
++ LEX_USER *user, *tmp_user;
++
++ List_iterator <LEX_USER> user_list(lex->users_list);
++ while ((tmp_user= user_list++))
++ {
++ if (!(user= get_current_user(thd, tmp_user)))
++ goto error;
++ if (specialflag & SPECIAL_NO_RESOLVE &&
++ hostname_requires_resolving(user->host.str))
++ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
++ ER_WARN_HOSTNAME_WONT_WORK,
++ ER(ER_WARN_HOSTNAME_WONT_WORK),
++ user->host.str);
++ // Are we trying to change a password of another user
++ DBUG_ASSERT(user->host.str != 0);
++ if (strcmp(thd->security_ctx->user, user->user.str) ||
++ my_strcasecmp(system_charset_info,
++ user->host.str, thd->security_ctx->host_or_ip))
++ {
++ // TODO: use check_change_password()
++ if (is_acl_user(user->host.str, user->user.str) &&
++ user->password.str &&
++ check_access(thd, UPDATE_ACL,"mysql",0,1,1,0))
++ {
++ my_message(ER_PASSWORD_NOT_ALLOWED,
++ ER(ER_PASSWORD_NOT_ALLOWED), MYF(0));
++ goto error;
++ }
++ }
++ }
++ }
++ if (first_table)
++ {
++ if (lex->type == TYPE_ENUM_PROCEDURE ||
++ lex->type == TYPE_ENUM_FUNCTION)
++ {
++ uint grants= lex->all_privileges
++ ? (PROC_ACLS & ~GRANT_ACL) | (lex->grant & GRANT_ACL)
++ : lex->grant;
++ if (grant_option &&
++ check_grant_routine(thd, grants | GRANT_ACL, all_tables,
++ lex->type == TYPE_ENUM_PROCEDURE, 0))
++ goto error;
++ /* Conditionally writes to binlog */
++ res= mysql_routine_grant(thd, all_tables,
++ lex->type == TYPE_ENUM_PROCEDURE,
++ lex->users_list, grants,
++ lex->sql_command == SQLCOM_REVOKE, 0);
++ }
++ else
++ {
++ if (grant_option && check_grant(thd,
++ (lex->grant | lex->grant_tot_col |
++ GRANT_ACL),
++ all_tables, 0, UINT_MAX, 0))
++ goto error;
++ /* Conditionally writes to binlog */
++ res= mysql_table_grant(thd, all_tables, lex->users_list,
++ lex->columns, lex->grant,
++ lex->sql_command == SQLCOM_REVOKE);
++ }
++ }
++ else
++ {
++ if (lex->columns.elements || lex->type)
++ {
++ my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER(ER_ILLEGAL_GRANT_FOR_TABLE),
++ MYF(0));
++ goto error;
++ }
++ else
++ /* Conditionally writes to binlog */
++ res = mysql_grant(thd, select_lex->db, lex->users_list, lex->grant,
++ lex->sql_command == SQLCOM_REVOKE);
++ if (!res)
++ {
++ if (lex->sql_command == SQLCOM_GRANT)
++ {
++ List_iterator <LEX_USER> str_list(lex->users_list);
++ LEX_USER *user, *tmp_user;
++ while ((tmp_user=str_list++))
++ {
++ if (!(user= get_current_user(thd, tmp_user)))
++ goto error;
++ reset_mqh(user);
++ }
++ }
++ }
++ }
++ break;
++ }
++#endif /*!NO_EMBEDDED_ACCESS_CHECKS*/
++ case SQLCOM_RESET:
++ /*
++ RESET commands are never written to the binary log, so we have to
++ initialize this variable because RESET shares the same code as FLUSH
++ */
++ lex->no_write_to_binlog= 1;
++ case SQLCOM_FLUSH:
++ {
++ bool write_to_binlog;
++ if (check_global_access(thd,RELOAD_ACL))
++ goto error;
++
++ /*
++ reload_acl_and_cache() will tell us if we are allowed to write to the
++ binlog or not.
++ */
++ if (!reload_acl_and_cache(thd, lex->type, first_table, &write_to_binlog))
++ {
++ /*
++ We WANT to write and we CAN write.
++ ! we write after unlocking the table.
++ */
++ /* Presumably, RESET and binlog writing doesn't require synchronization */
++ if (!lex->no_write_to_binlog && write_to_binlog)
++ {
++ if (mysql_bin_log.is_open())
++ {
++ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
++ mysql_bin_log.write(&qinfo);
++ }
++ }
++ send_ok(thd);
++ }
++
++ break;
++ }
++ case SQLCOM_KILL:
++ {
++ Item *it= (Item *)lex->value_list.head();
++
++ if ((!it->fixed && it->fix_fields(lex->thd, &it)) || it->check_cols(1))
++ {
++ my_message(ER_SET_CONSTANTS_ONLY, ER(ER_SET_CONSTANTS_ONLY),
++ MYF(0));
++ goto error;
++ }
++ kill_one_thread(thd, (ulong)it->val_int(), lex->type & ONLY_KILL_QUERY);
++ break;
++ }
++#ifndef NO_EMBEDDED_ACCESS_CHECKS
++ case SQLCOM_SHOW_GRANTS:
++ {
++ LEX_USER *grant_user= get_current_user(thd, lex->grant_user);
++ if (!grant_user)
++ goto error;
++ if ((thd->security_ctx->priv_user &&
++ !strcmp(thd->security_ctx->priv_user, grant_user->user.str)) ||
++ !check_access(thd, SELECT_ACL, "mysql",0,1,0,0))
++ {
++ res = mysql_show_grants(thd, grant_user);
++ }
++ break;
++ }
++#endif
++ case SQLCOM_HA_OPEN:
++ DBUG_ASSERT(first_table == all_tables && first_table != 0);
++ if (check_db_used(thd, all_tables) ||
++ check_table_access(thd, SELECT_ACL, all_tables, 0))
++ goto error;
++ res= mysql_ha_open(thd, first_table, 0);
++ break;
++ case SQLCOM_HA_CLOSE:
++ DBUG_ASSERT(first_table == all_tables && first_table != 0);
++ if (check_db_used(thd, all_tables))
++ goto error;
++ res= mysql_ha_close(thd, first_table);
++ break;
++ case SQLCOM_HA_READ:
++ DBUG_ASSERT(first_table == all_tables && first_table != 0);
++ /*
++ There is no need to check for table permissions here, because
++ if a user has no permissions to read a table, he won't be
++ able to open it (with SQLCOM_HA_OPEN) in the first place.
++ */
++ if (check_db_used(thd, all_tables))
++ goto error;
++ unit->set_limit(select_lex);
++ res= mysql_ha_read(thd, first_table, lex->ha_read_mode, lex->ident.str,
++ lex->insert_list, lex->ha_rkey_mode, select_lex->where,
++ unit->select_limit_cnt, unit->offset_limit_cnt);
++ break;
++
++ case SQLCOM_BEGIN:
++ if (thd->transaction.xid_state.xa_state != XA_NOTR)
++ {
++ my_error(ER_XAER_RMFAIL, MYF(0),
++ xa_state_names[thd->transaction.xid_state.xa_state]);
++ break;
++ }
++ if (begin_trans(thd))
++ goto error;
++ send_ok(thd);
++ break;
++ case SQLCOM_COMMIT:
++ if (end_trans(thd, lex->tx_release ? COMMIT_RELEASE :
++ lex->tx_chain ? COMMIT_AND_CHAIN : COMMIT))
++ goto error;
++ send_ok(thd);
++ break;
++ case SQLCOM_ROLLBACK:
++ if (end_trans(thd, lex->tx_release ? ROLLBACK_RELEASE :
++ lex->tx_chain ? ROLLBACK_AND_CHAIN : ROLLBACK))
++ goto error;
++ send_ok(thd);
++ break;
++ case SQLCOM_RELEASE_SAVEPOINT:
++ {
++ SAVEPOINT *sv;
++ for (sv=thd->transaction.savepoints; sv; sv=sv->prev)
++ {
++ if (my_strnncoll(system_charset_info,
++ (uchar *)lex->ident.str, lex->ident.length,
++ (uchar *)sv->name, sv->length) == 0)
++ break;
++ }
++ if (sv)
++ {
++ if (ha_release_savepoint(thd, sv))
++ res= TRUE; // cannot happen
++ else
++ send_ok(thd);
++ thd->transaction.savepoints=sv->prev;
++ }
++ else
++ my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", lex->ident.str);
++ break;
++ }
++ case SQLCOM_ROLLBACK_TO_SAVEPOINT:
++ {
++ SAVEPOINT *sv;
++ for (sv=thd->transaction.savepoints; sv; sv=sv->prev)
++ {
++ if (my_strnncoll(system_charset_info,
++ (uchar *)lex->ident.str, lex->ident.length,
++ (uchar *)sv->name, sv->length) == 0)
++ break;
++ }
++ if (sv)
++ {
++ if (ha_rollback_to_savepoint(thd, sv))
++ res= TRUE; // cannot happen
++ else
++ {
++ if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) &&
++ !thd->slave_thread)
++ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
++ ER_WARNING_NOT_COMPLETE_ROLLBACK,
++ ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
++ send_ok(thd);
++ }
++ thd->transaction.savepoints=sv;
++ }
++ else
++ my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", lex->ident.str);
++ break;
++ }
++ case SQLCOM_SAVEPOINT:
++ if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN) ||
++ thd->in_sub_stmt) || !opt_using_transactions)
++ send_ok(thd);
++ else
++ {
++ SAVEPOINT **sv, *newsv;
++ for (sv=&thd->transaction.savepoints; *sv; sv=&(*sv)->prev)
++ {
++ if (my_strnncoll(system_charset_info,
++ (uchar *)lex->ident.str, lex->ident.length,
++ (uchar *)(*sv)->name, (*sv)->length) == 0)
++ break;
++ }
++ if (*sv) /* old savepoint of the same name exists */
++ {
++ newsv=*sv;
++ ha_release_savepoint(thd, *sv); // it cannot fail
++ *sv=(*sv)->prev;
++ }
++ else if ((newsv=(SAVEPOINT *) alloc_root(&thd->transaction.mem_root,
++ savepoint_alloc_size)) == 0)
++ {
++ my_error(ER_OUT_OF_RESOURCES, MYF(0));
++ break;
++ }
++ newsv->name=strmake_root(&thd->transaction.mem_root,
++ lex->ident.str, lex->ident.length);
++ newsv->length=lex->ident.length;
++ /*
++ if we'll get an error here, don't add new savepoint to the list.
++ we'll lose a little bit of memory in transaction mem_root, but it'll
++ be free'd when transaction ends anyway
++ */
++ if (ha_savepoint(thd, newsv))
++ res= TRUE;
++ else
++ {
++ newsv->prev=thd->transaction.savepoints;
++ thd->transaction.savepoints=newsv;
++ send_ok(thd);
++ }
++ }
++ break;
++ case SQLCOM_CREATE_PROCEDURE:
++ case SQLCOM_CREATE_SPFUNCTION:
++ {
++ uint namelen;
++ char *name;
++ int result= SP_INTERNAL_ERROR;
++
++ DBUG_ASSERT(lex->sphead != 0);
++ DBUG_ASSERT(lex->sphead->m_db.str); /* Must be initialized in the parser */
++ /*
++ Verify that the database name is allowed, optionally
++ lowercase it.
++ */
++ if (check_db_name(lex->sphead->m_db.str))
++ {
++ my_error(ER_WRONG_DB_NAME, MYF(0), lex->sphead->m_db.str);
++ goto create_sp_error;
++ }
++
++ /*
++ Check that a database directory with this name
++ exists. Design note: This won't work on virtual databases
++ like information_schema.
++ */
++ if (check_db_dir_existence(lex->sphead->m_db.str))
++ {
++ my_error(ER_BAD_DB_ERROR, MYF(0), lex->sphead->m_db.str);
++ goto create_sp_error;
++ }
++
++ if (check_access(thd, CREATE_PROC_ACL, lex->sphead->m_db.str, 0, 0, 0,
++ is_schema_db(lex->sphead->m_db.str)))
++ goto create_sp_error;
++
++ if (end_active_trans(thd))
++ goto create_sp_error;
++
++ name= lex->sphead->name(&namelen);
++#ifdef HAVE_DLOPEN
++ if (lex->sphead->m_type == TYPE_ENUM_FUNCTION)
++ {
++ udf_func *udf = find_udf(name, namelen);
++
++ if (udf)
++ {
++ my_error(ER_UDF_EXISTS, MYF(0), name);
++ goto create_sp_error;
++ }
++ }
++#endif
++
++ /*
++ If the definer is not specified, this means that CREATE-statement missed
++ DEFINER-clause. DEFINER-clause can be missed in two cases:
++
++ - The user submitted a statement w/o the clause. This is a normal
++ case, we should assign CURRENT_USER as definer.
++
++ - Our slave received an updated from the master, that does not
++ replicate definer for stored rountines. We should also assign
++ CURRENT_USER as definer here, but also we should mark this routine
++ as NON-SUID. This is essential for the sake of backward
++ compatibility.
++
++ The problem is the slave thread is running under "special" user (@),
++ that actually does not exist. In the older versions we do not fail
++ execution of a stored routine if its definer does not exist and
++ continue the execution under the authorization of the invoker
++ (BUG#13198). And now if we try to switch to slave-current-user (@),
++ we will fail.
++
++ Actually, this leads to the inconsistent state of master and
++ slave (different definers, different SUID behaviour), but it seems,
++ this is the best we can do.
++ */
++
++ if (!lex->definer)
++ {
++ bool res= FALSE;
++ Query_arena original_arena;
++ Query_arena *ps_arena = thd->activate_stmt_arena_if_needed(&original_arena);
++
++ if (!(lex->definer= create_default_definer(thd)))
++ res= TRUE;
++
++ if (ps_arena)
++ thd->restore_active_arena(ps_arena, &original_arena);
++
++ /* Error has been already reported. */
++ if (res)
++ goto create_sp_error;
++
++ if (thd->slave_thread)
++ lex->sphead->m_chistics->suid= SP_IS_NOT_SUID;
++ }
++
++ /*
++ If the specified definer differs from the current user, we should check
++ that the current user has SUPER privilege (in order to create a stored
++ routine under another user one must have SUPER privilege).
++ */
++
++ else if (strcmp(lex->definer->user.str, thd->security_ctx->priv_user) ||
++ my_strcasecmp(system_charset_info,
++ lex->definer->host.str,
++ thd->security_ctx->priv_host))
++ {
++ if (check_global_access(thd, SUPER_ACL))
++ {
++ my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER");
++ goto create_sp_error;
++ }
++ }
++
++ /* Check that the specified definer exists. Emit a warning if not. */
++
++#ifndef NO_EMBEDDED_ACCESS_CHECKS
++ if (!is_acl_user(lex->definer->host.str,
++ lex->definer->user.str))
++ {
++ push_warning_printf(thd,
++ MYSQL_ERROR::WARN_LEVEL_NOTE,
++ ER_NO_SUCH_USER,
++ ER(ER_NO_SUCH_USER),
++ lex->definer->user.str,
++ lex->definer->host.str);
++ }
++#endif /* NO_EMBEDDED_ACCESS_CHECKS */
++
++ res= (result= lex->sphead->create(thd));
++ switch (result) {
++ case SP_OK:
++#ifndef NO_EMBEDDED_ACCESS_CHECKS
++ /* only add privileges if really neccessary */
++ if (sp_automatic_privileges && !opt_noacl &&
++ check_routine_access(thd, DEFAULT_CREATE_PROC_ACLS,
++ lex->sphead->m_db.str, name,
++ lex->sql_command == SQLCOM_CREATE_PROCEDURE, 1))
++ {
++ if (sp_grant_privileges(thd, lex->sphead->m_db.str, name,
++ lex->sql_command == SQLCOM_CREATE_PROCEDURE))
++ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
++ ER_PROC_AUTO_GRANT_FAIL,
++ ER(ER_PROC_AUTO_GRANT_FAIL));
++ close_thread_tables(thd);
++ }
++#endif
++ break;
++ case SP_WRITE_ROW_FAILED:
++ my_error(ER_SP_ALREADY_EXISTS, MYF(0), SP_TYPE_STRING(lex), name);
++ break;
++ case SP_BAD_IDENTIFIER:
++ my_error(ER_TOO_LONG_IDENT, MYF(0), name);
++ break;
++ case SP_BODY_TOO_LONG:
++ my_error(ER_TOO_LONG_BODY, MYF(0), name);
++ break;
++ default:
++ my_error(ER_SP_STORE_FAILED, MYF(0), SP_TYPE_STRING(lex), name);
++ break;
++ } /* end switch */
++
++ /*
++ Capture all errors within this CASE and
++ clean up the environment.
++ */
++create_sp_error:
++ lex->unit.cleanup();
++ delete lex->sphead;
++ lex->sphead= 0;
++ if (result != SP_OK )
++ goto error;
++ send_ok(thd);
++ break; /* break super switch */
++ } /* end case group bracket */
++ case SQLCOM_CALL:
++ {
++ sp_head *sp;
++
++ /*
++ 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.
++ */
++ if (!(sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname,
++ &thd->sp_proc_cache, TRUE)))
++ {
++ my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PROCEDURE",
++ lex->spname->m_qname.str);
++ goto error;
++ }
++ else
++ {
++ ha_rows select_limit;
++ /* bits that should be cleared in thd->server_status */
++ uint bits_to_be_cleared= 0;
++ /*
++ Check that the stored procedure doesn't contain Dynamic SQL
++ and doesn't return result sets: such stored procedures can't
++ be called from a function or trigger.
++ */
++ if (thd->in_sub_stmt)
++ {
++ const char *where= (thd->in_sub_stmt & SUB_STMT_TRIGGER ?
++ "trigger" : "function");
++ if (sp->is_not_allowed_in_function(where))
++ goto error;
++ }
++
++ my_bool nsok= thd->net.no_send_ok;
++ thd->net.no_send_ok= TRUE;
++ if (sp->m_flags & sp_head::MULTI_RESULTS)
++ {
++ if (! (thd->client_capabilities & CLIENT_MULTI_RESULTS))
++ {
++ /*
++ The client does not support multiple result sets being sent
++ back
++ */
++ my_error(ER_SP_BADSELECT, MYF(0), sp->m_qname.str);
++ thd->net.no_send_ok= nsok;
++ goto error;
++ }
++ /*
++ If SERVER_MORE_RESULTS_EXISTS is not set,
++ then remember that it should be cleared
++ */
++ bits_to_be_cleared= (~thd->server_status &
++ SERVER_MORE_RESULTS_EXISTS);
++ thd->server_status|= SERVER_MORE_RESULTS_EXISTS;
++ }
++
++#ifndef NO_EMBEDDED_ACCESS_CHECKS
++ if (check_routine_access(thd, EXECUTE_ACL,
++ sp->m_db.str, sp->m_name.str, TRUE, FALSE))
++ {
++ thd->net.no_send_ok= nsok;
++ goto error;
++ }
++#endif
++ select_limit= thd->variables.select_limit;
++ thd->variables.select_limit= HA_POS_ERROR;
++
++ /*
++ We never write CALL statements into binlog:
++ - If the mode is non-prelocked, each statement will be logged
++ separately.
++ - If the mode is prelocked, the invoking statement will care
++ about writing into binlog.
++ So just execute the statement.
++ */
++ res= sp->execute_procedure(thd, &lex->value_list);
++ /*
++ If warnings have been cleared, we have to clear total_warn_count
++ too, otherwise the clients get confused.
++ */
++ if (thd->warn_list.is_empty())
++ thd->total_warn_count= 0;
++
++ thd->variables.select_limit= select_limit;
++
++ thd->net.no_send_ok= nsok;
++ thd->server_status&= ~bits_to_be_cleared;
++
++ if (!res)
++ send_ok(thd, (ulong) (thd->row_count_func < 0 ? 0 :
++ thd->row_count_func));
++ else
++ goto error; // Substatement should already have sent error
++ }
++ break;
++ }
++ case SQLCOM_ALTER_PROCEDURE:
++ case SQLCOM_ALTER_FUNCTION:
++ {
++ int result;
++ sp_head *sp;
++ st_sp_chistics chistics;
++
++ memcpy(&chistics, &lex->sp_chistics, sizeof(chistics));
++ if (lex->sql_command == SQLCOM_ALTER_PROCEDURE)
++ sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname,
++ &thd->sp_proc_cache, FALSE);
++ else
++ sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname,
++ &thd->sp_func_cache, FALSE);
++ mysql_reset_errors(thd, 0);
++ if (! sp)
++ {
++ if (lex->spname->m_db.str)
++ result= SP_KEY_NOT_FOUND;
++ else
++ {
++ my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
++ goto error;
++ }
++ }
++ else
++ {
++ if (check_routine_access(thd, ALTER_PROC_ACL, sp->m_db.str,
++ sp->m_name.str,
++ lex->sql_command == SQLCOM_ALTER_PROCEDURE, 0))
++ goto error;
++
++ if (end_active_trans(thd))
++ goto error;
++ memcpy(&lex->sp_chistics, &chistics, sizeof(lex->sp_chistics));
++ if ((sp->m_type == TYPE_ENUM_FUNCTION) &&
++ !trust_function_creators && mysql_bin_log.is_open() &&
++ !sp->m_chistics->detistic &&
++ (chistics.daccess == SP_CONTAINS_SQL ||
++ chistics.daccess == SP_MODIFIES_SQL_DATA))
++ {
++ my_message(ER_BINLOG_UNSAFE_ROUTINE,
++ ER(ER_BINLOG_UNSAFE_ROUTINE), MYF(0));
++ result= SP_INTERNAL_ERROR;
++ }
++ else
++ {
++ /*
++ Note that if you implement the capability of ALTER FUNCTION to
++ alter the body of the function, this command should be made to
++ follow the restrictions that log-bin-trust-function-creators=0
++ already puts on CREATE FUNCTION.
++ */
++ if (lex->sql_command == SQLCOM_ALTER_PROCEDURE)
++ /* Conditionally writes to binlog */
++ result= sp_update_procedure(thd, lex->spname, &lex->sp_chistics);
++ else
++ /* Conditionally writes to binlog */
++ result= sp_update_function(thd, lex->spname, &lex->sp_chistics);
++ }
++ }
++ switch (result)
++ {
++ case SP_OK:
++ send_ok(thd);
++ break;
++ case SP_KEY_NOT_FOUND:
++ my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
++ SP_COM_STRING(lex), lex->spname->m_qname.str);
++ goto error;
++ default:
++ my_error(ER_SP_CANT_ALTER, MYF(0),
++ SP_COM_STRING(lex), lex->spname->m_qname.str);
++ goto error;
++ }
++ break;
++ }
++ case SQLCOM_DROP_PROCEDURE:
++ case SQLCOM_DROP_FUNCTION:
++ {
++ int result;
++ int type= (lex->sql_command == SQLCOM_DROP_PROCEDURE ?
++ TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION);
++
++ result= sp_routine_exists_in_table(thd, type, lex->spname);
++ mysql_reset_errors(thd, 0);
++ if (result == SP_OK)
++ {
++ char *db= lex->spname->m_db.str;
++ char *name= lex->spname->m_name.str;
++
++ if (check_routine_access(thd, ALTER_PROC_ACL, db, name,
++ lex->sql_command == SQLCOM_DROP_PROCEDURE, 0))
++ goto error;
++
++ if (end_active_trans(thd))
++ goto error;
++#ifndef NO_EMBEDDED_ACCESS_CHECKS
++ if (sp_automatic_privileges && !opt_noacl &&
++ sp_revoke_privileges(thd, db, name,
++ lex->sql_command == SQLCOM_DROP_PROCEDURE))
++ {
++ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
++ ER_PROC_AUTO_REVOKE_FAIL,
++ ER(ER_PROC_AUTO_REVOKE_FAIL));
++ }
++#endif
++ if (lex->sql_command == SQLCOM_DROP_PROCEDURE)
++ /* Conditionally writes to binlog */
++ result= sp_drop_procedure(thd, lex->spname); /* Conditionally writes to binlog */
++ else
++ /* Conditionally writes to binlog */
++ result= sp_drop_function(thd, lex->spname); /* Conditionally writes to binlog */
++ }
++ else
++ {
++#ifdef HAVE_DLOPEN
++ if (lex->sql_command == SQLCOM_DROP_FUNCTION)
++ {
++ udf_func *udf = find_udf(lex->spname->m_name.str,
++ lex->spname->m_name.length);
++ if (udf)
++ {
++ if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 0, 0))
++ goto error;
++
++ /* Does NOT write to binlog */
++ if (!(res = mysql_drop_function(thd, &lex->spname->m_name)))
++ {
++ send_ok(thd);
++ break;
++ }
++ }
++ }
++#endif
++ if (lex->spname->m_db.str)
++ result= SP_KEY_NOT_FOUND;
++ else
++ {
++ my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
++ goto error;
++ }
++ }
++ res= result;
++ switch (result)
++ {
++ case SP_OK:
++ send_ok(thd);
++ break;
++ case SP_KEY_NOT_FOUND:
++ if (lex->drop_if_exists)
++ {
++ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
++ ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST),
++ SP_COM_STRING(lex), lex->spname->m_name.str);
++ res= FALSE;
++ send_ok(thd);
++ break;
++ }
++ my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
++ SP_COM_STRING(lex), lex->spname->m_qname.str);
++ goto error;
++ default:
++ my_error(ER_SP_DROP_FAILED, MYF(0),
++ SP_COM_STRING(lex), lex->spname->m_qname.str);
++ goto error;
++ }
++ break;
++ }
++ case SQLCOM_SHOW_CREATE_PROC:
++ {
++ if (lex->spname->m_name.length > NAME_LEN)
++ {
++ my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str);
++ goto error;
++ }
++ if (sp_show_create_procedure(thd, lex->spname) != SP_OK)
++ { /* We don't distinguish between errors for now */
++ my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
++ SP_COM_STRING(lex), lex->spname->m_name.str);
++ goto error;
++ }
++ break;
++ }
++ case SQLCOM_SHOW_CREATE_FUNC:
++ {
++ if (lex->spname->m_name.length > NAME_LEN)
++ {
++ my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str);
++ goto error;
++ }
++ if (sp_show_create_function(thd, lex->spname) != SP_OK)
++ { /* We don't distinguish between errors for now */
++ my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
++ SP_COM_STRING(lex), lex->spname->m_name.str);
++ goto error;
++ }
++ break;
++ }
++ case SQLCOM_SHOW_STATUS_PROC:
++ {
++ res= sp_show_status_procedure(thd, (lex->wild ?
++ lex->wild->ptr() : NullS));
++ break;
++ }
++ case SQLCOM_SHOW_STATUS_FUNC:
++ {
++ res= sp_show_status_function(thd, (lex->wild ?
++ lex->wild->ptr() : NullS));
++ break;
++ }
++#ifndef DBUG_OFF
++ case SQLCOM_SHOW_PROC_CODE:
++ case SQLCOM_SHOW_FUNC_CODE:
++ {
++ sp_head *sp;
++
++ if (lex->spname->m_name.length > NAME_LEN)
++ {
++ my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str);
++ goto error;
++ }
++ if (lex->sql_command == SQLCOM_SHOW_PROC_CODE)
++ sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname,
++ &thd->sp_proc_cache, FALSE);
++ else
++ sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname,
++ &thd->sp_func_cache, FALSE);
++ if (!sp || sp->show_routine_code(thd))
++ {
++ /* We don't distinguish between errors for now */
++ my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
++ SP_COM_STRING(lex), lex->spname->m_name.str);
++ goto error;
++ }
++ break;
++ }
++#endif // ifndef DBUG_OFF
++ case SQLCOM_CREATE_VIEW:
++ {
++ if (end_active_trans(thd))
++ goto error;
++
++ res= mysql_create_view(thd, first_table, thd->lex->create_view_mode);
++ break;
++ }
++ case SQLCOM_DROP_VIEW:
++ {
++ if (check_table_access(thd, DROP_ACL, all_tables, 0) ||
++ end_active_trans(thd))
++ goto error;
++ /* Conditionally writes to binlog. */
++ res= mysql_drop_view(thd, first_table, thd->lex->drop_mode);
++ break;
++ }
++ case SQLCOM_CREATE_TRIGGER:
++ {
++ if (end_active_trans(thd))
++ goto error;
++
++ /* Conditionally writes to binlog. */
++ res= mysql_create_or_drop_trigger(thd, all_tables, 1);
++
++ /* We don't care about trigger body after this point */
++ delete lex->sphead;
++ lex->sphead= 0;
++ break;
++ }
++ case SQLCOM_DROP_TRIGGER:
++ {
++ if (end_active_trans(thd))
++ goto error;
++
++ /* Conditionally writes to binlog. */
++ res= mysql_create_or_drop_trigger(thd, all_tables, 0);
++ break;
++ }
++ case SQLCOM_XA_START:
++ if (thd->transaction.xid_state.xa_state == XA_IDLE &&
++ thd->lex->xa_opt == XA_RESUME)
++ {
++ if (! thd->transaction.xid_state.xid.eq(thd->lex->xid))
++ {
++ my_error(ER_XAER_NOTA, MYF(0));
++ break;
++ }
++ thd->transaction.xid_state.xa_state=XA_ACTIVE;
++ send_ok(thd);
++ break;
++ }
++ if (thd->lex->xa_opt != XA_NONE)
++ { // JOIN is not supported yet. TODO
++ my_error(ER_XAER_INVAL, MYF(0));
++ break;
++ }
++ if (thd->transaction.xid_state.xa_state != XA_NOTR)
++ {
++ my_error(ER_XAER_RMFAIL, MYF(0),
++ xa_state_names[thd->transaction.xid_state.xa_state]);
++ break;
++ }
++ if (thd->active_transaction() || thd->locked_tables)
++ {
++ my_error(ER_XAER_OUTSIDE, MYF(0));
++ break;
++ }
++ if (xid_cache_search(thd->lex->xid))
++ {
++ my_error(ER_XAER_DUPID, MYF(0));
++ break;
++ }
++ DBUG_ASSERT(thd->transaction.xid_state.xid.is_null());
++ thd->transaction.xid_state.xa_state=XA_ACTIVE;
++ thd->transaction.xid_state.xid.set(thd->lex->xid);
++ xid_cache_insert(&thd->transaction.xid_state);
++ thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) |
++ OPTION_BEGIN);
++ thd->server_status|= SERVER_STATUS_IN_TRANS;
++ send_ok(thd);
++ break;
++ case SQLCOM_XA_END:
++ /* fake it */
++ if (thd->lex->xa_opt != XA_NONE)
++ { // SUSPEND and FOR MIGRATE are not supported yet. TODO
++ my_error(ER_XAER_INVAL, MYF(0));
++ break;
++ }
++ if (thd->transaction.xid_state.xa_state != XA_ACTIVE)
++ {
++ my_error(ER_XAER_RMFAIL, MYF(0),
++ xa_state_names[thd->transaction.xid_state.xa_state]);
++ break;
++ }
++ if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
++ {
++ my_error(ER_XAER_NOTA, MYF(0));
++ break;
++ }
++ thd->transaction.xid_state.xa_state=XA_IDLE;
++ send_ok(thd);
++ break;
++ case SQLCOM_XA_PREPARE:
++ if (thd->transaction.xid_state.xa_state != XA_IDLE)
++ {
++ my_error(ER_XAER_RMFAIL, MYF(0),
++ xa_state_names[thd->transaction.xid_state.xa_state]);
++ break;
++ }
++ if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
++ {
++ my_error(ER_XAER_NOTA, MYF(0));
++ break;
++ }
++ if (ha_prepare(thd))
++ {
++ my_error(ER_XA_RBROLLBACK, MYF(0));
++ xid_cache_delete(&thd->transaction.xid_state);
++ thd->transaction.xid_state.xa_state=XA_NOTR;
++ break;
++ }
++ thd->transaction.xid_state.xa_state=XA_PREPARED;
++ send_ok(thd);
++ break;
++ case SQLCOM_XA_COMMIT:
++ if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
++ {
++ XID_STATE *xs=xid_cache_search(thd->lex->xid);
++ if (!xs || xs->in_thd)
++ my_error(ER_XAER_NOTA, MYF(0));
++ else
++ {
++ ha_commit_or_rollback_by_xid(thd->lex->xid, 1);
++ xid_cache_delete(xs);
++ send_ok(thd);
++ }
++ break;
++ }
++ if (thd->transaction.xid_state.xa_state == XA_IDLE &&
++ thd->lex->xa_opt == XA_ONE_PHASE)
++ {
++ int r;
++ if ((r= ha_commit(thd)))
++ my_error(r == 1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0));
++ else
++ send_ok(thd);
++ }
++ else if (thd->transaction.xid_state.xa_state == XA_PREPARED &&
++ thd->lex->xa_opt == XA_NONE)
++ {
++ if (wait_if_global_read_lock(thd, 0, 0))
++ {
++ ha_rollback(thd);
++ my_error(ER_XAER_RMERR, MYF(0));
++ }
++ else
++ {
++ if (ha_commit_one_phase(thd, 1))
++ my_error(ER_XAER_RMERR, MYF(0));
++ else
++ send_ok(thd);
++ start_waiting_global_read_lock(thd);
++ }
++ }
++ else
++ {
++ my_error(ER_XAER_RMFAIL, MYF(0),
++ xa_state_names[thd->transaction.xid_state.xa_state]);
++ break;
++ }
++ thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
++ thd->server_status&= ~SERVER_STATUS_IN_TRANS;
++ xid_cache_delete(&thd->transaction.xid_state);
++ thd->transaction.xid_state.xa_state=XA_NOTR;
++ break;
++ case SQLCOM_XA_ROLLBACK:
++ if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
++ {
++ XID_STATE *xs=xid_cache_search(thd->lex->xid);
++ if (!xs || xs->in_thd)
++ my_error(ER_XAER_NOTA, MYF(0));
++ else
++ {
++ ha_commit_or_rollback_by_xid(thd->lex->xid, 0);
++ xid_cache_delete(xs);
++ send_ok(thd);
++ }
++ break;
++ }
++ if (thd->transaction.xid_state.xa_state != XA_IDLE &&
++ thd->transaction.xid_state.xa_state != XA_PREPARED)
++ {
++ my_error(ER_XAER_RMFAIL, MYF(0),
++ xa_state_names[thd->transaction.xid_state.xa_state]);
++ break;
++ }
++ if (ha_rollback(thd))
++ my_error(ER_XAER_RMERR, MYF(0));
++ else
++ send_ok(thd);
++ thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
++ thd->server_status&= ~SERVER_STATUS_IN_TRANS;
++ xid_cache_delete(&thd->transaction.xid_state);
++ thd->transaction.xid_state.xa_state=XA_NOTR;
++ break;
++ case SQLCOM_XA_RECOVER:
++ res= mysql_xa_recover(thd);
++ break;
++ default:
++#ifndef EMBEDDED_LIBRARY
++ DBUG_ASSERT(0); /* Impossible */
++#endif
++ send_ok(thd);
++ break;
++ }
++ thd->proc_info="query end";
++ /* Two binlog-related cleanups: */
++
++ /*
++ Reset system variables temporarily modified by SET ONE SHOT.
++
++ Exception: If this is a SET, do nothing. This is to allow
++ mysqlbinlog to print many SET commands (in this case we want the
++ charset temp setting to live until the real query). This is also
++ needed so that SET CHARACTER_SET_CLIENT... does not cancel itself
++ immediately.
++ */
++ if (thd->one_shot_set && lex->sql_command != SQLCOM_SET_OPTION)
++ reset_one_shot_variables(thd);
++
++ /*
++ The return value for ROW_COUNT() is "implementation dependent" if the
++ statement is not DELETE, INSERT or UPDATE, but -1 is what JDBC and ODBC
++ wants.
++
++ We do not change the value for a CALL or EXECUTE statement, so the value
++ generated by the last called (or executed) statement is preserved.
++ */
++ if (lex->sql_command != SQLCOM_CALL && lex->sql_command != SQLCOM_EXECUTE &&
++ uc_update_queries[lex->sql_command]<2)
++ thd->row_count_func= -1;
++
++ goto end;
++
++error:
++ res= TRUE;
++
++end:
++ if (need_start_waiting)
++ {
++ /*
++ Release the protection against the global read lock and wake
++ everyone, who might want to set a global read lock.
++ */
++ start_waiting_global_read_lock(thd);
++ }
++ DBUG_RETURN(res || thd->net.report_error);
++}
++
++
++/*
++ Check grants for commands which work only with one table.
++
++ SYNOPSIS
++ check_single_table_access()
++ thd Thread handler
++ privilege requested privilege
++ all_tables global table list of query
++
++ RETURN
++ 0 - OK
++ 1 - access denied, error is sent to client
++*/
++
++bool check_single_table_access(THD *thd, ulong privilege,
++ TABLE_LIST *all_tables)
++{
++ Security_context * backup_ctx= thd->security_ctx;
++
++ /* we need to switch to the saved context (if any) */
++ if (all_tables->security_ctx)
++ thd->security_ctx= all_tables->security_ctx;
++
++ const char *db_name;
++ if ((all_tables->view || all_tables->field_translation) &&
++ !all_tables->schema_table)
++ db_name= all_tables->view_db.str;
++ else
++ db_name= all_tables->db;
++
++ if (check_access(thd, privilege, db_name,
++ &all_tables->grant.privilege, 0, 0,
++ test(all_tables->schema_table)))
++ goto deny;
++
++ /* Show only 1 table for check_grant */
++ if (grant_option && check_grant(thd, privilege, all_tables, 0, 1, 0))
++ goto deny;
++
++ thd->security_ctx= backup_ctx;
++ return 0;
++
++deny:
++ thd->security_ctx= backup_ctx;
++ return 1;
++}
++
++/*
++ Check grants for commands which work only with one table and all other
++ tables belonging to subselects or implicitly opened tables.
++
++ SYNOPSIS
++ check_one_table_access()
++ thd Thread handler
++ privilege requested privilege
++ all_tables global table list of query
++
++ RETURN
++ 0 - OK
++ 1 - access denied, error is sent to client
++*/
++
++bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables)
++{
++ if (check_single_table_access (thd,privilege,all_tables))
++ return 1;
++
++ /* Check rights on tables of subselects and implictly opened tables */
++ TABLE_LIST *subselects_tables, *view= all_tables->view ? all_tables : 0;
++ if ((subselects_tables= all_tables->next_global))
++ {
++ /*
++ Access rights asked for the first table of a view should be the same
++ as for the view
++ */
++ if (view && subselects_tables->belong_to_view == view)
++ {
++ if (check_single_table_access (thd, privilege, subselects_tables))
++ return 1;
++ subselects_tables= subselects_tables->next_global;
++ }
++ if (subselects_tables &&
++ (check_table_access(thd, SELECT_ACL, subselects_tables, 0)))
++ return 1;
++ }
++ return 0;
++}
++
++
++/****************************************************************************
++ Get the user (global) and database privileges for all used tables
++
++ NOTES
++ The idea of EXTRA_ACL is that one will be granted access to the table if
++ one has the asked privilege on any column combination of the table; For
++ example to be able to check a table one needs to have SELECT privilege on
++ any column of the table.
++
++ RETURN
++ 0 ok
++ 1 If we can't get the privileges and we don't use table/column grants.
++
++ save_priv In this we store global and db level grants for the table
++ Note that we don't store db level grants if the global grants
++ is enough to satisfy the request and the global grants contains
++ a SELECT grant.
++****************************************************************************/
++
++bool
++check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
++ bool dont_check_global_grants, bool no_errors, bool schema_db)
++{
++ Security_context *sctx= thd->security_ctx;
++#ifndef NO_EMBEDDED_ACCESS_CHECKS
++ ulong db_access;
++ bool db_is_pattern= test(want_access & GRANT_ACL);
++#endif
++ ulong dummy;
++ DBUG_ENTER("check_access");
++ DBUG_PRINT("enter",("db: %s want_access: %lu master_access: %lu",
++ db ? db : "", want_access, sctx->master_access));
++ if (save_priv)
++ *save_priv=0;
++ else
++ save_priv= &dummy;
++
++ if ((!db || !db[0]) && !thd->db && !dont_check_global_grants)
++ {
++ DBUG_PRINT("error",("No database"));
++ if (!no_errors)
++ my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR),
++ MYF(0)); /* purecov: tested */
++ DBUG_RETURN(TRUE); /* purecov: tested */
++ }
++
++ if (schema_db)
++ {
++ if (want_access & ~(SELECT_ACL | EXTRA_ACL))
++ {
++ if (!no_errors)
++ {
++ const char *db_name= db ? db : thd->db;
++ my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
++ sctx->priv_user, sctx->priv_host, db_name);
++ }
++ DBUG_RETURN(TRUE);
++ }
++ else
++ {
++ *save_priv= SELECT_ACL;
++ DBUG_RETURN(FALSE);
++ }
++ }
++
++#ifdef NO_EMBEDDED_ACCESS_CHECKS
++ DBUG_RETURN(0);
++#else
++ if ((sctx->master_access & want_access) == want_access)
++ {
++ /*
++ If we don't have a global SELECT privilege, we have to get the database
++ specific access rights to be able to handle queries of type
++ UPDATE t1 SET a=1 WHERE b > 0
++ */
++ db_access= sctx->db_access;
++ if (!(sctx->master_access & SELECT_ACL) &&
++ (db && (!thd->db || db_is_pattern || strcmp(db,thd->db))))
++ db_access=acl_get(sctx->host, sctx->ip, sctx->priv_user, db,
++ db_is_pattern);
++ *save_priv=sctx->master_access | db_access;
++ DBUG_RETURN(FALSE);
++ }
++ if (((want_access & ~sctx->master_access) & ~(DB_ACLS | EXTRA_ACL)) ||
++ ! db && dont_check_global_grants)
++ { // We can never grant this
++ DBUG_PRINT("error",("No possible access"));
++ if (!no_errors)
++ my_error(ER_ACCESS_DENIED_ERROR, MYF(0),
++ sctx->priv_user,
++ sctx->priv_host,
++ (thd->password ?
++ ER(ER_YES) :
++ ER(ER_NO))); /* purecov: tested */
++ DBUG_RETURN(TRUE); /* purecov: tested */
++ }
++
++ if (db == any_db)
++ DBUG_RETURN(FALSE); // Allow select on anything
++
++ if (db && (!thd->db || db_is_pattern || strcmp(db,thd->db)))
++ db_access= acl_get(sctx->host, sctx->ip, sctx->priv_user, db,
++ db_is_pattern);
++ else
++ db_access= sctx->db_access;
++ DBUG_PRINT("info",("db_access: %lu", db_access));
++ /* Remove SHOW attribute and access rights we already have */
++ want_access &= ~(sctx->master_access | EXTRA_ACL);
++ DBUG_PRINT("info",("db_access: %lu want_access: %lu",
++ db_access, want_access));
++ db_access= ((*save_priv=(db_access | sctx->master_access)) & want_access);
++
++ /* grant_option is set if there exists a single table or column grant */
++ if (db_access == want_access ||
++ (grant_option && !dont_check_global_grants &&
++ !(want_access & ~(db_access | TABLE_ACLS | PROC_ACLS))))
++ DBUG_RETURN(FALSE); /* Ok */
++
++ DBUG_PRINT("error",("Access denied"));
++ if (!no_errors)
++ my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
++ sctx->priv_user, sctx->priv_host,
++ (db ? db : (thd->db ?
++ thd->db :
++ "unknown"))); /* purecov: tested */
++ DBUG_RETURN(TRUE); /* purecov: tested */
++#endif /* NO_EMBEDDED_ACCESS_CHECKS */
++}
++
++
++/*
++ check for global access and give descriptive error message if it fails
++
++ SYNOPSIS
++ check_global_access()
++ thd Thread handler
++ want_access Use should have any of these global rights
++
++ WARNING
++ One gets access right if one has ANY of the rights in want_access
++ This is useful as one in most cases only need one global right,
++ but in some case we want to check if the user has SUPER or
++ REPL_CLIENT_ACL rights.
++
++ RETURN
++ 0 ok
++ 1 Access denied. In this case an error is sent to the client
++*/
++
++bool check_global_access(THD *thd, ulong want_access)
++{
++#ifdef NO_EMBEDDED_ACCESS_CHECKS
++ return 0;
++#else
++ char command[128];
++ if ((thd->security_ctx->master_access & want_access))
++ return 0;
++ get_privilege_desc(command, sizeof(command), want_access);
++ my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), command);
++ return 1;
++#endif /* NO_EMBEDDED_ACCESS_CHECKS */
++}
++
++
++/*
++ Check the privilege for all used tables.
++
++ SYNOPSYS
++ check_table_access()
++ thd Thread context
++ want_access Privileges requested
++ tables List of tables to be checked
++ no_errors FALSE/TRUE - report/don't report error to
++ the client (using my_error() call).
++
++ NOTES
++ Table privileges are cached in the table list for GRANT checking.
++ This functions assumes that table list used and
++ thd->lex->query_tables_own_last value correspond to each other
++ (the latter should be either 0 or point to next_global member
++ of one of elements of this table list).
++
++ RETURN VALUE
++ FALSE - OK
++ TRUE - Access denied
++*/
++
++bool
++check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
++ bool no_errors)
++{
++ uint found=0;
++ ulong found_access=0;
++ TABLE_LIST *org_tables= tables;
++ TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table();
++ Security_context *sctx= thd->security_ctx, *backup_ctx= thd->security_ctx;
++ /*
++ The check that first_not_own_table is not reached is for the case when
++ the given table list refers to the list for prelocking (contains tables
++ of other queries). For simple queries first_not_own_table is 0.
++ */
++ for (; tables != first_not_own_table; tables= tables->next_global)
++ {
++ if (tables->security_ctx)
++ sctx= tables->security_ctx;
++ else
++ sctx= backup_ctx;
++
++ if (tables->schema_table &&
++ (want_access & ~(SELECT_ACL | EXTRA_ACL | FILE_ACL)))
++ {
++ if (!no_errors)
++ my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
++ sctx->priv_user, sctx->priv_host,
++ information_schema_name.str);
++ return TRUE;
++ }
++ /*
++ Register access for view underlying table.
++ Remove SHOW_VIEW_ACL, because it will be checked during making view
++ */
++ tables->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL);
++ if (tables->derived || tables->schema_table ||
++ (tables->table && (int)tables->table->s->tmp_table) ||
++ my_tz_check_n_skip_implicit_tables(&tables,
++ thd->lex->time_zone_tables_used))
++ continue;
++ thd->security_ctx= sctx;
++ if ((sctx->master_access & want_access) ==
++ (want_access & ~EXTRA_ACL) &&
++ thd->db)
++ tables->grant.privilege= want_access;
++ else if (tables->db && thd->db && strcmp(tables->db, thd->db) == 0)
++ {
++ if (found && !grant_option) // db already checked
++ tables->grant.privilege=found_access;
++ else
++ {
++ if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
++ 0, no_errors, test(tables->schema_table)))
++ goto deny; // Access denied
++ found_access=tables->grant.privilege;
++ found=1;
++ }
++ }
++ else if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
++ 0, no_errors, test(tables->schema_table)))
++ goto deny;
++ }
++ thd->security_ctx= backup_ctx;
++ if (grant_option)
++ return check_grant(thd,want_access & ~EXTRA_ACL,org_tables,
++ test(want_access & EXTRA_ACL), UINT_MAX, no_errors);
++ return FALSE;
++deny:
++ thd->security_ctx= backup_ctx;
++ return TRUE;
++}
++
++
++bool
++check_routine_access(THD *thd, ulong want_access,char *db, char *name,
++ bool is_proc, bool no_errors)
++{
++ TABLE_LIST tables[1];
++
++ bzero((char *)tables, sizeof(TABLE_LIST));
++ tables->db= db;
++ tables->table_name= tables->alias= name;
++
++ /*
++ The following test is just a shortcut for check_access() (to avoid
++ calculating db_access) under the assumption that it's common to
++ give persons global right to execute all stored SP (but not
++ necessary to create them).
++ */
++ if ((thd->security_ctx->master_access & want_access) == want_access)
++ tables->grant.privilege= want_access;
++ else if (check_access(thd,want_access,db,&tables->grant.privilege,
++ 0, no_errors, 0))
++ return TRUE;
++
++#ifndef NO_EMBEDDED_ACCESS_CHECKS
++ if (grant_option)
++ return check_grant_routine(thd, want_access, tables, is_proc, no_errors);
++#endif
++
++ 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, const char *db, const char *name,
++ bool is_proc)
++{
++ ulong save_priv;
++ if (thd->security_ctx->master_access & SHOW_PROC_ACLS)
++ return FALSE;
++ /*
++ There are no routines in information_schema db. So we can safely
++ pass zero to last paramter of check_access function
++ */
++ if (!check_access(thd, SHOW_PROC_ACLS, db, &save_priv, 0, 1, 0) ||
++ (save_priv & SHOW_PROC_ACLS))
++ return FALSE;
++ return check_routine_level_acl(thd, db, name, is_proc);
++}
++
++
++/*
++ Check if the given table has any of the asked privileges
++
++ SYNOPSIS
++ check_some_access()
++ thd Thread handler
++ want_access Bitmap of possible privileges to check for
++
++ RETURN
++ 0 ok
++ 1 error
++*/
++
++
++bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table)
++{
++ ulong access;
++ DBUG_ENTER("check_some_access");
++
++ /* This loop will work as long as we have less than 32 privileges */
++ for (access= 1; access < want_access ; access<<= 1)
++ {
++ if (access & want_access)
++ {
++ if (!check_access(thd, access, table->db,
++ &table->grant.privilege, 0, 1,
++ test(table->schema_table)) &&
++ !grant_option || !check_grant(thd, access, table, 0, 1, 1))
++ DBUG_RETURN(0);
++ }
++ }
++ DBUG_PRINT("exit",("no matching access rights"));
++ DBUG_RETURN(1);
++}
++
++
++bool check_merge_table_access(THD *thd, char *db,
++ TABLE_LIST *table_list)
++{
++ int error=0;
++ if (table_list)
++ {
++ /* Check that all tables use the current database */
++ TABLE_LIST *tmp;
++ for (tmp= table_list; tmp; tmp= tmp->next_local)
++ {
++ if (!tmp->db || !tmp->db[0])
++ tmp->db=db;
++ }
++ error=check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL,
++ table_list,0);
++ }
++ return error;
++}
++
++
++static bool check_db_used(THD *thd,TABLE_LIST *tables)
++{
++ char *current_db= NULL;
++ for (; tables; tables= tables->next_global)
++ {
++ if (tables->db == NULL)
++ {
++ /*
++ This code never works and should be removed in 5.1. All tables
++ that are added to the list of tables should already have its
++ database field initialized properly (see st_lex::add_table_to_list).
++ */
++ DBUG_ASSERT(0);
++ if (thd->copy_db_to(¤t_db, 0))
++ return TRUE;
++ tables->db= current_db;
++ }
++ }
++ return FALSE;
++}
++
++/****************************************************************************
++ Check stack size; Send error if there isn't enough stack to continue
++****************************************************************************/
++
++#if STACK_DIRECTION < 0
++#define used_stack(A,B) (long) (A - B)
++#else
++#define used_stack(A,B) (long) (B - A)
++#endif
++
++#ifndef DBUG_OFF
++long max_stack_used;
++#endif
++
++#ifndef EMBEDDED_LIBRARY
++/*
++ Note: The 'buf' parameter is necessary, even if it is unused here.
++ - fix_fields functions has a "dummy" buffer large enough for the
++ corresponding exec. (Thus we only have to check in fix_fields.)
++ - Passing to check_stack_overrun() prevents the compiler from removing it.
++ */
++bool check_stack_overrun(THD *thd, long margin,
++ char *buf __attribute__((unused)))
++{
++ long stack_used;
++ DBUG_ASSERT(thd == current_thd);
++ if ((stack_used=used_stack(thd->thread_stack,(char*) &stack_used)) >=
++ (long) (thread_stack - margin))
++ {
++ sprintf(errbuff[0],ER(ER_STACK_OVERRUN_NEED_MORE),
++ stack_used,thread_stack,margin);
++ my_message(ER_STACK_OVERRUN_NEED_MORE,errbuff[0],MYF(0));
++ thd->fatal_error();
++ return 1;
++ }
++#ifndef DBUG_OFF
++ max_stack_used= max(max_stack_used, stack_used);
++#endif
++ return 0;
++}
++#endif /* EMBEDDED_LIBRARY */
++
++#define MY_YACC_INIT 1000 // Start with big alloc
++#define MY_YACC_MAX 32000 // Because of 'short'
++
++bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, ulong *yystacksize)
++{
++ LEX *lex= current_thd->lex;
++ ulong old_info=0;
++ if ((uint) *yystacksize >= MY_YACC_MAX)
++ return 1;
++ if (!lex->yacc_yyvs)
++ old_info= *yystacksize;
++ *yystacksize= set_zone((*yystacksize)*2,MY_YACC_INIT,MY_YACC_MAX);
++ if (!(lex->yacc_yyvs= (char*)
++ my_realloc((gptr) lex->yacc_yyvs,
++ *yystacksize*sizeof(**yyvs),
++ MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))) ||
++ !(lex->yacc_yyss= (char*)
++ my_realloc((gptr) lex->yacc_yyss,
++ *yystacksize*sizeof(**yyss),
++ MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))))
++ return 1;
++ if (old_info)
++ { // Copy old info from stack
++ memcpy(lex->yacc_yyss, (gptr) *yyss, old_info*sizeof(**yyss));
++ memcpy(lex->yacc_yyvs, (gptr) *yyvs, old_info*sizeof(**yyvs));
++ }
++ *yyss=(short*) lex->yacc_yyss;
++ *yyvs=(YYSTYPE*) lex->yacc_yyvs;
++ return 0;
++}
++
++
++/****************************************************************************
++ Initialize global thd variables needed for query
++****************************************************************************/
++
++void
++mysql_init_query(THD *thd, uchar *buf, uint length)
++{
++ DBUG_ENTER("mysql_init_query");
++ lex_start(thd, buf, length);
++ mysql_reset_thd_for_next_command(thd);
++ DBUG_VOID_RETURN;
++}
++
++
++/*
++ Reset THD part responsible for command processing state.
++
++ DESCRIPTION
++ This needs to be called before execution of every statement
++ (prepared or conventional).
++
++ TODO
++ Make it a method of THD and align its name with the rest of
++ reset/end/start/init methods.
++ Call it after we use THD for queries, not before.
++*/
++
++void mysql_reset_thd_for_next_command(THD *thd)
++{
++ DBUG_ENTER("mysql_reset_thd_for_next_command");
++ thd->free_list= 0;
++ thd->select_number= 1;
++ thd->query_start_used= thd->insert_id_used=0;
++ thd->last_insert_id_used_bin_log= FALSE;
++ thd->is_fatal_error= thd->time_zone_used= 0;
++ thd->server_status&= ~ (SERVER_MORE_RESULTS_EXISTS |
++ SERVER_QUERY_NO_INDEX_USED |
++ SERVER_QUERY_NO_GOOD_INDEX_USED);
++ DBUG_ASSERT(thd->security_ctx== &thd->main_security_ctx);
++ thd->tmp_table_used= 0;
++ if (!thd->in_sub_stmt)
++ {
++ if (opt_bin_log)
++ {
++ reset_dynamic(&thd->user_var_events);
++ thd->user_var_events_alloc= thd->mem_root;
++ }
++ thd->clear_error();
++ thd->total_warn_count=0; // Warnings for this query
++ thd->rand_used= 0;
++ thd->sent_row_count= thd->examined_row_count= 0;
++ }
++ DBUG_VOID_RETURN;
++}
++
++
++void
++mysql_init_select(LEX *lex)
++{
++ SELECT_LEX *select_lex= lex->current_select;
++ select_lex->init_select();
++ lex->wild= 0;
++ if (select_lex == &lex->select_lex)
++ {
++ DBUG_ASSERT(lex->result == 0);
++ lex->exchange= 0;
++ }
++}
++
++
++bool
++mysql_new_select(LEX *lex, bool move_down)
++{
++ SELECT_LEX *select_lex;
++ THD *thd= lex->thd;
++ DBUG_ENTER("mysql_new_select");
++
++ if (!(select_lex= new (thd->mem_root) SELECT_LEX()))
++ DBUG_RETURN(1);
++ select_lex->select_number= ++thd->select_number;
++ select_lex->parent_lex= lex; /* Used in init_query. */
++ select_lex->init_query();
++ select_lex->init_select();
++ lex->nest_level++;
++ select_lex->nest_level= lex->nest_level;
++ /*
++ Don't evaluate this subquery during statement prepare even if
++ it's a constant one. The flag is switched off in the end of
++ mysql_stmt_prepare.
++ */
++ if (thd->stmt_arena->is_stmt_prepare())
++ select_lex->uncacheable|= UNCACHEABLE_PREPARE;
++ if (move_down)
++ {
++ SELECT_LEX_UNIT *unit;
++ lex->subqueries= TRUE;
++ /* first select_lex of subselect or derived table */
++ if (!(unit= new (thd->mem_root) SELECT_LEX_UNIT()))
++ DBUG_RETURN(1);
++
++ unit->init_query();
++ unit->init_select();
++ unit->thd= thd;
++ unit->include_down(lex->current_select);
++ unit->link_next= 0;
++ unit->link_prev= 0;
++ unit->return_to= lex->current_select;
++ select_lex->include_down(unit);
++ /*
++ By default we assume that it is usual subselect and we have outer name
++ resolution context, if no we will assign it to 0 later
++ */
++ select_lex->context.outer_context= &select_lex->outer_select()->context;
++ }
++ else
++ {
++ if (lex->current_select->order_list.first && !lex->current_select->braces)
++ {
++ my_error(ER_WRONG_USAGE, MYF(0), "UNION", "ORDER BY");
++ DBUG_RETURN(1);
++ }
++ select_lex->include_neighbour(lex->current_select);
++ SELECT_LEX_UNIT *unit= select_lex->master_unit();
++ if (!unit->fake_select_lex && unit->add_fake_select_lex(lex->thd))
++ DBUG_RETURN(1);
++ select_lex->context.outer_context=
++ unit->first_select()->context.outer_context;
++ }
++
++ select_lex->master_unit()->global_parameters= select_lex;
++ select_lex->include_global((st_select_lex_node**)&lex->all_selects_list);
++ lex->current_select= select_lex;
++ /*
++ in subquery is SELECT query and we allow resolution of names in SELECT
++ list
++ */
++ select_lex->context.resolve_in_select_list= TRUE;
++ DBUG_RETURN(0);
++}
++
++/*
++ Create a select to return the same output as 'SELECT @@var_name'.
++
++ SYNOPSIS
++ create_select_for_variable()
++ var_name Variable name
++
++ DESCRIPTION
++ Used for SHOW COUNT(*) [ WARNINGS | ERROR]
++
++ This will crash with a core dump if the variable doesn't exists
++*/
++
++void create_select_for_variable(const char *var_name)
++{
++ THD *thd;
++ LEX *lex;
++ LEX_STRING tmp, null_lex_string;
++ Item *var;
++ char buff[MAX_SYS_VAR_LENGTH*2+4+8], *end;
++ DBUG_ENTER("create_select_for_variable");
++
++ thd= current_thd;
++ lex= thd->lex;
++ mysql_init_select(lex);
++ lex->sql_command= SQLCOM_SELECT;
++ tmp.str= (char*) var_name;
++ tmp.length=strlen(var_name);
++ bzero((char*) &null_lex_string.str, sizeof(null_lex_string));
++ /*
++ We set the name of Item to @@session.var_name because that then is used
++ as the column name in the output.
++ */
++ if ((var= get_system_var(thd, OPT_SESSION, tmp, null_lex_string)))
++ {
++ end= strxmov(buff, "@@session.", var_name, NullS);
++ var->set_name(buff, end-buff, system_charset_info);
++ add_item_to_list(thd, var);
++ }
++ DBUG_VOID_RETURN;
++}
++
++
++void mysql_init_multi_delete(LEX *lex)
++{
++ lex->sql_command= SQLCOM_DELETE_MULTI;
++ mysql_init_select(lex);
++ lex->select_lex.select_limit= 0;
++ lex->unit.select_limit_cnt= HA_POS_ERROR;
++ lex->select_lex.table_list.save_and_clear(&lex->auxiliary_table_list);
++ lex->lock_option= using_update_log ? TL_READ_NO_INSERT : TL_READ;
++ lex->query_tables= 0;
++ lex->query_tables_last= &lex->query_tables;
++}
++
++/*
++ When you modify mysql_parse(), you may need to mofify
++ mysql_test_parse_for_slave() in this same file.
++*/
++
++void mysql_parse(THD *thd, char *inBuf, uint length)
++{
++ DBUG_ENTER("mysql_parse");
++
++ DBUG_EXECUTE_IF("parser_debug", turn_parser_debug_on(););
++
++ mysql_init_query(thd, (uchar*) inBuf, length);
++ if (query_cache_send_result_to_client(thd, inBuf, length) <= 0)
++ {
++ LEX *lex= thd->lex;
++
++ sp_cache_flush_obsolete(&thd->sp_proc_cache);
++ sp_cache_flush_obsolete(&thd->sp_func_cache);
++
++ if (!MYSQLparse((void *)thd) && ! thd->is_fatal_error)
++ {
++#ifndef NO_EMBEDDED_ACCESS_CHECKS
++ if (mqh_used && thd->user_connect &&
++ check_mqh(thd, lex->sql_command))
++ {
++ thd->net.error = 0;
++ }
++ else
++#endif
++ {
++ if (thd->net.report_error)
++ {
++ if (thd->lex->sphead)
++ {
++ delete thd->lex->sphead;
++ thd->lex->sphead= NULL;
++ }
++ }
++ else
++ {
++ /*
++ Binlog logs a string starting from thd->query and having length
++ thd->query_length; so we set thd->query_length correctly (to not
++ log several statements in one event, when we executed only first).
++ We set it to not see the ';' (otherwise it would get into binlog
++ and Query_log_event::print() would give ';;' output).
++ This also helps display only the current query in SHOW
++ PROCESSLIST.
++ Note that we don't need LOCK_thread_count to modify query_length.
++ */
++ if (lex->found_semicolon &&
++ (thd->query_length= (ulong)(lex->found_semicolon - thd->query)))
++ thd->query_length--;
++ /* Actually execute the query */
++ mysql_execute_command(thd);
++ query_cache_end_of_result(thd);
++ }
++ }
++ lex->unit.cleanup();
++ }
++ else
++ {
++ DBUG_ASSERT(thd->net.report_error);
++ DBUG_PRINT("info",("Command aborted. Fatal_error: %d",
++ thd->is_fatal_error));
++
++ /*
++ The first thing we do after parse error is freeing sp_head to
++ ensure that we have restored original memroot.
++ */
++ if (thd->lex->sphead)
++ {
++ /* Clean up after failed stored procedure/function */
++ delete thd->lex->sphead;
++ thd->lex->sphead= NULL;
++ }
++ query_cache_abort(&thd->net);
++ lex->unit.cleanup();
++ }
++ thd->proc_info="freeing items";
++ thd->end_statement();
++ thd->cleanup_after_query();
++ DBUG_ASSERT(thd->change_list.is_empty());
++ }
++ DBUG_VOID_RETURN;
++}
++
++
++#ifdef HAVE_REPLICATION
++/*
++ Usable by the replication SQL thread only: just parse a query to know if it
++ can be ignored because of replicate-*-table rules.
++
++ RETURN VALUES
++ 0 cannot be ignored
++ 1 can be ignored
++*/
++
++bool mysql_test_parse_for_slave(THD *thd, char *inBuf, uint length)
++{
++ LEX *lex= thd->lex;
++ bool error= 0;
++ DBUG_ENTER("mysql_test_parse_for_slave");
++
++ mysql_init_query(thd, (uchar*) inBuf, length);
++ if (!MYSQLparse((void*) thd) && ! thd->is_fatal_error &&
++ all_tables_not_ok(thd,(TABLE_LIST*) lex->select_lex.table_list.first))
++ error= 1; /* Ignore question */
++ thd->end_statement();
++ thd->cleanup_after_query();
++ DBUG_RETURN(error);
++}
++#endif
++
++
++
++/*****************************************************************************
++** Store field definition for create
++** Return 0 if ok
++******************************************************************************/
++
++bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
++ char *length, char *decimals,
++ uint type_modifier,
++ Item *default_value, Item *on_update_value,
++ LEX_STRING *comment,
++ char *change,
++ List<String> *interval_list, CHARSET_INFO *cs,
++ uint uint_geom_type)
++{
++ register create_field *new_field;
++ LEX *lex= thd->lex;
++ DBUG_ENTER("add_field_to_list");
++
++ if (strlen(field_name) > NAME_LEN)
++ {
++ my_error(ER_TOO_LONG_IDENT, MYF(0), field_name); /* purecov: inspected */
++ DBUG_RETURN(1); /* purecov: inspected */
++ }
++ if (type_modifier & PRI_KEY_FLAG)
++ {
++ lex->col_list.push_back(new key_part_spec(field_name,0));
++ lex->key_list.push_back(new Key(Key::PRIMARY, NullS, HA_KEY_ALG_UNDEF,
++ 0, lex->col_list));
++ lex->col_list.empty();
++ }
++ if (type_modifier & (UNIQUE_FLAG | UNIQUE_KEY_FLAG))
++ {
++ lex->col_list.push_back(new key_part_spec(field_name,0));
++ lex->key_list.push_back(new Key(Key::UNIQUE, NullS, HA_KEY_ALG_UNDEF, 0,
++ lex->col_list));
++ lex->col_list.empty();
++ }
++
++ if (default_value)
++ {
++ /*
++ Default value should be literal => basic constants =>
++ no need fix_fields()
++
++ We allow only one function as part of default value -
++ NOW() as default for TIMESTAMP type.
++ */
++ if (default_value->type() == Item::FUNC_ITEM &&
++ !(((Item_func*)default_value)->functype() == Item_func::NOW_FUNC &&
++ type == FIELD_TYPE_TIMESTAMP))
++ {
++ my_error(ER_INVALID_DEFAULT, MYF(0), field_name);
++ DBUG_RETURN(1);
++ }
++ else if (default_value->type() == Item::NULL_ITEM)
++ {
++ default_value= 0;
++ if ((type_modifier & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) ==
++ NOT_NULL_FLAG)
++ {
++ my_error(ER_INVALID_DEFAULT, MYF(0), field_name);
++ DBUG_RETURN(1);
++ }
++ }
++ else if (type_modifier & AUTO_INCREMENT_FLAG)
++ {
++ my_error(ER_INVALID_DEFAULT, MYF(0), field_name);
++ DBUG_RETURN(1);
++ }
++ }
++
++ if (on_update_value && type != FIELD_TYPE_TIMESTAMP)
++ {
++ my_error(ER_INVALID_ON_UPDATE, MYF(0), field_name);
++ DBUG_RETURN(1);
++ }
++
++ if (type == FIELD_TYPE_TIMESTAMP && length)
++ {
++ /* Display widths are no longer supported for TIMSTAMP as of MySQL 4.1.
++ In other words, for declarations such as TIMESTAMP(2), TIMESTAMP(4),
++ and so on, the display width is ignored.
++ */
++ char buf[32];
++ my_snprintf(buf, sizeof(buf), "TIMESTAMP(%s)", length);
++ push_warning_printf(thd,MYSQL_ERROR::WARN_LEVEL_WARN,
++ ER_WARN_DEPRECATED_SYNTAX,
++ ER(ER_WARN_DEPRECATED_SYNTAX),
++ buf, "TIMESTAMP");
++ }
++
++ if (!(new_field= new create_field()) ||
++ new_field->init(thd, field_name, type, length, decimals, type_modifier,
++ default_value, on_update_value, comment, change,
++ interval_list, cs, uint_geom_type))
++ DBUG_RETURN(1);
++
++ lex->create_list.push_back(new_field);
++ lex->last_field=new_field;
++ DBUG_RETURN(0);
++}
++
++
++/* Store position for column in ALTER TABLE .. ADD column */
++
++void store_position_for_column(const char *name)
++{
++ current_thd->lex->last_field->after=my_const_cast(char*) (name);
++}
++
++bool
++add_proc_to_list(THD* thd, Item *item)
++{
++ ORDER *order;
++ Item **item_ptr;
++
++ if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)+sizeof(Item*))))
++ return 1;
++ item_ptr = (Item**) (order+1);
++ *item_ptr= item;
++ order->item=item_ptr;
++ order->free_me=0;
++ thd->lex->proc_list.link_in_list((byte*) order,(byte**) &order->next);
++ return 0;
++}
++
++
++/* Fix escaping of _, % and \ in database and table names (for ODBC) */
++
++static void remove_escape(char *name)
++{
++ if (!*name) // For empty DB names
++ return;
++ char *to;
++#ifdef USE_MB
++ char *strend=name+(uint) strlen(name);
++#endif
++ for (to=name; *name ; name++)
++ {
++#ifdef USE_MB
++ int l;
++ if (use_mb(system_charset_info) &&
++ (l = my_ismbchar(system_charset_info, name, strend)))
++ {
++ while (l--)
++ *to++ = *name++;
++ name--;
++ continue;
++ }
++#endif
++ if (*name == '\\' && name[1])
++ name++; // Skip '\\'
++ *to++= *name;
++ }
++ *to=0;
++}
++
++/****************************************************************************
++** save order by and tables in own lists
++****************************************************************************/
++
++
++bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc)
++{
++ ORDER *order;
++ DBUG_ENTER("add_to_list");
++ if (!(order = (ORDER *) thd->alloc(sizeof(ORDER))))
++ DBUG_RETURN(1);
++ order->item_ptr= item;
++ order->item= &order->item_ptr;
++ order->asc = asc;
++ order->free_me=0;
++ order->used=0;
++ order->counter_used= 0;
++ list.link_in_list((byte*) order,(byte**) &order->next);
++ DBUG_RETURN(0);
++}
++
++
++/*
++ Add a table to list of used tables
++
++ SYNOPSIS
++ add_table_to_list()
++ table Table to add
++ alias alias for table (or null if no alias)
++ table_options A set of the following bits:
++ TL_OPTION_UPDATING Table will be updated
++ TL_OPTION_FORCE_INDEX Force usage of index
++ TL_OPTION_ALIAS an alias in multi table DELETE
++ lock_type How table should be locked
++ use_index List of indexed used in USE INDEX
++ ignore_index List of indexed used in IGNORE INDEX
++
++ RETURN
++ 0 Error
++ # Pointer to TABLE_LIST element added to the total table list
++*/
++
++TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
++ Table_ident *table,
++ LEX_STRING *alias,
++ ulong table_options,
++ thr_lock_type lock_type,
++ List<String> *use_index_arg,
++ List<String> *ignore_index_arg,
++ LEX_STRING *option)
++{
++ register TABLE_LIST *ptr;
++ TABLE_LIST *previous_table_ref; /* The table preceding the current one. */
++ char *alias_str;
++ LEX *lex= thd->lex;
++ DBUG_ENTER("add_table_to_list");
++ LINT_INIT(previous_table_ref);
++
++ if (!table)
++ DBUG_RETURN(0); // End of memory
++ alias_str= alias ? alias->str : table->table.str;
++ if (!test(table_options & TL_OPTION_ALIAS) &&
++ check_table_name(table->table.str, table->table.length))
++ {
++ my_error(ER_WRONG_TABLE_NAME, MYF(0), table->table.str);
++ DBUG_RETURN(0);
++ }
++
++ if (!alias) /* Alias is case sensitive */
++ {
++ if (table->sel)
++ {
++ my_message(ER_DERIVED_MUST_HAVE_ALIAS,
++ ER(ER_DERIVED_MUST_HAVE_ALIAS), MYF(0));
++ DBUG_RETURN(0);
++ }
++ if (!(alias_str=thd->memdup(alias_str,table->table.length+1)))
++ DBUG_RETURN(0);
++ }
++ if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
++ DBUG_RETURN(0); /* purecov: inspected */
++ if (table->db.str)
++ {
++ if (table->is_derived_table() == FALSE && check_db_name(table->db.str))
++ {
++ my_error(ER_WRONG_DB_NAME, MYF(0), table->db.str);
++ DBUG_RETURN(0);
++ }
++ ptr->db= table->db.str;
++ ptr->db_length= table->db.length;
++ }
++ else if (thd->copy_db_to(&ptr->db, &ptr->db_length))
++ DBUG_RETURN(0);
++
++ ptr->alias= alias_str;
++ if (lower_case_table_names && table->table.length)
++ table->table.length= my_casedn_str(files_charset_info, table->table.str);
++ ptr->table_name=table->table.str;
++ ptr->table_name_length=table->table.length;
++ ptr->lock_type= lock_type;
++ ptr->updating= test(table_options & TL_OPTION_UPDATING);
++ ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX);
++ ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES);
++ ptr->derived= table->sel;
++ if (!ptr->derived && !my_strcasecmp(system_charset_info, ptr->db,
++ information_schema_name.str))
++ {
++ ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, ptr->table_name);
++ if (!schema_table ||
++ (schema_table->hidden &&
++ lex->orig_sql_command == SQLCOM_END)) // not a 'show' command
++ {
++ my_error(ER_UNKNOWN_TABLE, MYF(0),
++ ptr->table_name, information_schema_name.str);
++ DBUG_RETURN(0);
++ }
++ ptr->schema_table_name= ptr->table_name;
++ ptr->schema_table= schema_table;
++ }
++ ptr->select_lex= lex->current_select;
++ ptr->cacheable_table= 1;
++ if (use_index_arg)
++ ptr->use_index=(List<String> *) thd->memdup((gptr) use_index_arg,
++ sizeof(*use_index_arg));
++ if (ignore_index_arg)
++ ptr->ignore_index=(List<String> *) thd->memdup((gptr) ignore_index_arg,
++ sizeof(*ignore_index_arg));
++ ptr->option= option ? option->str : 0;
++ /* check that used name is unique */
++ if (lock_type != TL_IGNORE)
++ {
++ TABLE_LIST *first_table= (TABLE_LIST*) table_list.first;
++ if (lex->sql_command == SQLCOM_CREATE_VIEW)
++ first_table= first_table ? first_table->next_local : NULL;
++ for (TABLE_LIST *tables= first_table ;
++ tables ;
++ tables=tables->next_local)
++ {
++ if (!my_strcasecmp(table_alias_charset, alias_str, tables->alias) &&
++ !strcmp(ptr->db, tables->db))
++ {
++ my_error(ER_NONUNIQ_TABLE, MYF(0), alias_str); /* purecov: tested */
++ DBUG_RETURN(0); /* purecov: tested */
++ }
++ }
++ }
++ /* Store the table reference preceding the current one. */
++ if (table_list.elements > 0)
++ {
++ /*
++ table_list.next points to the last inserted TABLE_LIST->next_local'
++ element
++ We don't use the offsetof() macro here to avoid warnings from gcc
++ */
++ previous_table_ref= (TABLE_LIST*) ((char*) table_list.next -
++ ((char*) &(ptr->next_local) -
++ (char*) ptr));
++ /*
++ Set next_name_resolution_table of the previous table reference to point
++ to the current table reference. In effect the list
++ TABLE_LIST::next_name_resolution_table coincides with
++ TABLE_LIST::next_local. Later this may be changed in
++ store_top_level_join_columns() for NATURAL/USING joins.
++ */
++ previous_table_ref->next_name_resolution_table= ptr;
++ }
++
++ /*
++ Link the current table reference in a local list (list for current select).
++ Notice that as a side effect here we set the next_local field of the
++ previous table reference to 'ptr'. Here we also add one element to the
++ list 'table_list'.
++ */
++ table_list.link_in_list((byte*) ptr, (byte**) &ptr->next_local);
++ ptr->next_name_resolution_table= NULL;
++ /* Link table in global list (all used tables) */
++ lex->add_to_query_tables(ptr);
++ DBUG_RETURN(ptr);
++}
++
++
++/*
++ Initialize a new table list for a nested join
++
++ SYNOPSIS
++ init_nested_join()
++ thd current thread
++
++ DESCRIPTION
++ The function initializes a structure of the TABLE_LIST type
++ for a nested join. It sets up its nested join list as empty.
++ The created structure is added to the front of the current
++ join list in the st_select_lex object. Then the function
++ changes the current nest level for joins to refer to the newly
++ created empty list after having saved the info on the old level
++ in the initialized structure.
++
++ RETURN VALUE
++ 0, if success
++ 1, otherwise
++*/
++
++bool st_select_lex::init_nested_join(THD *thd)
++{
++ TABLE_LIST *ptr;
++ NESTED_JOIN *nested_join;
++ DBUG_ENTER("init_nested_join");
++
++ if (!(ptr= (TABLE_LIST*) thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST))+
++ sizeof(NESTED_JOIN))))
++ DBUG_RETURN(1);
++ nested_join= ptr->nested_join=
++ ((NESTED_JOIN*) ((byte*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST))));
++
++ join_list->push_front(ptr);
++ ptr->embedding= embedding;
++ ptr->join_list= join_list;
++ embedding= ptr;
++ join_list= &nested_join->join_list;
++ join_list->empty();
++ DBUG_RETURN(0);
++}
++
++
++/*
++ End a nested join table list
++
++ SYNOPSIS
++ end_nested_join()
++ thd current thread
++
++ DESCRIPTION
++ The function returns to the previous join nest level.
++ If the current level contains only one member, the function
++ moves it one level up, eliminating the nest.
++
++ RETURN VALUE
++ Pointer to TABLE_LIST element added to the total table list, if success
++ 0, otherwise
++*/
++
++TABLE_LIST *st_select_lex::end_nested_join(THD *thd)
++{
++ TABLE_LIST *ptr;
++ NESTED_JOIN *nested_join;
++ DBUG_ENTER("end_nested_join");
++
++ DBUG_ASSERT(embedding);
++ ptr= embedding;
++ join_list= ptr->join_list;
++ embedding= ptr->embedding;
++ nested_join= ptr->nested_join;
++ if (nested_join->join_list.elements == 1)
++ {
++ TABLE_LIST *embedded= nested_join->join_list.head();
++ join_list->pop();
++ embedded->join_list= join_list;
++ embedded->embedding= embedding;
++ join_list->push_front(embedded);
++ ptr= embedded;
++ }
++ else if (nested_join->join_list.elements == 0)
++ {
++ join_list->pop();
++ ptr= 0; // return value
++ }
++ DBUG_RETURN(ptr);
++}
++
++
++/*
++ Nest last join operation
++
++ SYNOPSIS
++ nest_last_join()
++ thd current thread
++
++ DESCRIPTION
++ The function nest last join operation as if it was enclosed in braces.
++
++ RETURN VALUE
++ 0 Error
++ # Pointer to TABLE_LIST element created for the new nested join
++
++*/
++
++TABLE_LIST *st_select_lex::nest_last_join(THD *thd)
++{
++ TABLE_LIST *ptr;
++ NESTED_JOIN *nested_join;
++ List<TABLE_LIST> *embedded_list;
++ DBUG_ENTER("nest_last_join");
++
++ if (!(ptr= (TABLE_LIST*) thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST))+
++ sizeof(NESTED_JOIN))))
++ DBUG_RETURN(0);
++ nested_join= ptr->nested_join=
++ ((NESTED_JOIN*) ((byte*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST))));
++
++ ptr->embedding= embedding;
++ ptr->join_list= join_list;
++ embedded_list= &nested_join->join_list;
++ embedded_list->empty();
++
++ for (uint i=0; i < 2; i++)
++ {
++ TABLE_LIST *table= join_list->pop();
++ table->join_list= embedded_list;
++ table->embedding= ptr;
++ embedded_list->push_back(table);
++ if (table->natural_join)
++ {
++ ptr->is_natural_join= TRUE;
++ /*
++ If this is a JOIN ... USING, move the list of joined fields to the
++ table reference that describes the join.
++ */
++ if (table->join_using_fields)
++ {
++ ptr->join_using_fields= table->join_using_fields;
++ table->join_using_fields= NULL;
++ }
++ }
++ }
++ join_list->push_front(ptr);
++ nested_join->used_tables= nested_join->not_null_tables= (table_map) 0;
++ DBUG_RETURN(ptr);
++}
++
++
++/*
++ Add a table to the current join list
++
++ SYNOPSIS
++ add_joined_table()
++ table the table to add
++
++ DESCRIPTION
++ The function puts a table in front of the current join list
++ of st_select_lex object.
++ Thus, joined tables are put into this list in the reverse order
++ (the most outer join operation follows first).
++
++ RETURN VALUE
++ None
++*/
++
++void st_select_lex::add_joined_table(TABLE_LIST *table)
++{
++ DBUG_ENTER("add_joined_table");
++ join_list->push_front(table);
++ table->join_list= join_list;
++ table->embedding= embedding;
++ DBUG_VOID_RETURN;
++}
++
++
++/*
++ Convert a right join into equivalent left join
++
++ SYNOPSIS
++ convert_right_join()
++ thd current thread
++
++ DESCRIPTION
++ The function takes the current join list t[0],t[1] ... and
++ effectively converts it into the list t[1],t[0] ...
++ Although the outer_join flag for the new nested table contains
++ JOIN_TYPE_RIGHT, it will be handled as the inner table of a left join
++ operation.
++
++ EXAMPLES
++ SELECT * FROM t1 RIGHT JOIN t2 ON on_expr =>
++ SELECT * FROM t2 LEFT JOIN t1 ON on_expr
++
++ SELECT * FROM t1,t2 RIGHT JOIN t3 ON on_expr =>
++ SELECT * FROM t1,t3 LEFT JOIN t2 ON on_expr
++
++ SELECT * FROM t1,t2 RIGHT JOIN (t3,t4) ON on_expr =>
++ SELECT * FROM t1,(t3,t4) LEFT JOIN t2 ON on_expr
++
++ SELECT * FROM t1 LEFT JOIN t2 ON on_expr1 RIGHT JOIN t3 ON on_expr2 =>
++ SELECT * FROM t3 LEFT JOIN (t1 LEFT JOIN t2 ON on_expr2) ON on_expr1
++
++ RETURN
++ Pointer to the table representing the inner table, if success
++ 0, otherwise
++*/
++
++TABLE_LIST *st_select_lex::convert_right_join()
++{
++ TABLE_LIST *tab2= join_list->pop();
++ TABLE_LIST *tab1= join_list->pop();
++ DBUG_ENTER("convert_right_join");
++
++ join_list->push_front(tab2);
++ join_list->push_front(tab1);
++ tab1->outer_join|= JOIN_TYPE_RIGHT;
++
++ DBUG_RETURN(tab1);
++}
++
++/*
++ Set lock for all tables in current select level
++
++ SYNOPSIS:
++ set_lock_for_tables()
++ lock_type Lock to set for tables
++
++ NOTE:
++ If lock is a write lock, then tables->updating is set 1
++ This is to get tables_ok to know that the table is updated by the
++ query
++*/
++
++void st_select_lex::set_lock_for_tables(thr_lock_type lock_type)
++{
++ bool for_update= lock_type >= TL_READ_NO_INSERT;
++ DBUG_ENTER("set_lock_for_tables");
++ DBUG_PRINT("enter", ("lock_type: %d for_update: %d", lock_type,
++ for_update));
++
++ for (TABLE_LIST *tables= (TABLE_LIST*) table_list.first;
++ tables;
++ tables= tables->next_local)
++ {
++ tables->lock_type= lock_type;
++ tables->updating= for_update;
++ }
++ DBUG_VOID_RETURN;
++}
++
++
++/*
++ Create a fake SELECT_LEX for a unit
++
++ SYNOPSIS:
++ add_fake_select_lex()
++ thd thread handle
++
++ DESCRIPTION
++ The method create a fake SELECT_LEX object for a unit.
++ This object is created for any union construct containing a union
++ operation and also for any single select union construct of the form
++ (SELECT ... ORDER BY order_list [LIMIT n]) ORDER BY ...
++ or of the form
++ (SELECT ... ORDER BY LIMIT n) ORDER BY ...
++
++ NOTES
++ The object is used to retrieve rows from the temporary table
++ where the result on the union is obtained.
++
++ RETURN VALUES
++ 1 on failure to create the object
++ 0 on success
++*/
++
++bool st_select_lex_unit::add_fake_select_lex(THD *thd)
++{
++ SELECT_LEX *first_sl= first_select();
++ DBUG_ENTER("add_fake_select_lex");
++ DBUG_ASSERT(!fake_select_lex);
++
++ if (!(fake_select_lex= new (thd->mem_root) SELECT_LEX()))
++ DBUG_RETURN(1);
++ fake_select_lex->include_standalone(this,
++ (SELECT_LEX_NODE**)&fake_select_lex);
++ fake_select_lex->select_number= INT_MAX;
++ fake_select_lex->parent_lex= thd->lex; /* Used in init_query. */
++ fake_select_lex->make_empty_select();
++ fake_select_lex->linkage= GLOBAL_OPTIONS_TYPE;
++ fake_select_lex->select_limit= 0;
++
++ fake_select_lex->context.outer_context=first_sl->context.outer_context;
++ /* allow item list resolving in fake select for ORDER BY */
++ fake_select_lex->context.resolve_in_select_list= TRUE;
++ fake_select_lex->context.select_lex= fake_select_lex;
++
++ if (!first_sl->next_select())
++ {
++ /*
++ This works only for
++ (SELECT ... ORDER BY list [LIMIT n]) ORDER BY order_list [LIMIT m],
++ (SELECT ... LIMIT n) ORDER BY order_list [LIMIT m]
++ just before the parser starts processing order_list
++ */
++ global_parameters= fake_select_lex;
++ fake_select_lex->no_table_names_allowed= 1;
++ thd->lex->current_select= fake_select_lex;
++ }
++ thd->lex->pop_context();
++ DBUG_RETURN(0);
++}
++
++
++/*
++ Push a new name resolution context for a JOIN ... ON clause to the
++ context stack of a query block.
++
++ SYNOPSIS
++ push_new_name_resolution_context()
++ thd pointer to current thread
++ left_op left operand of the JOIN
++ right_op rigth operand of the JOIN
++
++ DESCRIPTION
++ Create a new name resolution context for a JOIN ... ON clause,
++ set the first and last leaves of the list of table references
++ to be used for name resolution, and push the newly created
++ context to the stack of contexts of the query.
++
++ RETURN
++ FALSE if all is OK
++ TRUE if a memory allocation error occured
++*/
++
++bool
++push_new_name_resolution_context(THD *thd,
++ TABLE_LIST *left_op, TABLE_LIST *right_op)
++{
++ Name_resolution_context *on_context;
++ if (!(on_context= new (thd->mem_root) Name_resolution_context))
++ return TRUE;
++ on_context->init();
++ on_context->first_name_resolution_table=
++ left_op->first_leaf_for_name_resolution();
++ on_context->last_name_resolution_table=
++ right_op->last_leaf_for_name_resolution();
++ return thd->lex->push_context(on_context);
++}
++
++
++/*
++ Add an ON condition to the second operand of a JOIN ... ON.
++
++ SYNOPSIS
++ add_join_on
++ b the second operand of a JOIN ... ON
++ expr the condition to be added to the ON clause
++
++ DESCRIPTION
++ Add an ON condition to the right operand of a JOIN ... ON clause.
++
++ RETURN
++ FALSE if there was some error
++ TRUE if all is OK
++*/
++
++void add_join_on(TABLE_LIST *b, Item *expr)
++{
++ if (expr)
++ {
++ if (!b->on_expr)
++ b->on_expr= expr;
++ else
++ {
++ /*
++ If called from the parser, this happens if you have both a
++ right and left join. If called later, it happens if we add more
++ than one condition to the ON clause.
++ */
++ b->on_expr= new Item_cond_and(b->on_expr,expr);
++ }
++ b->on_expr->top_level_item();
++ }
++}
++
++
++/*
++ Mark that there is a NATURAL JOIN or JOIN ... USING between two
++ tables.
++
++ SYNOPSIS
++ add_join_natural()
++ a Left join argument
++ b Right join argument
++ using_fields Field names from USING clause
++
++ IMPLEMENTATION
++ This function marks that table b should be joined with a either via
++ a NATURAL JOIN or via JOIN ... USING. Both join types are special
++ cases of each other, so we treat them together. The function
++ setup_conds() creates a list of equal condition between all fields
++ of the same name for NATURAL JOIN or the fields in 'using_fields'
++ for JOIN ... USING. The list of equality conditions is stored
++ either in b->on_expr, or in JOIN::conds, depending on whether there
++ was an outer join.
++
++ EXAMPLE
++ SELECT * FROM t1 NATURAL LEFT JOIN t2
++ <=>
++ SELECT * FROM t1 LEFT JOIN t2 ON (t1.i=t2.i and t1.j=t2.j ... )
++
++ SELECT * FROM t1 NATURAL JOIN t2 WHERE <some_cond>
++ <=>
++ SELECT * FROM t1, t2 WHERE (t1.i=t2.i and t1.j=t2.j and <some_cond>)
++
++ SELECT * FROM t1 JOIN t2 USING(j) WHERE <some_cond>
++ <=>
++ SELECT * FROM t1, t2 WHERE (t1.j=t2.j and <some_cond>)
++
++ RETURN
++ None
++*/
++
++void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List<String> *using_fields)
++{
++ b->natural_join= a;
++ b->join_using_fields= using_fields;
++}
++
++
++/*
++ Reload/resets privileges and the different caches.
++
++ SYNOPSIS
++ reload_acl_and_cache()
++ thd Thread handler (can be NULL!)
++ options What should be reset/reloaded (tables, privileges,
++ slave...)
++ tables Tables to flush (if any)
++ write_to_binlog Depending on 'options', it may be very bad to write the
++ query to the binlog (e.g. FLUSH SLAVE); this is a
++ pointer where reload_acl_and_cache() will put 0 if
++ it thinks we really should not write to the binlog.
++ Otherwise it will put 1.
++
++ RETURN
++ 0 ok
++ !=0 error. thd->killed or thd->net.report_error is set
++*/
++
++bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
++ bool *write_to_binlog)
++{
++ bool result=0;
++ select_errors=0; /* Write if more errors */
++ bool tmp_write_to_binlog= 1;
++
++ DBUG_ASSERT(!thd || !thd->in_sub_stmt);
++
++#ifndef NO_EMBEDDED_ACCESS_CHECKS
++ if (options & REFRESH_GRANT)
++ {
++ THD *tmp_thd= 0;
++ /*
++ If reload_acl_and_cache() is called from SIGHUP handler we have to
++ allocate temporary THD for execution of acl_reload()/grant_reload().
++ */
++ if (!thd && (thd= (tmp_thd= new THD)))
++ {
++ thd->thread_stack= (char*) &tmp_thd;
++ thd->store_globals();
++ }
++ if (thd)
++ {
++ (void)acl_reload(thd);
++ (void)grant_reload(thd);
++ }
++ if (tmp_thd)
++ {
++ delete tmp_thd;
++ /* Remember that we don't have a THD */
++ my_pthread_setspecific_ptr(THR_THD, 0);
++ thd= 0;
++ }
++ reset_mqh((LEX_USER *)NULL, TRUE);
++ }
++#endif
++ if (options & REFRESH_LOG)
++ {
++ /*
++ Flush the normal query log, the update log, the binary log,
++ the slow query log, and the relay log (if it exists).
++ */
++
++ /*
++ Writing this command to the binlog may result in infinite loops
++ when doing mysqlbinlog|mysql, and anyway it does not really make
++ sense to log it automatically (would cause more trouble to users
++ than it would help them)
++ */
++ tmp_write_to_binlog= 0;
++ mysql_log.new_file(1);
++ mysql_slow_log.new_file(1);
++ if( mysql_bin_log.is_open() )
++ {
++ mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE);
++ }
++#ifdef HAVE_REPLICATION
++ pthread_mutex_lock(&LOCK_active_mi);
++ rotate_relay_log(active_mi);
++ pthread_mutex_unlock(&LOCK_active_mi);
++#endif
++ if (ha_flush_logs())
++ result=1;
++ if (flush_error_log())
++ result=1;
++ }
++#ifdef HAVE_QUERY_CACHE
++ if (options & REFRESH_QUERY_CACHE_FREE)
++ {
++ query_cache.pack(); // FLUSH QUERY CACHE
++ options &= ~REFRESH_QUERY_CACHE; // Don't flush cache, just free memory
++ }
++ if (options & (REFRESH_TABLES | REFRESH_QUERY_CACHE))
++ {
++ query_cache.flush(); // RESET QUERY CACHE
++ }
++#endif /*HAVE_QUERY_CACHE*/
++ /*
++ Note that if REFRESH_READ_LOCK bit is set then REFRESH_TABLES is set too
++ (see sql_yacc.yy)
++ */
++ if (options & (REFRESH_TABLES | REFRESH_READ_LOCK))
++ {
++ if ((options & REFRESH_READ_LOCK) && thd)
++ {
++ /*
++ We must not try to aspire a global read lock if we have a write
++ locked table. This would lead to a deadlock when trying to
++ reopen (and re-lock) the table after the flush.
++ */
++ if (thd->locked_tables)
++ {
++ THR_LOCK_DATA **lock_p= thd->locked_tables->locks;
++ THR_LOCK_DATA **end_p= lock_p + thd->locked_tables->lock_count;
++
++ for (; lock_p < end_p; lock_p++)
++ {
++ if ((*lock_p)->type == TL_WRITE)
++ {
++ my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
++ return 1;
++ }
++ }
++ }
++ /*
++ Writing to the binlog could cause deadlocks, as we don't log
++ UNLOCK TABLES
++ */
++ tmp_write_to_binlog= 0;
++ if (lock_global_read_lock(thd))
++ return 1; // Killed
++ result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1,
++ tables);
++ if (make_global_read_lock_block_commit(thd)) // Killed
++ {
++ /* Don't leave things in a half-locked state */
++ unlock_global_read_lock(thd);
++ return 1;
++ }
++ }
++ else
++ result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1, tables);
++ my_dbopt_cleanup();
++ }
++ if (options & REFRESH_HOSTS)
++ hostname_cache_refresh();
++ if (thd && (options & REFRESH_STATUS))
++ refresh_status(thd);
++ if (options & REFRESH_THREADS)
++ flush_thread_cache();
++#ifdef HAVE_REPLICATION
++ if (options & REFRESH_MASTER)
++ {
++ DBUG_ASSERT(thd);
++ tmp_write_to_binlog= 0;
++ if (reset_master(thd))
++ {
++ result=1;
++ thd->fatal_error(); // Ensure client get error
++ }
++ }
++#endif
++#ifdef OPENSSL
++ if (options & REFRESH_DES_KEY_FILE)
++ {
++ if (des_key_file)
++ result=load_des_key_file(des_key_file);
++ }
++#endif
++#ifdef HAVE_REPLICATION
++ if (options & REFRESH_SLAVE)
++ {
++ tmp_write_to_binlog= 0;
++ pthread_mutex_lock(&LOCK_active_mi);
++ if (reset_slave(thd, active_mi))
++ result=1;
++ pthread_mutex_unlock(&LOCK_active_mi);
++ }
++#endif
++ if (options & REFRESH_USER_RESOURCES)
++ reset_mqh((LEX_USER *) NULL);
++ *write_to_binlog= tmp_write_to_binlog;
++ return result;
++}
++
++/*
++ kill on thread
++
++ SYNOPSIS
++ kill_one_thread()
++ thd Thread class
++ id Thread id
++
++ NOTES
++ This is written such that we have a short lock on LOCK_thread_count
++*/
++
++void kill_one_thread(THD *thd, ulong id, bool only_kill_query)
++{
++ THD *tmp;
++ uint error=ER_NO_SUCH_THREAD;
++ VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
++ I_List_iterator<THD> it(threads);
++ while ((tmp=it++))
++ {
++ if (tmp->thread_id == id)
++ {
++ pthread_mutex_lock(&tmp->LOCK_delete); // Lock from delete
++ break;
++ }
++ }
++ VOID(pthread_mutex_unlock(&LOCK_thread_count));
++ if (tmp)
++ {
++ if ((thd->security_ctx->master_access & SUPER_ACL) ||
++ !strcmp(thd->security_ctx->user, tmp->security_ctx->user))
++ {
++ tmp->awake(only_kill_query ? THD::KILL_QUERY : THD::KILL_CONNECTION);
++ error=0;
++ }
++ else
++ error=ER_KILL_DENIED_ERROR;
++ pthread_mutex_unlock(&tmp->LOCK_delete);
++ }
++
++ if (!error)
++ send_ok(thd);
++ else
++ my_error(error, MYF(0), id);
++}
++
++
++ /* If pointer is not a null pointer, append filename to it */
++
++static bool append_file_to_dir(THD *thd, const char **filename_ptr,
++ const char *table_name)
++{
++ char buff[FN_REFLEN],*ptr, *end;
++ if (!*filename_ptr)
++ return 0; // nothing to do
++
++ /* Check that the filename is not too long and it's a hard path */
++ if (strlen(*filename_ptr)+strlen(table_name) >= FN_REFLEN-1 ||
++ !test_if_hard_path(*filename_ptr))
++ {
++ my_error(ER_WRONG_TABLE_NAME, MYF(0), *filename_ptr);
++ return 1;
++ }
++ /* Fix is using unix filename format on dos */
++ strmov(buff,*filename_ptr);
++ end=convert_dirname(buff, *filename_ptr, NullS);
++ if (!(ptr=thd->alloc((uint) (end-buff)+(uint) strlen(table_name)+1)))
++ return 1; // End of memory
++ *filename_ptr=ptr;
++ strxmov(ptr,buff,table_name,NullS);
++ return 0;
++}
++
++
++/*
++ Check if the select is a simple select (not an union)
++
++ SYNOPSIS
++ check_simple_select()
++
++ RETURN VALUES
++ 0 ok
++ 1 error ; In this case the error messege is sent to the client
++*/
++
++bool check_simple_select()
++{
++ THD *thd= current_thd;
++ LEX *lex= thd->lex;
++ if (lex->current_select != &lex->select_lex)
++ {
++ char command[80];
++ strmake(command, lex->yylval->symbol.str,
++ min(lex->yylval->symbol.length, sizeof(command)-1));
++ my_error(ER_CANT_USE_OPTION_HERE, MYF(0), command);
++ return 1;
++ }
++ return 0;
++}
++
++
++Comp_creator *comp_eq_creator(bool invert)
++{
++ return invert?(Comp_creator *)&ne_creator:(Comp_creator *)&eq_creator;
++}
++
++
++Comp_creator *comp_ge_creator(bool invert)
++{
++ return invert?(Comp_creator *)<_creator:(Comp_creator *)&ge_creator;
++}
++
++
++Comp_creator *comp_gt_creator(bool invert)
++{
++ return invert?(Comp_creator *)&le_creator:(Comp_creator *)>_creator;
++}
++
++
++Comp_creator *comp_le_creator(bool invert)
++{
++ return invert?(Comp_creator *)>_creator:(Comp_creator *)&le_creator;
++}
++
++
++Comp_creator *comp_lt_creator(bool invert)
++{
++ return invert?(Comp_creator *)&ge_creator:(Comp_creator *)<_creator;
++}
++
++
++Comp_creator *comp_ne_creator(bool invert)
++{
++ return invert?(Comp_creator *)&eq_creator:(Comp_creator *)&ne_creator;
++}
++
++
++/*
++ Construct ALL/ANY/SOME subquery Item
++
++ SYNOPSIS
++ all_any_subquery_creator()
++ left_expr - pointer to left expression
++ cmp - compare function creator
++ all - true if we create ALL subquery
++ select_lex - pointer on parsed subquery structure
++
++ RETURN VALUE
++ constructed Item (or 0 if out of memory)
++*/
++Item * all_any_subquery_creator(Item *left_expr,
++ chooser_compare_func_creator cmp,
++ bool all,
++ SELECT_LEX *select_lex)
++{
++ if ((cmp == &comp_eq_creator) && !all) // = ANY <=> IN
++ return new Item_in_subselect(left_expr, select_lex);
++
++ if ((cmp == &comp_ne_creator) && all) // <> ALL <=> NOT IN
++ return new Item_func_not(new Item_in_subselect(left_expr, select_lex));
++
++ Item_allany_subselect *it=
++ new Item_allany_subselect(left_expr, cmp, select_lex, all);
++ if (all)
++ return it->upper_item= new Item_func_not_all(it); /* ALL */
++
++ return it->upper_item= new Item_func_nop_all(it); /* ANY/SOME */
++}
++
++
++/*
++ CREATE INDEX and DROP INDEX are implemented by calling ALTER TABLE with
++ the proper arguments. This isn't very fast but it should work for most
++ cases.
++
++ In the future ALTER TABLE will notice that only added indexes
++ and create these one by one for the existing table without having to do
++ a full rebuild.
++
++ One should normally create all indexes with CREATE TABLE or ALTER TABLE.
++*/
++
++bool mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys)
++{
++ List<create_field> fields;
++ ALTER_INFO alter_info;
++ alter_info.flags= ALTER_ADD_INDEX;
++ HA_CREATE_INFO create_info;
++ DBUG_ENTER("mysql_create_index");
++ bzero((char*) &create_info,sizeof(create_info));
++ create_info.db_type=DB_TYPE_DEFAULT;
++ create_info.default_table_charset= thd->variables.collation_database;
++ DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->table_name,
++ &create_info, table_list,
++ fields, keys, 0, (ORDER*)0,
++ 0, &alter_info, 1));
++}
++
++
++bool mysql_drop_index(THD *thd, TABLE_LIST *table_list, ALTER_INFO *alter_info)
++{
++ List<create_field> fields;
++ List<Key> keys;
++ HA_CREATE_INFO create_info;
++ DBUG_ENTER("mysql_drop_index");
++ bzero((char*) &create_info,sizeof(create_info));
++ create_info.db_type=DB_TYPE_DEFAULT;
++ create_info.default_table_charset= thd->variables.collation_database;
++ alter_info->clear();
++ alter_info->flags= ALTER_DROP_INDEX;
++ DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->table_name,
++ &create_info, table_list,
++ fields, keys, 0, (ORDER*)0,
++ 0, alter_info, 1));
++}
++
++
++/*
++ Multi update query pre-check
++
++ SYNOPSIS
++ multi_update_precheck()
++ thd Thread handler
++ tables Global/local table list (have to be the same)
++
++ RETURN VALUE
++ FALSE OK
++ TRUE Error
++*/
++
++bool multi_update_precheck(THD *thd, TABLE_LIST *tables)
++{
++ const char *msg= 0;
++ TABLE_LIST *table;
++ LEX *lex= thd->lex;
++ SELECT_LEX *select_lex= &lex->select_lex;
++ DBUG_ENTER("multi_update_precheck");
++
++ if (select_lex->item_list.elements != lex->value_list.elements)
++ {
++ my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
++ DBUG_RETURN(TRUE);
++ }
++ /*
++ Ensure that we have UPDATE or SELECT privilege for each table
++ The exact privilege is checked in mysql_multi_update()
++ */
++ for (table= tables; table; table= table->next_local)
++ {
++ if (table->derived)
++ table->grant.privilege= SELECT_ACL;
++ else if ((check_access(thd, UPDATE_ACL, table->db,
++ &table->grant.privilege, 0, 1,
++ test(table->schema_table)) ||
++ grant_option &&
++ check_grant(thd, UPDATE_ACL, table, 0, 1, 1)) &&
++ (check_access(thd, SELECT_ACL, table->db,
++ &table->grant.privilege, 0, 0,
++ test(table->schema_table)) ||
++ grant_option && check_grant(thd, SELECT_ACL, table, 0, 1, 0)))
++ DBUG_RETURN(TRUE);
++
++ table->table_in_first_from_clause= 1;
++ }
++ /*
++ Is there tables of subqueries?
++ */
++ if (&lex->select_lex != lex->all_selects_list || lex->time_zone_tables_used)
++ {
++ DBUG_PRINT("info",("Checking sub query list"));
++ for (table= tables; table; table= table->next_global)
++ {
++ if (!my_tz_check_n_skip_implicit_tables(&table,
++ lex->time_zone_tables_used) &&
++ !table->table_in_first_from_clause)
++ {
++ if (check_access(thd, SELECT_ACL, table->db,
++ &table->grant.privilege, 0, 0,
++ test(table->schema_table)) ||
++ grant_option && check_grant(thd, SELECT_ACL, table, 0, 1, 0))
++ DBUG_RETURN(TRUE);
++ }
++ }
++ }
++
++ if (select_lex->order_list.elements)
++ msg= "ORDER BY";
++ else if (select_lex->select_limit)
++ msg= "LIMIT";
++ if (msg)
++ {
++ my_error(ER_WRONG_USAGE, MYF(0), "UPDATE", msg);
++ DBUG_RETURN(TRUE);
++ }
++ DBUG_RETURN(FALSE);
++}
++
++/*
++ Multi delete query pre-check
++
++ SYNOPSIS
++ multi_delete_precheck()
++ thd Thread handler
++ tables Global/local table list
++
++ RETURN VALUE
++ FALSE OK
++ TRUE error
++*/
++
++bool multi_delete_precheck(THD *thd, TABLE_LIST *tables)
++{
++ SELECT_LEX *select_lex= &thd->lex->select_lex;
++ TABLE_LIST *aux_tables=
++ (TABLE_LIST *)thd->lex->auxiliary_table_list.first;
++ TABLE_LIST **save_query_tables_own_last= thd->lex->query_tables_own_last;
++ DBUG_ENTER("multi_delete_precheck");
++
++ /* sql_yacc guarantees that tables and aux_tables are not zero */
++ DBUG_ASSERT(aux_tables != 0);
++ if (check_db_used(thd, tables) || check_db_used(thd,aux_tables) ||
++ check_table_access(thd, SELECT_ACL, tables, 0))
++ DBUG_RETURN(TRUE);
++
++ /*
++ Since aux_tables list is not part of LEX::query_tables list we
++ have to juggle with LEX::query_tables_own_last value to be able
++ call check_table_access() safely.
++ */
++ thd->lex->query_tables_own_last= 0;
++ if (check_table_access(thd, DELETE_ACL, aux_tables, 0))
++ {
++ thd->lex->query_tables_own_last= save_query_tables_own_last;
++ DBUG_RETURN(TRUE);
++ }
++ thd->lex->query_tables_own_last= save_query_tables_own_last;
++
++ if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where)
++ {
++ my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
++ ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
++ DBUG_RETURN(TRUE);
++ }
++ DBUG_RETURN(FALSE);
++}
++
++
++/*
++ Link tables in auxilary table list of multi-delete with corresponding
++ elements in main table list, and set proper locks for them.
++
++ SYNOPSIS
++ multi_delete_set_locks_and_link_aux_tables()
++ lex - pointer to LEX representing multi-delete
++
++ RETURN VALUE
++ FALSE - success
++ TRUE - error
++*/
++
++bool multi_delete_set_locks_and_link_aux_tables(LEX *lex)
++{
++ TABLE_LIST *tables= (TABLE_LIST*)lex->select_lex.table_list.first;
++ TABLE_LIST *target_tbl;
++ DBUG_ENTER("multi_delete_set_locks_and_link_aux_tables");
++
++ lex->table_count= 0;
++
++ for (target_tbl= (TABLE_LIST *)lex->auxiliary_table_list.first;
++ target_tbl; target_tbl= target_tbl->next_local)
++ {
++ lex->table_count++;
++ /* All tables in aux_tables must be found in FROM PART */
++ TABLE_LIST *walk;
++ for (walk= tables; walk; walk= walk->next_local)
++ {
++ if (!my_strcasecmp(table_alias_charset,
++ target_tbl->alias, walk->alias) &&
++ !strcmp(walk->db, target_tbl->db))
++ break;
++ }
++ if (!walk)
++ {
++ my_error(ER_UNKNOWN_TABLE, MYF(0),
++ target_tbl->table_name, "MULTI DELETE");
++ DBUG_RETURN(TRUE);
++ }
++ if (!walk->derived)
++ {
++ target_tbl->table_name= walk->table_name;
++ target_tbl->table_name_length= walk->table_name_length;
++ }
++ walk->updating= target_tbl->updating;
++ walk->lock_type= target_tbl->lock_type;
++ target_tbl->correspondent_table= walk; // Remember corresponding table
++ }
++ DBUG_RETURN(FALSE);
++}
++
++
++/*
++ simple UPDATE query pre-check
++
++ SYNOPSIS
++ update_precheck()
++ thd Thread handler
++ tables Global table list
++
++ RETURN VALUE
++ FALSE OK
++ TRUE Error
++*/
++
++bool update_precheck(THD *thd, TABLE_LIST *tables)
++{
++ DBUG_ENTER("update_precheck");
++ if (thd->lex->select_lex.item_list.elements != thd->lex->value_list.elements)
++ {
++ my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
++ DBUG_RETURN(TRUE);
++ }
++ DBUG_RETURN(check_db_used(thd, tables) ||
++ check_one_table_access(thd, UPDATE_ACL, tables));
++}
++
++
++/*
++ simple DELETE query pre-check
++
++ SYNOPSIS
++ delete_precheck()
++ thd Thread handler
++ tables Global table list
++
++ RETURN VALUE
++ FALSE OK
++ TRUE error
++*/
++
++bool delete_precheck(THD *thd, TABLE_LIST *tables)
++{
++ DBUG_ENTER("delete_precheck");
++ if (check_one_table_access(thd, DELETE_ACL, tables))
++ DBUG_RETURN(TRUE);
++ /* Set privilege for the WHERE clause */
++ tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
++ DBUG_RETURN(FALSE);
++}
++
++
++/*
++ simple INSERT query pre-check
++
++ SYNOPSIS
++ insert_precheck()
++ thd Thread handler
++ tables Global table list
++
++ RETURN VALUE
++ FALSE OK
++ TRUE error
++*/
++
++bool insert_precheck(THD *thd, TABLE_LIST *tables)
++{
++ LEX *lex= thd->lex;
++ DBUG_ENTER("insert_precheck");
++
++ /*
++ Check that we have modify privileges for the first table and
++ select privileges for the rest
++ */
++ ulong privilege= (INSERT_ACL |
++ (lex->duplicates == DUP_REPLACE ? DELETE_ACL : 0) |
++ (lex->value_list.elements ? UPDATE_ACL : 0));
++
++ if (check_one_table_access(thd, privilege, tables))
++ DBUG_RETURN(TRUE);
++
++ if (lex->update_list.elements != lex->value_list.elements)
++ {
++ my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
++ DBUG_RETURN(TRUE);
++ }
++ if (check_db_used(thd, tables))
++ DBUG_RETURN(TRUE);
++ DBUG_RETURN(FALSE);
++}
++
++
++/*
++ CREATE TABLE query pre-check
++
++ SYNOPSIS
++ create_table_precheck()
++ thd Thread handler
++ tables Global table list
++ create_table Table which will be created
++
++ RETURN VALUE
++ FALSE OK
++ TRUE Error
++*/
++
++bool create_table_precheck(THD *thd, TABLE_LIST *tables,
++ TABLE_LIST *create_table)
++{
++ LEX *lex= thd->lex;
++ SELECT_LEX *select_lex= &lex->select_lex;
++ ulong want_priv;
++ bool error= TRUE; // Error message is given
++ DBUG_ENTER("create_table_precheck");
++
++ want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
++ CREATE_TMP_ACL : CREATE_ACL);
++ lex->create_info.alias= create_table->alias;
++ if (check_access(thd, want_priv, create_table->db,
++ &create_table->grant.privilege, 0, 0,
++ test(create_table->schema_table)) ||
++ check_merge_table_access(thd, create_table->db,
++ (TABLE_LIST *)
++ lex->create_info.merge_list.first))
++ goto err;
++ if (grant_option && want_priv != CREATE_TMP_ACL &&
++ check_grant(thd, want_priv, create_table, 0, 1, 0))
++ goto err;
++
++ if (select_lex->item_list.elements)
++ {
++ /* Check permissions for used tables in CREATE TABLE ... SELECT */
++
++#ifdef NOT_NECESSARY_TO_CHECK_CREATE_TABLE_EXIST_WHEN_PREPARING_STATEMENT
++ /* This code throws an ill error for CREATE TABLE t1 SELECT * FROM t1 */
++ /*
++ Only do the check for PS, becasue we on execute we have to check that
++ against the opened tables to ensure we don't use a table that is part
++ of the view (which can only be done after the table has been opened).
++ */
++ if (thd->stmt_arena->is_stmt_prepare_or_first_sp_execute())
++ {
++ /*
++ For temporary tables we don't have to check if the created table exists
++ */
++ if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
++ find_table_in_global_list(tables, create_table->db,
++ create_table->table_name))
++ {
++ error= FALSE;
++ goto err;
++ }
++ }
++#endif
++ if (tables && check_table_access(thd, SELECT_ACL, tables,0))
++ goto err;
++ }
++ error= FALSE;
++
++err:
++ DBUG_RETURN(error);
++}
++
++
++/*
++ negate given expression
++
++ SYNOPSIS
++ negate_expression()
++ thd thread handler
++ expr expression for negation
++
++ RETURN
++ negated expression
++*/
++
++Item *negate_expression(THD *thd, Item *expr)
++{
++ Item *negated;
++ if (expr->type() == Item::FUNC_ITEM &&
++ ((Item_func *) expr)->functype() == Item_func::NOT_FUNC)
++ {
++ /* it is NOT(NOT( ... )) */
++ Item *arg= ((Item_func *) expr)->arguments()[0];
++ enum_parsing_place place= thd->lex->current_select->parsing_place;
++ if (arg->is_bool_func() || place == IN_WHERE || place == IN_HAVING)
++ return arg;
++ /*
++ if it is not boolean function then we have to emulate value of
++ not(not(a)), it will be a != 0
++ */
++ return new Item_func_ne(arg, new Item_int((char*) "0", 0, 1));
++ }
++
++ if ((negated= expr->neg_transformer(thd)) != 0)
++ return negated;
++ return new Item_func_not(expr);
++}
++
++/*
++ Set the specified definer to the default value, which is the current user in
++ the thread.
++
++ SYNOPSIS
++ get_default_definer()
++ thd [in] thread handler
++ definer [out] definer
++*/
++
++void get_default_definer(THD *thd, LEX_USER *definer)
++{
++ const Security_context *sctx= thd->security_ctx;
++
++ definer->user.str= (char *) sctx->priv_user;
++ definer->user.length= strlen(definer->user.str);
++
++ definer->host.str= (char *) sctx->priv_host;
++ definer->host.length= strlen(definer->host.str);
++}
++
++
++/*
++ Create default definer for the specified THD.
++
++ SYNOPSIS
++ create_default_definer()
++ thd [in] thread handler
++
++ RETURN
++ On success, return a valid pointer to the created and initialized
++ LEX_USER, which contains definer information.
++ On error, return 0.
++*/
++
++LEX_USER *create_default_definer(THD *thd)
++{
++ LEX_USER *definer;
++
++ if (! (definer= (LEX_USER*) thd->alloc(sizeof(LEX_USER))))
++ return 0;
++
++ get_default_definer(thd, definer);
++
++ return definer;
++}
++
++
++/*
++ Create definer with the given user and host names.
++
++ SYNOPSIS
++ create_definer()
++ thd [in] thread handler
++ user_name [in] user name
++ host_name [in] host name
++
++ RETURN
++ On success, return a valid pointer to the created and initialized
++ LEX_USER, which contains definer information.
++ On error, return 0.
++*/
++
++LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name)
++{
++ LEX_USER *definer;
++
++ /* Create and initialize. */
++
++ if (! (definer= (LEX_USER*) thd->alloc(sizeof(LEX_USER))))
++ return 0;
++
++ definer->user= *user_name;
++ definer->host= *host_name;
++
++ return definer;
++}
++
++
++/*
++ Retuns information about user or current user.
++
++ SYNOPSIS
++ get_current_user()
++ thd [in] thread handler
++ user [in] user
++
++ RETURN
++ On success, return a valid pointer to initialized
++ LEX_USER, which contains user information.
++ On error, return 0.
++*/
++
++LEX_USER *get_current_user(THD *thd, LEX_USER *user)
++{
++ if (!user->user.str) // current_user
++ return create_default_definer(thd);
++
++ return user;
++}
++
++
++/*
++ Check that length of a string does not exceed some limit.
++
++ SYNOPSIS
++ check_string_length()
++ str string to be checked
++ err_msg error message to be displayed if the string is too long
++ max_length max length
++
++ RETURN
++ FALSE the passed string is not longer than max_length
++ TRUE the passed string is longer than max_length
++*/
++
++bool check_string_length(LEX_STRING *str, const char *err_msg,
++ uint max_length)
++{
++ if (str->length <= max_length)
++ return FALSE;
++
++ my_error(ER_WRONG_STRING_LENGTH, MYF(0), str->str, err_msg, max_length);
++
++ return TRUE;
++}
+diff -urNad mysql-5.0-etch~/sql/sql_show.cc mysql-5.0-etch/sql/sql_show.cc
+--- mysql-5.0-etch~/sql/sql_show.cc 2007-05-28 18:56:15.000000000 +0200
++++ mysql-5.0-etch/sql/sql_show.cc 2007-05-28 19:12:52.000000000 +0200
+@@ -2141,7 +2141,7 @@
+ */
+ thd->reset_n_backup_open_tables_state(&open_tables_state_backup);
+
+- if (lsel)
++ if (lsel && lsel->table_list.first)
+ {
+ TABLE_LIST *show_table_list= (TABLE_LIST*) lsel->table_list.first;
+ bool res;
+diff -urNad mysql-5.0-etch~/sql/sql_show.cc.orig mysql-5.0-etch/sql/sql_show.cc.orig
+--- mysql-5.0-etch~/sql/sql_show.cc.orig 1970-01-01 01:00:00.000000000 +0100
++++ mysql-5.0-etch/sql/sql_show.cc.orig 2007-05-28 18:56:15.000000000 +0200
+@@ -0,0 +1,4350 @@
++/* Copyright (C) 2000-2004 MySQL AB
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
++
++
++/* Function with list databases, tables or fields */
++
++#include "mysql_priv.h"
++#include "sql_select.h" // For select_describe
++#include "repl_failsafe.h"
++#include "sp.h"
++#include "sp_head.h"
++#include "sql_trigger.h"
++#include <my_dir.h>
++
++#ifdef HAVE_BERKELEY_DB
++#include "ha_berkeley.h" // For berkeley_show_logs
++#endif
++
++static const char *grant_names[]={
++ "select","insert","update","delete","create","drop","reload","shutdown",
++ "process","file","grant","references","index","alter"};
++
++#ifndef NO_EMBEDDED_ACCESS_CHECKS
++static TYPELIB grant_types = { sizeof(grant_names)/sizeof(char **),
++ "grant_types",
++ grant_names, NULL};
++#endif
++
++static int
++store_create_info(THD *thd, TABLE_LIST *table_list, String *packet);
++static void
++append_algorithm(TABLE_LIST *table, String *buff);
++static int
++view_store_create_info(THD *thd, TABLE_LIST *table, String *buff);
++static bool schema_table_store_record(THD *thd, TABLE *table);
++
++
++/***************************************************************************
++** List all table types supported
++***************************************************************************/
++
++bool mysqld_show_storage_engines(THD *thd)
++{
++ List<Item> field_list;
++ Protocol *protocol= thd->protocol;
++ DBUG_ENTER("mysqld_show_storage_engines");
++
++ field_list.push_back(new Item_empty_string("Engine",10));
++ field_list.push_back(new Item_empty_string("Support",10));
++ field_list.push_back(new Item_empty_string("Comment",80));
++
++ if (protocol->send_fields(&field_list,
++ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
++ DBUG_RETURN(TRUE);
++
++ const char *default_type_name=
++ ha_get_storage_engine((enum db_type)thd->variables.table_type);
++
++ handlerton **types;
++ for (types= sys_table_types; *types; types++)
++ {
++ if (!((*types)->flags & HTON_HIDDEN))
++ {
++ protocol->prepare_for_resend();
++ protocol->store((*types)->name, system_charset_info);
++ const char *option_name= show_comp_option_name[(int) (*types)->state];
++
++ if ((*types)->state == SHOW_OPTION_YES &&
++ !my_strcasecmp(system_charset_info, default_type_name, (*types)->name))
++ option_name= "DEFAULT";
++ protocol->store(option_name, system_charset_info);
++ protocol->store((*types)->comment, system_charset_info);
++ if (protocol->write())
++ DBUG_RETURN(TRUE);
++ }
++ }
++ send_eof(thd);
++ DBUG_RETURN(FALSE);
++}
++
++
++/***************************************************************************
++ List all privileges supported
++***************************************************************************/
++
++struct show_privileges_st {
++ const char *privilege;
++ const char *context;
++ const char *comment;
++};
++
++static struct show_privileges_st sys_privileges[]=
++{
++ {"Alter", "Tables", "To alter the table"},
++ {"Alter routine", "Functions,Procedures", "To alter or drop stored functions/procedures"},
++ {"Create", "Databases,Tables,Indexes", "To create new databases and tables"},
++ {"Create routine","Functions,Procedures","To use CREATE FUNCTION/PROCEDURE"},
++ {"Create temporary tables","Databases","To use CREATE TEMPORARY TABLE"},
++ {"Create view", "Tables", "To create new views"},
++ {"Create user", "Server Admin", "To create new users"},
++ {"Delete", "Tables", "To delete existing rows"},
++ {"Drop", "Databases,Tables", "To drop databases, tables, and views"},
++ {"Execute", "Functions,Procedures", "To execute stored routines"},
++ {"File", "File access on server", "To read and write files on the server"},
++ {"Grant option", "Databases,Tables,Functions,Procedures", "To give to other users those privileges you possess"},
++ {"Index", "Tables", "To create or drop indexes"},
++ {"Insert", "Tables", "To insert data into tables"},
++ {"Lock tables","Databases","To use LOCK TABLES (together with SELECT privilege)"},
++ {"Process", "Server Admin", "To view the plain text of currently executing queries"},
++ {"References", "Databases,Tables", "To have references on tables"},
++ {"Reload", "Server Admin", "To reload or refresh tables, logs and privileges"},
++ {"Replication client","Server Admin","To ask where the slave or master servers are"},
++ {"Replication slave","Server Admin","To read binary log events from the master"},
++ {"Select", "Tables", "To retrieve rows from table"},
++ {"Show databases","Server Admin","To see all databases with SHOW DATABASES"},
++ {"Show view","Tables","To see views with SHOW CREATE VIEW"},
++ {"Shutdown","Server Admin", "To shut down the server"},
++ {"Super","Server Admin","To use KILL thread, SET GLOBAL, CHANGE MASTER, etc."},
++ {"Update", "Tables", "To update existing rows"},
++ {"Usage","Server Admin","No privileges - allow connect only"},
++ {NullS, NullS, NullS}
++};
++
++bool mysqld_show_privileges(THD *thd)
++{
++ List<Item> field_list;
++ Protocol *protocol= thd->protocol;
++ DBUG_ENTER("mysqld_show_privileges");
++
++ field_list.push_back(new Item_empty_string("Privilege",10));
++ field_list.push_back(new Item_empty_string("Context",15));
++ field_list.push_back(new Item_empty_string("Comment",NAME_LEN));
++
++ if (protocol->send_fields(&field_list,
++ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
++ DBUG_RETURN(TRUE);
++
++ show_privileges_st *privilege= sys_privileges;
++ for (privilege= sys_privileges; privilege->privilege ; privilege++)
++ {
++ protocol->prepare_for_resend();
++ protocol->store(privilege->privilege, system_charset_info);
++ protocol->store(privilege->context, system_charset_info);
++ protocol->store(privilege->comment, system_charset_info);
++ if (protocol->write())
++ DBUG_RETURN(TRUE);
++ }
++ send_eof(thd);
++ DBUG_RETURN(FALSE);
++}
++
++
++/***************************************************************************
++ List all column types
++***************************************************************************/
++
++struct show_column_type_st
++{
++ const char *type;
++ uint size;
++ const char *min_value;
++ const char *max_value;
++ uint precision;
++ uint scale;
++ const char *nullable;
++ const char *auto_increment;
++ const char *unsigned_attr;
++ const char *zerofill;
++ const char *searchable;
++ const char *case_sensitivity;
++ const char *default_value;
++ const char *comment;
++};
++
++/* TODO: Add remaning types */
++
++static struct show_column_type_st sys_column_types[]=
++{
++ {"tinyint",
++ 1, "-128", "127", 0, 0, "YES", "YES",
++ "NO", "YES", "YES", "NO", "NULL,0",
++ "A very small integer"},
++ {"tinyint unsigned",
++ 1, "0" , "255", 0, 0, "YES", "YES",
++ "YES", "YES", "YES", "NO", "NULL,0",
++ "A very small integer"},
++};
++
++bool mysqld_show_column_types(THD *thd)
++{
++ List<Item> field_list;
++ Protocol *protocol= thd->protocol;
++ DBUG_ENTER("mysqld_show_column_types");
++
++ field_list.push_back(new Item_empty_string("Type",30));
++ field_list.push_back(new Item_int("Size",(longlong) 1,21));
++ field_list.push_back(new Item_empty_string("Min_Value",20));
++ field_list.push_back(new Item_empty_string("Max_Value",20));
++ field_list.push_back(new Item_return_int("Prec", 4, MYSQL_TYPE_SHORT));
++ field_list.push_back(new Item_return_int("Scale", 4, MYSQL_TYPE_SHORT));
++ field_list.push_back(new Item_empty_string("Nullable",4));
++ field_list.push_back(new Item_empty_string("Auto_Increment",4));
++ field_list.push_back(new Item_empty_string("Unsigned",4));
++ field_list.push_back(new Item_empty_string("Zerofill",4));
++ field_list.push_back(new Item_empty_string("Searchable",4));
++ field_list.push_back(new Item_empty_string("Case_Sensitive",4));
++ field_list.push_back(new Item_empty_string("Default",NAME_LEN));
++ field_list.push_back(new Item_empty_string("Comment",NAME_LEN));
++
++ if (protocol->send_fields(&field_list,
++ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
++ DBUG_RETURN(TRUE);
++
++ /* TODO: Change the loop to not use 'i' */
++ for (uint i=0; i < sizeof(sys_column_types)/sizeof(sys_column_types[0]); i++)
++ {
++ protocol->prepare_for_resend();
++ protocol->store(sys_column_types[i].type, system_charset_info);
++ protocol->store((ulonglong) sys_column_types[i].size);
++ protocol->store(sys_column_types[i].min_value, system_charset_info);
++ protocol->store(sys_column_types[i].max_value, system_charset_info);
++ protocol->store_short((longlong) sys_column_types[i].precision);
++ protocol->store_short((longlong) sys_column_types[i].scale);
++ protocol->store(sys_column_types[i].nullable, system_charset_info);
++ protocol->store(sys_column_types[i].auto_increment, system_charset_info);
++ protocol->store(sys_column_types[i].unsigned_attr, system_charset_info);
++ protocol->store(sys_column_types[i].zerofill, system_charset_info);
++ protocol->store(sys_column_types[i].searchable, system_charset_info);
++ protocol->store(sys_column_types[i].case_sensitivity, system_charset_info);
++ protocol->store(sys_column_types[i].default_value, system_charset_info);
++ protocol->store(sys_column_types[i].comment, system_charset_info);
++ if (protocol->write())
++ DBUG_RETURN(TRUE);
++ }
++ send_eof(thd);
++ DBUG_RETURN(FALSE);
++}
++
++
++/*
++ find_files() - find files in a given directory.
++
++ SYNOPSIS
++ find_files()
++ thd thread handler
++ files put found files in this list
++ db database name to set in TABLE_LIST structure
++ path path to database
++ wild filter for found files
++ dir read databases in path if TRUE, read .frm files in
++ database otherwise
++
++ RETURN
++ FIND_FILES_OK success
++ FIND_FILES_OOM out of memory error
++ FIND_FILES_DIR no such directory, or directory can't be read
++*/
++
++enum find_files_result {
++ FIND_FILES_OK,
++ FIND_FILES_OOM,
++ FIND_FILES_DIR
++};
++
++static
++find_files_result
++find_files(THD *thd, List<char> *files, const char *db,
++ const char *path, const char *wild, bool dir)
++{
++ uint i;
++ char *ext;
++ MY_DIR *dirp;
++ FILEINFO *file;
++#ifndef NO_EMBEDDED_ACCESS_CHECKS
++ uint col_access=thd->col_access;
++#endif
++ TABLE_LIST table_list;
++ DBUG_ENTER("find_files");
++
++ if (wild && !wild[0])
++ wild=0;
++
++ bzero((char*) &table_list,sizeof(table_list));
++
++ if (!(dirp = my_dir(path,MYF(dir ? MY_WANT_STAT : 0))))
++ {
++ if (my_errno == ENOENT)
++ my_error(ER_BAD_DB_ERROR, MYF(ME_BELL+ME_WAITTANG), db);
++ else
++ my_error(ER_CANT_READ_DIR, MYF(ME_BELL+ME_WAITTANG), path, my_errno);
++ DBUG_RETURN(FIND_FILES_DIR);
++ }
++
++ for (i=0 ; i < (uint) dirp->number_off_files ; i++)
++ {
++ file=dirp->dir_entry+i;
++ if (dir)
++ { /* Return databases */
++#ifdef USE_SYMDIR
++ char *ext;
++ char buff[FN_REFLEN];
++ if (my_use_symdir && !strcmp(ext=fn_ext(file->name), ".sym"))
++ {
++ /* Only show the sym file if it points to a directory */
++ char *end;
++ *ext=0; /* Remove extension */
++ unpack_dirname(buff, file->name);
++ end= strend(buff);
++ if (end != buff && end[-1] == FN_LIBCHAR)
++ end[-1]= 0; // Remove end FN_LIBCHAR
++ if (!my_stat(buff, file->mystat, MYF(0)))
++ continue;
++ }
++#endif
++ if (file->name[0] == '.' || !MY_S_ISDIR(file->mystat->st_mode) ||
++ (wild && wild_compare(file->name,wild,0)))
++ continue;
++ }
++ else
++ {
++ // Return only .frm files which aren't temp files.
++ if (my_strcasecmp(system_charset_info, ext=fn_ext(file->name),reg_ext) ||
++ is_prefix(file->name,tmp_file_prefix))
++ continue;
++ *ext=0;
++ if (wild)
++ {
++ if (lower_case_table_names)
++ {
++ if (wild_case_compare(files_charset_info, file->name, wild))
++ continue;
++ }
++ else if (wild_compare(file->name,wild,0))
++ continue;
++ }
++ }
++#ifndef NO_EMBEDDED_ACCESS_CHECKS
++ /* Don't show tables where we don't have any privileges */
++ if (db && !(col_access & TABLE_ACLS))
++ {
++ table_list.db= (char*) db;
++ table_list.db_length= strlen(db);
++ table_list.table_name= file->name;
++ table_list.table_name_length= strlen(file->name);
++ table_list.grant.privilege=col_access;
++ if (check_grant(thd, TABLE_ACLS, &table_list, 1, 1, 1))
++ continue;
++ }
++#endif
++ if (files->push_back(thd->strdup(file->name)))
++ {
++ my_dirend(dirp);
++ DBUG_RETURN(FIND_FILES_OOM);
++ }
++ }
++ DBUG_PRINT("info",("found: %d files", files->elements));
++ my_dirend(dirp);
++
++ VOID(ha_find_files(thd,db,path,wild,dir,files));
++
++ DBUG_RETURN(FIND_FILES_OK);
++}
++
++
++bool
++mysqld_show_create(THD *thd, TABLE_LIST *table_list)
++{
++ Protocol *protocol= thd->protocol;
++ char buff[2048];
++ String buffer(buff, sizeof(buff), system_charset_info);
++ DBUG_ENTER("mysqld_show_create");
++ DBUG_PRINT("enter",("db: %s table: %s",table_list->db,
++ table_list->table_name));
++
++ /* We want to preserve the tree for views. */
++ thd->lex->view_prepare_mode= TRUE;
++
++ /* Only one table for now, but VIEW can involve several tables */
++ if (open_normal_and_derived_tables(thd, table_list, 0))
++ {
++ if (!table_list->view || thd->net.last_errno != ER_VIEW_INVALID)
++ DBUG_RETURN(TRUE);
++
++ /*
++ Clear all messages with 'error' level status and
++ issue a warning with 'warning' level status in
++ case of invalid view and last error is ER_VIEW_INVALID
++ */
++ mysql_reset_errors(thd, true);
++ thd->clear_error();
++
++ push_warning_printf(thd,MYSQL_ERROR::WARN_LEVEL_WARN,
++ ER_VIEW_INVALID,
++ ER(ER_VIEW_INVALID),
++ table_list->view_db.str,
++ table_list->view_name.str);
++ }
++
++ /* TODO: add environment variables show when it become possible */
++ if (thd->lex->only_view && !table_list->view)
++ {
++ my_error(ER_WRONG_OBJECT, MYF(0),
++ table_list->db, table_list->table_name, "VIEW");
++ DBUG_RETURN(TRUE);
++ }
++
++ buffer.length(0);
++ if ((table_list->view ?
++ view_store_create_info(thd, table_list, &buffer) :
++ store_create_info(thd, table_list, &buffer)))
++ DBUG_RETURN(TRUE);
++
++ List<Item> field_list;
++ if (table_list->view)
++ {
++ field_list.push_back(new Item_empty_string("View",NAME_LEN));
++ field_list.push_back(new Item_empty_string("Create View",
++ max(buffer.length(),1024)));
++ }
++ else
++ {
++ field_list.push_back(new Item_empty_string("Table",NAME_LEN));
++ // 1024 is for not to confuse old clients
++ field_list.push_back(new Item_empty_string("Create Table",
++ max(buffer.length(),1024)));
++ }
++
++ if (protocol->send_fields(&field_list,
++ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
++ DBUG_RETURN(TRUE);
++ protocol->prepare_for_resend();
++ if (table_list->view)
++ protocol->store(table_list->view_name.str, system_charset_info);
++ else
++ {
++ if (table_list->schema_table)
++ protocol->store(table_list->schema_table->table_name,
++ system_charset_info);
++ else
++ protocol->store(table_list->table->alias, system_charset_info);
++ }
++ protocol->store(buffer.ptr(), buffer.length(), buffer.charset());
++
++ if (protocol->write())
++ DBUG_RETURN(TRUE);
++ send_eof(thd);
++ DBUG_RETURN(FALSE);
++}
++
++bool mysqld_show_create_db(THD *thd, char *dbname,
++ HA_CREATE_INFO *create_info)
++{
++ Security_context *sctx= thd->security_ctx;
++ char buff[2048];
++ String buffer(buff, sizeof(buff), system_charset_info);
++#ifndef NO_EMBEDDED_ACCESS_CHECKS
++ uint db_access;
++#endif
++ HA_CREATE_INFO create;
++ uint create_options = create_info ? create_info->options : 0;
++ Protocol *protocol=thd->protocol;
++ DBUG_ENTER("mysql_show_create_db");
++
++ if (check_db_name(dbname))
++ {
++ my_error(ER_WRONG_DB_NAME, MYF(0), dbname);
++ DBUG_RETURN(TRUE);
++ }
++
++#ifndef NO_EMBEDDED_ACCESS_CHECKS
++ if (test_all_bits(sctx->master_access, DB_ACLS))
++ db_access=DB_ACLS;
++ else
++ db_access= (acl_get(sctx->host, sctx->ip, sctx->priv_user, dbname, 0) |
++ sctx->master_access);
++ if (!(db_access & DB_ACLS) && (!grant_option || check_grant_db(thd,dbname)))
++ {
++ my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
++ sctx->priv_user, sctx->host_or_ip, dbname);
++ mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR),
++ sctx->priv_user, sctx->host_or_ip, dbname);
++ DBUG_RETURN(TRUE);
++ }
++#endif
++ if (!my_strcasecmp(system_charset_info, dbname,
++ information_schema_name.str))
++ {
++ dbname= information_schema_name.str;
++ create.default_table_charset= system_charset_info;
++ }
++ else
++ {
++ if (check_db_dir_existence(dbname))
++ {
++ my_error(ER_BAD_DB_ERROR, MYF(0), dbname);
++ DBUG_RETURN(TRUE);
++ }
++
++ load_db_opt_by_name(thd, dbname, &create);
++ }
++ List<Item> field_list;
++ field_list.push_back(new Item_empty_string("Database",NAME_LEN));
++ field_list.push_back(new Item_empty_string("Create Database",1024));
++
++ if (protocol->send_fields(&field_list,
++ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
++ DBUG_RETURN(TRUE);
++
++ protocol->prepare_for_resend();
++ protocol->store(dbname, strlen(dbname), system_charset_info);
++ buffer.length(0);
++ buffer.append(STRING_WITH_LEN("CREATE DATABASE "));
++ if (create_options & HA_LEX_CREATE_IF_NOT_EXISTS)
++ buffer.append(STRING_WITH_LEN("/*!32312 IF NOT EXISTS*/ "));
++ append_identifier(thd, &buffer, dbname, strlen(dbname));
++
++ if (create.default_table_charset)
++ {
++ buffer.append(STRING_WITH_LEN(" /*!40100"));
++ buffer.append(STRING_WITH_LEN(" DEFAULT CHARACTER SET "));
++ buffer.append(create.default_table_charset->csname);
++ if (!(create.default_table_charset->state & MY_CS_PRIMARY))
++ {
++ buffer.append(STRING_WITH_LEN(" COLLATE "));
++ buffer.append(create.default_table_charset->name);
++ }
++ buffer.append(STRING_WITH_LEN(" */"));
++ }
++ protocol->store(buffer.ptr(), buffer.length(), buffer.charset());
++
++ if (protocol->write())
++ DBUG_RETURN(TRUE);
++ send_eof(thd);
++ DBUG_RETURN(FALSE);
++}
++
++bool
++mysqld_show_logs(THD *thd)
++{
++ List<Item> field_list;
++ Protocol *protocol= thd->protocol;
++ DBUG_ENTER("mysqld_show_logs");
++
++ field_list.push_back(new Item_empty_string("File",FN_REFLEN));
++ field_list.push_back(new Item_empty_string("Type",10));
++ field_list.push_back(new Item_empty_string("Status",10));
++
++ if (protocol->send_fields(&field_list,
++ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
++ DBUG_RETURN(TRUE);
++
++#ifdef HAVE_BERKELEY_DB
++ if ((have_berkeley_db == SHOW_OPTION_YES) && berkeley_show_logs(protocol))
++ DBUG_RETURN(TRUE);
++#endif
++
++ send_eof(thd);
++ DBUG_RETURN(FALSE);
++}
++
++
++/****************************************************************************
++ Return only fields for API mysql_list_fields
++ Use "show table wildcard" in mysql instead of this
++****************************************************************************/
++
++void
++mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild)
++{
++ TABLE *table;
++ DBUG_ENTER("mysqld_list_fields");
++ DBUG_PRINT("enter",("table: %s",table_list->table_name));
++
++ if (open_normal_and_derived_tables(thd, table_list, 0))
++ DBUG_VOID_RETURN;
++ table= table_list->table;
++
++ List<Item> field_list;
++
++ Field **ptr,*field;
++ for (ptr=table->field ; (field= *ptr); ptr++)
++ {
++ if (!wild || !wild[0] ||
++ !wild_case_compare(system_charset_info, field->field_name,wild))
++ {
++ if (table_list->view)
++ field_list.push_back(new Item_ident_for_show(field,
++ table_list->view_db.str,
++ table_list->view_name.str));
++ else
++ field_list.push_back(new Item_field(field));
++ }
++ }
++ restore_record(table, s->default_values); // Get empty record
++ if (thd->protocol->send_fields(&field_list, Protocol::SEND_DEFAULTS |
++ Protocol::SEND_EOF))
++ DBUG_VOID_RETURN;
++ thd->protocol->flush();
++ DBUG_VOID_RETURN;
++}
++
++
++int
++mysqld_dump_create_info(THD *thd, TABLE_LIST *table_list, int fd)
++{
++ Protocol *protocol= thd->protocol;
++ String *packet= protocol->storage_packet();
++ DBUG_ENTER("mysqld_dump_create_info");
++ DBUG_PRINT("enter",("table: %s",table_list->table->s->table_name));
++
++ protocol->prepare_for_resend();
++ if (store_create_info(thd, table_list, packet))
++ DBUG_RETURN(-1);
++
++ if (fd < 0)
++ {
++ if (protocol->write())
++ DBUG_RETURN(-1);
++ protocol->flush();
++ }
++ else
++ {
++ if (my_write(fd, (const byte*) packet->ptr(), packet->length(),
++ MYF(MY_WME)))
++ DBUG_RETURN(-1);
++ }
++ DBUG_RETURN(0);
++}
++
++/*
++ Go through all character combinations and ensure that sql_lex.cc can
++ parse it as an identifier.
++
++ SYNOPSIS
++ require_quotes()
++ name attribute name
++ name_length length of name
++
++ RETURN
++ # Pointer to conflicting character
++ 0 No conflicting character
++*/
++
++static const char *require_quotes(const char *name, uint name_length)
++{
++ uint length;
++ const char *end= name + name_length;
++
++ for (; name < end ; name++)
++ {
++ uchar chr= (uchar) *name;
++ length= my_mbcharlen(system_charset_info, chr);
++ if (length == 1 && !system_charset_info->ident_map[chr])
++ return name;
++ }
++ return 0;
++}
++
++
++/*
++ Quote the given identifier if needed and append it to the target string.
++ If the given identifier is empty, it will be quoted.
++
++ SYNOPSIS
++ append_identifier()
++ thd thread handler
++ packet target string
++ name the identifier to be appended
++ name_length length of the appending identifier
++*/
++
++void
++append_identifier(THD *thd, String *packet, const char *name, uint length)
++{
++ const char *name_end;
++ char quote_char;
++ int q= get_quote_char_for_identifier(thd, name, length);
++
++ if (q == EOF)
++ {
++ packet->append(name, length, system_charset_info);
++ return;
++ }
++
++ /*
++ The identifier must be quoted as it includes a quote character or
++ it's a keyword
++ */
++
++ VOID(packet->reserve(length*2 + 2));
++ quote_char= (char) q;
++ packet->append("e_char, 1, system_charset_info);
++
++ for (name_end= name+length ; name < name_end ; name+= length)
++ {
++ uchar chr= (uchar) *name;
++ length= my_mbcharlen(system_charset_info, chr);
++ /*
++ my_mbcharlen can retur 0 on a wrong multibyte
++ sequence. It is possible when upgrading from 4.0,
++ and identifier contains some accented characters.
++ The manual says it does not work. So we'll just
++ change length to 1 not to hang in the endless loop.
++ */
++ if (!length)
++ length= 1;
++ if (length == 1 && chr == (uchar) quote_char)
++ packet->append("e_char, 1, system_charset_info);
++ packet->append(name, length, packet->charset());
++ }
++ packet->append("e_char, 1, system_charset_info);
++}
++
++
++/*
++ Get the quote character for displaying an identifier.
++
++ SYNOPSIS
++ get_quote_char_for_identifier()
++ thd Thread handler
++ name name to quote
++ length length of name
++
++ IMPLEMENTATION
++ Force quoting in the following cases:
++ - name is empty (for one, it is possible when we use this function for
++ quoting user and host names for DEFINER clause);
++ - name is a keyword;
++ - name includes a special character;
++ Otherwise identifier is quoted only if the option OPTION_QUOTE_SHOW_CREATE
++ is set.
++
++ RETURN
++ EOF No quote character is needed
++ # Quote character
++*/
++
++int get_quote_char_for_identifier(THD *thd, const char *name, uint length)
++{
++ if (length &&
++ !is_keyword(name,length) &&
++ !require_quotes(name, length) &&
++ !(thd->options & OPTION_QUOTE_SHOW_CREATE))
++ return EOF;
++ if (thd->variables.sql_mode & MODE_ANSI_QUOTES)
++ return '"';
++ return '`';
++}
++
++
++/* Append directory name (if exists) to CREATE INFO */
++
++static void append_directory(THD *thd, String *packet, const char *dir_type,
++ const char *filename)
++{
++ if (filename && !(thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE))
++ {
++ uint length= dirname_length(filename);
++ packet->append(' ');
++ packet->append(dir_type);
++ packet->append(STRING_WITH_LEN(" DIRECTORY='"));
++#ifdef __WIN__
++ /* Convert \ to / to be able to create table on unix */
++ char *winfilename= (char*) thd->memdup(filename, length);
++ char *pos, *end;
++ for (pos= winfilename, end= pos+length ; pos < end ; pos++)
++ {
++ if (*pos == '\\')
++ *pos = '/';
++ }
++ filename= winfilename;
++#endif
++ packet->append(filename, length);
++ packet->append('\'');
++ }
++}
++
++
++#define LIST_PROCESS_HOST_LEN 64
++
++static int
++store_create_info(THD *thd, TABLE_LIST *table_list, String *packet)
++{
++ List<Item> field_list;
++ char tmp[MAX_FIELD_WIDTH], *for_str, buff[128], *end;
++ const char *alias;
++ String type(tmp, sizeof(tmp), system_charset_info);
++ Field **ptr,*field;
++ uint primary_key;
++ KEY *key_info;
++ TABLE *table= table_list->table;
++ handler *file= table->file;
++ TABLE_SHARE *share= table->s;
++ HA_CREATE_INFO create_info;
++ my_bool foreign_db_mode= (thd->variables.sql_mode & (MODE_POSTGRESQL |
++ MODE_ORACLE |
++ MODE_MSSQL |
++ MODE_DB2 |
++ MODE_MAXDB |
++ MODE_ANSI)) != 0;
++ my_bool limited_mysql_mode= (thd->variables.sql_mode &
++ (MODE_NO_FIELD_OPTIONS | MODE_MYSQL323 |
++ MODE_MYSQL40)) != 0;
++ DBUG_ENTER("store_create_info");
++ DBUG_PRINT("enter",("table: %s", table->s->table_name));
++
++ restore_record(table, s->default_values); // Get empty record
++
++ if (share->tmp_table)
++ packet->append(STRING_WITH_LEN("CREATE TEMPORARY TABLE "));
++ else
++ packet->append(STRING_WITH_LEN("CREATE TABLE "));
++ if (table_list->schema_table)
++ alias= table_list->schema_table->table_name;
++ else
++ alias= (lower_case_table_names == 2 ? table->alias :
++ share->table_name);
++ append_identifier(thd, packet, alias, strlen(alias));
++ packet->append(STRING_WITH_LEN(" (\n"));
++
++ for (ptr=table->field ; (field= *ptr); ptr++)
++ {
++ bool has_default;
++ bool has_now_default;
++ uint flags = field->flags;
++
++ if (ptr != table->field)
++ packet->append(STRING_WITH_LEN(",\n"));
++
++ packet->append(STRING_WITH_LEN(" "));
++ append_identifier(thd,packet,field->field_name, strlen(field->field_name));
++ packet->append(' ');
++ // check for surprises from the previous call to Field::sql_type()
++ if (type.ptr() != tmp)
++ type.set(tmp, sizeof(tmp), system_charset_info);
++ else
++ type.set_charset(system_charset_info);
++
++ field->sql_type(type);
++ packet->append(type.ptr(), type.length(), system_charset_info);
++
++ if (field->has_charset() &&
++ !(thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)))
++ {
++ if (field->charset() != share->table_charset)
++ {
++ packet->append(STRING_WITH_LEN(" character set "));
++ packet->append(field->charset()->csname);
++ }
++ /*
++ For string types dump collation name only if
++ collation is not primary for the given charset
++ */
++ if (!(field->charset()->state & MY_CS_PRIMARY))
++ {
++ packet->append(STRING_WITH_LEN(" collate "));
++ packet->append(field->charset()->name);
++ }
++ }
++
++ if (flags & NOT_NULL_FLAG)
++ packet->append(STRING_WITH_LEN(" NOT NULL"));
++ else if (field->type() == FIELD_TYPE_TIMESTAMP)
++ {
++ /*
++ TIMESTAMP field require explicit NULL flag, because unlike
++ all other fields they are treated as NOT NULL by default.
++ */
++ packet->append(STRING_WITH_LEN(" NULL"));
++ }
++
++ /*
++ Again we are using CURRENT_TIMESTAMP instead of NOW because it is
++ more standard
++ */
++ has_now_default= table->timestamp_field == field &&
++ field->unireg_check != Field::TIMESTAMP_UN_FIELD;
++
++ has_default= (field->type() != FIELD_TYPE_BLOB &&
++ !(field->flags & NO_DEFAULT_VALUE_FLAG) &&
++ field->unireg_check != Field::NEXT_NUMBER &&
++ !((thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40))
++ && has_now_default));
++
++ if (has_default)
++ {
++ packet->append(STRING_WITH_LEN(" default "));
++ if (has_now_default)
++ packet->append(STRING_WITH_LEN("CURRENT_TIMESTAMP"));
++ else if (!field->is_null())
++ { // Not null by default
++ type.set(tmp, sizeof(tmp), field->charset());
++ field->val_str(&type);
++ if (type.length())
++ {
++ String def_val;
++ uint dummy_errors;
++ /* convert to system_charset_info == utf8 */
++ def_val.copy(type.ptr(), type.length(), field->charset(),
++ system_charset_info, &dummy_errors);
++ append_unescaped(packet, def_val.ptr(), def_val.length());
++ }
++ else
++ packet->append(STRING_WITH_LEN("''"));
++ }
++ else if (field->maybe_null())
++ packet->append(STRING_WITH_LEN("NULL")); // Null as default
++ else
++ packet->append(tmp);
++ }
++
++ if (!limited_mysql_mode && table->timestamp_field == field &&
++ field->unireg_check != Field::TIMESTAMP_DN_FIELD)
++ packet->append(STRING_WITH_LEN(" on update CURRENT_TIMESTAMP"));
++
++ if (field->unireg_check == Field::NEXT_NUMBER &&
++ !(thd->variables.sql_mode & MODE_NO_FIELD_OPTIONS))
++ packet->append(STRING_WITH_LEN(" auto_increment"));
++
++ if (field->comment.length)
++ {
++ packet->append(STRING_WITH_LEN(" COMMENT "));
++ append_unescaped(packet, field->comment.str, field->comment.length);
++ }
++ }
++
++ key_info= table->key_info;
++ bzero((char*) &create_info, sizeof(create_info));
++ file->update_create_info(&create_info);
++ primary_key= share->primary_key;
++
++ for (uint i=0 ; i < share->keys ; i++,key_info++)
++ {
++ KEY_PART_INFO *key_part= key_info->key_part;
++ bool found_primary=0;
++ packet->append(STRING_WITH_LEN(",\n "));
++
++ if (i == primary_key && !strcmp(key_info->name, primary_key_name))
++ {
++ found_primary=1;
++ packet->append(STRING_WITH_LEN("PRIMARY "));
++ }
++ else if (key_info->flags & HA_NOSAME)
++ packet->append(STRING_WITH_LEN("UNIQUE "));
++ else if (key_info->flags & HA_FULLTEXT)
++ packet->append(STRING_WITH_LEN("FULLTEXT "));
++ else if (key_info->flags & HA_SPATIAL)
++ packet->append(STRING_WITH_LEN("SPATIAL "));
++ packet->append(STRING_WITH_LEN("KEY "));
++
++ if (!found_primary)
++ append_identifier(thd, packet, key_info->name, strlen(key_info->name));
++
++ if (!(thd->variables.sql_mode & MODE_NO_KEY_OPTIONS) &&
++ !limited_mysql_mode && !foreign_db_mode)
++ {
++ if (key_info->algorithm == HA_KEY_ALG_BTREE)
++ packet->append(STRING_WITH_LEN(" USING BTREE"));
++
++ if (key_info->algorithm == HA_KEY_ALG_HASH)
++ packet->append(STRING_WITH_LEN(" USING HASH"));
++
++ // +BAR: send USING only in non-default case: non-spatial rtree
++ if ((key_info->algorithm == HA_KEY_ALG_RTREE) &&
++ !(key_info->flags & HA_SPATIAL))
++ packet->append(STRING_WITH_LEN(" USING RTREE"));
++
++ // No need to send USING FULLTEXT, it is sent as FULLTEXT KEY
++ }
++ packet->append(STRING_WITH_LEN(" ("));
++
++ for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
++ {
++ if (j)
++ packet->append(',');
++
++ if (key_part->field)
++ append_identifier(thd,packet,key_part->field->field_name,
++ strlen(key_part->field->field_name));
++ if (key_part->field &&
++ (key_part->length !=
++ table->field[key_part->fieldnr-1]->key_length() &&
++ !(key_info->flags & HA_FULLTEXT)))
++ {
++ buff[0] = '(';
++ char* end=int10_to_str((long) key_part->length /
++ key_part->field->charset()->mbmaxlen,
++ buff + 1,10);
++ *end++ = ')';
++ packet->append(buff,(uint) (end-buff));
++ }
++ }
++ packet->append(')');
++ }
++
++ /*
++ Get possible foreign key definitions stored in InnoDB and append them
++ to the CREATE TABLE statement
++ */
++
++ if ((for_str= file->get_foreign_key_create_info()))
++ {
++ packet->append(for_str, strlen(for_str));
++ file->free_foreign_key_create_info(for_str);
++ }
++
++ packet->append(STRING_WITH_LEN("\n)"));
++ if (!(thd->variables.sql_mode & MODE_NO_TABLE_OPTIONS) && !foreign_db_mode)
++ {
++ if (thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40))
++ packet->append(STRING_WITH_LEN(" TYPE="));
++ else
++ packet->append(STRING_WITH_LEN(" ENGINE="));
++ packet->append(file->table_type());
++
++ /*
++ Add AUTO_INCREMENT=... if there is an AUTO_INCREMENT column,
++ and NEXT_ID > 1 (the default). We must not print the clause
++ for engines that do not support this as it would break the
++ import of dumps, but as of this writing, the test for whether
++ AUTO_INCREMENT columns are allowed and wether AUTO_INCREMENT=...
++ is supported is identical, !(file->table_flags() & HA_NO_AUTO_INCREMENT))
++ Because of that, we do not explicitly test for the feature,
++ but may extrapolate its existence from that of an AUTO_INCREMENT column.
++ */
++
++ if(create_info.auto_increment_value > 1)
++ {
++ packet->append(" AUTO_INCREMENT=", 16);
++ end= longlong10_to_str(create_info.auto_increment_value, buff,10);
++ packet->append(buff, (uint) (end - buff));
++ }
++
++
++ if (share->table_charset &&
++ !(thd->variables.sql_mode & MODE_MYSQL323) &&
++ !(thd->variables.sql_mode & MODE_MYSQL40))
++ {
++ packet->append(STRING_WITH_LEN(" DEFAULT CHARSET="));
++ packet->append(share->table_charset->csname);
++ if (!(share->table_charset->state & MY_CS_PRIMARY))
++ {
++ packet->append(STRING_WITH_LEN(" COLLATE="));
++ packet->append(table->s->table_charset->name);
++ }
++ }
++
++ if (share->min_rows)
++ {
++ packet->append(STRING_WITH_LEN(" MIN_ROWS="));
++ end= longlong10_to_str(share->min_rows, buff, 10);
++ packet->append(buff, (uint) (end- buff));
++ }
++
++ if (share->max_rows && !table_list->schema_table)
++ {
++ packet->append(STRING_WITH_LEN(" MAX_ROWS="));
++ end= longlong10_to_str(share->max_rows, buff, 10);
++ packet->append(buff, (uint) (end - buff));
++ }
++
++ if (share->avg_row_length)
++ {
++ packet->append(STRING_WITH_LEN(" AVG_ROW_LENGTH="));
++ end= longlong10_to_str(share->avg_row_length, buff,10);
++ packet->append(buff, (uint) (end - buff));
++ }
++
++ if (share->db_create_options & HA_OPTION_PACK_KEYS)
++ packet->append(STRING_WITH_LEN(" PACK_KEYS=1"));
++ if (share->db_create_options & HA_OPTION_NO_PACK_KEYS)
++ packet->append(STRING_WITH_LEN(" PACK_KEYS=0"));
++ if (share->db_create_options & HA_OPTION_CHECKSUM)
++ packet->append(STRING_WITH_LEN(" CHECKSUM=1"));
++ if (share->db_create_options & HA_OPTION_DELAY_KEY_WRITE)
++ packet->append(STRING_WITH_LEN(" DELAY_KEY_WRITE=1"));
++ if (share->row_type != ROW_TYPE_DEFAULT)
++ {
++ packet->append(STRING_WITH_LEN(" ROW_FORMAT="));
++ packet->append(ha_row_type[(uint) share->row_type]);
++ }
++ table->file->append_create_info(packet);
++ if (share->comment.length)
++ {
++ packet->append(STRING_WITH_LEN(" COMMENT="));
++ append_unescaped(packet, share->comment.str, share->comment.length);
++ }
++ if (share->connect_string.length)
++ {
++ packet->append(STRING_WITH_LEN(" CONNECTION="));
++ append_unescaped(packet, share->connect_string.str, share->connect_string.length);
++ }
++ if (file->raid_type)
++ {
++ uint length;
++ length= my_snprintf(buff,sizeof(buff),
++ " RAID_TYPE=%s RAID_CHUNKS=%d RAID_CHUNKSIZE=%ld",
++ my_raid_type(file->raid_type), file->raid_chunks,
++ file->raid_chunksize/RAID_BLOCK_SIZE);
++ packet->append(buff, length);
++ }
++ append_directory(thd, packet, "DATA", create_info.data_file_name);
++ append_directory(thd, packet, "INDEX", create_info.index_file_name);
++ }
++ DBUG_RETURN(0);
++}
++
++void
++view_store_options(THD *thd, TABLE_LIST *table, String *buff)
++{
++ append_algorithm(table, buff);
++ append_definer(thd, buff, &table->definer.user, &table->definer.host);
++ if (table->view_suid)
++ buff->append(STRING_WITH_LEN("SQL SECURITY DEFINER "));
++ else
++ buff->append(STRING_WITH_LEN("SQL SECURITY INVOKER "));
++}
++
++
++/*
++ Append DEFINER clause to the given buffer.
++
++ SYNOPSIS
++ append_definer()
++ thd [in] thread handle
++ buffer [inout] buffer to hold DEFINER clause
++ definer_user [in] user name part of definer
++ definer_host [in] host name part of definer
++*/
++
++static void append_algorithm(TABLE_LIST *table, String *buff)
++{
++ buff->append(STRING_WITH_LEN("ALGORITHM="));
++ switch ((int8)table->algorithm) {
++ case VIEW_ALGORITHM_UNDEFINED:
++ buff->append(STRING_WITH_LEN("UNDEFINED "));
++ break;
++ case VIEW_ALGORITHM_TMPTABLE:
++ buff->append(STRING_WITH_LEN("TEMPTABLE "));
++ break;
++ case VIEW_ALGORITHM_MERGE:
++ buff->append(STRING_WITH_LEN("MERGE "));
++ break;
++ default:
++ DBUG_ASSERT(0); // never should happen
++ }
++}
++
++
++/*
++ Append DEFINER clause to the given buffer.
++
++ SYNOPSIS
++ append_definer()
++ thd [in] thread handle
++ buffer [inout] buffer to hold DEFINER clause
++ definer_user [in] user name part of definer
++ definer_host [in] host name part of definer
++*/
++
++void append_definer(THD *thd, String *buffer, const LEX_STRING *definer_user,
++ const LEX_STRING *definer_host)
++{
++ buffer->append(STRING_WITH_LEN("DEFINER="));
++ append_identifier(thd, buffer, definer_user->str, definer_user->length);
++ buffer->append('@');
++ append_identifier(thd, buffer, definer_host->str, definer_host->length);
++ buffer->append(' ');
++}
++
++
++static int
++view_store_create_info(THD *thd, TABLE_LIST *table, String *buff)
++{
++ my_bool foreign_db_mode= (thd->variables.sql_mode & (MODE_POSTGRESQL |
++ MODE_ORACLE |
++ MODE_MSSQL |
++ MODE_DB2 |
++ MODE_MAXDB |
++ MODE_ANSI)) != 0;
++ /*
++ Compact output format for view can be used
++ - if user has db of this view as current db
++ - if this view only references table inside it's own db
++ */
++ if (!thd->db || strcmp(thd->db, table->view_db.str))
++ table->compact_view_format= FALSE;
++ else
++ {
++ TABLE_LIST *tbl;
++ table->compact_view_format= TRUE;
++ for (tbl= thd->lex->query_tables;
++ tbl;
++ tbl= tbl->next_global)
++ {
++ if (strcmp(table->view_db.str, tbl->view ? tbl->view_db.str :tbl->db)!= 0)
++ {
++ table->compact_view_format= FALSE;
++ break;
++ }
++ }
++ }
++
++ buff->append(STRING_WITH_LEN("CREATE "));
++ if (!foreign_db_mode)
++ {
++ view_store_options(thd, table, buff);
++ }
++ buff->append(STRING_WITH_LEN("VIEW "));
++ if (!table->compact_view_format)
++ {
++ append_identifier(thd, buff, table->view_db.str, table->view_db.length);
++ buff->append('.');
++ }
++ append_identifier(thd, buff, table->view_name.str, table->view_name.length);
++ buff->append(STRING_WITH_LEN(" AS "));
++
++ /*
++ We can't just use table->query, because our SQL_MODE may trigger
++ a different syntax, like when ANSI_QUOTES is defined.
++ */
++ table->view->unit.print(buff);
++
++ if (table->with_check != VIEW_CHECK_NONE)
++ {
++ if (table->with_check == VIEW_CHECK_LOCAL)
++ buff->append(STRING_WITH_LEN(" WITH LOCAL CHECK OPTION"));
++ else
++ buff->append(STRING_WITH_LEN(" WITH CASCADED CHECK OPTION"));
++ }
++ return 0;
++}
++
++
++/****************************************************************************
++ Return info about all processes
++ returns for each thread: thread id, user, host, db, command, info
++****************************************************************************/
++
++class thread_info :public ilink {
++public:
++ static void *operator new(size_t size)
++ {
++ return (void*) sql_alloc((uint) size);
++ }
++ static void operator delete(void *ptr __attribute__((unused)),
++ size_t size __attribute__((unused)))
++ { TRASH(ptr, size); }
++
++ ulong thread_id;
++ time_t start_time;
++ uint command;
++ const char *user,*host,*db,*proc_info,*state_info;
++ char *query;
++};
++
++#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
++template class I_List<thread_info>;
++#endif
++
++void mysqld_list_processes(THD *thd,const char *user, bool verbose)
++{
++ Item *field;
++ List<Item> field_list;
++ I_List<thread_info> thread_infos;
++ ulong max_query_length= (verbose ? thd->variables.max_allowed_packet :
++ PROCESS_LIST_WIDTH);
++ Protocol *protocol= thd->protocol;
++ DBUG_ENTER("mysqld_list_processes");
++
++ field_list.push_back(new Item_int("Id",0,11));
++ field_list.push_back(new Item_empty_string("User",16));
++ field_list.push_back(new Item_empty_string("Host",LIST_PROCESS_HOST_LEN));
++ field_list.push_back(field=new Item_empty_string("db",NAME_LEN));
++ field->maybe_null=1;
++ field_list.push_back(new Item_empty_string("Command",16));
++ field_list.push_back(new Item_return_int("Time",7, FIELD_TYPE_LONG));
++ field_list.push_back(field=new Item_empty_string("State",30));
++ field->maybe_null=1;
++ field_list.push_back(field=new Item_empty_string("Info",max_query_length));
++ field->maybe_null=1;
++ if (protocol->send_fields(&field_list,
++ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
++ DBUG_VOID_RETURN;
++
++ VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
++ if (!thd->killed)
++ {
++ I_List_iterator<THD> it(threads);
++ THD *tmp;
++ while ((tmp=it++))
++ {
++ Security_context *tmp_sctx= tmp->security_ctx;
++ struct st_my_thread_var *mysys_var;
++ if ((tmp->vio_ok() || tmp->system_thread) &&
++ (!user || (tmp_sctx->user && !strcmp(tmp_sctx->user, user))))
++ {
++ thread_info *thd_info= new thread_info;
++
++ thd_info->thread_id=tmp->thread_id;
++ thd_info->user= thd->strdup(tmp_sctx->user ? tmp_sctx->user :
++ (tmp->system_thread ?
++ "system user" : "unauthenticated user"));
++ if (tmp->peer_port && (tmp_sctx->host || tmp_sctx->ip) &&
++ thd->security_ctx->host_or_ip[0])
++ {
++ if ((thd_info->host= thd->alloc(LIST_PROCESS_HOST_LEN+1)))
++ my_snprintf((char *) thd_info->host, LIST_PROCESS_HOST_LEN,
++ "%s:%u", tmp_sctx->host_or_ip, tmp->peer_port);
++ }
++ else
++ thd_info->host= thd->strdup(tmp_sctx->host_or_ip[0] ?
++ tmp_sctx->host_or_ip :
++ tmp_sctx->host ? tmp_sctx->host : "");
++ if ((thd_info->db=tmp->db)) // Safe test
++ thd_info->db=thd->strdup(thd_info->db);
++ thd_info->command=(int) tmp->command;
++ if ((mysys_var= tmp->mysys_var))
++ pthread_mutex_lock(&mysys_var->mutex);
++ thd_info->proc_info= (char*) (tmp->killed == THD::KILL_CONNECTION? "Killed" : 0);
++#ifndef EMBEDDED_LIBRARY
++ thd_info->state_info= (char*) (tmp->locked ? "Locked" :
++ tmp->net.reading_or_writing ?
++ (tmp->net.reading_or_writing == 2 ?
++ "Writing to net" :
++ thd_info->command == COM_SLEEP ? "" :
++ "Reading from net") :
++ tmp->proc_info ? tmp->proc_info :
++ tmp->mysys_var &&
++ tmp->mysys_var->current_cond ?
++ "Waiting on cond" : NullS);
++#else
++ thd_info->state_info= (char*)"Writing to net";
++#endif
++ if (mysys_var)
++ pthread_mutex_unlock(&mysys_var->mutex);
++
++#if !defined(DONT_USE_THR_ALARM) && ! defined(SCO)
++ if (pthread_kill(tmp->real_id,0))
++ tmp->proc_info="*** DEAD ***"; // This shouldn't happen
++#endif
++#ifdef EXTRA_DEBUG
++ thd_info->start_time= tmp->time_after_lock;
++#else
++ thd_info->start_time= tmp->start_time;
++#endif
++ thd_info->query=0;
++ if (tmp->query)
++ {
++ /*
++ query_length is always set to 0 when we set query = NULL; see
++ the comment in sql_class.h why this prevents crashes in possible
++ races with query_length
++ */
++ uint length= min(max_query_length, tmp->query_length);
++ thd_info->query=(char*) thd->strmake(tmp->query,length);
++ }
++ thread_infos.append(thd_info);
++ }
++ }
++ }
++ VOID(pthread_mutex_unlock(&LOCK_thread_count));
++
++ thread_info *thd_info;
++ time_t now= time(0);
++ while ((thd_info=thread_infos.get()))
++ {
++ protocol->prepare_for_resend();
++ protocol->store((ulonglong) thd_info->thread_id);
++ protocol->store(thd_info->user, system_charset_info);
++ protocol->store(thd_info->host, system_charset_info);
++ protocol->store(thd_info->db, system_charset_info);
++ if (thd_info->proc_info)
++ protocol->store(thd_info->proc_info, system_charset_info);
++ else
++ protocol->store(command_name[thd_info->command], system_charset_info);
++ if (thd_info->start_time)
++ protocol->store((uint32) (now - thd_info->start_time));
++ else
++ protocol->store_null();
++ protocol->store(thd_info->state_info, system_charset_info);
++ protocol->store(thd_info->query, system_charset_info);
++ if (protocol->write())
++ break; /* purecov: inspected */
++ }
++ send_eof(thd);
++ DBUG_VOID_RETURN;
++}
++
++/*****************************************************************************
++ Status functions
++*****************************************************************************/
++
++
++static bool show_status_array(THD *thd, const char *wild,
++ show_var_st *variables,
++ enum enum_var_type value_type,
++ struct system_status_var *status_var,
++ const char *prefix, TABLE *table)
++{
++ char buff[1024], *prefix_end;
++ /* the variable name should not be longer then 80 characters */
++ char name_buffer[80];
++ int len;
++ LEX_STRING null_lex_str;
++ DBUG_ENTER("show_status_array");
++
++ null_lex_str.str= 0; // For sys_var->value_ptr()
++ null_lex_str.length= 0;
++
++ prefix_end=strnmov(name_buffer, prefix, sizeof(name_buffer)-1);
++ len=name_buffer + sizeof(name_buffer) - prefix_end;
++
++ for (; variables->name; variables++)
++ {
++ strnmov(prefix_end, variables->name, len);
++ name_buffer[sizeof(name_buffer)-1]=0; /* Safety */
++ SHOW_TYPE show_type=variables->type;
++ if (show_type == SHOW_VARS)
++ {
++ show_status_array(thd, wild, (show_var_st *) variables->value,
++ value_type, status_var, variables->name, table);
++ }
++ else
++ {
++ if (!(wild && wild[0] && wild_case_compare(system_charset_info,
++ name_buffer, wild)))
++ {
++ char *value=variables->value;
++ const char *pos, *end; // We assign a lot of const's
++ long nr;
++ if (show_type == SHOW_SYS)
++ {
++ show_type= ((sys_var*) value)->type();
++ value= (char*) ((sys_var*) value)->value_ptr(thd, value_type,
++ &null_lex_str);
++ }
++
++ pos= end= buff;
++ switch (show_type) {
++ case SHOW_LONG_STATUS:
++ case SHOW_LONG_CONST_STATUS:
++ value= ((char *) status_var + (ulong) value);
++ /* fall through */
++ case SHOW_LONG:
++ case SHOW_LONG_CONST:
++ end= int10_to_str(*(long*) value, buff, 10);
++ break;
++ case SHOW_LONGLONG:
++ end= longlong10_to_str(*(longlong*) value, buff, 10);
++ break;
++ case SHOW_HA_ROWS:
++ end= longlong10_to_str((longlong) *(ha_rows*) value, buff, 10);
++ break;
++ case SHOW_BOOL:
++ end= strmov(buff, *(bool*) value ? "ON" : "OFF");
++ break;
++ case SHOW_MY_BOOL:
++ end= strmov(buff, *(my_bool*) value ? "ON" : "OFF");
++ break;
++ case SHOW_INT_CONST:
++ case SHOW_INT:
++ end= int10_to_str((long) *(uint32*) value, buff, 10);
++ break;
++ case SHOW_HAVE:
++ {
++ SHOW_COMP_OPTION tmp= *(SHOW_COMP_OPTION*) value;
++ pos= show_comp_option_name[(int) tmp];
++ end= strend(pos);
++ break;
++ }
++ case SHOW_CHAR:
++ {
++ if (!(pos= value))
++ pos= "";
++ end= strend(pos);
++ break;
++ }
++ case SHOW_STARTTIME:
++ nr= (long) (thd->query_start() - start_time);
++ end= int10_to_str(nr, buff, 10);
++ break;
++ case SHOW_QUESTION:
++ end= int10_to_str((long) thd->query_id, buff, 10);
++ break;
++#ifdef HAVE_REPLICATION
++ case SHOW_RPL_STATUS:
++ end= strmov(buff, rpl_status_type[(int)rpl_status]);
++ break;
++ case SHOW_SLAVE_RUNNING:
++ {
++ pthread_mutex_lock(&LOCK_active_mi);
++ end= strmov(buff, (active_mi && active_mi->slave_running &&
++ active_mi->rli.slave_running) ? "ON" : "OFF");
++ pthread_mutex_unlock(&LOCK_active_mi);
++ break;
++ }
++ case SHOW_SLAVE_RETRIED_TRANS:
++ {
++ /*
++ TODO: in 5.1 with multimaster, have one such counter per line in
++ SHOW SLAVE STATUS, and have the sum over all lines here.
++ */
++ pthread_mutex_lock(&LOCK_active_mi);
++ if (active_mi)
++ {
++ pthread_mutex_lock(&active_mi->rli.data_lock);
++ end= int10_to_str(active_mi->rli.retried_trans, buff, 10);
++ pthread_mutex_unlock(&active_mi->rli.data_lock);
++ }
++ pthread_mutex_unlock(&LOCK_active_mi);
++ break;
++ }
++ case SHOW_SLAVE_SKIP_ERRORS:
++ {
++ MY_BITMAP *bitmap= (MY_BITMAP *)value;
++ if (!use_slave_mask || bitmap_is_clear_all(bitmap))
++ {
++ end= strmov(buff, "OFF");
++ }
++ else if (bitmap_is_set_all(bitmap))
++ {
++ end= strmov(buff, "ALL");
++ }
++ else
++ {
++ /* 10 is enough assuming errors are max 4 digits */
++ int i;
++ for (i= 1;
++ i < MAX_SLAVE_ERROR && (uint) (end-buff) < sizeof(buff)-10;
++ i++)
++ {
++ if (bitmap_is_set(bitmap, i))
++ {
++ end= int10_to_str(i, (char*) end, 10);
++ *(char*) end++= ',';
++ }
++ }
++ if (end != buff)
++ end--; // Remove last ','
++ if (i < MAX_SLAVE_ERROR)
++ end= strmov((char*) end, "..."); // Couldn't show all errors
++ }
++ break;
++ }
++#endif /* HAVE_REPLICATION */
++ case SHOW_OPENTABLES:
++ end= int10_to_str((long) cached_tables(), buff, 10);
++ break;
++ case SHOW_CHAR_PTR:
++ {
++ if (!(pos= *(char**) value))
++ pos= "";
++ end= strend(pos);
++ break;
++ }
++ case SHOW_DOUBLE_STATUS:
++ {
++ value= ((char *) status_var + (ulong) value);
++ end= buff + sprintf(buff, "%f", *(double*) value);
++ break;
++ }
++#ifdef HAVE_OPENSSL
++ /* First group - functions relying on CTX */
++ case SHOW_SSL_CTX_SESS_ACCEPT:
++ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
++ SSL_CTX_sess_accept(ssl_acceptor_fd->
++ ssl_context)),
++ buff, 10);
++ break;
++ case SHOW_SSL_CTX_SESS_ACCEPT_GOOD:
++ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
++ SSL_CTX_sess_accept_good(ssl_acceptor_fd->
++ ssl_context)),
++ buff, 10);
++ break;
++ case SHOW_SSL_CTX_SESS_CONNECT_GOOD:
++ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
++ SSL_CTX_sess_connect_good(ssl_acceptor_fd->
++ ssl_context)),
++ buff, 10);
++ break;
++ case SHOW_SSL_CTX_SESS_ACCEPT_RENEGOTIATE:
++ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
++ SSL_CTX_sess_accept_renegotiate(ssl_acceptor_fd->ssl_context)),
++ buff, 10);
++ break;
++ case SHOW_SSL_CTX_SESS_CONNECT_RENEGOTIATE:
++ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
++ SSL_CTX_sess_connect_renegotiate(ssl_acceptor_fd-> ssl_context)),
++ buff, 10);
++ break;
++ case SHOW_SSL_CTX_SESS_CB_HITS:
++ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
++ SSL_CTX_sess_cb_hits(ssl_acceptor_fd->
++ ssl_context)),
++ buff, 10);
++ break;
++ case SHOW_SSL_CTX_SESS_HITS:
++ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
++ SSL_CTX_sess_hits(ssl_acceptor_fd->
++ ssl_context)),
++ buff, 10);
++ break;
++ case SHOW_SSL_CTX_SESS_CACHE_FULL:
++ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
++ SSL_CTX_sess_cache_full(ssl_acceptor_fd->
++ ssl_context)),
++ buff, 10);
++ break;
++ case SHOW_SSL_CTX_SESS_MISSES:
++ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
++ SSL_CTX_sess_misses(ssl_acceptor_fd->
++ ssl_context)),
++ buff, 10);
++ break;
++ case SHOW_SSL_CTX_SESS_TIMEOUTS:
++ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
++ SSL_CTX_sess_timeouts(ssl_acceptor_fd->ssl_context)),
++ buff,10);
++ break;
++ case SHOW_SSL_CTX_SESS_NUMBER:
++ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
++ SSL_CTX_sess_number(ssl_acceptor_fd->ssl_context)),
++ buff,10);
++ break;
++ case SHOW_SSL_CTX_SESS_CONNECT:
++ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
++ SSL_CTX_sess_connect(ssl_acceptor_fd->ssl_context)),
++ buff,10);
++ break;
++ case SHOW_SSL_CTX_SESS_GET_CACHE_SIZE:
++ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
++ SSL_CTX_sess_get_cache_size(ssl_acceptor_fd->ssl_context)),
++ buff,10);
++ break;
++ case SHOW_SSL_CTX_GET_VERIFY_MODE:
++ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
++ SSL_CTX_get_verify_mode(ssl_acceptor_fd->ssl_context)),
++ buff,10);
++ break;
++ case SHOW_SSL_CTX_GET_VERIFY_DEPTH:
++ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
++ SSL_CTX_get_verify_depth(ssl_acceptor_fd->ssl_context)),
++ buff,10);
++ break;
++ case SHOW_SSL_CTX_GET_SESSION_CACHE_MODE:
++ if (!ssl_acceptor_fd)
++ {
++ pos= "NONE";
++ end= pos+4;
++ break;
++ }
++ switch (SSL_CTX_get_session_cache_mode(ssl_acceptor_fd->ssl_context))
++ {
++ case SSL_SESS_CACHE_OFF:
++ pos= "OFF";
++ break;
++ case SSL_SESS_CACHE_CLIENT:
++ pos= "CLIENT";
++ break;
++ case SSL_SESS_CACHE_SERVER:
++ pos= "SERVER";
++ break;
++ case SSL_SESS_CACHE_BOTH:
++ pos= "BOTH";
++ break;
++ case SSL_SESS_CACHE_NO_AUTO_CLEAR:
++ pos= "NO_AUTO_CLEAR";
++ break;
++ case SSL_SESS_CACHE_NO_INTERNAL_LOOKUP:
++ pos= "NO_INTERNAL_LOOKUP";
++ break;
++ default:
++ pos= "Unknown";
++ break;
++ }
++ end= strend(pos);
++ break;
++ /* First group - functions relying on SSL */
++ case SHOW_SSL_GET_VERSION:
++ pos= (thd->net.vio->ssl_arg ?
++ SSL_get_version((SSL*) thd->net.vio->ssl_arg) : "");
++ end= strend(pos);
++ break;
++ case SHOW_SSL_SESSION_REUSED:
++ end= int10_to_str((long) (thd->net.vio->ssl_arg ?
++ SSL_session_reused((SSL*) thd->net.vio->
++ ssl_arg) :
++ 0),
++ buff, 10);
++ break;
++ case SHOW_SSL_GET_DEFAULT_TIMEOUT:
++ end= int10_to_str((long) (thd->net.vio->ssl_arg ?
++ SSL_get_default_timeout((SSL*) thd->net.vio->
++ ssl_arg) :
++ 0),
++ buff, 10);
++ break;
++ case SHOW_SSL_GET_VERIFY_MODE:
++ end= int10_to_str((long) (thd->net.vio->ssl_arg ?
++ SSL_get_verify_mode((SSL*) thd->net.vio->
++ ssl_arg):
++ 0),
++ buff, 10);
++ break;
++ case SHOW_SSL_GET_VERIFY_DEPTH:
++ end= int10_to_str((long) (thd->net.vio->ssl_arg ?
++ SSL_get_verify_depth((SSL*) thd->net.vio->
++ ssl_arg):
++ 0),
++ buff, 10);
++ break;
++ case SHOW_SSL_GET_CIPHER:
++ pos= (thd->net.vio->ssl_arg ?
++ SSL_get_cipher((SSL*) thd->net.vio->ssl_arg) : "" );
++ end= strend(pos);
++ break;
++ case SHOW_SSL_GET_CIPHER_LIST:
++ if (thd->net.vio->ssl_arg)
++ {
++ char *to= buff;
++ for (int i=0 ; i++ ;)
++ {
++ const char *p= SSL_get_cipher_list((SSL*) thd->net.vio->ssl_arg,i);
++ if (p == NULL)
++ break;
++ to= strmov(to, p);
++ *to++= ':';
++ }
++ if (to != buff)
++ to--; // Remove last ':'
++ end= to;
++ }
++ break;
++
++#endif /* HAVE_OPENSSL */
++ case SHOW_KEY_CACHE_LONG:
++ case SHOW_KEY_CACHE_CONST_LONG:
++ value= (value-(char*) &dflt_key_cache_var)+ (char*) dflt_key_cache;
++ end= int10_to_str(*(long*) value, buff, 10);
++ break;
++ case SHOW_KEY_CACHE_LONGLONG:
++ value= (value-(char*) &dflt_key_cache_var)+ (char*) dflt_key_cache;
++ end= longlong10_to_str(*(longlong*) value, buff, 10);
++ break;
++ case SHOW_NET_COMPRESSION:
++ end= strmov(buff, thd->net.compress ? "ON" : "OFF");
++ break;
++ case SHOW_UNDEF: // Show never happen
++ case SHOW_SYS:
++ break; // Return empty string
++ default:
++ break;
++ }
++ restore_record(table, s->default_values);
++ table->field[0]->store(name_buffer, strlen(name_buffer),
++ system_charset_info);
++ table->field[1]->store(pos, (uint32) (end - pos), system_charset_info);
++ if (schema_table_store_record(thd, table))
++ DBUG_RETURN(TRUE);
++ }
++ }
++ }
++
++ DBUG_RETURN(FALSE);
++}
++
++
++/* collect status for all running threads */
++
++void calc_sum_of_all_status(STATUS_VAR *to)
++{
++ DBUG_ENTER("calc_sum_of_all_status");
++
++ /* Ensure that thread id not killed during loop */
++ VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
++
++ I_List_iterator<THD> it(threads);
++ THD *tmp;
++
++ /* Get global values as base */
++ *to= global_status_var;
++
++ /* Add to this status from existing threads */
++ while ((tmp= it++))
++ add_to_status(to, &tmp->status_var);
++
++ VOID(pthread_mutex_unlock(&LOCK_thread_count));
++ DBUG_VOID_RETURN;
++}
++
++
++LEX_STRING *make_lex_string(THD *thd, LEX_STRING *lex_str,
++ const char* str, uint length,
++ bool allocate_lex_string)
++{
++ MEM_ROOT *mem= thd->mem_root;
++ if (allocate_lex_string)
++ if (!(lex_str= (LEX_STRING *)thd->alloc(sizeof(LEX_STRING))))
++ return 0;
++ lex_str->str= strmake_root(mem, str, length);
++ lex_str->length= length;
++ return lex_str;
++}
++
++
++/* INFORMATION_SCHEMA name */
++LEX_STRING information_schema_name= {(char*)"information_schema", 18};
++
++/* This is only used internally, but we need it here as a forward reference */
++extern ST_SCHEMA_TABLE schema_tables[];
++
++typedef struct st_index_field_values
++{
++ const char *db_value, *table_value;
++} INDEX_FIELD_VALUES;
++
++
++/*
++ Store record to I_S table, convert HEAP table
++ to MyISAM if necessary
++
++ SYNOPSIS
++ schema_table_store_record()
++ thd thread handler
++ table Information schema table to be updated
++
++ RETURN
++ 0 success
++ 1 error
++*/
++
++static bool schema_table_store_record(THD *thd, TABLE *table)
++{
++ int error;
++ if ((error= table->file->write_row(table->record[0])))
++ {
++ if (create_myisam_from_heap(thd, table,
++ table->pos_in_table_list->schema_table_param,
++ error, 0))
++ return 1;
++ }
++ return 0;
++}
++
++
++void get_index_field_values(LEX *lex, INDEX_FIELD_VALUES *index_field_values)
++{
++ const char *wild= lex->wild ? lex->wild->ptr() : NullS;
++ switch (lex->orig_sql_command) {
++ case SQLCOM_SHOW_DATABASES:
++ index_field_values->db_value= wild;
++ break;
++ case SQLCOM_SHOW_TABLES:
++ case SQLCOM_SHOW_TABLE_STATUS:
++ case SQLCOM_SHOW_TRIGGERS:
++ index_field_values->db_value= lex->select_lex.db;
++ index_field_values->table_value= wild;
++ break;
++ default:
++ index_field_values->db_value= NullS;
++ index_field_values->table_value= NullS;
++ break;
++ }
++}
++
++
++int make_table_list(THD *thd, SELECT_LEX *sel,
++ char *db, char *table)
++{
++ Table_ident *table_ident;
++ LEX_STRING ident_db, ident_table;
++ ident_db.str= db;
++ ident_db.length= strlen(db);
++ ident_table.str= table;
++ ident_table.length= strlen(table);
++ table_ident= new Table_ident(thd, ident_db, ident_table, 1);
++ sel->init_query();
++ if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ,
++ (List<String> *) 0, (List<String> *) 0))
++ return 1;
++ return 0;
++}
++
++
++bool uses_only_table_name_fields(Item *item, TABLE_LIST *table)
++{
++ if (item->type() == Item::FUNC_ITEM)
++ {
++ Item_func *item_func= (Item_func*)item;
++ Item **child;
++ Item **item_end= (item_func->arguments()) + item_func->argument_count();
++ for (child= item_func->arguments(); child != item_end; child++)
++ {
++ if (!uses_only_table_name_fields(*child, table))
++ return 0;
++ }
++ }
++ else if (item->type() == Item::FIELD_ITEM)
++ {
++ Item_field *item_field= (Item_field*)item;
++ CHARSET_INFO *cs= system_charset_info;
++ ST_SCHEMA_TABLE *schema_table= table->schema_table;
++ ST_FIELD_INFO *field_info= schema_table->fields_info;
++ const char *field_name1= schema_table->idx_field1 >= 0 ? field_info[schema_table->idx_field1].field_name : "";
++ const char *field_name2= schema_table->idx_field2 >= 0 ? field_info[schema_table->idx_field2].field_name : "";
++ if (table->table != item_field->field->table ||
++ (cs->coll->strnncollsp(cs, (uchar *) field_name1, strlen(field_name1),
++ (uchar *) item_field->field_name,
++ strlen(item_field->field_name), 0) &&
++ cs->coll->strnncollsp(cs, (uchar *) field_name2, strlen(field_name2),
++ (uchar *) item_field->field_name,
++ strlen(item_field->field_name), 0)))
++ return 0;
++ }
++ else if (item->type() == Item::REF_ITEM)
++ return uses_only_table_name_fields(item->real_item(), table);
++ if (item->type() == Item::SUBSELECT_ITEM &&
++ !item->const_item())
++ return 0;
++
++ return 1;
++}
++
++
++static COND * make_cond_for_info_schema(COND *cond, TABLE_LIST *table)
++{
++ if (!cond)
++ return (COND*) 0;
++ if (cond->type() == Item::COND_ITEM)
++ {
++ if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
++ {
++ /* Create new top level AND item */
++ Item_cond_and *new_cond=new Item_cond_and;
++ if (!new_cond)
++ return (COND*) 0;
++ List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
++ Item *item;
++ while ((item=li++))
++ {
++ Item *fix= make_cond_for_info_schema(item, table);
++ if (fix)
++ new_cond->argument_list()->push_back(fix);
++ }
++ switch (new_cond->argument_list()->elements) {
++ case 0:
++ return (COND*) 0;
++ case 1:
++ return new_cond->argument_list()->head();
++ default:
++ new_cond->quick_fix_field();
++ return new_cond;
++ }
++ }
++ else
++ { // Or list
++ Item_cond_or *new_cond=new Item_cond_or;
++ if (!new_cond)
++ return (COND*) 0;
++ List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
++ Item *item;
++ while ((item=li++))
++ {
++ Item *fix=make_cond_for_info_schema(item, table);
++ if (!fix)
++ return (COND*) 0;
++ new_cond->argument_list()->push_back(fix);
++ }
++ new_cond->quick_fix_field();
++ new_cond->top_level_item();
++ return new_cond;
++ }
++ }
++
++ if (!uses_only_table_name_fields(cond, table))
++ return (COND*) 0;
++ return cond;
++}
++
++
++enum enum_schema_tables get_schema_table_idx(ST_SCHEMA_TABLE *schema_table)
++{
++ return (enum enum_schema_tables) (schema_table - &schema_tables[0]);
++}
++
++
++/*
++ Create db names list. Information schema name always is first in list
++
++ SYNOPSIS
++ make_db_list()
++ thd thread handler
++ files list of db names
++ wild wild string
++ idx_field_vals idx_field_vals->db_name contains db name or
++ wild string
++ with_i_schema returns 1 if we added 'IS' name to list
++ otherwise returns 0
++ is_wild_value if value is 1 then idx_field_vals->db_name is
++ wild string otherwise it's db name;
++
++ RETURN
++ zero success
++ non-zero error
++*/
++
++int make_db_list(THD *thd, List<char> *files,
++ INDEX_FIELD_VALUES *idx_field_vals,
++ bool *with_i_schema, bool is_wild_value)
++{
++ LEX *lex= thd->lex;
++ *with_i_schema= 0;
++ get_index_field_values(lex, idx_field_vals);
++ if (is_wild_value)
++ {
++ /*
++ This part of code is only for SHOW DATABASES command.
++ idx_field_vals->db_value can be 0 when we don't use
++ LIKE clause (see also get_index_field_values() function)
++ */
++ if (!idx_field_vals->db_value ||
++ !wild_case_compare(system_charset_info,
++ information_schema_name.str,
++ idx_field_vals->db_value))
++ {
++ *with_i_schema= 1;
++ if (files->push_back(thd->strdup(information_schema_name.str)))
++ return 1;
++ }
++ return (find_files(thd, files, NullS, mysql_data_home,
++ idx_field_vals->db_value, 1) != FIND_FILES_OK);
++ }
++
++ /*
++ This part of code is for SHOW TABLES, SHOW TABLE STATUS commands.
++ idx_field_vals->db_value can't be 0 (see get_index_field_values()
++ function). lex->orig_sql_command can be not equal to SQLCOM_END
++ only in case of executing of SHOW commands.
++ */
++ if (lex->orig_sql_command != SQLCOM_END)
++ {
++ if (!my_strcasecmp(system_charset_info, information_schema_name.str,
++ idx_field_vals->db_value))
++ {
++ *with_i_schema= 1;
++ return files->push_back(thd->strdup(information_schema_name.str));
++ }
++ return files->push_back(thd->strdup(idx_field_vals->db_value));
++ }
++
++ /*
++ Create list of existing databases. It is used in case
++ of select from information schema table
++ */
++ if (files->push_back(thd->strdup(information_schema_name.str)))
++ return 1;
++ *with_i_schema= 1;
++ return (find_files(thd, files, NullS,
++ mysql_data_home, NullS, 1) != FIND_FILES_OK);
++}
++
++
++int schema_tables_add(THD *thd, List<char> *files, const char *wild)
++{
++ ST_SCHEMA_TABLE *tmp_schema_table= schema_tables;
++ for (; tmp_schema_table->table_name; tmp_schema_table++)
++ {
++ if (tmp_schema_table->hidden)
++ continue;
++ if (wild)
++ {
++ if (lower_case_table_names)
++ {
++ if (wild_case_compare(files_charset_info,
++ tmp_schema_table->table_name,
++ wild))
++ continue;
++ }
++ else if (wild_compare(tmp_schema_table->table_name, wild, 0))
++ continue;
++ }
++ if (files->push_back(thd->strdup(tmp_schema_table->table_name)))
++ return 1;
++ }
++ return 0;
++}
++
++
++int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
++{
++ LEX *lex= thd->lex;
++ TABLE *table= tables->table;
++ SELECT_LEX *select_lex= &lex->select_lex;
++ SELECT_LEX *old_all_select_lex= lex->all_selects_list;
++ enum_sql_command save_sql_command= lex->sql_command;
++ SELECT_LEX *lsel= tables->schema_select_lex;
++ ST_SCHEMA_TABLE *schema_table= tables->schema_table;
++ SELECT_LEX sel;
++ INDEX_FIELD_VALUES idx_field_vals;
++ char path[FN_REFLEN], *end, *base_name, *orig_base_name, *file_name;
++ uint len;
++ bool with_i_schema;
++ enum enum_schema_tables schema_table_idx;
++ List<char> bases;
++ List_iterator_fast<char> it(bases);
++ COND *partial_cond;
++ Security_context *sctx= thd->security_ctx;
++ uint derived_tables= lex->derived_tables;
++ int error= 1;
++ db_type not_used;
++ Open_tables_state open_tables_state_backup;
++ bool save_view_prepare_mode= lex->view_prepare_mode;
++ Query_tables_list query_tables_list_backup;
++ lex->view_prepare_mode= TRUE;
++ DBUG_ENTER("get_all_tables");
++
++ LINT_INIT(end);
++ LINT_INIT(len);
++
++ lex->reset_n_backup_query_tables_list(&query_tables_list_backup);
++
++ /*
++ We should not introduce deadlocks even if we already have some
++ tables open and locked, since we won't lock tables which we will
++ open and will ignore possible name-locks for these tables.
++ */
++ thd->reset_n_backup_open_tables_state(&open_tables_state_backup);
++
++ if (lsel)
++ {
++ TABLE_LIST *show_table_list= (TABLE_LIST*) lsel->table_list.first;
++ bool res;
++
++ lex->all_selects_list= lsel;
++ /*
++ Restore thd->temporary_tables to be able to process
++ temporary tables(only for 'show index' & 'show columns').
++ This should be changed when processing of temporary tables for
++ I_S tables will be done.
++ */
++ thd->temporary_tables= open_tables_state_backup.temporary_tables;
++ /*
++ Let us set fake sql_command so views won't try to merge
++ themselves into main statement. If we don't do this,
++ SELECT * from information_schema.xxxx will cause problems.
++ SQLCOM_SHOW_FIELDS is used because it satisfies 'only_view_structure()'
++ */
++ lex->sql_command= SQLCOM_SHOW_FIELDS;
++ res= open_normal_and_derived_tables(thd, show_table_list,
++ MYSQL_LOCK_IGNORE_FLUSH);
++ lex->sql_command= save_sql_command;
++ /*
++ get_all_tables() returns 1 on failure and 0 on success thus
++ return only these and not the result code of ::process_table()
++
++ We should use show_table_list->alias instead of
++ show_table_list->table_name because table_name
++ could be changed during opening of I_S tables. It's safe
++ to use alias because alias contains original table name
++ in this case(this part of code is used only for
++ 'show columns' & 'show statistics' commands).
++ */
++ error= test(schema_table->process_table(thd, show_table_list,
++ table, res,
++ (show_table_list->view ?
++ show_table_list->view_db.str :
++ show_table_list->db),
++ show_table_list->alias));
++ thd->temporary_tables= 0;
++ close_tables_for_reopen(thd, &show_table_list);
++ goto err;
++ }
++
++ schema_table_idx= get_schema_table_idx(schema_table);
++
++ if (make_db_list(thd, &bases, &idx_field_vals,
++ &with_i_schema, 0))
++ goto err;
++
++ partial_cond= make_cond_for_info_schema(cond, tables);
++ it.rewind(); /* To get access to new elements in basis list */
++ while ((orig_base_name= base_name= it++) ||
++ /*
++ generate error for non existing database.
++ (to save old behaviour for SHOW TABLES FROM db)
++ */
++ ((lex->orig_sql_command == SQLCOM_SHOW_TABLES ||
++ lex->orig_sql_command == SQLCOM_SHOW_TABLE_STATUS) &&
++ (base_name= select_lex->db) && !bases.elements))
++ {
++#ifndef NO_EMBEDDED_ACCESS_CHECKS
++ if (!check_access(thd,SELECT_ACL, base_name,
++ &thd->col_access, 0, 1, with_i_schema) ||
++ sctx->master_access & (DB_ACLS | SHOW_DB_ACL) ||
++ acl_get(sctx->host, sctx->ip, sctx->priv_user, base_name,0) ||
++ (grant_option && !check_grant_db(thd, base_name)))
++#endif
++ {
++ List<char> files;
++ if (with_i_schema) // information schema table names
++ {
++ if (schema_tables_add(thd, &files, idx_field_vals.table_value))
++ goto err;
++ }
++ else
++ {
++ strxmov(path, mysql_data_home, "/", base_name, NullS);
++ end= path + (len= unpack_dirname(path,path));
++ len= FN_LEN - len;
++ find_files_result res= find_files(thd, &files, base_name,
++ path, idx_field_vals.table_value, 0);
++ if (res != FIND_FILES_OK)
++ {
++ /*
++ Downgrade errors about problems with database directory to
++ warnings if this is not a 'SHOW' command. Another thread
++ may have dropped database, and we may still have a name
++ for that directory.
++ */
++ if (res == FIND_FILES_DIR && lex->orig_sql_command == SQLCOM_END)
++ {
++ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
++ thd->net.last_errno, thd->net.last_error);
++ thd->clear_error();
++ continue;
++ }
++ else
++ {
++ goto err;
++ }
++ }
++ if (lower_case_table_names)
++ orig_base_name= thd->strdup(base_name);
++ }
++
++ List_iterator_fast<char> it_files(files);
++ while ((file_name= it_files++))
++ {
++ restore_record(table, s->default_values);
++ table->field[schema_table->idx_field1]->
++ store(base_name, strlen(base_name), system_charset_info);
++ table->field[schema_table->idx_field2]->
++ store(file_name, strlen(file_name),system_charset_info);
++ if (!partial_cond || partial_cond->val_int())
++ {
++ if (schema_table_idx == SCH_TABLE_NAMES)
++ {
++ if (lex->verbose || lex->orig_sql_command == SQLCOM_END)
++ {
++ if (with_i_schema)
++ {
++ table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"),
++ system_charset_info);
++ }
++ else
++ {
++ my_snprintf(end, len, "/%s%s", file_name, reg_ext);
++ switch (mysql_frm_type(thd, path, ¬_used)) {
++ case FRMTYPE_ERROR:
++ table->field[3]->store(STRING_WITH_LEN("ERROR"),
++ system_charset_info);
++ break;
++ case FRMTYPE_TABLE:
++ table->field[3]->store(STRING_WITH_LEN("BASE TABLE"),
++ system_charset_info);
++ break;
++ case FRMTYPE_VIEW:
++ table->field[3]->store(STRING_WITH_LEN("VIEW"),
++ system_charset_info);
++ break;
++ default:
++ DBUG_ASSERT(0);
++ }
++ }
++ }
++ if (schema_table_store_record(thd, table))
++ goto err;
++ }
++ else
++ {
++ int res;
++ /*
++ Set the parent lex of 'sel' because it is needed by sel.init_query()
++ which is called inside make_table_list.
++ */
++ sel.parent_lex= lex;
++ if (make_table_list(thd, &sel, base_name, file_name))
++ goto err;
++ TABLE_LIST *show_table_list= (TABLE_LIST*) sel.table_list.first;
++ lex->all_selects_list= &sel;
++ lex->derived_tables= 0;
++ lex->sql_command= SQLCOM_SHOW_FIELDS;
++ res= open_normal_and_derived_tables(thd, show_table_list,
++ MYSQL_LOCK_IGNORE_FLUSH);
++ lex->sql_command= save_sql_command;
++ /*
++ We should use show_table_list->alias instead of
++ show_table_list->table_name because table_name
++ could be changed during opening of I_S tables. It's safe
++ to use alias because alias contains original table name
++ in this case.
++ */
++ res= schema_table->process_table(thd, show_table_list, table,
++ res, orig_base_name,
++ show_table_list->alias);
++ close_tables_for_reopen(thd, &show_table_list);
++ DBUG_ASSERT(!lex->query_tables_own_last);
++ if (res)
++ goto err;
++ }
++ }
++ }
++ /*
++ If we have information schema its always the first table and only
++ the first table. Reset for other tables.
++ */
++ with_i_schema= 0;
++ }
++ }
++
++ error= 0;
++err:
++ thd->restore_backup_open_tables_state(&open_tables_state_backup);
++ lex->restore_backup_query_tables_list(&query_tables_list_backup);
++ lex->derived_tables= derived_tables;
++ lex->all_selects_list= old_all_select_lex;
++ lex->view_prepare_mode= save_view_prepare_mode;
++ lex->sql_command= save_sql_command;
++ DBUG_RETURN(error);
++}
++
++
++bool store_schema_shemata(THD* thd, TABLE *table, const char *db_name,
++ CHARSET_INFO *cs)
++{
++ restore_record(table, s->default_values);
++ table->field[1]->store(db_name, strlen(db_name), system_charset_info);
++ table->field[2]->store(cs->csname, strlen(cs->csname), system_charset_info);
++ table->field[3]->store(cs->name, strlen(cs->name), system_charset_info);
++ return schema_table_store_record(thd, table);
++}
++
++
++int fill_schema_shemata(THD *thd, TABLE_LIST *tables, COND *cond)
++{
++ /*
++ TODO: fill_schema_shemata() is called when new client is connected.
++ Returning error status in this case leads to client hangup.
++ */
++
++ INDEX_FIELD_VALUES idx_field_vals;
++ List<char> files;
++ char *file_name;
++ bool with_i_schema;
++ HA_CREATE_INFO create;
++ TABLE *table= tables->table;
++ Security_context *sctx= thd->security_ctx;
++ DBUG_ENTER("fill_schema_shemata");
++
++ if (make_db_list(thd, &files, &idx_field_vals,
++ &with_i_schema, 1))
++ DBUG_RETURN(1);
++
++ List_iterator_fast<char> it(files);
++ while ((file_name=it++))
++ {
++ if (with_i_schema) // information schema name is always first in list
++ {
++ if (store_schema_shemata(thd, table, file_name,
++ system_charset_info))
++ DBUG_RETURN(1);
++ with_i_schema= 0;
++ continue;
++ }
++#ifndef NO_EMBEDDED_ACCESS_CHECKS
++ if (sctx->master_access & (DB_ACLS | SHOW_DB_ACL) ||
++ acl_get(sctx->host, sctx->ip, sctx->priv_user, file_name,0) ||
++ (grant_option && !check_grant_db(thd, file_name)))
++#endif
++ {
++ load_db_opt_by_name(thd, file_name, &create);
++
++ if (store_schema_shemata(thd, table, file_name,
++ create.default_table_charset))
++ DBUG_RETURN(1);
++ }
++ }
++ DBUG_RETURN(0);
++}
++
++
++static int get_schema_tables_record(THD *thd, struct st_table_list *tables,
++ TABLE *table, bool res,
++ const char *base_name,
++ const char *file_name)
++{
++ const char *tmp_buff;
++ TIME time;
++ CHARSET_INFO *cs= system_charset_info;
++ DBUG_ENTER("get_schema_tables_record");
++
++ restore_record(table, s->default_values);
++ table->field[1]->store(base_name, strlen(base_name), cs);
++ table->field[2]->store(file_name, strlen(file_name), cs);
++ if (res)
++ {
++ /*
++ there was errors during opening tables
++ */
++ const char *error= thd->net.last_error;
++ if (tables->view)
++ table->field[3]->store(STRING_WITH_LEN("VIEW"), cs);
++ else if (tables->schema_table)
++ table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"), cs);
++ else
++ table->field[3]->store(STRING_WITH_LEN("BASE TABLE"), cs);
++ table->field[20]->store(error, strlen(error), cs);
++ thd->clear_error();
++ }
++ else if (tables->view)
++ {
++ table->field[3]->store(STRING_WITH_LEN("VIEW"), cs);
++ table->field[20]->store(STRING_WITH_LEN("VIEW"), cs);
++ }
++ else
++ {
++ TABLE *show_table= tables->table;
++ TABLE_SHARE *share= show_table->s;
++ handler *file= show_table->file;
++
++ file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_AUTO |
++ HA_STATUS_NO_LOCK);
++ if (share->tmp_table == SYSTEM_TMP_TABLE)
++ table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"), cs);
++ else if (share->tmp_table)
++ table->field[3]->store(STRING_WITH_LEN("LOCAL TEMPORARY"), cs);
++ else
++ table->field[3]->store(STRING_WITH_LEN("BASE TABLE"), cs);
++
++ for (int i= 4; i < 20; i++)
++ {
++ if (i == 7 || (i > 12 && i < 17) || i == 18)
++ continue;
++ table->field[i]->set_notnull();
++ }
++ tmp_buff= file->table_type();
++ table->field[4]->store(tmp_buff, strlen(tmp_buff), cs);
++ table->field[5]->store((longlong) share->frm_version, TRUE);
++ enum row_type row_type = file->get_row_type();
++ switch (row_type) {
++ case ROW_TYPE_NOT_USED:
++ case ROW_TYPE_DEFAULT:
++ tmp_buff= ((share->db_options_in_use &
++ HA_OPTION_COMPRESS_RECORD) ? "Compressed" :
++ (share->db_options_in_use & HA_OPTION_PACK_RECORD) ?
++ "Dynamic" : "Fixed");
++ break;
++ case ROW_TYPE_FIXED:
++ tmp_buff= "Fixed";
++ break;
++ case ROW_TYPE_DYNAMIC:
++ tmp_buff= "Dynamic";
++ break;
++ case ROW_TYPE_COMPRESSED:
++ tmp_buff= "Compressed";
++ break;
++ case ROW_TYPE_REDUNDANT:
++ tmp_buff= "Redundant";
++ break;
++ case ROW_TYPE_COMPACT:
++ tmp_buff= "Compact";
++ break;
++ }
++ table->field[6]->store(tmp_buff, strlen(tmp_buff), cs);
++ if (!tables->schema_table)
++ {
++ table->field[7]->store((longlong) file->records, TRUE);
++ table->field[7]->set_notnull();
++ }
++ table->field[8]->store((longlong) file->mean_rec_length, TRUE);
++ table->field[9]->store((longlong) file->data_file_length, TRUE);
++ if (file->max_data_file_length)
++ {
++ table->field[10]->store((longlong) file->max_data_file_length, TRUE);
++ }
++ table->field[11]->store((longlong) file->index_file_length, TRUE);
++ table->field[12]->store((longlong) file->delete_length, TRUE);
++ if (show_table->found_next_number_field)
++ {
++ table->field[13]->store((longlong) file->auto_increment_value, TRUE);
++ table->field[13]->set_notnull();
++ }
++ if (file->create_time)
++ {
++ thd->variables.time_zone->gmt_sec_to_TIME(&time,
++ file->create_time);
++ table->field[14]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
++ table->field[14]->set_notnull();
++ }
++ if (file->update_time)
++ {
++ thd->variables.time_zone->gmt_sec_to_TIME(&time,
++ file->update_time);
++ table->field[15]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
++ table->field[15]->set_notnull();
++ }
++ if (file->check_time)
++ {
++ thd->variables.time_zone->gmt_sec_to_TIME(&time, file->check_time);
++ table->field[16]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
++ table->field[16]->set_notnull();
++ }
++ tmp_buff= (share->table_charset ?
++ share->table_charset->name : "default");
++ table->field[17]->store(tmp_buff, strlen(tmp_buff), cs);
++ if (file->table_flags() & (ulong) HA_HAS_CHECKSUM)
++ {
++ table->field[18]->store((longlong) file->checksum(), TRUE);
++ table->field[18]->set_notnull();
++ }
++
++ char option_buff[350],*ptr;
++ ptr=option_buff;
++ if (share->min_rows)
++ {
++ ptr=strmov(ptr," min_rows=");
++ ptr=longlong10_to_str(share->min_rows,ptr,10);
++ }
++ if (share->max_rows)
++ {
++ ptr=strmov(ptr," max_rows=");
++ ptr=longlong10_to_str(share->max_rows,ptr,10);
++ }
++ if (share->avg_row_length)
++ {
++ ptr=strmov(ptr," avg_row_length=");
++ ptr=longlong10_to_str(share->avg_row_length,ptr,10);
++ }
++ if (share->db_create_options & HA_OPTION_PACK_KEYS)
++ ptr=strmov(ptr," pack_keys=1");
++ if (share->db_create_options & HA_OPTION_NO_PACK_KEYS)
++ ptr=strmov(ptr," pack_keys=0");
++ if (share->db_create_options & HA_OPTION_CHECKSUM)
++ ptr=strmov(ptr," checksum=1");
++ if (share->db_create_options & HA_OPTION_DELAY_KEY_WRITE)
++ ptr=strmov(ptr," delay_key_write=1");
++ if (share->row_type != ROW_TYPE_DEFAULT)
++ ptr=strxmov(ptr, " row_format=",
++ ha_row_type[(uint) share->row_type],
++ NullS);
++ if (file->raid_type)
++ {
++ char buff[100];
++ my_snprintf(buff,sizeof(buff),
++ " raid_type=%s raid_chunks=%d raid_chunksize=%ld",
++ my_raid_type(file->raid_type), file->raid_chunks,
++ file->raid_chunksize/RAID_BLOCK_SIZE);
++ ptr=strmov(ptr,buff);
++ }
++ table->field[19]->store(option_buff+1,
++ (ptr == option_buff ? 0 :
++ (uint) (ptr-option_buff)-1), cs);
++ {
++ char *comment;
++ comment= show_table->file->update_table_comment(share->comment.str);
++ if (comment)
++ {
++ table->field[20]->store(comment,
++ (comment == share->comment.str ?
++ share->comment.length :
++ strlen(comment)), cs);
++ if (comment != share->comment.str)
++ my_free(comment, MYF(0));
++ }
++ }
++ }
++ DBUG_RETURN(schema_table_store_record(thd, table));
++}
++
++
++static int get_schema_column_record(THD *thd, struct st_table_list *tables,
++ TABLE *table, bool res,
++ const char *base_name,
++ const char *file_name)
++{
++ LEX *lex= thd->lex;
++ const char *wild= lex->wild ? lex->wild->ptr() : NullS;
++ CHARSET_INFO *cs= system_charset_info;
++ TABLE *show_table;
++ handler *file;
++ Field **ptr,*field;
++ int count;
++ uint base_name_length, file_name_length;
++ DBUG_ENTER("get_schema_column_record");
++
++ if (res)
++ {
++ if (lex->orig_sql_command != SQLCOM_SHOW_FIELDS)
++ {
++ /*
++ I.e. we are in SELECT FROM INFORMATION_SCHEMA.COLUMS
++ rather than in SHOW COLUMNS
++ */
++ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
++ thd->net.last_errno, thd->net.last_error);
++ thd->clear_error();
++ res= 0;
++ }
++ DBUG_RETURN(res);
++ }
++
++ show_table= tables->table;
++ file= show_table->file;
++ count= 0;
++ file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
++ restore_record(show_table, s->default_values);
++ base_name_length= strlen(base_name);
++ file_name_length= strlen(file_name);
++
++ for (ptr=show_table->field; (field= *ptr) ; ptr++)
++ {
++ const char *tmp_buff;
++ byte *pos;
++ bool is_blob;
++ uint flags=field->flags;
++ char tmp[MAX_FIELD_WIDTH];
++ char tmp1[MAX_FIELD_WIDTH];
++ String type(tmp,sizeof(tmp), system_charset_info);
++ char *end;
++ int decimals, field_length;
++
++ if (wild && wild[0] &&
++ wild_case_compare(system_charset_info, field->field_name,wild))
++ continue;
++
++ flags= field->flags;
++ count++;
++ /* Get default row, with all NULL fields set to NULL */
++ restore_record(table, s->default_values);
++
++#ifndef NO_EMBEDDED_ACCESS_CHECKS
++ uint col_access;
++ check_access(thd,SELECT_ACL | EXTRA_ACL, base_name,
++ &tables->grant.privilege, 0, 0, test(tables->schema_table));
++ col_access= get_column_grant(thd, &tables->grant,
++ base_name, file_name,
++ field->field_name) & COL_ACLS;
++ if (lex->orig_sql_command != SQLCOM_SHOW_FIELDS &&
++ !tables->schema_table && !col_access)
++ continue;
++ end= tmp;
++ for (uint bitnr=0; col_access ; col_access>>=1,bitnr++)
++ {
++ if (col_access & 1)
++ {
++ *end++=',';
++ end=strmov(end,grant_types.type_names[bitnr]);
++ }
++ }
++ table->field[17]->store(tmp+1,end == tmp ? 0 : (uint) (end-tmp-1), cs);
++
++#endif
++ table->field[1]->store(base_name, base_name_length, cs);
++ table->field[2]->store(file_name, file_name_length, cs);
++ table->field[3]->store(field->field_name, strlen(field->field_name),
++ cs);
++ table->field[4]->store((longlong) count, TRUE);
++ field->sql_type(type);
++ table->field[14]->store(type.ptr(), type.length(), cs);
++ tmp_buff= strchr(type.ptr(), '(');
++ table->field[7]->store(type.ptr(),
++ (tmp_buff ? tmp_buff - type.ptr() :
++ type.length()), cs);
++ if (show_table->timestamp_field == field &&
++ field->unireg_check != Field::TIMESTAMP_UN_FIELD)
++ {
++ table->field[5]->store(STRING_WITH_LEN("CURRENT_TIMESTAMP"), cs);
++ table->field[5]->set_notnull();
++ }
++ else if (field->unireg_check != Field::NEXT_NUMBER &&
++ !field->is_null() &&
++ !(field->flags & NO_DEFAULT_VALUE_FLAG))
++ {
++ String def(tmp1,sizeof(tmp1), cs);
++ type.set(tmp, sizeof(tmp), field->charset());
++ field->val_str(&type);
++ uint dummy_errors;
++ def.copy(type.ptr(), type.length(), type.charset(), cs, &dummy_errors);
++ table->field[5]->store(def.ptr(), def.length(), def.charset());
++ table->field[5]->set_notnull();
++ }
++ else if (field->unireg_check == Field::NEXT_NUMBER ||
++ lex->orig_sql_command != SQLCOM_SHOW_FIELDS ||
++ field->maybe_null())
++ table->field[5]->set_null(); // Null as default
++ else
++ {
++ table->field[5]->store("",0, cs);
++ table->field[5]->set_notnull();
++ }
++ pos=(byte*) ((flags & NOT_NULL_FLAG) ? "NO" : "YES");
++ table->field[6]->store((const char*) pos,
++ strlen((const char*) pos), cs);
++ is_blob= (field->type() == FIELD_TYPE_BLOB);
++ if (field->has_charset() || is_blob ||
++ field->real_type() == MYSQL_TYPE_VARCHAR || // For varbinary type
++ field->real_type() == MYSQL_TYPE_STRING) // For binary type
++ {
++ uint32 octet_max_length= field->max_length();
++ if (is_blob && octet_max_length != (uint32) 4294967295U)
++ octet_max_length /= field->charset()->mbmaxlen;
++ longlong char_max_len= is_blob ?
++ (longlong) octet_max_length / field->charset()->mbminlen :
++ (longlong) octet_max_length / field->charset()->mbmaxlen;
++ table->field[8]->store(char_max_len, TRUE);
++ table->field[8]->set_notnull();
++ table->field[9]->store((longlong) octet_max_length, TRUE);
++ table->field[9]->set_notnull();
++ }
++
++ /*
++ Calculate field_length and decimals.
++ They are set to -1 if they should not be set (we should return NULL)
++ */
++
++ decimals= field->decimals();
++ switch (field->type()) {
++ case FIELD_TYPE_NEWDECIMAL:
++ field_length= ((Field_new_decimal*) field)->precision;
++ break;
++ case FIELD_TYPE_DECIMAL:
++ field_length= field->field_length - (decimals ? 2 : 1);
++ break;
++ case FIELD_TYPE_TINY:
++ case FIELD_TYPE_SHORT:
++ case FIELD_TYPE_LONG:
++ case FIELD_TYPE_LONGLONG:
++ case FIELD_TYPE_INT24:
++ field_length= field->max_length() - 1;
++ break;
++ case FIELD_TYPE_BIT:
++ field_length= field->max_length();
++ decimals= -1; // return NULL
++ break;
++ case FIELD_TYPE_FLOAT:
++ case FIELD_TYPE_DOUBLE:
++ field_length= field->field_length;
++ if (decimals == NOT_FIXED_DEC)
++ decimals= -1; // return NULL
++ break;
++ default:
++ field_length= decimals= -1;
++ break;
++ }
++
++ if (field_length >= 0)
++ {
++ table->field[10]->store((longlong) field_length, TRUE);
++ table->field[10]->set_notnull();
++ }
++ if (decimals >= 0)
++ {
++ table->field[11]->store((longlong) decimals, TRUE);
++ table->field[11]->set_notnull();
++ }
++
++ if (field->has_charset())
++ {
++ pos=(byte*) field->charset()->csname;
++ table->field[12]->store((const char*) pos,
++ strlen((const char*) pos), cs);
++ table->field[12]->set_notnull();
++ pos=(byte*) field->charset()->name;
++ table->field[13]->store((const char*) pos,
++ strlen((const char*) pos), cs);
++ table->field[13]->set_notnull();
++ }
++ pos=(byte*) ((field->flags & PRI_KEY_FLAG) ? "PRI" :
++ (field->flags & UNIQUE_KEY_FLAG) ? "UNI" :
++ (field->flags & MULTIPLE_KEY_FLAG) ? "MUL":"");
++ table->field[15]->store((const char*) pos,
++ strlen((const char*) pos), cs);
++
++ end= tmp;
++ if (field->unireg_check == Field::NEXT_NUMBER)
++ end=strmov(tmp,"auto_increment");
++ table->field[16]->store(tmp, (uint) (end-tmp), cs);
++
++ table->field[18]->store(field->comment.str, field->comment.length, cs);
++ if (schema_table_store_record(thd, table))
++ DBUG_RETURN(1);
++ }
++ DBUG_RETURN(0);
++}
++
++
++
++int fill_schema_charsets(THD *thd, TABLE_LIST *tables, COND *cond)
++{
++ CHARSET_INFO **cs;
++ const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
++ TABLE *table= tables->table;
++ CHARSET_INFO *scs= system_charset_info;
++
++ for (cs= all_charsets ; cs < all_charsets+255 ; cs++)
++ {
++ CHARSET_INFO *tmp_cs= cs[0];
++ if (tmp_cs && (tmp_cs->state & MY_CS_PRIMARY) &&
++ (tmp_cs->state & MY_CS_AVAILABLE) &&
++ !(wild && wild[0] &&
++ wild_case_compare(scs, tmp_cs->csname,wild)))
++ {
++ const char *comment;
++ restore_record(table, s->default_values);
++ table->field[0]->store(tmp_cs->csname, strlen(tmp_cs->csname), scs);
++ table->field[1]->store(tmp_cs->name, strlen(tmp_cs->name), scs);
++ comment= tmp_cs->comment ? tmp_cs->comment : "";
++ table->field[2]->store(comment, strlen(comment), scs);
++ table->field[3]->store((longlong) tmp_cs->mbmaxlen, TRUE);
++ if (schema_table_store_record(thd, table))
++ return 1;
++ }
++ }
++ return 0;
++}
++
++
++int fill_schema_collation(THD *thd, TABLE_LIST *tables, COND *cond)
++{
++ CHARSET_INFO **cs;
++ const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
++ TABLE *table= tables->table;
++ CHARSET_INFO *scs= system_charset_info;
++ for (cs= all_charsets ; cs < all_charsets+255 ; cs++ )
++ {
++ CHARSET_INFO **cl;
++ CHARSET_INFO *tmp_cs= cs[0];
++ if (!tmp_cs || !(tmp_cs->state & MY_CS_AVAILABLE) ||
++ !(tmp_cs->state & MY_CS_PRIMARY))
++ continue;
++ for (cl= all_charsets; cl < all_charsets+255 ;cl ++)
++ {
++ CHARSET_INFO *tmp_cl= cl[0];
++ if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) ||
++ !my_charset_same(tmp_cs, tmp_cl))
++ continue;
++ if (!(wild && wild[0] &&
++ wild_case_compare(scs, tmp_cl->name,wild)))
++ {
++ const char *tmp_buff;
++ restore_record(table, s->default_values);
++ table->field[0]->store(tmp_cl->name, strlen(tmp_cl->name), scs);
++ table->field[1]->store(tmp_cl->csname , strlen(tmp_cl->csname), scs);
++ table->field[2]->store((longlong) tmp_cl->number, TRUE);
++ tmp_buff= (tmp_cl->state & MY_CS_PRIMARY) ? "Yes" : "";
++ table->field[3]->store(tmp_buff, strlen(tmp_buff), scs);
++ tmp_buff= (tmp_cl->state & MY_CS_COMPILED)? "Yes" : "";
++ table->field[4]->store(tmp_buff, strlen(tmp_buff), scs);
++ table->field[5]->store((longlong) tmp_cl->strxfrm_multiply, TRUE);
++ if (schema_table_store_record(thd, table))
++ return 1;
++ }
++ }
++ }
++ return 0;
++}
++
++
++int fill_schema_coll_charset_app(THD *thd, TABLE_LIST *tables, COND *cond)
++{
++ CHARSET_INFO **cs;
++ TABLE *table= tables->table;
++ CHARSET_INFO *scs= system_charset_info;
++ for (cs= all_charsets ; cs < all_charsets+255 ; cs++ )
++ {
++ CHARSET_INFO **cl;
++ CHARSET_INFO *tmp_cs= cs[0];
++ if (!tmp_cs || !(tmp_cs->state & MY_CS_AVAILABLE) ||
++ !(tmp_cs->state & MY_CS_PRIMARY))
++ continue;
++ for (cl= all_charsets; cl < all_charsets+255 ;cl ++)
++ {
++ CHARSET_INFO *tmp_cl= cl[0];
++ if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) ||
++ !my_charset_same(tmp_cs,tmp_cl))
++ continue;
++ restore_record(table, s->default_values);
++ table->field[0]->store(tmp_cl->name, strlen(tmp_cl->name), scs);
++ table->field[1]->store(tmp_cl->csname , strlen(tmp_cl->csname), scs);
++ if (schema_table_store_record(thd, table))
++ return 1;
++ }
++ }
++ return 0;
++}
++
++
++bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table,
++ const char *wild, bool full_access, const char *sp_user)
++{
++ String tmp_string;
++ String sp_db, sp_name, definer;
++ TIME time;
++ LEX *lex= thd->lex;
++ CHARSET_INFO *cs= system_charset_info;
++ get_field(thd->mem_root, proc_table->field[0], &sp_db);
++ get_field(thd->mem_root, proc_table->field[1], &sp_name);
++ get_field(thd->mem_root, proc_table->field[11], &definer);
++ if (!full_access)
++ full_access= !strcmp(sp_user, definer.ptr());
++ if (!full_access && check_some_routine_access(thd, sp_db.ptr(), sp_name.ptr(),
++ proc_table->field[2]->val_int() ==
++ TYPE_ENUM_PROCEDURE))
++ return 0;
++
++ 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)
++ {
++ restore_record(table, s->default_values);
++ if (!wild || !wild[0] || !wild_compare(sp_name.ptr(), wild, 0))
++ {
++ int enum_idx= (int) proc_table->field[5]->val_int();
++ table->field[3]->store(sp_name.ptr(), sp_name.length(), cs);
++ get_field(thd->mem_root, proc_table->field[3], &tmp_string);
++ table->field[0]->store(tmp_string.ptr(), tmp_string.length(), cs);
++ table->field[2]->store(sp_db.ptr(), sp_db.length(), cs);
++ get_field(thd->mem_root, proc_table->field[2], &tmp_string);
++ table->field[4]->store(tmp_string.ptr(), tmp_string.length(), cs);
++ if (proc_table->field[2]->val_int() == TYPE_ENUM_FUNCTION)
++ {
++ get_field(thd->mem_root, proc_table->field[9], &tmp_string);
++ table->field[5]->store(tmp_string.ptr(), tmp_string.length(), cs);
++ table->field[5]->set_notnull();
++ }
++ if (full_access)
++ {
++ get_field(thd->mem_root, proc_table->field[10], &tmp_string);
++ table->field[7]->store(tmp_string.ptr(), tmp_string.length(), cs);
++ table->field[7]->set_notnull();
++ }
++ table->field[6]->store(STRING_WITH_LEN("SQL"), cs);
++ table->field[10]->store(STRING_WITH_LEN("SQL"), cs);
++ get_field(thd->mem_root, proc_table->field[6], &tmp_string);
++ table->field[11]->store(tmp_string.ptr(), tmp_string.length(), cs);
++ table->field[12]->store(sp_data_access_name[enum_idx].str,
++ sp_data_access_name[enum_idx].length , cs);
++ get_field(thd->mem_root, proc_table->field[7], &tmp_string);
++ table->field[14]->store(tmp_string.ptr(), tmp_string.length(), cs);
++ bzero((char *)&time, sizeof(time));
++ ((Field_timestamp *) proc_table->field[12])->get_time(&time);
++ table->field[15]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
++ bzero((char *)&time, sizeof(time));
++ ((Field_timestamp *) proc_table->field[13])->get_time(&time);
++ table->field[16]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
++ get_field(thd->mem_root, proc_table->field[14], &tmp_string);
++ table->field[17]->store(tmp_string.ptr(), tmp_string.length(), cs);
++ get_field(thd->mem_root, proc_table->field[15], &tmp_string);
++ table->field[18]->store(tmp_string.ptr(), tmp_string.length(), cs);
++ table->field[19]->store(definer.ptr(), definer.length(), cs);
++ return schema_table_store_record(thd, table);
++ }
++ }
++ return 0;
++}
++
++
++int fill_schema_proc(THD *thd, TABLE_LIST *tables, COND *cond)
++{
++ TABLE *proc_table;
++ TABLE_LIST proc_tables;
++ const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
++ int res= 0;
++ TABLE *table= tables->table;
++ bool full_access;
++ char definer[USER_HOST_BUFF_SIZE];
++ Open_tables_state open_tables_state_backup;
++ DBUG_ENTER("fill_schema_proc");
++
++ strxmov(definer, thd->security_ctx->priv_user, "@",
++ thd->security_ctx->priv_host, NullS);
++ /* We use this TABLE_LIST instance only for checking of privileges. */
++ 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_proc_table_for_read(thd, &open_tables_state_backup)))
++ {
++ DBUG_RETURN(1);
++ }
++ proc_table->file->ha_index_init(0);
++ if ((res= proc_table->file->index_first(proc_table->record[0])))
++ {
++ res= (res == HA_ERR_END_OF_FILE) ? 0 : 1;
++ goto err;
++ }
++ if (store_schema_proc(thd, table, proc_table, wild, full_access, definer))
++ {
++ res= 1;
++ goto err;
++ }
++ while (!proc_table->file->index_next(proc_table->record[0]))
++ {
++ if (store_schema_proc(thd, table, proc_table, wild, full_access, definer))
++ {
++ res= 1;
++ goto err;
++ }
++ }
++
++err:
++ proc_table->file->ha_index_end();
++ close_proc_table(thd, &open_tables_state_backup);
++ DBUG_RETURN(res);
++}
++
++
++static int get_schema_stat_record(THD *thd, struct st_table_list *tables,
++ TABLE *table, bool res,
++ const char *base_name,
++ const char *file_name)
++{
++ CHARSET_INFO *cs= system_charset_info;
++ DBUG_ENTER("get_schema_stat_record");
++ if (res)
++ {
++ if (thd->lex->orig_sql_command != SQLCOM_SHOW_KEYS)
++ {
++ /*
++ I.e. we are in SELECT FROM INFORMATION_SCHEMA.STATISTICS
++ rather than in SHOW KEYS
++ */
++ if (!tables->view)
++ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
++ thd->net.last_errno, thd->net.last_error);
++ thd->clear_error();
++ res= 0;
++ }
++ DBUG_RETURN(res);
++ }
++ else if (!tables->view)
++ {
++ TABLE *show_table= tables->table;
++ KEY *key_info=show_table->key_info;
++ show_table->file->info(HA_STATUS_VARIABLE |
++ HA_STATUS_NO_LOCK |
++ HA_STATUS_TIME);
++ for (uint i=0 ; i < show_table->s->keys ; i++,key_info++)
++ {
++ KEY_PART_INFO *key_part= key_info->key_part;
++ const char *str;
++ for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
++ {
++ restore_record(table, s->default_values);
++ table->field[1]->store(base_name, strlen(base_name), cs);
++ table->field[2]->store(file_name, strlen(file_name), cs);
++ table->field[3]->store((longlong) ((key_info->flags &
++ HA_NOSAME) ? 0 : 1), TRUE);
++ table->field[4]->store(base_name, strlen(base_name), cs);
++ table->field[5]->store(key_info->name, strlen(key_info->name), cs);
++ table->field[6]->store((longlong) (j+1), TRUE);
++ str=(key_part->field ? key_part->field->field_name :
++ "?unknown field?");
++ table->field[7]->store(str, strlen(str), cs);
++ if (show_table->file->index_flags(i, j, 0) & HA_READ_ORDER)
++ {
++ table->field[8]->store(((key_part->key_part_flag &
++ HA_REVERSE_SORT) ?
++ "D" : "A"), 1, cs);
++ table->field[8]->set_notnull();
++ }
++ KEY *key=show_table->key_info+i;
++ if (key->rec_per_key[j])
++ {
++ ha_rows records=(show_table->file->records /
++ key->rec_per_key[j]);
++ table->field[9]->store((longlong) records, TRUE);
++ table->field[9]->set_notnull();
++ }
++ if (!(key_info->flags & HA_FULLTEXT) &&
++ (key_part->field &&
++ key_part->length !=
++ show_table->field[key_part->fieldnr-1]->key_length()))
++ {
++ table->field[10]->store((longlong) key_part->length /
++ key_part->field->charset()->mbmaxlen, 1);
++ table->field[10]->set_notnull();
++ }
++ uint flags= key_part->field ? key_part->field->flags : 0;
++ const char *pos=(char*) ((flags & NOT_NULL_FLAG) ? "" : "YES");
++ table->field[12]->store(pos, strlen(pos), cs);
++ pos= show_table->file->index_type(i);
++ table->field[13]->store(pos, strlen(pos), cs);
++ if (!show_table->s->keys_in_use.is_set(i))
++ table->field[14]->store(STRING_WITH_LEN("disabled"), cs);
++ else
++ table->field[14]->store("", 0, cs);
++ table->field[14]->set_notnull();
++ if (schema_table_store_record(thd, table))
++ DBUG_RETURN(1);
++ }
++ }
++ }
++ DBUG_RETURN(res);
++}
++
++
++static int get_schema_views_record(THD *thd, struct st_table_list *tables,
++ TABLE *table, bool res,
++ const char *base_name,
++ const char *file_name)
++{
++ CHARSET_INFO *cs= system_charset_info;
++ DBUG_ENTER("get_schema_views_record");
++ char definer[USER_HOST_BUFF_SIZE];
++ uint definer_len;
++
++ if (tables->view)
++ {
++ Security_context *sctx= thd->security_ctx;
++ if (!tables->allowed_show)
++ {
++ if (!my_strcasecmp(system_charset_info, tables->definer.user.str,
++ sctx->priv_user) &&
++ !my_strcasecmp(system_charset_info, tables->definer.host.str,
++ sctx->priv_host))
++ tables->allowed_show= TRUE;
++ }
++ restore_record(table, s->default_values);
++ table->field[1]->store(tables->view_db.str, tables->view_db.length, cs);
++ table->field[2]->store(tables->view_name.str, tables->view_name.length, cs);
++ if (tables->allowed_show)
++ {
++ char buff[2048];
++ String qwe_str(buff, sizeof(buff), cs);
++ qwe_str.length(0);
++ qwe_str.append(STRING_WITH_LEN("/* "));
++ append_algorithm(tables, &qwe_str);
++ qwe_str.append(STRING_WITH_LEN("*/ "));
++ qwe_str.append(tables->query.str, tables->query.length);
++ table->field[3]->store(qwe_str.ptr(), qwe_str.length(), cs);
++ }
++
++ if (tables->with_check != VIEW_CHECK_NONE)
++ {
++ if (tables->with_check == VIEW_CHECK_LOCAL)
++ table->field[4]->store(STRING_WITH_LEN("LOCAL"), cs);
++ else
++ table->field[4]->store(STRING_WITH_LEN("CASCADED"), cs);
++ }
++ else
++ table->field[4]->store(STRING_WITH_LEN("NONE"), cs);
++
++ if (tables->updatable_view)
++ table->field[5]->store(STRING_WITH_LEN("YES"), cs);
++ else
++ table->field[5]->store(STRING_WITH_LEN("NO"), cs);
++ definer_len= (strxmov(definer, tables->definer.user.str, "@",
++ tables->definer.host.str, NullS) - definer);
++ table->field[6]->store(definer, definer_len, cs);
++ if (tables->view_suid)
++ table->field[7]->store(STRING_WITH_LEN("DEFINER"), cs);
++ else
++ table->field[7]->store(STRING_WITH_LEN("INVOKER"), cs);
++ if (schema_table_store_record(thd, table))
++ DBUG_RETURN(1);
++ if (res)
++ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
++ thd->net.last_errno, thd->net.last_error);
++ }
++ if (res)
++ thd->clear_error();
++ DBUG_RETURN(0);
++}
++
++
++bool store_constraints(THD *thd, TABLE *table, const char *db,
++ const char *tname, const char *key_name,
++ uint key_len, const char *con_type, uint con_len)
++{
++ CHARSET_INFO *cs= system_charset_info;
++ restore_record(table, s->default_values);
++ table->field[1]->store(db, strlen(db), cs);
++ table->field[2]->store(key_name, key_len, cs);
++ table->field[3]->store(db, strlen(db), cs);
++ table->field[4]->store(tname, strlen(tname), cs);
++ table->field[5]->store(con_type, con_len, cs);
++ return schema_table_store_record(thd, table);
++}
++
++
++static int get_schema_constraints_record(THD *thd, struct st_table_list *tables,
++ TABLE *table, bool res,
++ const char *base_name,
++ const char *file_name)
++{
++ DBUG_ENTER("get_schema_constraints_record");
++ if (res)
++ {
++ if (!tables->view)
++ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
++ thd->net.last_errno, thd->net.last_error);
++ thd->clear_error();
++ DBUG_RETURN(0);
++ }
++ else if (!tables->view)
++ {
++ List<FOREIGN_KEY_INFO> f_key_list;
++ TABLE *show_table= tables->table;
++ KEY *key_info=show_table->key_info;
++ uint primary_key= show_table->s->primary_key;
++ show_table->file->info(HA_STATUS_VARIABLE |
++ HA_STATUS_NO_LOCK |
++ HA_STATUS_TIME);
++ for (uint i=0 ; i < show_table->s->keys ; i++, key_info++)
++ {
++ if (i != primary_key && !(key_info->flags & HA_NOSAME))
++ continue;
++
++ if (i == primary_key && !strcmp(key_info->name, primary_key_name))
++ {
++ if (store_constraints(thd, table, base_name, file_name, key_info->name,
++ strlen(key_info->name),
++ STRING_WITH_LEN("PRIMARY KEY")))
++ DBUG_RETURN(1);
++ }
++ else if (key_info->flags & HA_NOSAME)
++ {
++ if (store_constraints(thd, table, base_name, file_name, key_info->name,
++ strlen(key_info->name),
++ STRING_WITH_LEN("UNIQUE")))
++ DBUG_RETURN(1);
++ }
++ }
++
++ show_table->file->get_foreign_key_list(thd, &f_key_list);
++ FOREIGN_KEY_INFO *f_key_info;
++ List_iterator_fast<FOREIGN_KEY_INFO> it(f_key_list);
++ while ((f_key_info=it++))
++ {
++ if (store_constraints(thd, table, base_name, file_name,
++ f_key_info->forein_id->str,
++ strlen(f_key_info->forein_id->str),
++ "FOREIGN KEY", 11))
++ DBUG_RETURN(1);
++ }
++ }
++ DBUG_RETURN(res);
++}
++
++
++static bool store_trigger(THD *thd, TABLE *table, const char *db,
++ const char *tname, LEX_STRING *trigger_name,
++ enum trg_event_type event,
++ enum trg_action_time_type timing,
++ LEX_STRING *trigger_stmt,
++ ulong sql_mode,
++ LEX_STRING *definer_buffer)
++{
++ CHARSET_INFO *cs= system_charset_info;
++ byte *sql_mode_str;
++ ulong sql_mode_len;
++
++ restore_record(table, s->default_values);
++ table->field[1]->store(db, strlen(db), cs);
++ table->field[2]->store(trigger_name->str, trigger_name->length, cs);
++ table->field[3]->store(trg_event_type_names[event].str,
++ trg_event_type_names[event].length, cs);
++ table->field[5]->store(db, strlen(db), cs);
++ table->field[6]->store(tname, strlen(tname), cs);
++ table->field[9]->store(trigger_stmt->str, trigger_stmt->length, cs);
++ table->field[10]->store(STRING_WITH_LEN("ROW"), cs);
++ table->field[11]->store(trg_action_time_type_names[timing].str,
++ trg_action_time_type_names[timing].length, cs);
++ table->field[14]->store(STRING_WITH_LEN("OLD"), cs);
++ table->field[15]->store(STRING_WITH_LEN("NEW"), cs);
++
++ sql_mode_str=
++ sys_var_thd_sql_mode::symbolic_mode_representation(thd,
++ sql_mode,
++ &sql_mode_len);
++ table->field[17]->store((const char*)sql_mode_str, sql_mode_len, cs);
++ table->field[18]->store((const char *)definer_buffer->str, definer_buffer->length, cs);
++ return schema_table_store_record(thd, table);
++}
++
++
++static int get_schema_triggers_record(THD *thd, struct st_table_list *tables,
++ TABLE *table, bool res,
++ const char *base_name,
++ const char *file_name)
++{
++ DBUG_ENTER("get_schema_triggers_record");
++ /*
++ res can be non zero value when processed table is a view or
++ error happened during opening of processed table.
++ */
++ if (res)
++ {
++ if (!tables->view)
++ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
++ thd->net.last_errno, thd->net.last_error);
++ thd->clear_error();
++ DBUG_RETURN(0);
++ }
++ if (!tables->view && tables->table->triggers)
++ {
++ Table_triggers_list *triggers= tables->table->triggers;
++ int event, timing;
++ for (event= 0; event < (int)TRG_EVENT_MAX; event++)
++ {
++ for (timing= 0; timing < (int)TRG_ACTION_MAX; timing++)
++ {
++ LEX_STRING trigger_name;
++ LEX_STRING trigger_stmt;
++ ulong sql_mode;
++ char definer_holder[USER_HOST_BUFF_SIZE];
++ LEX_STRING definer_buffer;
++ definer_buffer.str= definer_holder;
++ if (triggers->get_trigger_info(thd, (enum trg_event_type) event,
++ (enum trg_action_time_type)timing,
++ &trigger_name, &trigger_stmt,
++ &sql_mode,
++ &definer_buffer))
++ continue;
++
++ if (store_trigger(thd, table, base_name, file_name, &trigger_name,
++ (enum trg_event_type) event,
++ (enum trg_action_time_type) timing, &trigger_stmt,
++ sql_mode,
++ &definer_buffer))
++ DBUG_RETURN(1);
++ }
++ }
++ }
++ DBUG_RETURN(0);
++}
++
++
++void store_key_column_usage(TABLE *table, const char*db, const char *tname,
++ const char *key_name, uint key_len,
++ const char *con_type, uint con_len, longlong idx)
++{
++ CHARSET_INFO *cs= system_charset_info;
++ table->field[1]->store(db, strlen(db), cs);
++ table->field[2]->store(key_name, key_len, cs);
++ table->field[4]->store(db, strlen(db), cs);
++ table->field[5]->store(tname, strlen(tname), cs);
++ table->field[6]->store(con_type, con_len, cs);
++ table->field[7]->store((longlong) idx, TRUE);
++}
++
++
++static int get_schema_key_column_usage_record(THD *thd,
++ struct st_table_list *tables,
++ TABLE *table, bool res,
++ const char *base_name,
++ const char *file_name)
++{
++ DBUG_ENTER("get_schema_key_column_usage_record");
++ if (res)
++ {
++ if (!tables->view)
++ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
++ thd->net.last_errno, thd->net.last_error);
++ thd->clear_error();
++ DBUG_RETURN(0);
++ }
++ else if (!tables->view)
++ {
++ List<FOREIGN_KEY_INFO> f_key_list;
++ TABLE *show_table= tables->table;
++ KEY *key_info=show_table->key_info;
++ uint primary_key= show_table->s->primary_key;
++ show_table->file->info(HA_STATUS_VARIABLE |
++ HA_STATUS_NO_LOCK |
++ HA_STATUS_TIME);
++ for (uint i=0 ; i < show_table->s->keys ; i++, key_info++)
++ {
++ if (i != primary_key && !(key_info->flags & HA_NOSAME))
++ continue;
++ uint f_idx= 0;
++ KEY_PART_INFO *key_part= key_info->key_part;
++ for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
++ {
++ if (key_part->field)
++ {
++ f_idx++;
++ restore_record(table, s->default_values);
++ store_key_column_usage(table, base_name, file_name,
++ key_info->name,
++ strlen(key_info->name),
++ key_part->field->field_name,
++ strlen(key_part->field->field_name),
++ (longlong) f_idx);
++ if (schema_table_store_record(thd, table))
++ DBUG_RETURN(1);
++ }
++ }
++ }
++
++ show_table->file->get_foreign_key_list(thd, &f_key_list);
++ FOREIGN_KEY_INFO *f_key_info;
++ List_iterator_fast<FOREIGN_KEY_INFO> it(f_key_list);
++ while ((f_key_info= it++))
++ {
++ LEX_STRING *f_info;
++ LEX_STRING *r_info;
++ List_iterator_fast<LEX_STRING> it(f_key_info->foreign_fields),
++ it1(f_key_info->referenced_fields);
++ uint f_idx= 0;
++ while ((f_info= it++))
++ {
++ r_info= it1++;
++ f_idx++;
++ restore_record(table, s->default_values);
++ store_key_column_usage(table, base_name, file_name,
++ f_key_info->forein_id->str,
++ f_key_info->forein_id->length,
++ f_info->str, f_info->length,
++ (longlong) f_idx);
++ table->field[8]->store((longlong) f_idx, TRUE);
++ table->field[8]->set_notnull();
++ table->field[9]->store(f_key_info->referenced_db->str,
++ f_key_info->referenced_db->length,
++ system_charset_info);
++ table->field[9]->set_notnull();
++ table->field[10]->store(f_key_info->referenced_table->str,
++ f_key_info->referenced_table->length,
++ system_charset_info);
++ table->field[10]->set_notnull();
++ table->field[11]->store(r_info->str, r_info->length,
++ system_charset_info);
++ table->field[11]->set_notnull();
++ if (schema_table_store_record(thd, table))
++ DBUG_RETURN(1);
++ }
++ }
++ }
++ DBUG_RETURN(res);
++}
++
++
++int fill_open_tables(THD *thd, TABLE_LIST *tables, COND *cond)
++{
++ DBUG_ENTER("fill_open_tables");
++ const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
++ TABLE *table= tables->table;
++ CHARSET_INFO *cs= system_charset_info;
++ OPEN_TABLE_LIST *open_list;
++ if (!(open_list=list_open_tables(thd,thd->lex->select_lex.db, wild))
++ && thd->is_fatal_error)
++ DBUG_RETURN(1);
++
++ for (; open_list ; open_list=open_list->next)
++ {
++ restore_record(table, s->default_values);
++ table->field[0]->store(open_list->db, strlen(open_list->db), cs);
++ table->field[1]->store(open_list->table, strlen(open_list->table), cs);
++ table->field[2]->store((longlong) open_list->in_use, TRUE);
++ table->field[3]->store((longlong) open_list->locked, TRUE);
++ if (schema_table_store_record(thd, table))
++ DBUG_RETURN(1);
++ }
++ DBUG_RETURN(0);
++}
++
++
++int fill_variables(THD *thd, TABLE_LIST *tables, COND *cond)
++{
++ DBUG_ENTER("fill_variables");
++ int res= 0;
++ LEX *lex= thd->lex;
++ const char *wild= lex->wild ? lex->wild->ptr() : NullS;
++ pthread_mutex_lock(&LOCK_global_system_variables);
++ res= show_status_array(thd, wild, init_vars,
++ lex->option_type, 0, "", tables->table);
++ pthread_mutex_unlock(&LOCK_global_system_variables);
++ DBUG_RETURN(res);
++}
++
++
++int fill_status(THD *thd, TABLE_LIST *tables, COND *cond)
++{
++ DBUG_ENTER("fill_status");
++ LEX *lex= thd->lex;
++ const char *wild= lex->wild ? lex->wild->ptr() : NullS;
++ int res= 0;
++ STATUS_VAR tmp;
++ ha_update_statistics(); /* Export engines statistics */
++ pthread_mutex_lock(&LOCK_status);
++ if (lex->option_type == OPT_GLOBAL)
++ calc_sum_of_all_status(&tmp);
++ res= show_status_array(thd, wild, status_vars, OPT_GLOBAL,
++ (lex->option_type == OPT_GLOBAL ?
++ &tmp: &thd->status_var), "",tables->table);
++ pthread_mutex_unlock(&LOCK_status);
++ DBUG_RETURN(res);
++}
++
++
++/*
++ Find schema_tables elment by name
++
++ SYNOPSIS
++ find_schema_table()
++ thd thread handler
++ table_name table name
++
++ RETURN
++ 0 table not found
++ # pointer to 'shema_tables' element
++*/
++
++ST_SCHEMA_TABLE *find_schema_table(THD *thd, const char* table_name)
++{
++ ST_SCHEMA_TABLE *schema_table= schema_tables;
++ for (; schema_table->table_name; schema_table++)
++ {
++ if (!my_strcasecmp(system_charset_info,
++ schema_table->table_name,
++ table_name))
++ return schema_table;
++ }
++ return 0;
++}
++
++
++ST_SCHEMA_TABLE *get_schema_table(enum enum_schema_tables schema_table_idx)
++{
++ return &schema_tables[schema_table_idx];
++}
++
++
++/*
++ Create information_schema table using schema_table data
++
++ SYNOPSIS
++ create_schema_table()
++ thd thread handler
++ schema_table pointer to 'shema_tables' element
++
++ RETURN
++ # Pointer to created table
++ 0 Can't create table
++*/
++
++TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list)
++{
++ int field_count= 0;
++ Item *item;
++ TABLE *table;
++ List<Item> field_list;
++ ST_SCHEMA_TABLE *schema_table= table_list->schema_table;
++ ST_FIELD_INFO *fields_info= schema_table->fields_info;
++ CHARSET_INFO *cs= system_charset_info;
++ DBUG_ENTER("create_schema_table");
++
++ for (; fields_info->field_name; fields_info++)
++ {
++ switch (fields_info->field_type) {
++ case MYSQL_TYPE_LONG:
++ if (!(item= new Item_int(fields_info->field_name,
++ fields_info->value,
++ fields_info->field_length)))
++ {
++ DBUG_RETURN(0);
++ }
++ break;
++ case MYSQL_TYPE_TIMESTAMP:
++ if (!(item=new Item_datetime(fields_info->field_name)))
++ {
++ DBUG_RETURN(0);
++ }
++ break;
++ default:
++ /* this should be changed when Item_empty_string is fixed(in 4.1) */
++ if (!(item= new Item_empty_string("", 0, cs)))
++ {
++ DBUG_RETURN(0);
++ }
++ item->max_length= fields_info->field_length * cs->mbmaxlen;
++ item->set_name(fields_info->field_name,
++ strlen(fields_info->field_name), cs);
++ break;
++ }
++ field_list.push_back(item);
++ item->maybe_null= fields_info->maybe_null;
++ field_count++;
++ }
++ TMP_TABLE_PARAM *tmp_table_param =
++ (TMP_TABLE_PARAM*) (thd->calloc(sizeof(TMP_TABLE_PARAM)));
++ tmp_table_param->init();
++ tmp_table_param->table_charset= cs;
++ tmp_table_param->field_count= field_count;
++ tmp_table_param->schema_table= 1;
++ SELECT_LEX *select_lex= thd->lex->current_select;
++ if (!(table= create_tmp_table(thd, tmp_table_param,
++ field_list, (ORDER*) 0, 0, 0,
++ (select_lex->options | thd->options |
++ TMP_TABLE_ALL_COLUMNS),
++ HA_POS_ERROR, table_list->alias)))
++ DBUG_RETURN(0);
++ table_list->schema_table_param= tmp_table_param;
++ DBUG_RETURN(table);
++}
++
++
++/*
++ For old SHOW compatibility. It is used when
++ old SHOW doesn't have generated column names
++ Make list of fields for SHOW
++
++ SYNOPSIS
++ make_old_format()
++ thd thread handler
++ schema_table pointer to 'schema_tables' element
++
++ RETURN
++ -1 errror
++ 0 success
++*/
++
++int make_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
++{
++ ST_FIELD_INFO *field_info= schema_table->fields_info;
++ Name_resolution_context *context= &thd->lex->select_lex.context;
++ for (; field_info->field_name; field_info++)
++ {
++ if (field_info->old_name)
++ {
++ Item_field *field= new Item_field(context,
++ NullS, NullS, field_info->field_name);
++ if (field)
++ {
++ field->set_name(field_info->old_name,
++ strlen(field_info->old_name),
++ system_charset_info);
++ if (add_item_to_list(thd, field))
++ return 1;
++ }
++ }
++ }
++ return 0;
++}
++
++
++int make_schemata_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
++{
++ char tmp[128];
++ LEX *lex= thd->lex;
++ SELECT_LEX *sel= lex->current_select;
++ Name_resolution_context *context= &sel->context;
++
++ if (!sel->item_list.elements)
++ {
++ ST_FIELD_INFO *field_info= &schema_table->fields_info[1];
++ String buffer(tmp,sizeof(tmp), system_charset_info);
++ Item_field *field= new Item_field(context,
++ NullS, NullS, field_info->field_name);
++ if (!field || add_item_to_list(thd, field))
++ return 1;
++ buffer.length(0);
++ buffer.append(field_info->old_name);
++ if (lex->wild && lex->wild->ptr())
++ {
++ buffer.append(STRING_WITH_LEN(" ("));
++ buffer.append(lex->wild->ptr());
++ buffer.append(')');
++ }
++ field->set_name(buffer.ptr(), buffer.length(), system_charset_info);
++ }
++ return 0;
++}
++
++
++int make_table_names_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
++{
++ char tmp[128];
++ String buffer(tmp,sizeof(tmp), thd->charset());
++ LEX *lex= thd->lex;
++ Name_resolution_context *context= &lex->select_lex.context;
++
++ ST_FIELD_INFO *field_info= &schema_table->fields_info[2];
++ buffer.length(0);
++ buffer.append(field_info->old_name);
++ buffer.append(lex->select_lex.db);
++ if (lex->wild && lex->wild->ptr())
++ {
++ buffer.append(STRING_WITH_LEN(" ("));
++ buffer.append(lex->wild->ptr());
++ buffer.append(')');
++ }
++ Item_field *field= new Item_field(context,
++ NullS, NullS, field_info->field_name);
++ if (add_item_to_list(thd, field))
++ return 1;
++ field->set_name(buffer.ptr(), buffer.length(), system_charset_info);
++ if (thd->lex->verbose)
++ {
++ field->set_name(buffer.ptr(), buffer.length(), system_charset_info);
++ field_info= &schema_table->fields_info[3];
++ field= new Item_field(context, NullS, NullS, field_info->field_name);
++ if (add_item_to_list(thd, field))
++ return 1;
++ field->set_name(field_info->old_name, strlen(field_info->old_name),
++ system_charset_info);
++ }
++ return 0;
++}
++
++
++int make_columns_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
++{
++ int fields_arr[]= {3, 14, 13, 6, 15, 5, 16, 17, 18, -1};
++ int *field_num= fields_arr;
++ ST_FIELD_INFO *field_info;
++ Name_resolution_context *context= &thd->lex->select_lex.context;
++
++ for (; *field_num >= 0; field_num++)
++ {
++ field_info= &schema_table->fields_info[*field_num];
++ if (!thd->lex->verbose && (*field_num == 13 ||
++ *field_num == 17 ||
++ *field_num == 18))
++ continue;
++ Item_field *field= new Item_field(context,
++ NullS, NullS, field_info->field_name);
++ if (field)
++ {
++ field->set_name(field_info->old_name,
++ strlen(field_info->old_name),
++ system_charset_info);
++ if (add_item_to_list(thd, field))
++ return 1;
++ }
++ }
++ return 0;
++}
++
++
++int make_character_sets_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
++{
++ int fields_arr[]= {0, 2, 1, 3, -1};
++ int *field_num= fields_arr;
++ ST_FIELD_INFO *field_info;
++ Name_resolution_context *context= &thd->lex->select_lex.context;
++
++ for (; *field_num >= 0; field_num++)
++ {
++ field_info= &schema_table->fields_info[*field_num];
++ Item_field *field= new Item_field(context,
++ NullS, NullS, field_info->field_name);
++ if (field)
++ {
++ field->set_name(field_info->old_name,
++ strlen(field_info->old_name),
++ system_charset_info);
++ if (add_item_to_list(thd, field))
++ return 1;
++ }
++ }
++ return 0;
++}
++
++
++int make_proc_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
++{
++ int fields_arr[]= {2, 3, 4, 19, 16, 15, 14, 18, -1};
++ int *field_num= fields_arr;
++ ST_FIELD_INFO *field_info;
++ Name_resolution_context *context= &thd->lex->select_lex.context;
++
++ for (; *field_num >= 0; field_num++)
++ {
++ field_info= &schema_table->fields_info[*field_num];
++ Item_field *field= new Item_field(context,
++ NullS, NullS, field_info->field_name);
++ if (field)
++ {
++ field->set_name(field_info->old_name,
++ strlen(field_info->old_name),
++ system_charset_info);
++ if (add_item_to_list(thd, field))
++ return 1;
++ }
++ }
++ return 0;
++}
++
++
++/*
++ Create information_schema table
++
++ SYNOPSIS
++ mysql_schema_table()
++ thd thread handler
++ lex pointer to LEX
++ table_list pointer to table_list
++
++ RETURN
++ 0 success
++ 1 error
++*/
++
++int mysql_schema_table(THD *thd, LEX *lex, TABLE_LIST *table_list)
++{
++ TABLE *table;
++ DBUG_ENTER("mysql_schema_table");
++ if (!(table= table_list->schema_table->create_table(thd, table_list)))
++ {
++ DBUG_RETURN(1);
++ }
++ table->s->tmp_table= SYSTEM_TMP_TABLE;
++ table->grant.privilege= SELECT_ACL;
++ /*
++ This test is necessary to make
++ case insensitive file systems +
++ upper case table names(information schema tables) +
++ views
++ working correctly
++ */
++ if (table_list->schema_table_name)
++ table->alias_name_used= my_strcasecmp(table_alias_charset,
++ table_list->schema_table_name,
++ table_list->alias);
++ table_list->table_name= (char*) table->s->table_name;
++ table_list->table_name_length= strlen(table->s->table_name);
++ table_list->table= table;
++ table->next= thd->derived_tables;
++ thd->derived_tables= table;
++ table_list->select_lex->options |= OPTION_SCHEMA_TABLE;
++ lex->safe_to_cache_query= 0;
++
++ if (table_list->schema_table_reformed) // show command
++ {
++ SELECT_LEX *sel= lex->current_select;
++ Item *item;
++ Field_translator *transl, *org_transl;
++
++ if (table_list->field_translation)
++ {
++ Field_translator *end= table_list->field_translation_end;
++ for (transl= table_list->field_translation; transl < end; transl++)
++ {
++ if (!transl->item->fixed &&
++ transl->item->fix_fields(thd, &transl->item))
++ DBUG_RETURN(1);
++ }
++ DBUG_RETURN(0);
++ }
++ List_iterator_fast<Item> it(sel->item_list);
++ if (!(transl=
++ (Field_translator*)(thd->stmt_arena->
++ alloc(sel->item_list.elements *
++ sizeof(Field_translator)))))
++ {
++ DBUG_RETURN(1);
++ }
++ for (org_transl= transl; (item= it++); transl++)
++ {
++ transl->item= item;
++ transl->name= item->name;
++ if (!item->fixed && item->fix_fields(thd, &transl->item))
++ {
++ DBUG_RETURN(1);
++ }
++ }
++ table_list->field_translation= org_transl;
++ table_list->field_translation_end= transl;
++ }
++
++ DBUG_RETURN(0);
++}
++
++
++/*
++ Generate select from information_schema table
++
++ SYNOPSIS
++ make_schema_select()
++ thd thread handler
++ sel pointer to SELECT_LEX
++ schema_table_idx index of 'schema_tables' element
++
++ RETURN
++ 0 success
++ 1 error
++*/
++
++int make_schema_select(THD *thd, SELECT_LEX *sel,
++ enum enum_schema_tables schema_table_idx)
++{
++ ST_SCHEMA_TABLE *schema_table= get_schema_table(schema_table_idx);
++ LEX_STRING db, table;
++ DBUG_ENTER("mysql_schema_select");
++ /*
++ We have to make non const db_name & table_name
++ because of lower_case_table_names
++ */
++ make_lex_string(thd, &db, information_schema_name.str,
++ information_schema_name.length, 0);
++ make_lex_string(thd, &table, schema_table->table_name,
++ strlen(schema_table->table_name), 0);
++ if (schema_table->old_format(thd, schema_table) || /* Handle old syntax */
++ !sel->add_table_to_list(thd, new Table_ident(thd, db, table, 0),
++ 0, 0, TL_READ, (List<String> *) 0,
++ (List<String> *) 0))
++ {
++ DBUG_RETURN(1);
++ }
++ DBUG_RETURN(0);
++}
++
++
++/*
++ Fill temporary schema tables before SELECT
++
++ SYNOPSIS
++ get_schema_tables_result()
++ join join which use schema tables
++ executed_place place where I_S table processed
++
++ RETURN
++ FALSE success
++ TRUE error
++*/
++
++bool get_schema_tables_result(JOIN *join,
++ enum enum_schema_table_state executed_place)
++{
++ JOIN_TAB *tmp_join_tab= join->join_tab+join->tables;
++ THD *thd= join->thd;
++ LEX *lex= thd->lex;
++ bool result= 0;
++ DBUG_ENTER("get_schema_tables_result");
++
++ thd->no_warnings_for_error= 1;
++ for (JOIN_TAB *tab= join->join_tab; tab < tmp_join_tab; tab++)
++ {
++ if (!tab->table || !tab->table->pos_in_table_list)
++ break;
++
++ TABLE_LIST *table_list= tab->table->pos_in_table_list;
++ if (table_list->schema_table && thd->fill_derived_tables())
++ {
++ bool is_subselect= (&lex->unit != lex->current_select->master_unit() &&
++ lex->current_select->master_unit()->item);
++ /*
++ If schema table is already processed and
++ the statement is not a subselect then
++ we don't need to fill this table again.
++ If schema table is already processed and
++ schema_table_state != executed_place then
++ table is already processed and
++ we should skip second data processing.
++ */
++ if (table_list->schema_table_state &&
++ (!is_subselect || table_list->schema_table_state != executed_place))
++ continue;
++
++ /*
++ if table is used in a subselect and
++ table has been processed earlier with the same
++ 'executed_place' value then we should refresh the table.
++ */
++ if (table_list->schema_table_state && is_subselect)
++ {
++ table_list->table->file->extra(HA_EXTRA_RESET_STATE);
++ table_list->table->file->delete_all_rows();
++ free_io_cache(table_list->table);
++ filesort_free_buffers(table_list->table,1);
++ table_list->table->null_row= 0;
++ }
++ else
++ table_list->table->file->records= 0;
++
++ if (table_list->schema_table->fill_table(thd, table_list,
++ tab->select_cond))
++ {
++ result= 1;
++ join->error= 1;
++ table_list->schema_table_state= executed_place;
++ break;
++ }
++ table_list->schema_table_state= executed_place;
++ }
++ }
++ thd->no_warnings_for_error= 0;
++ DBUG_RETURN(result);
++}
++
++
++ST_FIELD_INFO schema_fields_info[]=
++{
++ {"CATALOG_NAME", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
++ {"SCHEMA_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Database"},
++ {"DEFAULT_CHARACTER_SET_NAME", 64, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"DEFAULT_COLLATION_NAME", 64, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"SQL_PATH", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
++ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
++};
++
++
++ST_FIELD_INFO tables_fields_info[]=
++{
++ {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
++ {"TABLE_SCHEMA",NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Name"},
++ {"TABLE_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"ENGINE", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, "Engine"},
++ {"VERSION", 21 , MYSQL_TYPE_LONG, 0, 1, "Version"},
++ {"ROW_FORMAT", 10, MYSQL_TYPE_STRING, 0, 1, "Row_format"},
++ {"TABLE_ROWS", 21 , MYSQL_TYPE_LONG, 0, 1, "Rows"},
++ {"AVG_ROW_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, "Avg_row_length"},
++ {"DATA_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, "Data_length"},
++ {"MAX_DATA_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, "Max_data_length"},
++ {"INDEX_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, "Index_length"},
++ {"DATA_FREE", 21 , MYSQL_TYPE_LONG, 0, 1, "Data_free"},
++ {"AUTO_INCREMENT", 21 , MYSQL_TYPE_LONG, 0, 1, "Auto_increment"},
++ {"CREATE_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Create_time"},
++ {"UPDATE_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Update_time"},
++ {"CHECK_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Check_time"},
++ {"TABLE_COLLATION", 64, MYSQL_TYPE_STRING, 0, 1, "Collation"},
++ {"CHECKSUM", 21 , MYSQL_TYPE_LONG, 0, 1, "Checksum"},
++ {"CREATE_OPTIONS", 255, MYSQL_TYPE_STRING, 0, 1, "Create_options"},
++ {"TABLE_COMMENT", 80, MYSQL_TYPE_STRING, 0, 0, "Comment"},
++ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
++};
++
++
++ST_FIELD_INFO columns_fields_info[]=
++{
++ {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
++ {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"COLUMN_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Field"},
++ {"ORDINAL_POSITION", 21 , MYSQL_TYPE_LONG, 0, 0, 0},
++ {"COLUMN_DEFAULT", MAX_FIELD_VARCHARLENGTH, MYSQL_TYPE_STRING, 0, 1, "Default"},
++ {"IS_NULLABLE", 3, MYSQL_TYPE_STRING, 0, 0, "Null"},
++ {"DATA_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"CHARACTER_MAXIMUM_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0},
++ {"CHARACTER_OCTET_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0},
++ {"NUMERIC_PRECISION", 21 , MYSQL_TYPE_LONG, 0, 1, 0},
++ {"NUMERIC_SCALE", 21 , MYSQL_TYPE_LONG, 0, 1, 0},
++ {"CHARACTER_SET_NAME", 64, MYSQL_TYPE_STRING, 0, 1, 0},
++ {"COLLATION_NAME", 64, MYSQL_TYPE_STRING, 0, 1, "Collation"},
++ {"COLUMN_TYPE", 65535, MYSQL_TYPE_STRING, 0, 0, "Type"},
++ {"COLUMN_KEY", 3, MYSQL_TYPE_STRING, 0, 0, "Key"},
++ {"EXTRA", 20, MYSQL_TYPE_STRING, 0, 0, "Extra"},
++ {"PRIVILEGES", 80, MYSQL_TYPE_STRING, 0, 0, "Privileges"},
++ {"COLUMN_COMMENT", 255, MYSQL_TYPE_STRING, 0, 0, "Comment"},
++ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
++};
++
++
++ST_FIELD_INFO charsets_fields_info[]=
++{
++ {"CHARACTER_SET_NAME", 64, MYSQL_TYPE_STRING, 0, 0, "Charset"},
++ {"DEFAULT_COLLATE_NAME", 64, MYSQL_TYPE_STRING, 0, 0, "Default collation"},
++ {"DESCRIPTION", 60, MYSQL_TYPE_STRING, 0, 0, "Description"},
++ {"MAXLEN", 3 ,MYSQL_TYPE_LONG, 0, 0, "Maxlen"},
++ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
++};
++
++
++ST_FIELD_INFO collation_fields_info[]=
++{
++ {"COLLATION_NAME", 64, MYSQL_TYPE_STRING, 0, 0, "Collation"},
++ {"CHARACTER_SET_NAME", 64, MYSQL_TYPE_STRING, 0, 0, "Charset"},
++ {"ID", 11, MYSQL_TYPE_LONG, 0, 0, "Id"},
++ {"IS_DEFAULT", 3, MYSQL_TYPE_STRING, 0, 0, "Default"},
++ {"IS_COMPILED", 3, MYSQL_TYPE_STRING, 0, 0, "Compiled"},
++ {"SORTLEN", 3 ,MYSQL_TYPE_LONG, 0, 0, "Sortlen"},
++ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
++};
++
++
++ST_FIELD_INFO coll_charset_app_fields_info[]=
++{
++ {"COLLATION_NAME", 64, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"CHARACTER_SET_NAME", 64, MYSQL_TYPE_STRING, 0, 0, 0},
++ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
++};
++
++
++ST_FIELD_INFO proc_fields_info[]=
++{
++ {"SPECIFIC_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"ROUTINE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
++ {"ROUTINE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Db"},
++ {"ROUTINE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Name"},
++ {"ROUTINE_TYPE", 9, MYSQL_TYPE_STRING, 0, 0, "Type"},
++ {"DTD_IDENTIFIER", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
++ {"ROUTINE_BODY", 8, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"ROUTINE_DEFINITION", 65535, MYSQL_TYPE_STRING, 0, 1, 0},
++ {"EXTERNAL_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
++ {"EXTERNAL_LANGUAGE", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
++ {"PARAMETER_STYLE", 8, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"IS_DETERMINISTIC", 3, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"SQL_DATA_ACCESS", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"SQL_PATH", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
++ {"SECURITY_TYPE", 7, MYSQL_TYPE_STRING, 0, 0, "Security_type"},
++ {"CREATED", 0, MYSQL_TYPE_TIMESTAMP, 0, 0, "Created"},
++ {"LAST_ALTERED", 0, MYSQL_TYPE_TIMESTAMP, 0, 0, "Modified"},
++ {"SQL_MODE", 65535, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"ROUTINE_COMMENT", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Comment"},
++ {"DEFINER", 77, MYSQL_TYPE_STRING, 0, 0, "Definer"},
++ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
++};
++
++
++ST_FIELD_INFO stat_fields_info[]=
++{
++ {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
++ {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table"},
++ {"NON_UNIQUE", 1, MYSQL_TYPE_LONG, 0, 0, "Non_unique"},
++ {"INDEX_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"INDEX_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Key_name"},
++ {"SEQ_IN_INDEX", 2, MYSQL_TYPE_LONG, 0, 0, "Seq_in_index"},
++ {"COLUMN_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Column_name"},
++ {"COLLATION", 1, MYSQL_TYPE_STRING, 0, 1, "Collation"},
++ {"CARDINALITY", 21, MYSQL_TYPE_LONG, 0, 1, "Cardinality"},
++ {"SUB_PART", 3, MYSQL_TYPE_LONG, 0, 1, "Sub_part"},
++ {"PACKED", 10, MYSQL_TYPE_STRING, 0, 1, "Packed"},
++ {"NULLABLE", 3, MYSQL_TYPE_STRING, 0, 0, "Null"},
++ {"INDEX_TYPE", 16, MYSQL_TYPE_STRING, 0, 0, "Index_type"},
++ {"COMMENT", 16, MYSQL_TYPE_STRING, 0, 1, "Comment"},
++ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
++};
++
++
++ST_FIELD_INFO view_fields_info[]=
++{
++ {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
++ {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"VIEW_DEFINITION", 65535, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"CHECK_OPTION", 8, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"IS_UPDATABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"DEFINER", 77, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"SECURITY_TYPE", 7, MYSQL_TYPE_STRING, 0, 0, 0},
++ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
++};
++
++
++ST_FIELD_INFO user_privileges_fields_info[]=
++{
++ {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
++ {"PRIVILEGE_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0},
++ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
++};
++
++
++ST_FIELD_INFO schema_privileges_fields_info[]=
++{
++ {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
++ {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"PRIVILEGE_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0},
++ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
++};
++
++
++ST_FIELD_INFO table_privileges_fields_info[]=
++{
++ {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
++ {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"PRIVILEGE_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0},
++ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
++};
++
++
++ST_FIELD_INFO column_privileges_fields_info[]=
++{
++ {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
++ {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"COLUMN_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"PRIVILEGE_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0},
++ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
++};
++
++
++ST_FIELD_INFO table_constraints_fields_info[]=
++{
++ {"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
++ {"CONSTRAINT_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"CONSTRAINT_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"CONSTRAINT_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
++ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
++};
++
++
++ST_FIELD_INFO key_column_usage_fields_info[]=
++{
++ {"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
++ {"CONSTRAINT_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"CONSTRAINT_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
++ {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"COLUMN_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"ORDINAL_POSITION", 10 ,MYSQL_TYPE_LONG, 0, 0, 0},
++ {"POSITION_IN_UNIQUE_CONSTRAINT", 10 ,MYSQL_TYPE_LONG, 0, 1, 0},
++ {"REFERENCED_TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
++ {"REFERENCED_TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
++ {"REFERENCED_COLUMN_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
++ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
++};
++
++
++ST_FIELD_INFO table_names_fields_info[]=
++{
++ {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
++ {"TABLE_SCHEMA",NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Tables_in_"},
++ {"TABLE_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table_type"},
++ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
++};
++
++
++ST_FIELD_INFO open_tables_fields_info[]=
++{
++ {"Database", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Database"},
++ {"Table",NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table"},
++ {"In_use", 1, MYSQL_TYPE_LONG, 0, 0, "In_use"},
++ {"Name_locked", 4, MYSQL_TYPE_LONG, 0, 0, "Name_locked"},
++ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
++};
++
++
++ST_FIELD_INFO triggers_fields_info[]=
++{
++ {"TRIGGER_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
++ {"TRIGGER_SCHEMA",NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"TRIGGER_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Trigger"},
++ {"EVENT_MANIPULATION", 6, MYSQL_TYPE_STRING, 0, 0, "Event"},
++ {"EVENT_OBJECT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
++ {"EVENT_OBJECT_SCHEMA",NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"EVENT_OBJECT_TABLE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table"},
++ {"ACTION_ORDER", 4, MYSQL_TYPE_LONG, 0, 0, 0},
++ {"ACTION_CONDITION", 65535, MYSQL_TYPE_STRING, 0, 1, 0},
++ {"ACTION_STATEMENT", 65535, MYSQL_TYPE_STRING, 0, 0, "Statement"},
++ {"ACTION_ORIENTATION", 9, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"ACTION_TIMING", 6, MYSQL_TYPE_STRING, 0, 0, "Timing"},
++ {"ACTION_REFERENCE_OLD_TABLE", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
++ {"ACTION_REFERENCE_NEW_TABLE", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
++ {"ACTION_REFERENCE_OLD_ROW", 3, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"ACTION_REFERENCE_NEW_ROW", 3, MYSQL_TYPE_STRING, 0, 0, 0},
++ {"CREATED", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Created"},
++ {"SQL_MODE", 65535, MYSQL_TYPE_STRING, 0, 0, "sql_mode"},
++ {"DEFINER", 65535, MYSQL_TYPE_STRING, 0, 0, "Definer"},
++ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
++};
++
++
++ST_FIELD_INFO variables_fields_info[]=
++{
++ {"Variable_name", 80, MYSQL_TYPE_STRING, 0, 0, "Variable_name"},
++ {"Value", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, "Value"},
++ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
++};
++
++
++/*
++ Description of ST_FIELD_INFO in table.h
++*/
++
++ST_SCHEMA_TABLE schema_tables[]=
++{
++ {"CHARACTER_SETS", charsets_fields_info, create_schema_table,
++ fill_schema_charsets, make_character_sets_old_format, 0, -1, -1, 0},
++ {"COLLATIONS", collation_fields_info, create_schema_table,
++ fill_schema_collation, make_old_format, 0, -1, -1, 0},
++ {"COLLATION_CHARACTER_SET_APPLICABILITY", coll_charset_app_fields_info,
++ create_schema_table, fill_schema_coll_charset_app, 0, 0, -1, -1, 0},
++ {"COLUMNS", columns_fields_info, create_schema_table,
++ get_all_tables, make_columns_old_format, get_schema_column_record, 1, 2, 0},
++ {"COLUMN_PRIVILEGES", column_privileges_fields_info, create_schema_table,
++ fill_schema_column_privileges, 0, 0, -1, -1, 0},
++ {"KEY_COLUMN_USAGE", key_column_usage_fields_info, create_schema_table,
++ get_all_tables, 0, get_schema_key_column_usage_record, 4, 5, 0},
++ {"OPEN_TABLES", open_tables_fields_info, create_schema_table,
++ fill_open_tables, make_old_format, 0, -1, -1, 1},
++ {"ROUTINES", proc_fields_info, create_schema_table,
++ fill_schema_proc, make_proc_old_format, 0, -1, -1, 0},
++ {"SCHEMATA", schema_fields_info, create_schema_table,
++ fill_schema_shemata, make_schemata_old_format, 0, 1, -1, 0},
++ {"SCHEMA_PRIVILEGES", schema_privileges_fields_info, create_schema_table,
++ fill_schema_schema_privileges, 0, 0, -1, -1, 0},
++ {"STATISTICS", stat_fields_info, create_schema_table,
++ get_all_tables, make_old_format, get_schema_stat_record, 1, 2, 0},
++ {"STATUS", variables_fields_info, create_schema_table, fill_status,
++ make_old_format, 0, -1, -1, 1},
++ {"TABLES", tables_fields_info, create_schema_table,
++ get_all_tables, make_old_format, get_schema_tables_record, 1, 2, 0},
++ {"TABLE_CONSTRAINTS", table_constraints_fields_info, create_schema_table,
++ get_all_tables, 0, get_schema_constraints_record, 3, 4, 0},
++ {"TABLE_NAMES", table_names_fields_info, create_schema_table,
++ get_all_tables, make_table_names_old_format, 0, 1, 2, 1},
++ {"TABLE_PRIVILEGES", table_privileges_fields_info, create_schema_table,
++ fill_schema_table_privileges, 0, 0, -1, -1, 0},
++ {"TRIGGERS", triggers_fields_info, create_schema_table,
++ get_all_tables, make_old_format, get_schema_triggers_record, 5, 6, 0},
++ {"USER_PRIVILEGES", user_privileges_fields_info, create_schema_table,
++ fill_schema_user_privileges, 0, 0, -1, -1, 0},
++ {"VARIABLES", variables_fields_info, create_schema_table, fill_variables,
++ make_old_format, 0, -1, -1, 1},
++ {"VIEWS", view_fields_info, create_schema_table,
++ get_all_tables, 0, get_schema_views_record, 1, 2, 0},
++ {0, 0, 0, 0, 0, 0, 0, 0, 0}
++};
++
++
++#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
++template class List_iterator_fast<char>;
++template class List<char>;
++#endif
Copied: branches/etch-5.0/debian/patches/93_SECURITY_CVE-2007-3780.dpatch (from rev 967, branches/etch-5.0/debian/patches/91_CVE-2007-3780.dpatch)
===================================================================
--- branches/etch-5.0/debian/patches/93_SECURITY_CVE-2007-3780.dpatch (rev 0)
+++ branches/etch-5.0/debian/patches/93_SECURITY_CVE-2007-3780.dpatch 2007-11-06 21:06:03 UTC (rev 968)
@@ -0,0 +1,20 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## 91_CVE-2007-3780.dpatch by Jamie Strandboge <jamie at ubuntu.com>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: fix for CVE-2007-3780
+
+ at DPATCH@
+
+diff -Nru mysql-dfsg-5.0-5.0.38.orig/sql/sql_parse.cc mysql-dfsg-5.0-5.0.38/sql/sql_parse.cc
+--- mysql-dfsg-5.0-5.0.38.orig/sql/sql_parse.cc 2007-10-02 10:27:41.000000000 -0400
++++ mysql-dfsg-5.0-5.0.38/sql/sql_parse.cc 2007-10-02 10:30:39.000000000 -0400
+@@ -1008,7 +1008,7 @@
+ password both send '\0'.
+ */
+ uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
+- *passwd++ : strlen(passwd);
++ (uchar) (*passwd++) : strlen(passwd);
+ db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ?
+ db + passwd_len + 1 : 0;
+ uint db_len= db ? strlen(db) : 0;
Copied: branches/etch-5.0/debian/patches/93_SECURITY_CVE-2007-3782.dpatch (from rev 967, branches/etch-5.0/debian/patches/91_CVE-2007-3782.dpatch)
===================================================================
--- branches/etch-5.0/debian/patches/93_SECURITY_CVE-2007-3782.dpatch (rev 0)
+++ branches/etch-5.0/debian/patches/93_SECURITY_CVE-2007-3782.dpatch 2007-11-06 21:06:03 UTC (rev 968)
@@ -0,0 +1,39 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## 91_CVE-2007-3782.dpatch by Jamie Strandboge <jamie at ubuntu.com>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: fix for CVE-2007-3782
+## DP: (patches to mysql-test/ removed as they didn't apply cleanly --ch)
+
+ at DPATCH@
+
+diff -Nru mysql-dfsg-5.0-5.0.38.orig/sql/sql_prepare.cc mysql-dfsg-5.0-5.0.38/sql/sql_prepare.cc
+--- mysql-dfsg-5.0-5.0.38.orig/sql/sql_prepare.cc 2007-03-20 15:12:48.000000000 -0400
++++ mysql-dfsg-5.0-5.0.38/sql/sql_prepare.cc 2007-10-02 11:02:20.000000000 -0400
+@@ -1164,8 +1164,9 @@
+ goto error;
+
+ #ifndef NO_EMBEDDED_ACCESS_CHECKS
+- /* TABLE_LIST contain right privilages request */
+- want_privilege= table_list->grant.want_privilege;
++ /* Force privilege re-checking for views after they are being opened. */
++ want_privilege= (table_list->view ? UPDATE_ACL :
++ table_list->grant.want_privilege);
+ #endif
+
+ if (mysql_prepare_update(thd, table_list, &select->where,
+diff -Nru mysql-dfsg-5.0-5.0.38.orig/sql/sql_update.cc mysql-dfsg-5.0-5.0.38/sql/sql_update.cc
+--- mysql-dfsg-5.0-5.0.38.orig/sql/sql_update.cc 2007-03-20 15:12:18.000000000 -0400
++++ mysql-dfsg-5.0-5.0.38/sql/sql_update.cc 2007-10-02 11:02:20.000000000 -0400
+@@ -173,8 +173,9 @@
+ table->quick_keys.clear_all();
+
+ #ifndef NO_EMBEDDED_ACCESS_CHECKS
+- /* TABLE_LIST contain right privilages request */
+- want_privilege= table_list->grant.want_privilege;
++ /* Force privilege re-checking for views after they are being opened. */
++ want_privilege= (table_list->view ? UPDATE_ACL :
++ table_list->grant.want_privilege);
+ #endif
+ if (mysql_prepare_update(thd, table_list, &conds, order_num, order))
+ DBUG_RETURN(1);
More information about the Pkg-mysql-commits
mailing list