summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <tomas@poseidon.ndb.mysql.com>2005-10-06 10:54:07 +0200
committerunknown <tomas@poseidon.ndb.mysql.com>2005-10-06 10:54:07 +0200
commitd04832d195aba5badc42310eaa69c628a4a183bd (patch)
treecbe58ba165511396b212afaa1654a226d8ae88a4 /sql
parent282855e90bf052e2cf126adfaada61924cd8dd41 (diff)
parent3c2dca475dfa91c95f2488831fafacacaf852347 (diff)
downloadmariadb-git-d04832d195aba5badc42310eaa69c628a4a183bd.tar.gz
Merge
BitKeeper/etc/ignore: auto-union BUILD/autorun.sh: Auto merged BitKeeper/deleted/.del-bdb.vcproj~ed8534936e40cefb: Auto merged BitKeeper/deleted/.del-heap.vcproj~70c0cc1d680a51c1: Auto merged BitKeeper/deleted/.del-innobase.vcproj~71e1de81f11138bf: Auto merged BitKeeper/deleted/.del-myisam.vcproj~32bb9e4a163fcb5a: Auto merged BitKeeper/deleted/.del-myisammrg.vcproj~6534e59acbfbb63: Auto merged BitKeeper/deleted/.del-mysqld.vcproj~703886a28862bb2: Auto merged Makefile.am: Auto merged client/mysqltest.c: Auto merged include/my_global.h: Auto merged include/mysql_com.h: Auto merged mysql-test/mysql-test-run.pl: Auto merged mysql-test/r/ndb_alter_table.result: Auto merged mysql-test/r/ps_6bdb.result: Auto merged mysql-test/r/ps_7ndb.result: Auto merged mysql-test/t/query_cache.test: Auto merged mysys/default.c: Auto merged scripts/make_win_src_distribution.sh: Auto merged scripts/mysql_create_system_tables.sh: Auto merged scripts/mysql_fix_privilege_tables.sql: Auto merged sql/Makefile.am: Auto merged sql/field.cc: Auto merged sql/ha_berkeley.cc: Auto merged sql/ha_berkeley.h: Auto merged sql/ha_federated.cc: Auto merged sql/ha_heap.cc: Auto merged sql/ha_innodb.cc: Auto merged sql/ha_innodb.h: Auto merged sql/ha_myisam.cc: Auto merged sql/ha_myisammrg.cc: Auto merged sql/ha_ndbcluster.h: Auto merged sql/handler.cc: Auto merged sql/item.cc: Auto merged sql/item_subselect.cc: Auto merged sql/log.cc: Auto merged sql/mysql_priv.h: Auto merged sql/opt_sum.cc: Auto merged sql/repl_failsafe.cc: Auto merged sql/set_var.cc: Auto merged sql/sp.cc: Auto merged sql/sql_acl.cc: Auto merged sql/sql_acl.h: Auto merged sql/sql_base.cc: Auto merged sql/sql_cache.cc: Auto merged sql/sql_class.h: Auto merged sql/sql_delete.cc: Auto merged sql/sql_insert.cc: Auto merged sql/sql_lex.cc: Auto merged sql/sql_lex.h: Auto merged sql/sql_load.cc: Auto merged sql/sql_prepare.cc: Auto merged sql/sql_select.cc: Auto merged sql/sql_select.h: Auto merged sql/sql_show.cc: Auto merged sql/sql_table.cc: Auto merged sql/sql_update.cc: Auto merged sql/sql_yacc.yy: Auto merged sql/table.h: Auto merged sql/unireg.cc: Auto merged storage/innobase/buf/buf0buf.c: Auto merged storage/innobase/buf/buf0flu.c: Auto merged storage/innobase/data/data0data.c: Auto merged storage/innobase/dict/dict0dict.c: Auto merged storage/innobase/include/btr0btr.h: Auto merged storage/innobase/include/data0type.ic: Auto merged storage/innobase/include/dict0dict.h: Auto merged storage/innobase/include/dict0mem.h: Auto merged storage/innobase/include/mem0mem.h: Auto merged storage/innobase/include/mem0mem.ic: Auto merged storage/innobase/include/os0file.h: Auto merged storage/innobase/include/row0mysql.h: Auto merged storage/innobase/include/trx0trx.h: Auto merged storage/innobase/include/ut0mem.h: Auto merged storage/innobase/mem/mem0mem.c: Auto merged storage/innobase/os/os0file.c: Auto merged storage/innobase/os/os0proc.c: Auto merged storage/innobase/rem/rem0rec.c: Auto merged storage/innobase/row/row0ins.c: Auto merged storage/innobase/row/row0mysql.c: Auto merged storage/innobase/srv/srv0start.c: Auto merged storage/innobase/trx/trx0sys.c: Auto merged storage/innobase/trx/trx0trx.c: Auto merged storage/innobase/ut/ut0mem.c: Auto merged storage/myisam/ft_boolean_search.c: Auto merged storage/myisam/mi_check.c: Auto merged storage/myisam/mi_dbug.c: Auto merged storage/myisam/mi_delete.c: Auto merged storage/myisam/mi_delete_all.c: Auto merged storage/myisam/mi_key.c: Auto merged storage/myisam/mi_open.c: Auto merged storage/myisam/mi_rkey.c: Auto merged storage/myisam/mi_search.c: Auto merged storage/myisam/mi_test1.c: Auto merged storage/myisam/mi_update.c: Auto merged storage/myisam/mi_write.c: Auto merged storage/myisam/myisamchk.c: Auto merged storage/myisam/myisamdef.h: Auto merged storage/myisam/myisampack.c: Auto merged storage/myisam/sp_key.c: Auto merged storage/myisammrg/myrg_rkey.c: Auto merged storage/ndb/include/kernel/GlobalSignalNumbers.h: Auto merged storage/ndb/include/kernel/signaldata/ApiVersion.hpp: Auto merged storage/ndb/include/kernel/signaldata/EventReport.hpp: Auto merged storage/ndb/include/kernel/signaldata/StopReq.hpp: Auto merged storage/ndb/include/mgmapi/ndb_logevent.h: Auto merged storage/ndb/include/ndbapi/NdbBlob.hpp: Auto merged storage/ndb/include/ndbapi/NdbIndexOperation.hpp: Auto merged storage/ndb/include/ndbapi/NdbIndexScanOperation.hpp: Auto merged storage/ndb/include/ndbapi/NdbOperation.hpp: Auto merged storage/ndb/include/ndbapi/NdbRecAttr.hpp: Auto merged storage/ndb/include/ndbapi/NdbTransaction.hpp: Auto merged storage/ndb/src/common/util/SimpleProperties.cpp: Auto merged storage/ndb/src/kernel/blocks/backup/Backup.cpp: Auto merged storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp: Auto merged storage/ndb/src/kernel/blocks/dbdict/printSchemaFile.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp: Auto merged storage/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp: Auto merged storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp: Auto merged storage/ndb/src/mgmapi/ndb_logevent.cpp: Auto merged storage/ndb/src/mgmclient/CommandInterpreter.cpp: Auto merged storage/ndb/src/mgmsrv/Config.cpp: Auto merged storage/ndb/src/mgmsrv/Config.hpp: Auto merged storage/ndb/src/mgmsrv/ConfigInfo.cpp: Auto merged storage/ndb/src/mgmsrv/InitConfigFileParser.cpp: Auto merged storage/ndb/src/mgmsrv/InitConfigFileParser.hpp: Auto merged storage/ndb/src/mgmsrv/MgmtSrvr.hpp: Auto merged storage/ndb/src/mgmsrv/MgmtSrvrConfig.cpp: Auto merged storage/ndb/src/mgmsrv/MgmtSrvrGeneralSignalHandling.cpp: Auto merged storage/ndb/src/mgmsrv/Services.cpp: Auto merged storage/ndb/src/mgmsrv/Services.hpp: Auto merged storage/ndb/src/mgmsrv/main.cpp: Auto merged storage/ndb/src/ndbapi/NdbApiSignal.cpp: Auto merged storage/ndb/src/ndbapi/NdbApiSignal.hpp: Auto merged storage/ndb/src/ndbapi/NdbBlob.cpp: Auto merged storage/ndb/src/ndbapi/NdbImpl.hpp: Auto merged storage/ndb/src/ndbapi/NdbRecAttr.cpp: Auto merged storage/ndb/src/ndbapi/NdbUtil.cpp: Auto merged storage/ndb/src/ndbapi/NdbUtil.hpp: Auto merged storage/ndb/src/ndbapi/Ndbif.cpp: Auto merged storage/ndb/src/ndbapi/Ndblist.cpp: Auto merged storage/ndb/src/ndbapi/ObjectMap.hpp: Auto merged storage/ndb/test/include/NDBT_Test.hpp: Auto merged storage/ndb/test/ndbapi/bank/BankLoad.cpp: Auto merged storage/ndb/test/ndbapi/testOIBasic.cpp: Auto merged storage/ndb/test/src/HugoCalculator.cpp: Auto merged storage/ndb/test/src/NDBT_Test.cpp: Auto merged storage/ndb/test/src/NdbBackup.cpp: Auto merged storage/ndb/test/src/NdbRestarts.cpp: Auto merged storage/ndb/tools/ndb_condig.cpp: Auto merged storage/ndb/tools/restore/Restore.cpp: Auto merged storage/ndb/tools/restore/consumer_restore.cpp: Auto merged support-files/mysql.spec.sh: Auto merged configure.in: merge BUILD/SETUP.sh: merge BitKeeper/deleted/.del-mysql.sln~f2120278f8a437be: SCCS merged libmysqld/Makefile.am: merge sql/ha_ndbcluster.cc: merge sql/handler.h: merge sql/mysqld.cc: merge sql/opt_range.cc: merge sql/slave.cc: merge sql/slave.h: e merge sql/sql_parse.cc: merge sql/table.cc: merge sql/examples/ha_tina.cc: merge sql/examples/ha_tina.h: merge sql/share/errmsg.txt: merge storage/ndb/include/ndbapi/Ndb.hpp: merge storage/ndb/src/common/debugger/EventLogger.cpp: merge storage/ndb/src/kernel/blocks/dbdict/Makefile.am: merge storage/ndb/src/mgmsrv/MgmtSrvr.cpp: merge storage/ndb/src/ndbapi/Ndbinit.cpp: SCCS merged
Diffstat (limited to 'sql')
-rw-r--r--sql/Makefile.am8
-rw-r--r--sql/examples/ha_example.cc10
-rw-r--r--sql/examples/ha_tina.cc32
-rw-r--r--sql/examples/ha_tina.h12
-rw-r--r--sql/field.cc2
-rw-r--r--sql/ha_archive.cc (renamed from sql/examples/ha_archive.cc)36
-rw-r--r--sql/ha_archive.h (renamed from sql/examples/ha_archive.h)2
-rw-r--r--sql/ha_berkeley.cc22
-rw-r--r--sql/ha_berkeley.h4
-rw-r--r--sql/ha_blackhole.cc8
-rw-r--r--sql/ha_federated.cc90
-rw-r--r--sql/ha_heap.cc8
-rw-r--r--sql/ha_innodb.cc101
-rw-r--r--sql/ha_innodb.h8
-rw-r--r--sql/ha_myisam.cc19
-rw-r--r--sql/ha_myisammrg.cc10
-rw-r--r--sql/ha_ndbcluster.cc69
-rw-r--r--sql/ha_ndbcluster.h6
-rw-r--r--sql/handler.cc355
-rw-r--r--sql/handler.h69
-rw-r--r--sql/item.cc58
-rw-r--r--sql/item.h6
-rw-r--r--sql/item_cmpfunc.cc32
-rw-r--r--sql/item_cmpfunc.h4
-rw-r--r--sql/item_func.cc101
-rw-r--r--sql/item_func.h10
-rw-r--r--sql/item_strfunc.cc42
-rw-r--r--sql/item_subselect.cc2
-rw-r--r--sql/item_sum.cc3
-rw-r--r--sql/log.cc28
-rw-r--r--sql/mysql_priv.h13
-rw-r--r--sql/mysqld.cc57
-rw-r--r--sql/opt_range.cc17
-rw-r--r--sql/opt_sum.cc74
-rw-r--r--sql/parse_file.cc53
-rw-r--r--sql/parse_file.h3
-rw-r--r--sql/password.c4
-rw-r--r--sql/protocol.h24
-rw-r--r--sql/repl_failsafe.cc4
-rw-r--r--sql/set_var.cc27
-rw-r--r--sql/share/errmsg.txt19
-rw-r--r--sql/slave.cc11
-rw-r--r--sql/slave.h2
-rw-r--r--sql/sp.cc5
-rw-r--r--sql/sp_head.cc186
-rw-r--r--sql/sp_head.h34
-rw-r--r--sql/sp_rcontext.cc222
-rw-r--r--sql/sp_rcontext.h70
-rw-r--r--sql/sql_acl.cc217
-rw-r--r--sql/sql_acl.h3
-rw-r--r--sql/sql_base.cc106
-rw-r--r--sql/sql_cache.cc3
-rw-r--r--sql/sql_class.cc88
-rw-r--r--sql/sql_class.h70
-rw-r--r--sql/sql_cursor.cc660
-rw-r--r--sql/sql_cursor.h65
-rw-r--r--sql/sql_db.cc19
-rw-r--r--sql/sql_delete.cc34
-rw-r--r--sql/sql_derived.cc43
-rw-r--r--sql/sql_insert.cc11
-rw-r--r--sql/sql_lex.h12
-rw-r--r--sql/sql_list.h2
-rw-r--r--sql/sql_load.cc16
-rw-r--r--sql/sql_parse.cc316
-rw-r--r--sql/sql_prepare.cc260
-rw-r--r--sql/sql_rename.cc42
-rw-r--r--sql/sql_select.cc454
-rw-r--r--sql/sql_select.h59
-rw-r--r--sql/sql_show.cc81
-rw-r--r--sql/sql_table.cc29
-rw-r--r--sql/sql_trigger.cc2
-rw-r--r--sql/sql_union.cc176
-rw-r--r--sql/sql_update.cc22
-rw-r--r--sql/sql_view.cc114
-rw-r--r--sql/sql_view.h1
-rw-r--r--sql/sql_yacc.yy96
-rw-r--r--sql/table.cc101
-rw-r--r--sql/table.h5
-rw-r--r--sql/unireg.cc4
79 files changed, 3251 insertions, 1842 deletions
diff --git a/sql/Makefile.am b/sql/Makefile.am
index e90be7630fa..ada462f5e09 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -61,8 +61,8 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
tztime.h my_decimal.h\
sp_head.h sp_pcontext.h sp_rcontext.h sp.h sp_cache.h \
parse_file.h sql_view.h sql_trigger.h \
- sql_array.h \
- examples/ha_example.h examples/ha_archive.h \
+ sql_array.h sql_cursor.h \
+ examples/ha_example.h ha_archive.h \
examples/ha_tina.h ha_blackhole.h \
ha_federated.h ha_partition.h
mysqld_SOURCES = sql_lex.cc sql_handler.cc \
@@ -95,11 +95,11 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \
client.c sql_client.cc mini_client_errors.c pack.c\
stacktrace.c repl_failsafe.h repl_failsafe.cc \
sql_olap.cc sql_view.cc \
- gstream.cc spatial.cc sql_help.cc protocol_cursor.cc \
+ gstream.cc spatial.cc sql_help.cc sql_cursor.cc \
tztime.cc my_time.c my_decimal.cc\
sp_head.cc sp_pcontext.cc sp_rcontext.cc sp.cc \
sp_cache.cc parse_file.cc sql_trigger.cc \
- examples/ha_example.cc examples/ha_archive.cc \
+ examples/ha_example.cc ha_archive.cc \
examples/ha_tina.cc ha_blackhole.cc \
ha_partition.cc sql_partition.cc \
ha_federated.cc
diff --git a/sql/examples/ha_example.cc b/sql/examples/ha_example.cc
index dfc2fa7a260..d340b9289ec 100644
--- a/sql/examples/ha_example.cc
+++ b/sql/examples/ha_example.cc
@@ -73,8 +73,12 @@
#include "ha_example.h"
-static handlerton example_hton= {
- "CSV",
+handlerton example_hton= {
+ "EXAMPLE",
+ SHOW_OPTION_YES,
+ "Example storage engine",
+ DB_TYPE_EXAMPLE_DB,
+ NULL, /* We do need to write one! */
0, /* slot */
0, /* savepoint size. */
NULL, /* close_connection */
@@ -90,7 +94,7 @@ static handlerton example_hton= {
NULL, /* create_cursor_read_view */
NULL, /* set_cursor_read_view */
NULL, /* close_cursor_read_view */
- HTON_NO_FLAGS
+ HTON_CAN_RECREATE
};
/* Variables for example share methods */
diff --git a/sql/examples/ha_tina.cc b/sql/examples/ha_tina.cc
index a611466ca1d..2c193f4ce84 100644
--- a/sql/examples/ha_tina.cc
+++ b/sql/examples/ha_tina.cc
@@ -58,8 +58,12 @@ pthread_mutex_t tina_mutex;
static HASH tina_open_tables;
static int tina_init= 0;
-static handlerton tina_hton= {
+handlerton tina_hton= {
"CSV",
+ SHOW_OPTION_YES,
+ "CSV storage engine",
+ DB_TYPE_CSV_DB,
+ NULL, /* One needs to be written! */
0, /* slot */
0, /* savepoint size. */
NULL, /* close_connection */
@@ -75,7 +79,7 @@ static handlerton tina_hton= {
NULL, /* create_cursor_read_view */
NULL, /* set_cursor_read_view */
NULL, /* close_cursor_read_view */
- HTON_NO_FLAGS
+ HTON_CAN_RECREATE
};
/*****************************************************************************
@@ -243,6 +247,16 @@ static int free_share(TINA_SHARE *share)
DBUG_RETURN(result_code);
}
+bool tina_end()
+{
+ if (tina_init)
+ {
+ hash_free(&tina_open_tables);
+ VOID(pthread_mutex_destroy(&tina_mutex));
+ }
+ tina_init= 0;
+ return FALSE;
+}
/*
Finds the end of a line.
@@ -873,19 +887,7 @@ THR_LOCK_DATA **ha_tina::store_lock(THD *thd,
return to;
}
-/*
- Range optimizer calls this.
- I need to update the information on this.
-*/
-ha_rows ha_tina::records_in_range(uint inx, key_range *min_key,
- key_range *max_key)
-{
- DBUG_ENTER("ha_tina::records_in_range ");
- DBUG_RETURN(records); // Good guess
-}
-
-
-/*
+/*
Create a table. You do not want to leave the table open after a call to
this (the database will call ::open() if it needs to).
*/
diff --git a/sql/examples/ha_tina.h b/sql/examples/ha_tina.h
index 43479c7c11c..0ac90a05812 100644
--- a/sql/examples/ha_tina.h
+++ b/sql/examples/ha_tina.h
@@ -83,11 +83,6 @@ public:
*/
virtual double scan_time() { return (double) (records+deleted) / 20.0+10; }
/* The next method will never be called */
- virtual double read_time(uint index, uint ranges, ha_rows rows)
- {
- DBUG_ASSERT(0);
- return((double) rows / 20.0+1);
- }
virtual bool fast_key_read() { return 1;}
/*
TODO: return actual upper bound of number of records in the table.
@@ -119,10 +114,6 @@ public:
int reset(void);
int external_lock(THD *thd, int lock_type);
int delete_all_rows(void);
- ha_rows records_in_range(uint inx, key_range *min_key,
- key_range *max_key);
-// int delete_table(const char *from);
-// int rename_table(const char * from, const char * to);
int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info);
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
@@ -133,3 +124,6 @@ public:
int find_current_row(byte *buf);
int chain_append();
};
+
+bool tina_end();
+
diff --git a/sql/field.cc b/sql/field.cc
index 779dae20220..d334dc1ab53 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -3440,7 +3440,7 @@ int Field_long::store(longlong nr, bool unsigned_val)
else
{
if (nr < 0 && unsigned_val)
- nr= INT_MAX32+1; // Generate overflow
+ nr= ((longlong) INT_MAX32) + 1; // Generate overflow
if (nr < (longlong) INT_MIN32)
{
res=(int32) INT_MIN32;
diff --git a/sql/examples/ha_archive.cc b/sql/ha_archive.cc
index 85104405024..59c56e80cc3 100644
--- a/sql/examples/ha_archive.cc
+++ b/sql/ha_archive.cc
@@ -18,7 +18,7 @@
#pragma implementation // gcc: Class implementation
#endif
-#include "../mysql_priv.h"
+#include "mysql_priv.h"
#ifdef HAVE_ARCHIVE_DB
#include "ha_archive.h"
@@ -116,7 +116,7 @@
*/
/* If the archive storage engine has been inited */
-static bool archive_inited= 0;
+static bool archive_inited= FALSE;
/* Variables for archive share methods */
pthread_mutex_t archive_mutex;
static HASH archive_open_tables;
@@ -136,8 +136,12 @@ static HASH archive_open_tables;
#define ARCHIVE_CHECK_HEADER 254 // The number we use to determine corruption
/* dummy handlerton - only to have something to return from archive_db_init */
-static handlerton archive_hton = {
- "archive",
+handlerton archive_hton = {
+ "ARCHIVE",
+ SHOW_OPTION_YES,
+ "Archive storage engine",
+ DB_TYPE_ARCHIVE_DB,
+ archive_db_init,
0, /* slot */
0, /* savepoint size. */
NULL, /* close_connection */
@@ -176,18 +180,28 @@ static byte* archive_get_key(ARCHIVE_SHARE *share,uint *length,
void
RETURN
- &archive_hton OK
- 0 Error
+ FALSE OK
+ TRUE Error
*/
-handlerton *archive_db_init()
+bool archive_db_init()
{
- archive_inited= 1;
- VOID(pthread_mutex_init(&archive_mutex, MY_MUTEX_INIT_FAST));
+ DBUG_ENTER("archive_db_init");
+ if (pthread_mutex_init(&archive_mutex, MY_MUTEX_INIT_FAST))
+ goto error;
if (hash_init(&archive_open_tables, system_charset_info, 32, 0, 0,
(hash_get_key) archive_get_key, 0, 0))
- return 0;
- return &archive_hton;
+ {
+ VOID(pthread_mutex_destroy(&archive_mutex));
+ }
+ else
+ {
+ archive_inited= TRUE;
+ DBUG_RETURN(FALSE);
+ }
+error:
+ have_archive_db= SHOW_OPTION_DISABLED; // If we couldn't use handler
+ DBUG_RETURN(TRUE);
}
/*
diff --git a/sql/examples/ha_archive.h b/sql/ha_archive.h
index e2d8aa49add..849b5b5bd6c 100644
--- a/sql/examples/ha_archive.h
+++ b/sql/ha_archive.h
@@ -105,6 +105,6 @@ public:
enum thr_lock_type lock_type);
};
-handlerton *archive_db_init(void);
+bool archive_db_init(void);
bool archive_db_end(void);
diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc
index 5bead36600b..3312b60e6c4 100644
--- a/sql/ha_berkeley.cc
+++ b/sql/ha_berkeley.cc
@@ -108,8 +108,12 @@ static int berkeley_close_connection(THD *thd);
static int berkeley_commit(THD *thd, bool all);
static int berkeley_rollback(THD *thd, bool all);
-static handlerton berkeley_hton = {
+handlerton berkeley_hton = {
"BerkeleyDB",
+ SHOW_OPTION_YES,
+ "Supports transactions and page-level locking",
+ DB_TYPE_BERKELEY_DB,
+ berkeley_init,
0, /* slot */
0, /* savepoint size */
berkeley_close_connection,
@@ -136,10 +140,13 @@ typedef struct st_berkeley_trx_data {
/* General functions */
-handlerton *berkeley_init(void)
+bool berkeley_init(void)
{
DBUG_ENTER("berkeley_init");
+ if (have_berkeley_db != SHOW_OPTION_YES)
+ goto error;
+
if (!berkeley_tmpdir)
berkeley_tmpdir=mysql_tmpdir;
if (!berkeley_home)
@@ -165,7 +172,7 @@ handlerton *berkeley_init(void)
berkeley_log_file_size= max(berkeley_log_file_size, 10*1024*1024L);
if (db_env_create(&db_env,0))
- DBUG_RETURN(0);
+ goto error;
db_env->set_errcall(db_env,berkeley_print_error);
db_env->set_errpfx(db_env,"bdb");
db_env->set_noticecall(db_env, berkeley_noticecall);
@@ -195,13 +202,16 @@ handlerton *berkeley_init(void)
{
db_env->close(db_env,0);
db_env=0;
- DBUG_RETURN(0);
+ goto error;
}
(void) hash_init(&bdb_open_tables,system_charset_info,32,0,0,
(hash_get_key) bdb_get_key,0,0);
pthread_mutex_init(&bdb_mutex,MY_MUTEX_INIT_FAST);
- DBUG_RETURN(&berkeley_hton);
+ DBUG_RETURN(FALSE);
+error:
+ have_berkeley_db= SHOW_OPTION_DISABLED; // If we couldn't use handler
+ DBUG_RETURN(TRUE);
}
@@ -1897,7 +1907,7 @@ int ha_berkeley::external_lock(THD *thd, int lock_type)
Under LOCK TABLES, each used tables will force a call to start_stmt.
*/
-int ha_berkeley::start_stmt(THD *thd)
+int ha_berkeley::start_stmt(THD *thd, thr_lock_type lock_type)
{
int error=0;
DBUG_ENTER("ha_berkeley::start_stmt");
diff --git a/sql/ha_berkeley.h b/sql/ha_berkeley.h
index aab76accefa..95ff64a082a 100644
--- a/sql/ha_berkeley.h
+++ b/sql/ha_berkeley.h
@@ -124,7 +124,7 @@ class ha_berkeley: public handler
int extra(enum ha_extra_function operation);
int reset(void);
int external_lock(THD *thd, int lock_type);
- int start_stmt(THD *thd);
+ int start_stmt(THD *thd, thr_lock_type lock_type);
void position(byte *record);
int analyze(THD* thd,HA_CHECK_OPT* check_opt);
int optimize(THD* thd, HA_CHECK_OPT* check_opt);
@@ -162,7 +162,7 @@ extern char *berkeley_home, *berkeley_tmpdir, *berkeley_logdir;
extern long berkeley_lock_scan_time;
extern TYPELIB berkeley_lock_typelib;
-handlerton *berkeley_init(void);
+bool berkeley_init(void);
bool berkeley_end(void);
bool berkeley_flush_logs(void);
int berkeley_show_logs(Protocol *protocol);
diff --git a/sql/ha_blackhole.cc b/sql/ha_blackhole.cc
index a287d6e446b..2505919af39 100644
--- a/sql/ha_blackhole.cc
+++ b/sql/ha_blackhole.cc
@@ -26,8 +26,12 @@
/* Blackhole storage engine handlerton */
-static handlerton blackhole_hton= {
+handlerton blackhole_hton= {
"BLACKHOLE",
+ SHOW_OPTION_YES,
+ "/dev/null storage engine (anything you write to it disappears)",
+ DB_TYPE_BLACKHOLE_DB,
+ NULL,
0, /* slot */
0, /* savepoint size. */
NULL, /* close_connection */
@@ -43,7 +47,7 @@ static handlerton blackhole_hton= {
NULL, /* create_cursor_read_view */
NULL, /* set_cursor_read_view */
NULL, /* close_cursor_read_view */
- HTON_NO_FLAGS
+ HTON_CAN_RECREATE
};
/*****************************************************************************
diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc
index fa027ce71b5..66c2431844d 100644
--- a/sql/ha_federated.cc
+++ b/sql/ha_federated.cc
@@ -363,6 +363,33 @@ pthread_mutex_t federated_mutex; // This is the mutex we use to
static int federated_init= FALSE; // Variable for checking the
// init state of hash
+/* Federated storage engine handlerton */
+
+handlerton federated_hton= {
+ "FEDERATED",
+ SHOW_OPTION_YES,
+ "Federated MySQL storage engine",
+ DB_TYPE_FEDERATED_DB,
+ federated_db_init,
+ 0, /* slot */
+ 0, /* savepoint size. */
+ NULL, /* close_connection */
+ NULL, /* savepoint */
+ NULL, /* rollback to savepoint */
+ NULL, /* release savepoint */
+ NULL, /* commit */
+ NULL, /* rollback */
+ NULL, /* prepare */
+ NULL, /* recover */
+ NULL, /* commit_by_xid */
+ NULL, /* rollback_by_xid */
+ NULL, /* create_cursor_read_view */
+ NULL, /* set_cursor_read_view */
+ NULL, /* close_cursor_read_view */
+ HTON_ALTER_NOT_SUPPORTED
+};
+
+
/* Function we use in the creation of our hash to get key. */
static byte *federated_get_key(FEDERATED_SHARE *share, uint *length,
@@ -386,10 +413,22 @@ static byte *federated_get_key(FEDERATED_SHARE *share, uint *length,
bool federated_db_init()
{
- federated_init= 1;
- VOID(pthread_mutex_init(&federated_mutex, MY_MUTEX_INIT_FAST));
- return (hash_init(&federated_open_tables, system_charset_info, 32, 0, 0,
- (hash_get_key) federated_get_key, 0, 0));
+ DBUG_ENTER("federated_db_init");
+ if (pthread_mutex_init(&federated_mutex, MY_MUTEX_INIT_FAST))
+ goto error;
+ if (hash_init(&federated_open_tables, system_charset_info, 32, 0, 0,
+ (hash_get_key) federated_get_key, 0, 0))
+ {
+ VOID(pthread_mutex_destroy(&federated_mutex));
+ }
+ else
+ {
+ federated_init= TRUE;
+ DBUG_RETURN(FALSE);
+ }
+error:
+ have_federated_db= SHOW_OPTION_DISABLED; // If we couldn't use handler
+ DBUG_RETURN(TRUE);
}
@@ -588,12 +627,15 @@ static int parse_url(FEDERATED_SHARE *share, TABLE *table,
DBUG_ENTER("ha_federated::parse_url");
share->port= 0;
+ share->socket= 0;
DBUG_PRINT("info", ("Length %d \n", table->s->connect_string.length));
DBUG_PRINT("info", ("String %.*s \n", table->s->connect_string.length,
table->s->connect_string.str));
- share->scheme= my_strdup_with_length(table->s->connect_string.str,
- table->s->connect_string.length+1,
- MYF(0));
+ share->scheme= my_strdup_with_length((const byte*)table->s->
+ connect_string.str,
+ table->s->connect_string.length,
+ MYF(0));
+
// Add a null for later termination of table name
share->scheme[table->s->connect_string.length]= 0;
DBUG_PRINT("info",("parse_url alloced share->scheme %lx", share->scheme));
@@ -691,29 +733,6 @@ error:
}
-/* Federated storage engine handlerton */
-
-static handlerton federated_hton= {
- "FEDERATED",
- 0, /* slot */
- 0, /* savepoint size. */
- NULL, /* close_connection */
- NULL, /* savepoint */
- NULL, /* rollback to savepoint */
- NULL, /* release savepoint */
- NULL, /* commit */
- NULL, /* rollback */
- NULL, /* prepare */
- NULL, /* recover */
- NULL, /* commit_by_xid */
- NULL, /* rollback_by_xid */
- NULL, /* create_cursor_read_view */
- NULL, /* set_cursor_read_view */
- NULL, /* close_cursor_read_view */
- HTON_NO_FLAGS
-};
-
-
/*****************************************************************************
** FEDERATED tables
*****************************************************************************/
@@ -1374,13 +1393,9 @@ static int free_share(FEDERATED_SHARE *share)
if (!--share->use_count)
{
- if (share->scheme)
- {
- my_free((gptr) share->scheme, MYF(0));
- share->scheme= 0;
- }
-
hash_delete(&federated_open_tables, (byte*) share);
+ my_free((gptr) share->scheme, MYF(MY_ALLOW_ZERO_PTR));
+ share->scheme= 0;
thr_lock_delete(&share->lock);
VOID(pthread_mutex_destroy(&share->mutex));
my_free((gptr) share, MYF(0));
@@ -2601,7 +2616,8 @@ int ha_federated::stash_remote_error()
{
DBUG_ENTER("ha_federated::stash_remote_error()");
remote_error_number= mysql_errno(mysql);
- snprintf(remote_error_buf, FEDERATED_QUERY_BUFFER_SIZE, mysql_error(mysql));
+ my_snprintf(remote_error_buf, FEDERATED_QUERY_BUFFER_SIZE,
+ mysql_error(mysql));
DBUG_RETURN(HA_FEDERATED_ERROR_WITH_REMOTE_SYSTEM);
}
diff --git a/sql/ha_heap.cc b/sql/ha_heap.cc
index 01e693978db..ab13f03825d 100644
--- a/sql/ha_heap.cc
+++ b/sql/ha_heap.cc
@@ -23,8 +23,12 @@
#include <myisampack.h>
#include "ha_heap.h"
-static handlerton heap_hton= {
+handlerton heap_hton= {
"MEMORY",
+ SHOW_OPTION_YES,
+ "Hash based, stored in memory, useful for temporary tables",
+ DB_TYPE_HEAP,
+ NULL,
0, /* slot */
0, /* savepoint size. */
NULL, /* close_connection */
@@ -40,7 +44,7 @@ static handlerton heap_hton= {
NULL, /* create_cursor_read_view */
NULL, /* set_cursor_read_view */
NULL, /* close_cursor_read_view */
- HTON_NO_FLAGS
+ HTON_CAN_RECREATE
};
/*****************************************************************************
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index 638bda49002..dc019bc7a3a 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -206,8 +206,12 @@ static int innobase_rollback_to_savepoint(THD* thd, void *savepoint);
static int innobase_savepoint(THD* thd, void *savepoint);
static int innobase_release_savepoint(THD* thd, void *savepoint);
-static handlerton innobase_hton = {
+handlerton innobase_hton = {
"InnoDB",
+ SHOW_OPTION_YES,
+ "Supports transactions, row-level locking, and foreign keys",
+ DB_TYPE_INNODB,
+ innobase_init,
0, /* slot */
sizeof(trx_named_savept_t), /* savepoint size. TODO: use it */
innobase_close_connection,
@@ -563,25 +567,29 @@ innobase_mysql_print_thd(
use the default max length */
{
const THD* thd;
+ const Security_context *sctx;
const char* s;
thd = (const THD*) input_thd;
+ /* We probably want to have original user as part of debug output. */
+ sctx = &thd->main_security_ctx;
+
fprintf(f, "MySQL thread id %lu, query id %lu",
thd->thread_id, (ulong) thd->query_id);
- if (thd->host) {
+ if (sctx->host) {
putc(' ', f);
- fputs(thd->host, f);
+ fputs(sctx->host, f);
}
- if (thd->ip) {
+ if (sctx->ip) {
putc(' ', f);
- fputs(thd->ip, f);
+ fputs(sctx->ip, f);
}
- if (thd->user) {
+ if (sctx->user) {
putc(' ', f);
- fputs(thd->user, f);
+ fputs(sctx->user, f);
}
if ((s = thd->proc_info)) {
@@ -1184,10 +1192,10 @@ ha_innobase::init_table_handle_for_HANDLER(void)
/*************************************************************************
Opens an InnoDB database. */
-handlerton*
+bool
innobase_init(void)
/*===============*/
- /* out: TRUE if error */
+ /* out: &innobase_hton, or NULL on error */
{
static char current_dir[3]; /* Set if using current lib */
int err;
@@ -1196,6 +1204,9 @@ innobase_init(void)
DBUG_ENTER("innobase_init");
+ if (have_innodb != SHOW_OPTION_YES)
+ goto error;
+
ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)MYSQL_TYPE_VARCHAR);
os_innodb_umask = (ulint)my_umask;
@@ -1248,7 +1259,7 @@ innobase_init(void)
copy of it: */
internal_innobase_data_file_path = my_strdup(innobase_data_file_path,
- MYF(MY_WME));
+ MYF(MY_FAE));
ret = (bool) srv_parse_data_file_paths_and_sizes(
internal_innobase_data_file_path,
@@ -1263,7 +1274,7 @@ innobase_init(void)
"InnoDB: syntax error in innodb_data_file_path");
my_free(internal_innobase_data_file_path,
MYF(MY_ALLOW_ZERO_PTR));
- DBUG_RETURN(0);
+ goto error;
}
/* -------------- Log files ---------------------------*/
@@ -1294,7 +1305,7 @@ innobase_init(void)
my_free(internal_innobase_data_file_path,
MYF(MY_ALLOW_ZERO_PTR));
- DBUG_RETURN(0);
+ goto error;
}
/* --------------------------------------------------*/
@@ -1382,7 +1393,7 @@ innobase_init(void)
if (err != DB_SUCCESS) {
my_free(internal_innobase_data_file_path,
MYF(MY_ALLOW_ZERO_PTR));
- DBUG_RETURN(0);
+ goto error;
}
(void) hash_init(&innobase_open_tables,system_charset_info, 32, 0, 0,
@@ -1409,7 +1420,10 @@ innobase_init(void)
glob_mi.pos = trx_sys_mysql_master_log_pos;
}
*/
- DBUG_RETURN(&innobase_hton);
+ DBUG_RETURN(FALSE);
+error:
+ have_innodb= SHOW_OPTION_DISABLED; // If we couldn't use handler
+ DBUG_RETURN(TRUE);
}
/***********************************************************************
@@ -2112,7 +2126,7 @@ innobase_rollback_to_savepoint(
/* TODO: use provided savepoint data area to store savepoint data */
- longlong2str((ulonglong)savepoint, name, 36);
+ longlong2str((ulint)savepoint, name, 36);
error = (int) trx_rollback_to_savepoint_for_mysql(trx, name,
&mysql_binlog_cache_pos);
@@ -2141,7 +2155,7 @@ innobase_release_savepoint(
/* TODO: use provided savepoint data area to store savepoint data */
- longlong2str((ulonglong)savepoint, name, 36);
+ longlong2str((ulint)savepoint, name, 36);
error = (int) trx_release_savepoint_for_mysql(trx, name);
@@ -2182,7 +2196,7 @@ innobase_savepoint(
/* TODO: use provided savepoint data area to store savepoint data */
char name[64];
- longlong2str((ulonglong)savepoint,name,36);
+ longlong2str((ulint)savepoint,name,36);
error = (int) trx_savepoint_for_mysql(trx, name, (ib_longlong)0);
@@ -2382,7 +2396,7 @@ ha_innobase::open(
"how you can resolve the problem.\n",
norm_name);
free_share(share);
- my_free((char*) upd_buff, MYF(0));
+ my_free((gptr) upd_buff, MYF(0));
my_errno = ENOENT;
DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
@@ -2400,7 +2414,7 @@ ha_innobase::open(
"how you can resolve the problem.\n",
norm_name);
free_share(share);
- my_free((char*) upd_buff, MYF(0));
+ my_free((gptr) upd_buff, MYF(0));
my_errno = ENOENT;
dict_table_decrement_handle_count(ib_table);
@@ -2488,13 +2502,13 @@ Closes a handle to an InnoDB table. */
int
ha_innobase::close(void)
/*====================*/
- /* out: error number */
+ /* out: 0 */
{
DBUG_ENTER("ha_innobase::close");
row_prebuilt_free((row_prebuilt_t*) innobase_prebuilt);
- my_free((char*) upd_buff, MYF(0));
+ my_free((gptr) upd_buff, MYF(0));
free_share(share);
/* Tell InnoDB server that there might be work for
@@ -4490,7 +4504,8 @@ create_index(
ulint is_unsigned;
ulint i;
ulint j;
-
+ ulint* field_lengths;
+
DBUG_ENTER("create_index");
key = form->key_info + key_num;
@@ -4512,6 +4527,10 @@ create_index(
index = dict_mem_index_create((char*) table_name, key->name, 0,
ind_type, n_fields);
+
+ field_lengths = (ulint*) my_malloc(sizeof(ulint) * n_fields,
+ MYF(MY_FAE));
+
for (i = 0; i < n_fields; i++) {
key_part = key->key_part + i;
@@ -4566,6 +4585,8 @@ create_index(
prefix_len = 0;
}
+ field_lengths[i] = key_part->length;
+
/* We assume all fields should be sorted in ascending
order, hence the '0': */
@@ -4574,10 +4595,12 @@ create_index(
0, prefix_len);
}
- error = row_create_index_for_mysql(index, trx);
+ error = row_create_index_for_mysql(index, trx, field_lengths);
error = convert_error_code_to_mysql(error, NULL);
+ my_free((gptr) field_lengths, MYF(0));
+
DBUG_RETURN(error);
}
@@ -4600,7 +4623,7 @@ create_clustered_index_when_no_primary(
index = dict_mem_index_create((char*) table_name,
(char*) "GEN_CLUST_INDEX",
0, DICT_CLUSTERED, 0);
- error = row_create_index_for_mysql(index, trx);
+ error = row_create_index_for_mysql(index, trx, NULL);
error = convert_error_code_to_mysql(error, NULL);
@@ -5136,7 +5159,7 @@ ha_innobase::records_in_range(
mysql_byte* key_val_buff2 = (mysql_byte*) my_malloc(
table->s->reclength
+ table->s->max_key_length + 100,
- MYF(MY_WME));
+ MYF(MY_FAE));
ulint buff2_len = table->s->reclength
+ table->s->max_key_length + 100;
dtuple_t* range_start;
@@ -5195,7 +5218,7 @@ ha_innobase::records_in_range(
dtuple_free_for_mysql(heap1);
dtuple_free_for_mysql(heap2);
- my_free((char*) key_val_buff2, MYF(0));
+ my_free((gptr) key_val_buff2, MYF(0));
prebuilt->trx->op_info = (char*)"";
@@ -5989,7 +6012,8 @@ int
ha_innobase::start_stmt(
/*====================*/
/* out: 0 or error code */
- THD* thd) /* in: handle to the user thread */
+ THD* thd, /* in: handle to the user thread */
+ thr_lock_type lock_type)
{
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
trx_t* trx;
@@ -6030,7 +6054,7 @@ ha_innobase::start_stmt(
} else {
if (trx->isolation_level != TRX_ISO_SERIALIZABLE
&& thd->lex->sql_command == SQLCOM_SELECT
- && thd->lex->lock_option == TL_READ) {
+ && lock_type == TL_READ) {
/* For other than temporary tables, we obtain
no lock for consistent read (plain SELECT). */
@@ -6063,6 +6087,8 @@ ha_innobase::start_stmt(
}
}
+ trx->detailed_error[0] = '\0';
+
/* Set the MySQL flag to mark that there is an active transaction */
if (trx->active_trans == 0) {
@@ -6136,6 +6162,8 @@ ha_innobase::external_lock(
if (lock_type != F_UNLCK) {
/* MySQL is setting a new table lock */
+ trx->detailed_error[0] = '\0';
+
/* Set the MySQL flag to mark that there is an active
transaction */
if (trx->active_trans == 0) {
@@ -6673,6 +6701,11 @@ ha_innobase::store_lock(
prebuilt->select_lock_type = LOCK_NONE;
prebuilt->stored_select_lock_type = LOCK_NONE;
+ } else if (thd->lex->sql_command == SQLCOM_CHECKSUM) {
+ /* Use consistent read for checksum table */
+
+ prebuilt->select_lock_type = LOCK_NONE;
+ prebuilt->stored_select_lock_type = LOCK_NONE;
} else {
prebuilt->select_lock_type = LOCK_S;
prebuilt->stored_select_lock_type = LOCK_S;
@@ -6939,6 +6972,18 @@ ha_innobase::reset_auto_increment(ulonglong value)
DBUG_RETURN(0);
}
+/* See comment in handler.cc */
+bool
+ha_innobase::get_error_message(int error, String *buf)
+{
+ trx_t* trx = check_trx_exists(current_thd);
+
+ buf->copy(trx->detailed_error, strlen(trx->detailed_error),
+ system_charset_info);
+
+ return FALSE;
+}
+
/***********************************************************************
Compares two 'refs'. A 'ref' is the (internal) primary key value of the row.
If there is no explicitly declared non-null unique key or a primary key, then
diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h
index 595ab5ccde2..d687e8bf160 100644
--- a/sql/ha_innodb.h
+++ b/sql/ha_innodb.h
@@ -150,7 +150,7 @@ class ha_innobase: public handler
int extra(enum ha_extra_function operation);
int external_lock(THD *thd, int lock_type);
int transactional_table_lock(THD *thd, int lock_type);
- int start_stmt(THD *thd);
+ int start_stmt(THD *thd, thr_lock_type lock_type);
int ha_retrieve_all_cols()
{
@@ -184,6 +184,8 @@ class ha_innobase: public handler
void init_table_handle_for_HANDLER();
ulonglong get_auto_increment();
int reset_auto_increment(ulonglong value);
+
+ virtual bool get_error_message(int error, String *buf);
uint8 table_cache_type() { return HA_CACHE_TBL_ASKTRANSACT; }
/*
@@ -251,7 +253,7 @@ extern ulong srv_commit_concurrency;
extern TYPELIB innobase_lock_typelib;
-handlerton *innobase_init(void);
+bool innobase_init(void);
bool innobase_end(void);
bool innobase_flush_logs(void);
uint innobase_get_free_space(void);
@@ -356,4 +358,4 @@ restored to a transaction read view. */
void
innobase_set_cursor_view(
/*=====================*/
- void* curview); /* in: Consistent read view to be closed */
+ void* curview); /* in: Consistent read view to be set */
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index 715ee3da8b9..689dbf2fc24 100644
--- a/sql/ha_myisam.cc
+++ b/sql/ha_myisam.cc
@@ -39,6 +39,12 @@ const char *myisam_recover_names[] =
TYPELIB myisam_recover_typelib= {array_elements(myisam_recover_names)-1,"",
myisam_recover_names, NULL};
+const char *myisam_stats_method_names[] = {"nulls_unequal", "nulls_equal",
+ NullS};
+TYPELIB myisam_stats_method_typelib= {
+ array_elements(myisam_stats_method_names) - 1, "",
+ myisam_stats_method_names, NULL};
+
/*****************************************************************************
** MyISAM tables
@@ -46,8 +52,12 @@ TYPELIB myisam_recover_typelib= {array_elements(myisam_recover_names)-1,"",
/* MyISAM handlerton */
-static handlerton myisam_hton= {
+handlerton myisam_hton= {
"MyISAM",
+ SHOW_OPTION_YES,
+ "Default engine as of MySQL 3.23 with great performance",
+ DB_TYPE_MYISAM,
+ NULL,
0, /* slot */
0, /* savepoint size. */
NULL, /* close_connection */
@@ -67,7 +77,7 @@ static handlerton myisam_hton= {
MyISAM doesn't support transactions and doesn't have
transaction-dependent context: cursors can survive a commit.
*/
- HTON_NO_FLAGS
+ HTON_CAN_RECREATE
};
// collect errors printed by mi_check routines
@@ -324,6 +334,7 @@ int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt)
param.db_name= table->s->db;
param.table_name= table->alias;
param.testflag = check_opt->flags | T_CHECK | T_SILENT;
+ param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method;
if (!(table->db_stat & HA_READ_ONLY))
param.testflag|= T_STATISTICS;
@@ -413,6 +424,7 @@ int ha_myisam::analyze(THD *thd, HA_CHECK_OPT* check_opt)
param.testflag= (T_FAST | T_CHECK | T_SILENT | T_STATISTICS |
T_DONT_CHECK_CHECKSUM);
param.using_global_keycache = 1;
+ param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method;
if (!(share->state.changed & STATE_NOT_ANALYZED))
return HA_ADMIN_ALREADY_DONE;
@@ -967,6 +979,7 @@ int ha_myisam::enable_indexes(uint mode)
T_CREATE_MISSING_KEYS);
param.myf_rw&= ~MY_WAIT_IF_FULL;
param.sort_buffer_length= thd->variables.myisam_sort_buff_size;
+ param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method;
param.tmpdir=&mysql_tmpdir_list;
if ((error= (repair(thd,param,0) != HA_ADMIN_OK)) && param.retry_repair)
{
@@ -1694,7 +1707,7 @@ int ha_myisam::ft_read(byte * buf)
uint ha_myisam::checksum() const
{
- return (uint)file->s->state.checksum;
+ return (uint)file->state->checksum;
}
diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc
index 388ecfb331f..cdea97bcea3 100644
--- a/sql/ha_myisammrg.cc
+++ b/sql/ha_myisammrg.cc
@@ -34,8 +34,12 @@
/* MyISAM MERGE handlerton */
-static handlerton myisammrg_hton= {
- "MRG_MyISAM",
+handlerton myisammrg_hton= {
+ "MRG_MYISAM",
+ SHOW_OPTION_YES,
+ "Collection of identical MyISAM tables",
+ DB_TYPE_MRG_MYISAM,
+ NULL,
0, /* slot */
0, /* savepoint size. */
NULL, /* close_connection */
@@ -51,7 +55,7 @@ static handlerton myisammrg_hton= {
NULL, /* create_cursor_read_view */
NULL, /* set_cursor_read_view */
NULL, /* close_cursor_read_view */
- HTON_NO_FLAGS
+ HTON_CAN_RECREATE
};
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index c7d281a1ba0..490d00c55d0 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -51,8 +51,12 @@ static int ndbcluster_close_connection(THD *thd);
static int ndbcluster_commit(THD *thd, bool all);
static int ndbcluster_rollback(THD *thd, bool all);
-static handlerton ndbcluster_hton = {
+handlerton ndbcluster_hton = {
"ndbcluster",
+ SHOW_OPTION_YES,
+ "Clustered, fault-tolerant, memory-based tables",
+ DB_TYPE_NDBCLUSTER,
+ ndbcluster_init,
0, /* slot */
0, /* savepoint size */
ndbcluster_close_connection,
@@ -1239,7 +1243,8 @@ inline ulong ha_ndbcluster::index_flags(uint idx_no, uint part,
DBUG_ENTER("ha_ndbcluster::index_flags");
DBUG_PRINT("info", ("idx_no: %d", idx_no));
DBUG_ASSERT(get_index_type_from_table(idx_no) < index_flags_size);
- DBUG_RETURN(index_type_flags[get_index_type_from_table(idx_no)]);
+ DBUG_RETURN(index_type_flags[get_index_type_from_table(idx_no)] |
+ HA_KEY_SCAN_NOT_ROR);
}
static void shrink_varchar(Field* field, const byte* & ptr, char* buf)
@@ -3390,7 +3395,7 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type)
startTransaction for each transaction/statement.
*/
-int ha_ndbcluster::start_stmt(THD *thd)
+int ha_ndbcluster::start_stmt(THD *thd, thr_lock_type lock_type)
{
int error=0;
DBUG_ENTER("start_stmt");
@@ -4701,11 +4706,14 @@ static int connect_callback()
return 0;
}
-handlerton *
-ndbcluster_init()
+bool ndbcluster_init()
{
int res;
DBUG_ENTER("ndbcluster_init");
+
+ if (have_ndbcluster != SHOW_OPTION_YES)
+ goto ndbcluster_init_error;
+
// Set connectstring if specified
if (opt_ndbcluster_connectstring != 0)
DBUG_PRINT("connectstring", ("%s", opt_ndbcluster_connectstring));
@@ -4786,16 +4794,17 @@ ndbcluster_init()
}
ndbcluster_inited= 1;
- DBUG_RETURN(&ndbcluster_hton);
+ DBUG_RETURN(FALSE);
- ndbcluster_init_error:
+ndbcluster_init_error:
if (g_ndb)
delete g_ndb;
g_ndb= NULL;
if (g_ndb_cluster_connection)
delete g_ndb_cluster_connection;
g_ndb_cluster_connection= NULL;
- DBUG_RETURN(NULL);
+ have_ndbcluster= SHOW_OPTION_DISABLED; // If we couldn't use handler
+ DBUG_RETURN(TRUE);
}
@@ -7472,6 +7481,50 @@ ha_ndbcluster::generate_scan_filter(Ndb_cond_stack *ndb_cond_stack,
DBUG_RETURN(0);
}
+int
+ndbcluster_show_status(THD* thd)
+{
+ Protocol *protocol= thd->protocol;
+
+ DBUG_ENTER("ndbcluster_show_status");
+
+ if (have_ndbcluster != SHOW_OPTION_YES)
+ {
+ my_message(ER_NOT_SUPPORTED_YET,
+ "Cannot call SHOW NDBCLUSTER STATUS because skip-ndbcluster is defined",
+ MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+
+ List<Item> field_list;
+ field_list.push_back(new Item_empty_string("free_list", 255));
+ field_list.push_back(new Item_return_int("created", 10,MYSQL_TYPE_LONG));
+ field_list.push_back(new Item_return_int("free", 10,MYSQL_TYPE_LONG));
+ field_list.push_back(new Item_return_int("sizeof", 10,MYSQL_TYPE_LONG));
+
+ if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
+ DBUG_RETURN(TRUE);
+
+ if (get_thd_ndb(thd) && get_thd_ndb(thd)->ndb)
+ {
+ Ndb* ndb= (get_thd_ndb(thd))->ndb;
+ Ndb::Free_list_usage tmp; tmp.m_name= 0;
+ while (ndb->get_free_list_usage(&tmp))
+ {
+ protocol->prepare_for_resend();
+
+ protocol->store(tmp.m_name, &my_charset_bin);
+ protocol->store((uint)tmp.m_created);
+ protocol->store((uint)tmp.m_free);
+ protocol->store((uint)tmp.m_sizeof);
+ if (protocol->write())
+ DBUG_RETURN(TRUE);
+ }
+ }
+ send_eof(thd);
+
+ DBUG_RETURN(FALSE);
+}
/*
Create a table in NDB Cluster
diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h
index 0d99e9c1220..4530e5f1977 100644
--- a/sql/ha_ndbcluster.h
+++ b/sql/ha_ndbcluster.h
@@ -510,7 +510,7 @@ class ha_ndbcluster: public handler
int extra(enum ha_extra_function operation);
int extra_opt(enum ha_extra_function operation, ulong cache_size);
int external_lock(THD *thd, int lock_type);
- int start_stmt(THD *thd);
+ int start_stmt(THD *thd, thr_lock_type lock_type);
const char * table_type() const;
const char ** bas_ext() const;
ulong table_flags(void) const;
@@ -746,7 +746,7 @@ private:
extern struct show_var_st ndb_status_variables[];
-handlerton *ndbcluster_init(void);
+bool ndbcluster_init(void);
bool ndbcluster_end(void);
int ndbcluster_discover(THD* thd, const char* dbname, const char* name,
@@ -758,3 +758,5 @@ int ndbcluster_table_exists_in_engine(THD* thd,
int ndbcluster_drop_database(const char* path);
void ndbcluster_print_error(int error, const NdbOperation *error_op);
+
+int ndbcluster_show_status(THD*);
diff --git a/sql/handler.cc b/sql/handler.cc
index 8c8904b1df0..5b07c9e9c24 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -25,42 +25,110 @@
#include "ha_heap.h"
#include "ha_myisam.h"
#include "ha_myisammrg.h"
+
+
+/*
+ We have dummy hanldertons in case the handler has not been compiled
+ in. This will be removed in 5.1.
+*/
#ifdef HAVE_BERKELEY_DB
#include "ha_berkeley.h"
+extern handlerton berkeley_hton;
+#else
+handlerton berkeley_hton = { "BerkeleyDB", SHOW_OPTION_NO,
+ "Supports transactions and page-level locking", DB_TYPE_BERKELEY_DB, NULL,
+ 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, HTON_NO_FLAGS };
#endif
#ifdef HAVE_BLACKHOLE_DB
#include "ha_blackhole.h"
+extern handlerton blackhole_hton;
+#else
+handlerton blackhole_hton = { "BLACKHOLE", SHOW_OPTION_NO,
+ "/dev/null storage engine (anything you write to it disappears)",
+ DB_TYPE_BLACKHOLE_DB, NULL, 0, 0, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ HTON_NO_FLAGS };
#endif
#ifdef HAVE_EXAMPLE_DB
#include "examples/ha_example.h"
+extern handlerton example_hton;
+#else
+handlerton example_hton = { "EXAMPLE", SHOW_OPTION_NO,
+ "Example storage engine",
+ DB_TYPE_EXAMPLE_DB, NULL, 0, 0, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ HTON_NO_FLAGS };
#endif
#ifdef HAVE_PARTITION_DB
#include "ha_partition.h"
#endif
#ifdef HAVE_ARCHIVE_DB
-#include "examples/ha_archive.h"
+#include "ha_archive.h"
+extern handlerton archive_hton;
+#else
+handlerton archive_hton = { "ARCHIVE", SHOW_OPTION_NO,
+ "Archive storage engine", DB_TYPE_ARCHIVE_DB, NULL, 0, 0, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ HTON_NO_FLAGS };
#endif
#ifdef HAVE_CSV_DB
#include "examples/ha_tina.h"
+extern handlerton tina_hton;
+#else
+handlerton tina_hton = { "CSV", SHOW_OPTION_NO, "CSV storage engine",
+ DB_TYPE_CSV_DB, NULL, 0, 0, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ HTON_NO_FLAGS };
#endif
#ifdef HAVE_INNOBASE_DB
#include "ha_innodb.h"
+extern handlerton innobase_hton;
+#else
+handlerton innobase_hton = { "InnoDB", SHOW_OPTION_NO,
+ "Supports transactions, row-level locking, and foreign keys",
+ DB_TYPE_INNODB, NULL, 0, 0, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ HTON_NO_FLAGS };
#endif
#ifdef HAVE_NDBCLUSTER_DB
#include "ha_ndbcluster.h"
+extern handlerton ndbcluster_hton;
+#else
+handlerton ndbcluster_hton = { "ndbcluster", SHOW_OPTION_NO,
+ "Clustered, fault-tolerant, memory-based tables",
+ DB_TYPE_NDBCLUSTER, NULL, 0, 0, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ HTON_NO_FLAGS };
#endif
#ifdef HAVE_FEDERATED_DB
#include "ha_federated.h"
+extern handlerton federated_hton;
+#else
+handlerton federated_hton = { "FEDERATED", SHOW_OPTION_NO,
+ "Federated MySQL storage engine", DB_TYPE_FEDERATED_DB, NULL, 0, 0, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ HTON_NO_FLAGS };
#endif
#include <myisampack.h>
#include <errno.h>
- /* static functions defined in this file */
+extern handlerton myisam_hton;
+extern handlerton myisammrg_hton;
+extern handlerton heap_hton;
+extern handlerton binlog_hton;
-static SHOW_COMP_OPTION have_yes= SHOW_OPTION_YES;
+/*
+ Obsolete
+*/
+handlerton isam_hton = { "ISAM", SHOW_OPTION_NO, "Obsolete storage engine",
+ DB_TYPE_ISAM, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, HTON_NO_FLAGS };
-/* list of all available storage engines (of their handlertons) */
-handlerton *handlertons[MAX_HA]={0};
+
+/* static functions defined in this file */
+
+static SHOW_COMP_OPTION have_yes= SHOW_OPTION_YES;
/* number of entries in handlertons[] */
ulong total_ha;
@@ -69,46 +137,35 @@ ulong total_ha_2pc;
/* size of savepoint storage area (see ha_init) */
ulong savepoint_alloc_size;
-struct show_table_type_st sys_table_types[]=
-{
- {"MyISAM", &have_yes,
- "Default engine as of MySQL 3.23 with great performance", DB_TYPE_MYISAM},
- {"MEMORY", &have_yes,
- "Hash based, stored in memory, useful for temporary tables", DB_TYPE_HEAP},
- {"HEAP", &have_yes,
- "Alias for MEMORY", DB_TYPE_HEAP},
- {"MERGE", &have_yes,
- "Collection of identical MyISAM tables", DB_TYPE_MRG_MYISAM},
- {"MRG_MYISAM",&have_yes,
- "Alias for MERGE", DB_TYPE_MRG_MYISAM},
- {"ISAM", &have_isam,
- "Obsolete storage engine, now replaced by MyISAM", DB_TYPE_ISAM},
- {"MRG_ISAM", &have_isam,
- "Obsolete storage engine, now replaced by MERGE", DB_TYPE_MRG_ISAM},
- {"InnoDB", &have_innodb,
- "Supports transactions, row-level locking, and foreign keys", DB_TYPE_INNODB},
- {"INNOBASE", &have_innodb,
- "Alias for INNODB", DB_TYPE_INNODB},
- {"BDB", &have_berkeley_db,
- "Supports transactions and page-level locking", DB_TYPE_BERKELEY_DB},
- {"BERKELEYDB",&have_berkeley_db,
- "Alias for BDB", DB_TYPE_BERKELEY_DB},
- {"NDBCLUSTER", &have_ndbcluster,
- "Clustered, fault-tolerant, memory-based tables", DB_TYPE_NDBCLUSTER},
- {"NDB", &have_ndbcluster,
- "Alias for NDBCLUSTER", DB_TYPE_NDBCLUSTER},
- {"EXAMPLE",&have_example_db,
- "Example storage engine", DB_TYPE_EXAMPLE_DB},
- {"ARCHIVE",&have_archive_db,
- "Archive storage engine", DB_TYPE_ARCHIVE_DB},
- {"CSV",&have_csv_db,
- "CSV storage engine", DB_TYPE_CSV_DB},
- {"FEDERATED",&have_federated_db,
- "Federated MySQL storage engine", DB_TYPE_FEDERATED_DB},
- {"BLACKHOLE",&have_blackhole_db,
- "/dev/null storage engine (anything you write to it disappears)",
- DB_TYPE_BLACKHOLE_DB},
- {NullS, NULL, NullS, DB_TYPE_UNKNOWN}
+/*
+ This array is used for processing compiled in engines.
+*/
+handlerton *sys_table_types[]=
+{
+ &myisam_hton,
+ &heap_hton,
+ &innobase_hton,
+ &berkeley_hton,
+ &blackhole_hton,
+ &example_hton,
+ &archive_hton,
+ &tina_hton,
+ &ndbcluster_hton,
+ &federated_hton,
+ &myisammrg_hton,
+ &binlog_hton,
+ &isam_hton,
+ NULL
+};
+
+struct show_table_alias_st sys_table_aliases[]=
+{
+ {"INNOBASE", "InnoDB"},
+ {"NDB", "NDBCLUSTER"},
+ {"BDB", "BERKELEYDB"},
+ {"HEAP", "MEMORY"},
+ {"MERGE", "MRG_MYISAM"},
+ {NullS, NullS}
};
const char *ha_row_type[] = {
@@ -127,46 +184,78 @@ uint known_extensions_id= 0;
enum db_type ha_resolve_by_name(const char *name, uint namelen)
{
THD *thd= current_thd;
- if (thd && !my_strcasecmp(&my_charset_latin1, name, "DEFAULT")) {
+ show_table_alias_st *table_alias;
+ handlerton **types;
+ const char *ptr= name;
+
+ if (thd && !my_strcasecmp(&my_charset_latin1, ptr, "DEFAULT"))
return (enum db_type) thd->variables.table_type;
+
+retest:
+ for (types= sys_table_types; *types; types++)
+ {
+ if (!my_strcasecmp(&my_charset_latin1, ptr, (*types)->name))
+ return (enum db_type) (*types)->db_type;
}
- show_table_type_st *types;
- for (types= sys_table_types; types->type; types++)
+ /*
+ We check for the historical aliases.
+ */
+ for (table_alias= sys_table_aliases; table_alias->type; table_alias++)
{
- if (!my_strcasecmp(&my_charset_latin1, name, types->type))
- return (enum db_type) types->db_type;
+ if (!my_strcasecmp(&my_charset_latin1, ptr, table_alias->alias))
+ {
+ ptr= table_alias->type;
+ goto retest;
+ }
}
+
return DB_TYPE_UNKNOWN;
}
-
const char *ha_get_storage_engine(enum db_type db_type)
{
- show_table_type_st *types;
- for (types= sys_table_types; types->type; types++)
+ handlerton **types;
+ for (types= sys_table_types; *types; types++)
{
- if (db_type == types->db_type)
- return types->type;
+ if (db_type == (*types)->db_type)
+ return (*types)->name;
}
return "none";
}
+bool ha_check_storage_engine_flag(enum db_type db_type, uint32 flag)
+{
+ handlerton **types;
+ for (types= sys_table_types; *types; types++)
+ {
+ if (db_type == (*types)->db_type)
+ {
+ if ((*types)->flags & flag)
+ return TRUE;
+ else
+ return FALSE;
+ }
+ }
+
+ return FALSE;
+}
+
my_bool ha_storage_engine_is_enabled(enum db_type database_type)
{
- show_table_type_st *types;
- for (types= sys_table_types; types->type; types++)
+ handlerton **types;
+ for (types= sys_table_types; *types; types++)
{
- if ((database_type == types->db_type) &&
- (*types->value == SHOW_OPTION_YES))
+ if ((database_type == (*types)->db_type) &&
+ ((*types)->state == SHOW_OPTION_YES))
return TRUE;
}
return FALSE;
}
- /* Use other database handler if databasehandler is not incompiled */
+/* Use other database handler if databasehandler is not compiled in */
enum db_type ha_checktype(THD *thd, enum db_type database_type,
bool no_substitute, bool report_error)
@@ -372,8 +461,8 @@ static int ha_init_errors(void)
SETMSG(HA_ERR_READ_ONLY_TRANSACTION, ER(ER_READ_ONLY_TRANSACTION));
SETMSG(HA_ERR_LOCK_DEADLOCK, ER(ER_LOCK_DEADLOCK));
SETMSG(HA_ERR_CANNOT_ADD_FOREIGN, ER(ER_CANNOT_ADD_FOREIGN));
- SETMSG(HA_ERR_NO_REFERENCED_ROW, ER(ER_NO_REFERENCED_ROW));
- SETMSG(HA_ERR_ROW_IS_REFERENCED, ER(ER_ROW_IS_REFERENCED));
+ SETMSG(HA_ERR_NO_REFERENCED_ROW, ER(ER_NO_REFERENCED_ROW_2));
+ SETMSG(HA_ERR_ROW_IS_REFERENCED, ER(ER_ROW_IS_REFERENCED_2));
SETMSG(HA_ERR_NO_SAVEPOINT, "No savepoint with that name");
SETMSG(HA_ERR_NON_UNIQUE_BLOCK_SIZE, "Non unique key block size");
SETMSG(HA_ERR_NO_SUCH_TABLE, "No such table: '%.64s'");
@@ -422,81 +511,24 @@ static inline void ha_was_inited_ok(handlerton **ht)
int ha_init()
{
int error= 0;
- handlerton **ht= handlertons;
+ handlerton **types;
+ show_table_alias_st *table_alias;
total_ha= savepoint_alloc_size= 0;
if (ha_init_errors())
return 1;
- if (opt_bin_log)
- {
- if (!(*ht= binlog_init())) // Always succeed
- {
- mysql_bin_log.close(LOG_CLOSE_INDEX); // Never used
- opt_bin_log= 0; // Never used
- error= 1; // Never used
- }
- else
- ha_was_inited_ok(ht++);
- }
-#ifdef HAVE_BERKELEY_DB
- if (have_berkeley_db == SHOW_OPTION_YES)
- {
- if (!(*ht= berkeley_init()))
- {
- have_berkeley_db= SHOW_OPTION_DISABLED; // If we couldn't use handler
- error= 1;
- }
- else
- ha_was_inited_ok(ht++);
- }
-#endif
-#ifdef HAVE_INNOBASE_DB
- if (have_innodb == SHOW_OPTION_YES)
- {
- if (!(*ht= innobase_init()))
- {
- have_innodb= SHOW_OPTION_DISABLED; // If we couldn't use handler
- error= 1;
- }
- else
- ha_was_inited_ok(ht++);
- }
-#endif
-#ifdef HAVE_NDBCLUSTER_DB
- if (have_ndbcluster == SHOW_OPTION_YES)
- {
- if (!(*ht= ndbcluster_init()))
- {
- have_ndbcluster= SHOW_OPTION_DISABLED;
- error= 1;
- }
- else
- ha_was_inited_ok(ht++);
- }
-#endif
-#ifdef HAVE_FEDERATED_DB
- if (have_federated_db == SHOW_OPTION_YES)
- {
- if (federated_db_init())
- {
- have_federated_db= SHOW_OPTION_DISABLED;
- error= 1;
- }
- }
-#endif
-#ifdef HAVE_ARCHIVE_DB
- if (have_archive_db == SHOW_OPTION_YES)
+ /*
+ We now initialize everything here.
+ */
+ for (types= sys_table_types; *types; types++)
{
- if (!(*ht= archive_db_init()))
- {
- have_archive_db= SHOW_OPTION_DISABLED;
- error= 1;
- }
+ if (!(*types)->init || !(*types)->init())
+ ha_was_inited_ok(types);
else
- ha_was_inited_ok(ht++);
+ (*types)->state= SHOW_OPTION_DISABLED;
}
-#endif
+
DBUG_ASSERT(total_ha < MAX_HA);
/*
Check if there is a transaction-capable storage engine besides the
@@ -544,6 +576,10 @@ int ha_panic(enum ha_panic_function flag)
if (have_archive_db == SHOW_OPTION_YES)
error|= archive_db_end();
#endif
+#ifdef HAVE_CSV_DB
+ if (have_csv_db == SHOW_OPTION_YES)
+ error|= tina_end();
+#endif
if (ha_finish_errors())
error= 1;
return error;
@@ -564,9 +600,10 @@ void ha_drop_database(char* path)
/* don't bother to rollback here, it's done already */
void ha_close_connection(THD* thd)
{
- for (uint i=0; i < total_ha; i++)
- if (thd->ha_data[i])
- (*handlertons[i]->close_connection)(thd);
+ handlerton **types;
+ for (types= sys_table_types; *types; types++)
+ if (thd->ha_data[(*types)->slot])
+ (*types)->close_connection(thd);
}
/* ========================================================================
@@ -877,13 +914,13 @@ int ha_autocommit_or_rollback(THD *thd, int error)
int ha_commit_or_rollback_by_xid(XID *xid, bool commit)
{
- handlerton **ht= handlertons, **end_ht=ht+total_ha;
+ handlerton **types;
int res= 1;
- for ( ; ht < end_ht ; ht++)
- if ((*ht)->recover)
+ for (types= sys_table_types; *types; types++)
+ if ((*types)->state == SHOW_OPTION_YES && (*types)->recover)
res= res &&
- (*(commit ? (*ht)->commit_by_xid : (*ht)->rollback_by_xid))(xid);
+ (*(commit ? (*types)->commit_by_xid : (*types)->rollback_by_xid))(xid);
return res;
}
@@ -962,7 +999,7 @@ static char* xid_to_str(char *buf, XID *xid)
int ha_recover(HASH *commit_list)
{
int len, got, found_foreign_xids=0, found_my_xids=0;
- handlerton **ht= handlertons, **end_ht=ht+total_ha;
+ handlerton **types;
XID *list=0;
bool dry_run=(commit_list==0 && tc_heuristic_recover==0);
DBUG_ENTER("ha_recover");
@@ -998,14 +1035,14 @@ int ha_recover(HASH *commit_list)
DBUG_RETURN(1);
}
- for ( ; ht < end_ht ; ht++)
+ for (types= sys_table_types; *types; types++)
{
- if (!(*ht)->recover)
+ if ((*types)->state != SHOW_OPTION_YES || !(*types)->recover)
continue;
- while ((got=(*(*ht)->recover)(list, len)) > 0 )
+ while ((got=(*(*types)->recover)(list, len)) > 0 )
{
sql_print_information("Found %d prepared transaction(s) in %s",
- got, (*ht)->name);
+ got, (*types)->name);
for (int i=0; i < got; i ++)
{
my_xid x=list[i].get_my_xid();
@@ -1033,7 +1070,7 @@ int ha_recover(HASH *commit_list)
char buf[XIDDATASIZE*4+6]; // see xid_to_str
sql_print_information("commit xid %s", xid_to_str(buf, list+i));
#endif
- (*(*ht)->commit_by_xid)(list+i);
+ (*(*types)->commit_by_xid)(list+i);
}
else
{
@@ -1041,7 +1078,7 @@ int ha_recover(HASH *commit_list)
char buf[XIDDATASIZE*4+6]; // see xid_to_str
sql_print_information("rollback xid %s", xid_to_str(buf, list+i));
#endif
- (*(*ht)->rollback_by_xid)(list+i);
+ (*(*types)->rollback_by_xid)(list+i);
}
}
if (got < len)
@@ -1401,11 +1438,9 @@ int handler::ha_open(const char *name, int mode, int test_if_locked)
table->db_stat|=HA_READ_ONLY;
(void) extra(HA_EXTRA_NO_READCHECK); // Not needed in SQL
- if (!alloc_root_inited(&table->mem_root)) // If temporary table
- ref=(byte*) sql_alloc(ALIGN_SIZE(ref_length)*2);
- else
- ref=(byte*) alloc_root(&table->mem_root, ALIGN_SIZE(ref_length)*2);
- if (!ref)
+ DBUG_ASSERT(alloc_root_inited(&table->mem_root));
+
+ if (!(ref= (byte*) alloc_root(&table->mem_root, ALIGN_SIZE(ref_length)*2)))
{
close();
error=HA_ERR_OUT_OF_MEM;
@@ -1870,11 +1905,19 @@ void handler::print_error(int error, myf errflag)
textno=ER_CANNOT_ADD_FOREIGN;
break;
case HA_ERR_ROW_IS_REFERENCED:
- textno=ER_ROW_IS_REFERENCED;
- break;
+ {
+ String str;
+ get_error_message(error, &str);
+ my_error(ER_ROW_IS_REFERENCED_2, MYF(0), str.c_ptr_safe());
+ DBUG_VOID_RETURN;
+ }
case HA_ERR_NO_REFERENCED_ROW:
- textno=ER_NO_REFERENCED_ROW;
- break;
+ {
+ String str;
+ get_error_message(error, &str);
+ my_error(ER_NO_REFERENCED_ROW_2, MYF(0), str.c_ptr_safe());
+ DBUG_VOID_RETURN;
+ }
case HA_ERR_TABLE_DEF_CHANGED:
textno=ER_TABLE_DEF_CHANGED;
break;
@@ -2585,7 +2628,7 @@ TYPELIB *ha_known_exts(void)
{
if (!known_extensions.type_names || mysys_usage_id != known_extensions_id)
{
- show_table_type_st *types;
+ handlerton **types;
List<char> found_exts;
List_iterator_fast<char> it(found_exts);
const char **ext, *old_ext;
@@ -2593,11 +2636,11 @@ TYPELIB *ha_known_exts(void)
known_extensions_id= mysys_usage_id;
found_exts.push_back((char*) triggers_file_ext);
found_exts.push_back((char*) trigname_file_ext);
- for (types= sys_table_types; types->type; types++)
+ for (types= sys_table_types; *types; types++)
{
- if (*types->value == SHOW_OPTION_YES)
+ if ((*types)->state == SHOW_OPTION_YES)
{
- handler *file= get_new_handler(0,(enum db_type) types->db_type);
+ handler *file= get_new_handler(0,(enum db_type) (*types)->db_type);
for (ext= file->bas_ext(); *ext; ext++)
{
while ((old_ext= it++))
diff --git a/sql/handler.h b/sql/handler.h
index bd935da2a80..2347c03ae2d 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -107,6 +107,13 @@
#define HA_ONLINE_ADD_EMPTY_PARTITION 1
#define HA_ONLINE_DROP_PARTITION 2
+/*
+ Index scan will not return records in rowid order. Not guaranteed to be
+ set for unordered (e.g. HASH) indexes.
+*/
+#define HA_KEY_SCAN_NOT_ROR 128
+
+
/* operations for disable/enable indexes */
#define HA_KEY_SWITCH_NONUNIQ 0
#define HA_KEY_SWITCH_ALL 1
@@ -187,13 +194,6 @@ enum db_type
DB_TYPE_DEFAULT // Must be last
};
-struct show_table_type_st {
- const char *type;
- SHOW_COMP_OPTION *value;
- const char *comment;
- enum db_type db_type;
-};
-
enum row_type { ROW_TYPE_NOT_USED=-1, ROW_TYPE_DEFAULT, ROW_TYPE_FIXED,
ROW_TYPE_DYNAMIC, ROW_TYPE_COMPRESSED,
ROW_TYPE_REDUNDANT, ROW_TYPE_COMPACT };
@@ -241,7 +241,7 @@ struct xid_t {
char data[XIDDATASIZE]; // not \0-terminated !
bool eq(struct xid_t *xid)
- { return !memcmp(this, xid, length()); }
+ { return eq(xid->gtrid_length, xid->bqual_length, xid->data); }
bool eq(long g, long b, const char *d)
{ return g == gtrid_length && b == bqual_length && !memcmp(d, data, g+b); }
void set(struct xid_t *xid)
@@ -289,6 +289,14 @@ struct xid_t {
return sizeof(formatID)+sizeof(gtrid_length)+sizeof(bqual_length)+
gtrid_length+bqual_length;
}
+ byte *key()
+ {
+ return (byte *)&gtrid_length;
+ }
+ uint key_length()
+ {
+ return sizeof(gtrid_length)+sizeof(bqual_length)+gtrid_length+bqual_length;
+ }
};
typedef struct xid_t XID;
@@ -317,6 +325,27 @@ typedef struct
storage engine name as it should be printed to a user
*/
const char *name;
+
+ /*
+ Historical marker for if the engine is available of not
+ */
+ SHOW_COMP_OPTION state;
+
+ /*
+ A comment used by SHOW to describe an engine.
+ */
+ const char *comment;
+
+ /*
+ Historical number used for frm file to determine the correct storage engine.
+ This is going away and new engines will just use "name" for this.
+ */
+ enum db_type db_type;
+ /*
+ Method that initizlizes a storage engine
+ */
+ bool (*init)();
+
/*
each storage engine has it's own memory area (actually a pointer)
in the thd, for storing per-connection information.
@@ -376,9 +405,16 @@ typedef struct
uint32 flags; /* global handler flags */
} handlerton;
+struct show_table_alias_st {
+ const char *alias;
+ const char *type;
+};
+
/* Possible flags of a handlerton */
-#define HTON_NO_FLAGS 0
-#define HTON_CLOSE_CURSORS_AT_COMMIT 1
+#define HTON_NO_FLAGS 0
+#define HTON_CLOSE_CURSORS_AT_COMMIT (1 << 0)
+#define HTON_ALTER_NOT_SUPPORTED (1 << 1)
+#define HTON_CAN_RECREATE (1 << 2)
typedef struct st_thd_trans
{
@@ -1121,7 +1157,7 @@ public:
{ return extra(operation); }
virtual int external_lock(THD *thd, int lock_type) { return 0; }
virtual void unlock_row() {}
- virtual int start_stmt(THD *thd) {return 0;}
+ virtual int start_stmt(THD *thd, thr_lock_type lock_type) {return 0;}
/*
This is called to delete all rows in a table
If the handler don't support this, then this function will
@@ -1338,10 +1374,10 @@ public:
/* Some extern variables used with handlers */
-extern struct show_table_type_st sys_table_types[];
+extern handlerton *sys_table_types[];
extern const char *ha_row_type[];
extern TYPELIB tx_isolation_typelib;
-extern handlerton *handlertons[MAX_HA];
+extern TYPELIB myisam_stats_method_typelib;
extern ulong total_ha, total_ha_2pc;
/* Wrapper functions */
@@ -1350,18 +1386,13 @@ extern ulong total_ha, total_ha_2pc;
#define ha_commit(thd) (ha_commit_trans((thd), TRUE))
#define ha_rollback(thd) (ha_rollback_trans((thd), TRUE))
-#define ha_supports_generate(T) (T != DB_TYPE_INNODB && \
- T != DB_TYPE_BERKELEY_DB && \
- T != DB_TYPE_ARCHIVE_DB && \
- T != DB_TYPE_FEDERATED_DB && \
- T != DB_TYPE_NDBCLUSTER)
-
/* lookups */
enum db_type ha_resolve_by_name(const char *name, uint namelen);
const char *ha_get_storage_engine(enum db_type db_type);
handler *get_new_handler(TABLE *table, enum db_type db_type);
enum db_type ha_checktype(THD *thd, enum db_type database_type,
bool no_substitute, bool report_error);
+bool ha_check_storage_engine_flag(enum db_type db_type, uint32 flag);
/* basic stuff */
int ha_init(void);
diff --git a/sql/item.cc b/sql/item.cc
index 60ea00e1b89..5caac05f6ca 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -904,6 +904,7 @@ bool Item_splocal::fix_fields(THD *, Item **)
DBUG_ASSERT(it->fixed);
max_length= it->max_length;
decimals= it->decimals;
+ unsigned_flag= it->unsigned_flag;
fixed= 1;
return FALSE;
}
@@ -1687,7 +1688,7 @@ bool Item_field::eq(const Item *item, bool binary_cmp) const
return 0;
Item_field *item_field= (Item_field*) item;
- if (item_field->field)
+ if (item_field->field && field)
return item_field->field == field;
/*
We may come here when we are trying to find a function in a GROUP BY
@@ -1701,10 +1702,10 @@ bool Item_field::eq(const Item *item, bool binary_cmp) const
*/
return (!my_strcasecmp(system_charset_info, item_field->name,
field_name) &&
- (!item_field->table_name ||
+ (!item_field->table_name || !table_name ||
(!my_strcasecmp(table_alias_charset, item_field->table_name,
table_name) &&
- (!item_field->db_name ||
+ (!item_field->db_name || !db_name ||
(item_field->db_name && !strcmp(item_field->db_name,
db_name))))));
}
@@ -1804,6 +1805,7 @@ Item_decimal::Item_decimal(const char *str_arg, uint length,
name= (char*) str_arg;
decimals= (uint8) decimal_value.frac;
fixed= 1;
+ unsigned_flag= !decimal_value.sign();
max_length= my_decimal_precision_to_length(decimal_value.intg + decimals,
decimals, unsigned_flag);
}
@@ -1813,6 +1815,7 @@ Item_decimal::Item_decimal(longlong val, bool unsig)
int2my_decimal(E_DEC_FATAL_ERROR, val, unsig, &decimal_value);
decimals= (uint8) decimal_value.frac;
fixed= 1;
+ unsigned_flag= !decimal_value.sign();
max_length= my_decimal_precision_to_length(decimal_value.intg + decimals,
decimals, unsigned_flag);
}
@@ -1823,6 +1826,7 @@ Item_decimal::Item_decimal(double val, int precision, int scale)
double2my_decimal(E_DEC_FATAL_ERROR, val, &decimal_value);
decimals= (uint8) decimal_value.frac;
fixed= 1;
+ unsigned_flag= !decimal_value.sign();
max_length= my_decimal_precision_to_length(decimal_value.intg + decimals,
decimals, unsigned_flag);
}
@@ -1835,6 +1839,7 @@ Item_decimal::Item_decimal(const char *str, const my_decimal *val_arg,
name= (char*) str;
decimals= (uint8) decimal_par;
max_length= length;
+ unsigned_flag= !decimal_value.sign();
fixed= 1;
}
@@ -1844,8 +1849,9 @@ Item_decimal::Item_decimal(my_decimal *value_par)
my_decimal2decimal(value_par, &decimal_value);
decimals= (uint8) decimal_value.frac;
fixed= 1;
+ unsigned_flag= !decimal_value.sign();
max_length= my_decimal_precision_to_length(decimal_value.intg + decimals,
- decimals, !decimal_value.sign());
+ decimals, unsigned_flag);
}
@@ -1855,8 +1861,9 @@ Item_decimal::Item_decimal(const char *bin, int precision, int scale)
&decimal_value, precision, scale);
decimals= (uint8) decimal_value.frac;
fixed= 1;
+ unsigned_flag= !decimal_value.sign();
max_length= my_decimal_precision_to_length(precision, decimals,
- !decimal_value.sign());
+ unsigned_flag);
}
@@ -2966,7 +2973,7 @@ static Item** find_field_in_group_list(Item *find_item, ORDER *group_list)
const char *field_name;
ORDER *found_group= NULL;
int found_match_degree= 0;
- Item_field *cur_field;
+ Item_ident *cur_field;
int cur_match_degree= 0;
if (find_item->type() == Item::FIELD_ITEM ||
@@ -2983,9 +2990,9 @@ static Item** find_field_in_group_list(Item *find_item, ORDER *group_list)
for (ORDER *cur_group= group_list ; cur_group ; cur_group= cur_group->next)
{
- if ((*(cur_group->item))->type() == Item::FIELD_ITEM)
+ if ((*(cur_group->item))->real_item()->type() == Item::FIELD_ITEM)
{
- cur_field= (Item_field*) *cur_group->item;
+ cur_field= (Item_ident*) *cur_group->item;
cur_match_degree= 0;
DBUG_ASSERT(cur_field->field_name != 0);
@@ -3448,8 +3455,8 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
VIEW_ANY_ACL)))
{
my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0),
- "ANY", thd->priv_user, thd->host_or_ip,
- field_name, tab);
+ "ANY", thd->security_ctx->priv_user,
+ thd->security_ctx->host_or_ip, field_name, tab);
goto error;
}
}
@@ -5232,6 +5239,36 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item)
(Item*) new Item_int(name, result, length));
break;
}
+ case ROW_RESULT:
+ {
+ new_item= 0;
+ /*
+ If item and comp_item are both Item_rows and have same number of cols
+ then process items in Item_row one by one. If Item_row contain nulls
+ substitute it by Item_null. Otherwise just return.
+ */
+ if (item->result_type() == comp_item->result_type() &&
+ ((Item_row*)item)->cols() == ((Item_row*)comp_item)->cols())
+ {
+ Item_row *item_row= (Item_row*)item,*comp_item_row= (Item_row*)comp_item;
+ if (item_row->null_inside())
+ new_item= (Item*) new Item_null(name);
+ else
+ {
+ int i= item_row->cols() - 1;
+ for (; i >= 0; i--)
+ {
+ if (item_row->maybe_null && item_row->el(i)->is_null())
+ {
+ new_item= (Item*) new Item_null(name);
+ break;
+ }
+ resolve_const_item(thd, item_row->addr(i), comp_item_row->el(i));
+ }
+ }
+ }
+ break;
+ }
case REAL_RESULT:
{ // It must REAL_RESULT
double result= item->val_real();
@@ -5252,7 +5289,6 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item)
(Item*) new Item_decimal(name, result, length, decimals));
break;
}
- case ROW_RESULT:
default:
DBUG_ASSERT(0);
}
diff --git a/sql/item.h b/sql/item.h
index 381ba98e193..a8f013f60d4 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -164,6 +164,7 @@ struct Hybrid_type_traits
virtual my_decimal *val_decimal(Hybrid_type *val, my_decimal *buf) const;
virtual String *val_str(Hybrid_type *val, String *buf, uint8 decimals) const;
static const Hybrid_type_traits *instance();
+ Hybrid_type_traits() {};
};
@@ -185,6 +186,7 @@ struct Hybrid_type_traits_decimal: public Hybrid_type_traits
{ return &val->dec_buf[val->used_dec_buf_no]; }
virtual String *val_str(Hybrid_type *val, String *buf, uint8 decimals) const;
static const Hybrid_type_traits_decimal *instance();
+ Hybrid_type_traits_decimal() {};
};
@@ -215,6 +217,7 @@ struct Hybrid_type_traits_integer: public Hybrid_type_traits
virtual String *val_str(Hybrid_type *val, String *buf, uint8 decimals) const
{ buf->set(val->integer, &my_charset_bin); return buf;}
static const Hybrid_type_traits_integer *instance();
+ Hybrid_type_traits_integer() {};
};
@@ -1502,6 +1505,7 @@ public:
my_decimal *val_decimal(my_decimal *);
int save_in_field(Field *field, bool no_conversions);
enum Item_result result_type () const { return STRING_RESULT; }
+ enum Item_result cast_to_int_type() const { return INT_RESULT; }
enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; }
// to prevent drop fixed flag (no need parent cleanup call)
void cleanup() {}
@@ -1618,7 +1622,7 @@ public:
}
Item *real_item()
{
- return (*ref)->real_item();
+ return (ref && *ref) ? (*ref)->real_item() : this;
}
bool walk(Item_processor processor, byte *arg)
{ return (*ref)->walk(processor, arg); }
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 48839abcb10..85ba8ff794d 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -3072,14 +3072,14 @@ Item_func_regex::fix_fields(THD *thd, Item **ref)
return FALSE;
}
int error;
- if ((error= regcomp(&preg,res->c_ptr(),
- ((cmp_collation.collation->state &
- (MY_CS_BINSORT | MY_CS_CSSORT)) ?
- REG_EXTENDED | REG_NOSUB :
- REG_EXTENDED | REG_NOSUB | REG_ICASE),
- cmp_collation.collation)))
+ if ((error= my_regcomp(&preg,res->c_ptr(),
+ ((cmp_collation.collation->state &
+ (MY_CS_BINSORT | MY_CS_CSSORT)) ?
+ REG_EXTENDED | REG_NOSUB :
+ REG_EXTENDED | REG_NOSUB | REG_ICASE),
+ cmp_collation.collation)))
{
- (void) regerror(error,&preg,buff,sizeof(buff));
+ (void) my_regerror(error,&preg,buff,sizeof(buff));
my_error(ER_REGEXP_ERROR, MYF(0), buff);
return TRUE;
}
@@ -3121,15 +3121,15 @@ longlong Item_func_regex::val_int()
prev_regexp.copy(*res2);
if (regex_compiled)
{
- regfree(&preg);
+ my_regfree(&preg);
regex_compiled=0;
}
- if (regcomp(&preg,res2->c_ptr_safe(),
- ((cmp_collation.collation->state &
- (MY_CS_BINSORT | MY_CS_CSSORT)) ?
- REG_EXTENDED | REG_NOSUB :
- REG_EXTENDED | REG_NOSUB | REG_ICASE),
- cmp_collation.collation))
+ if (my_regcomp(&preg,res2->c_ptr_safe(),
+ ((cmp_collation.collation->state &
+ (MY_CS_BINSORT | MY_CS_CSSORT)) ?
+ REG_EXTENDED | REG_NOSUB :
+ REG_EXTENDED | REG_NOSUB | REG_ICASE),
+ cmp_collation.collation))
{
null_value=1;
return 0;
@@ -3138,7 +3138,7 @@ longlong Item_func_regex::val_int()
}
}
null_value=0;
- return regexec(&preg,res->c_ptr(),0,(regmatch_t*) 0,0) ? 0 : 1;
+ return my_regexec(&preg,res->c_ptr(),0,(my_regmatch_t*) 0,0) ? 0 : 1;
}
@@ -3148,7 +3148,7 @@ void Item_func_regex::cleanup()
Item_bool_func::cleanup();
if (regex_compiled)
{
- regfree(&preg);
+ my_regfree(&preg);
regex_compiled=0;
}
DBUG_VOID_RETURN;
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 09a0fa8c357..aa50593abf4 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -1002,11 +1002,11 @@ public:
#ifdef USE_REGEX
-#include <regex.h>
+#include "my_regex.h"
class Item_func_regex :public Item_bool_func
{
- regex_t preg;
+ my_regex_t preg;
bool regex_compiled;
bool regex_is_const;
String prev_regexp;
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 518fb011e0f..f07460f2a05 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -4711,27 +4711,11 @@ Item_func_sp::execute(Item **itp)
THD *thd= current_thd;
int res= -1;
Sub_statement_state statement_state;
+ Security_context *save_ctx;
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- st_sp_security_context save_ctx;
-#endif
-
- if (! m_sp && ! (m_sp= sp_find_function(thd, m_name, TRUE)))
- {
- my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str);
+ if (find_and_check_access(thd, EXECUTE_ACL, &save_ctx))
goto error;
- }
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (check_routine_access(thd, EXECUTE_ACL,
- m_sp->m_db.str, m_sp->m_name.str, 0, 0))
- goto error;
- sp_change_security_context(thd, m_sp, &save_ctx);
- if (save_ctx.changed &&
- check_routine_access(thd, EXECUTE_ACL,
- m_sp->m_db.str, m_sp->m_name.str, 0, 0))
- goto error_check_ctx;
-#endif
/*
Disable the binlogging if this is not a SELECT statement. If this is a
SELECT, leave binlogging on, so execute_function() code writes the
@@ -4740,7 +4724,7 @@ Item_func_sp::execute(Item **itp)
thd->reset_sub_statement_state(&statement_state, SUB_STMT_FUNCTION);
res= m_sp->execute_function(thd, args, arg_count, itp);
thd->restore_sub_statement_state(&statement_state);
-
+
if (res && mysql_bin_log.is_open() &&
(m_sp->m_chistics->daccess == SP_CONTAINS_SQL ||
m_sp->m_chistics->daccess == SP_MODIFIES_SQL_DATA))
@@ -4749,8 +4733,7 @@ Item_func_sp::execute(Item **itp)
ER(ER_FAILED_ROUTINE_BREAK_BINLOG));
#ifndef NO_EMBEDDED_ACCESS_CHECKS
-error_check_ctx:
- sp_restore_security_context(thd, m_sp, &save_ctx);
+ sp_restore_security_context(thd, save_ctx);
#endif
error:
@@ -4857,3 +4840,79 @@ Item_func_sp::tmp_table_field(TABLE *t_arg)
DBUG_RETURN(res);
}
+
+
+/*
+ Find the function and chack access rigths to the function
+
+ SYNOPSIS
+ find_and_check_access()
+ thd thread handler
+ want_access requested access
+ backup backup of security context or 0
+
+ RETURN
+ FALSE Access granted
+ TRUE Requested access can't be granted or function doesn't exists
+
+ NOTES
+ Checks if requested access to function can be granted to user.
+ If function isn't found yet, it searches function first.
+ If function can't be found or user don't have requested access
+ error is raised.
+ If security context sp_ctx is provided and access can be granted then
+ switch back to previous context isn't performed.
+ In case of access error or if context is not provided then
+ find_and_check_access() switches back to previous security context.
+*/
+
+bool
+Item_func_sp::find_and_check_access(THD *thd, ulong want_access,
+ Security_context **backup)
+{
+ bool res;
+ Security_context *local_save,
+ **save= (backup ? backup : &local_save);
+ res= TRUE;
+ if (! m_sp && ! (m_sp= sp_find_function(thd, m_name, TRUE)))
+ {
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str);
+ goto error;
+ }
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (check_routine_access(thd, want_access,
+ m_sp->m_db.str, m_sp->m_name.str, 0, FALSE))
+ {
+ goto error;
+ }
+
+ sp_change_security_context(thd, m_sp, save);
+ if (*save &&
+ check_routine_access(thd, want_access,
+ m_sp->m_db.str, m_sp->m_name.str, 0, FALSE))
+ {
+ goto error_check_ctx;
+ }
+ res= FALSE;
+error_check_ctx:
+ if (*save && (res || !backup))
+ sp_restore_security_context(thd, local_save);
+error:
+#else
+ res= 0;
+error:
+#endif
+ return res;
+}
+
+bool
+Item_func_sp::fix_fields(THD *thd, Item **ref)
+{
+ bool res;
+ DBUG_ASSERT(fixed == 0);
+ res= Item_func::fix_fields(thd, ref);
+ if (!res && find_and_check_access(thd, EXECUTE_ACL, NULL))
+ res= 1;
+ return res;
+}
diff --git a/sql/item_func.h b/sql/item_func.h
index 019abb0c072..223144a5d51 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -55,7 +55,7 @@ public:
NOT_FUNC, NOT_ALL_FUNC,
NOW_FUNC, TRIG_COND_FUNC,
GUSERVAR_FUNC, COLLATE_FUNC,
- EXTRACT_FUNC, CHAR_TYPECAST_FUNC };
+ EXTRACT_FUNC, CHAR_TYPECAST_FUNC, FUNC_SP };
enum optimize_type { OPTIMIZE_NONE,OPTIMIZE_KEY,OPTIMIZE_OP, OPTIMIZE_NULL,
OPTIMIZE_EQUAL };
enum Type type() const { return FUNC_ITEM; }
@@ -1286,9 +1286,6 @@ public:
{
ft_handler->please->close_search(ft_handler);
ft_handler=0;
- if (join_key)
- table->file->ft_handler=0;
- table->fulltext_searched=0;
}
concat= 0;
DBUG_VOID_RETURN;
@@ -1365,6 +1362,7 @@ public:
class sp_head;
class sp_name;
+struct st_sp_security_context;
class Item_func_sp :public Item_func
{
@@ -1434,7 +1432,11 @@ public:
{ context= (Name_resolution_context *)cntx; return FALSE; }
void fix_length_and_dec();
+ bool find_and_check_access(THD * thd, ulong want_access,
+ Security_context **backup);
+ virtual enum Functype functype() const { return FUNC_SP; }
+ bool fix_fields(THD *thd, Item **ref);
};
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 4fd33c06095..018afac3812 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -473,7 +473,8 @@ String *Item_func_des_decrypt::val_str(String *str)
{
uint key_number=(uint) (*res)[0] & 127;
// Check if automatic key and that we have privilege to uncompress using it
- if (!(current_thd->master_access & SUPER_ACL) || key_number > 9)
+ if (!(current_thd->security_ctx->master_access & SUPER_ACL) ||
+ key_number > 9)
goto error;
VOID(pthread_mutex_lock(&LOCK_des_key_file));
@@ -1601,13 +1602,13 @@ String *Item_func_user::val_str(String *str)
if (is_current)
{
- user= thd->priv_user;
- host= thd->priv_host;
+ user= thd->security_ctx->priv_user;
+ host= thd->security_ctx->priv_host;
}
else
{
- user= thd->user;
- host= thd->host_or_ip;
+ user= thd->main_security_ctx.user;
+ host= thd->main_security_ctx.host_or_ip;
}
// For system threads (e.g. replication SQL thread) user may be empty
@@ -1732,6 +1733,8 @@ String *Item_func_format::val_str(String *str)
{
my_decimal dec_val, rnd_dec, *res;
res= args[0]->val_decimal(&dec_val);
+ if ((null_value=args[0]->null_value))
+ return 0; /* purecov: inspected */
my_decimal_round(E_DEC_FATAL_ERROR, res, decimals, false, &rnd_dec);
my_decimal2string(E_DEC_FATAL_ERROR, &rnd_dec, 0, 0, 0, str);
str_length= str->length();
@@ -1980,6 +1983,33 @@ b1: str->append((char)(num>>8));
}
str->set_charset(collation.collation);
str->realloc(str->length()); // Add end 0 (for Purify)
+
+ /* Check whether we got a well-formed string */
+ CHARSET_INFO *cs= collation.collation;
+ int well_formed_error;
+ uint wlen= cs->cset->well_formed_len(cs,
+ str->ptr(), str->ptr() + str->length(),
+ str->length(), &well_formed_error);
+ if (wlen < str->length())
+ {
+ THD *thd= current_thd;
+ char hexbuf[7];
+ enum MYSQL_ERROR::enum_warning_level level;
+ uint diff= str->length() - wlen;
+ set_if_smaller(diff, 3);
+ octet2hex(hexbuf, (const uchar*) str->ptr() + wlen, diff);
+ if (thd->variables.sql_mode &
+ (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES))
+ {
+ level= MYSQL_ERROR::WARN_LEVEL_ERROR;
+ null_value= 1;
+ str= 0;
+ }
+ else
+ level= MYSQL_ERROR::WARN_LEVEL_WARN;
+ push_warning_printf(thd, level, ER_INVALID_CHARACTER_STRING,
+ ER(ER_INVALID_CHARACTER_STRING), cs->csname, hexbuf);
+ }
return str;
}
@@ -2518,7 +2548,7 @@ String *Item_load_file::val_str(String *str)
if (!(file_name= args[0]->val_str(str))
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- || !(current_thd->master_access & FILE_ACL)
+ || !(current_thd->security_ctx->master_access & FILE_ACL)
#endif
)
goto err;
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index aead2d67c2c..0e30bbd8a96 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -1468,7 +1468,7 @@ int subselect_single_select_engine::prepare()
int subselect_union_engine::prepare()
{
- return unit->prepare(thd, result, SELECT_NO_UNLOCK, "");
+ return unit->prepare(thd, result, SELECT_NO_UNLOCK);
}
int subselect_uniquesubquery_engine::prepare()
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 880ab4c8cb1..b56d99cf245 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -545,6 +545,7 @@ struct Hybrid_type_traits_fast_decimal: public
val->traits->div(val, u);
}
static const Hybrid_type_traits_fast_decimal *instance();
+ Hybrid_type_traits_fast_decimal() {};
};
static const Hybrid_type_traits_fast_decimal fast_decimal_traits_instance;
@@ -1367,8 +1368,8 @@ void Item_sum_hybrid::cleanup()
void Item_sum_hybrid::no_rows_in_result()
{
- Item_sum::no_rows_in_result();
was_values= FALSE;
+ clear();
}
diff --git a/sql/log.cc b/sql/log.cc
index 9d9f500fe80..0dc0b4d1682 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -39,6 +39,7 @@ ulong sync_binlog_counter= 0;
static bool test_if_number(const char *str,
long *res, bool allow_wildcards);
+static bool binlog_init();
static int binlog_close_connection(THD *thd);
static int binlog_savepoint_set(THD *thd, void *sv);
static int binlog_savepoint_rollback(THD *thd, void *sv);
@@ -46,8 +47,12 @@ static int binlog_commit(THD *thd, bool all);
static int binlog_rollback(THD *thd, bool all);
static int binlog_prepare(THD *thd, bool all);
-static handlerton binlog_hton = {
+handlerton binlog_hton = {
"binlog",
+ SHOW_OPTION_YES,
+ "This is a meta storage engine to represent the binlog in a transaction",
+ DB_TYPE_UNKNOWN, /* IGNORE for now */
+ binlog_init,
0,
sizeof(my_off_t), /* savepoint size = binlog offset */
binlog_close_connection,
@@ -72,9 +77,9 @@ static handlerton binlog_hton = {
should be moved here.
*/
-handlerton *binlog_init()
+bool binlog_init()
{
- return &binlog_hton;
+ return false;
}
static int binlog_close_connection(THD *thd)
@@ -1477,7 +1482,7 @@ bool MYSQL_LOG::write(THD *thd,enum enum_server_command command,
{ // Normal thread
if ((thd->options & OPTION_LOG_OFF)
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- && (thd->master_access & SUPER_ACL)
+ && (thd->security_ctx->master_access & SUPER_ACL)
#endif
)
{
@@ -1852,7 +1857,9 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event)
if (commit_event->write(&log_file))
goto err;
+#ifndef DBUG_OFF
DBUG_skip_commit:
+#endif
if (flush_and_sync())
goto err;
DBUG_EXECUTE_IF("half_binlogged_transaction", abort(););
@@ -1917,6 +1924,7 @@ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length,
}
if (!(specialflag & SPECIAL_SHORT_LOG_FORMAT) || query_start_arg)
{
+ Security_context *sctx= thd->security_ctx;
current_time=time(NULL);
if (current_time != last_time)
{
@@ -1937,10 +1945,12 @@ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length,
tmp_errno=errno;
}
if (my_b_printf(&log_file, "# User@Host: %s[%s] @ %s [%s]\n",
- thd->priv_user ? thd->priv_user : "",
- thd->user ? thd->user : "",
- thd->host ? thd->host : "",
- thd->ip ? thd->ip : "") == (uint) -1)
+ sctx->priv_user ?
+ sctx->priv_user : "",
+ sctx->user ? sctx->user : "",
+ sctx->host ? sctx->host : "",
+ sctx->ip ? sctx->ip : "") ==
+ (uint) -1)
tmp_errno=errno;
}
if (query_start_arg)
@@ -2792,7 +2802,7 @@ void TC_LOG_MMAP::close()
case 3:
my_free((gptr)pages, MYF(0));
case 2:
- my_munmap(data, (size_t)file_length);
+ my_munmap((byte*)data, (size_t)file_length);
case 1:
my_close(fd, MYF(0));
}
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index b15b1682d69..d46d0bd1e81 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -284,7 +284,7 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset;
/* 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 (1L << 31) // THD, user
+#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.
@@ -491,6 +491,7 @@ typedef my_bool (*qc_engine_callback)(THD *thd, char *table_key,
#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
@@ -522,7 +523,7 @@ 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);
-bool default_view_definer(THD *thd, st_lex_user *definer);
+bool default_view_definer(Security_context *sctx, st_lex_user *definer);
enum enum_mysql_completiontype {
@@ -1097,7 +1098,6 @@ 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);
-handlerton *binlog_init();
/* mysqld.cc */
extern void yyerror(const char*);
@@ -1182,12 +1182,13 @@ 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, locked_in_memory;
+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 bool opt_disable_networking, opt_skip_show_db;
-extern bool opt_character_set_client_handshake;
+extern my_bool opt_character_set_client_handshake;
extern bool volatile abort_loop, shutdown_in_progress, grant_option;
extern bool mysql_proc_table_exists;
extern uint volatile thread_count, thread_running, global_read_lock;
@@ -1202,7 +1203,7 @@ extern my_bool sp_automatic_privileges, opt_noacl;
extern my_bool opt_old_style_user_limits, trust_routine_creators;
extern uint opt_crash_binlog_innodb;
extern char *shared_memory_base_name, *mysqld_unix_port;
-extern bool opt_enable_shared_memory;
+extern my_bool opt_enable_shared_memory;
extern char *default_tz_name;
extern my_bool opt_large_pages;
extern uint opt_large_page_size;
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 81657a7657f..e79bce9cd9e 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -295,7 +295,7 @@ bool opt_large_files= sizeof(my_off_t) > 4;
/*
Used with --help for detailed option
*/
-static bool opt_help= 0, opt_verbose= 0;
+static my_bool opt_help= 0, opt_verbose= 0;
arg_cmp_func Arg_comparator::comparator_matrix[5][2] =
{{&Arg_comparator::compare_string, &Arg_comparator::compare_e_string},
@@ -339,9 +339,10 @@ static my_bool opt_sync_bdb_logs;
bool opt_log, opt_update_log, opt_bin_log, opt_slow_log;
bool opt_error_log= IF_WIN(1,0);
bool opt_disable_networking=0, opt_skip_show_db=0;
-bool opt_character_set_client_handshake= 1;
+my_bool opt_character_set_client_handshake= 1;
bool server_id_supplied = 0;
-bool opt_endinfo,using_udf_functions, locked_in_memory;
+bool opt_endinfo,using_udf_functions;
+my_bool locked_in_memory;
bool opt_using_transactions, using_update_log;
bool volatile abort_loop;
bool volatile shutdown_in_progress, grant_option;
@@ -439,6 +440,7 @@ char server_version[SERVER_VERSION_LENGTH];
char *mysqld_unix_port, *opt_mysql_tmpdir;
const char **errmesg; /* Error messages */
const char *myisam_recover_options_str="OFF";
+const char *myisam_stats_method_str="nulls_unequal";
/* name of reference on left espression in rewritten IN subquery */
const char *in_left_expr_name= "<left expr>";
/* name of additional condition */
@@ -577,7 +579,7 @@ Query_cache query_cache;
#endif
#ifdef HAVE_SMEM
char *shared_memory_base_name= default_shared_memory_base_name;
-bool opt_enable_shared_memory;
+my_bool opt_enable_shared_memory;
HANDLE smem_event_connect_request= 0;
#endif
@@ -782,7 +784,9 @@ static void close_connections(void)
{
if (global_system_variables.log_warnings)
sql_print_warning(ER(ER_FORCING_CLOSE),my_progname,
- tmp->thread_id,tmp->user ? tmp->user : "");
+ tmp->thread_id,
+ (tmp->main_security_ctx.user ?
+ tmp->main_security_ctx.user : ""));
close_connection(tmp,0,0);
}
#endif
@@ -1098,7 +1102,7 @@ void clean_up(bool print_message)
my_free((gptr) ssl_acceptor_fd, MYF(MY_ALLOW_ZERO_PTR));
#endif /* HAVE_OPENSSL */
#ifdef USE_REGEX
- regex_end();
+ my_regex_end();
#endif
if (print_message && errmesg)
@@ -2605,7 +2609,7 @@ static int init_common_variables(const char *conf_file_name, int argc,
set_var_init();
mysys_uses_curses=0;
#ifdef USE_REGEX
- regex_init(&my_charset_latin1);
+ my_regex_init(&my_charset_latin1);
#endif
if (!(default_charset_info= get_charset_by_csname(default_character_set_name,
MY_CS_PRIMARY,
@@ -3593,7 +3597,7 @@ static void bootstrap(FILE *file)
thd->client_capabilities=0;
my_net_init(&thd->net,(st_vio*) 0);
thd->max_client_packet_length= thd->net.max_packet;
- thd->master_access= ~(ulong)0;
+ thd->security_ctx->master_access= ~(ulong)0;
thd->thread_id=thread_id++;
thread_count++;
@@ -3933,7 +3937,7 @@ extern "C" pthread_handler_decl(handle_connections_sockets,
continue;
}
if (sock == unix_sock)
- thd->host=(char*) my_localhost;
+ thd->security_ctx->host=(char*) my_localhost;
#ifdef __WIN__
/* Set default wait_timeout */
ulong wait_timeout= global_system_variables.net_wait_timeout * 1000;
@@ -4024,8 +4028,8 @@ extern "C" pthread_handler_decl(handle_connections_namedpipes,arg)
delete thd;
continue;
}
- /* host name is unknown */
- thd->host = my_strdup(my_localhost,MYF(0)); /* Host is unknown */
+ /* Host is unknown */
+ thd->security_ctx->host= my_strdup(my_localhost, MYF(0));
create_new_thread(thd);
}
@@ -4216,7 +4220,7 @@ pthread_handler_decl(handle_connections_shared_memory,arg)
errmsg= 0;
goto errorconn;
}
- thd->host= my_strdup(my_localhost,MYF(0)); /* Host is unknown */
+ thd->security_ctx->host= my_strdup(my_localhost, MYF(0)); /* Host is unknown */
create_new_thread(thd);
connect_number++;
continue;
@@ -4372,6 +4376,7 @@ enum options_mysqld
OPT_MAX_ERROR_COUNT, OPT_MULTI_RANGE_COUNT, OPT_MYISAM_DATA_POINTER_SIZE,
OPT_MYISAM_BLOCK_SIZE, OPT_MYISAM_MAX_EXTRA_SORT_FILE_SIZE,
OPT_MYISAM_MAX_SORT_FILE_SIZE, OPT_MYISAM_SORT_BUFFER_SIZE,
+ OPT_MYISAM_STATS_METHOD,
OPT_NET_BUFFER_LENGTH, OPT_NET_RETRY_COUNT,
OPT_NET_READ_TIMEOUT, OPT_NET_WRITE_TIMEOUT,
OPT_OPEN_FILES_LIMIT,
@@ -5555,6 +5560,11 @@ The minimum value for this variable is 4096.",
(gptr*) &global_system_variables.myisam_sort_buff_size,
(gptr*) &max_system_variables.myisam_sort_buff_size, 0,
GET_ULONG, REQUIRED_ARG, 8192*1024, 4, ~0L, 0, 1, 0},
+ {"myisam_stats_method", OPT_MYISAM_STATS_METHOD,
+ "Specifies how MyISAM index statistics collection code should threat NULLs. "
+ "Possible values of name are \"nulls_unequal\" (default behavior for 4.1/5.0), and \"nulls_equal\" (emulate 4.0 behavior).",
+ (gptr*) &myisam_stats_method_str, (gptr*) &myisam_stats_method_str, 0,
+ GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"net_buffer_length", OPT_NET_BUFFER_LENGTH,
"Buffer length for TCP/IP and socket communication.",
(gptr*) &global_system_variables.net_buffer_length,
@@ -5863,6 +5873,7 @@ struct show_var_st status_vars[]= {
{"Com_show_keys", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_KEYS]), SHOW_LONG_STATUS},
{"Com_show_logs", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_LOGS]), SHOW_LONG_STATUS},
{"Com_show_master_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_MASTER_STAT]), SHOW_LONG_STATUS},
+ {"Com_show_ndb_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_NDBCLUSTER_STATUS]), SHOW_LONG_STATUS},
{"Com_show_new_master", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_NEW_MASTER]), SHOW_LONG_STATUS},
{"Com_show_open_tables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_OPEN_TABLES]), SHOW_LONG_STATUS},
{"Com_show_privileges", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_PRIVILEGES]), SHOW_LONG_STATUS},
@@ -6138,6 +6149,7 @@ static void mysql_init_variables(void)
query_id= thread_id= 1L;
strmov(server_version, MYSQL_SERVER_VERSION);
myisam_recover_options_str= sql_mode_str= "OFF";
+ myisam_stats_method_str= "nulls_unequal";
my_bind_addr = htonl(INADDR_ANY);
threads.empty();
thread_cache.empty();
@@ -6180,6 +6192,12 @@ static void mysql_init_variables(void)
max_system_variables.max_join_size= (ulonglong) HA_POS_ERROR;
global_system_variables.old_passwords= 0;
global_system_variables.old_alter_table= 0;
+
+ /*
+ Default behavior for 4.1 and 5.0 is to treat NULL values as unequal
+ when collecting index statistics for MyISAM tables.
+ */
+ global_system_variables.myisam_stats_method= MI_STATS_METHOD_NULLS_NOT_EQUAL;
/* Variables that depends on compile options */
#ifndef DBUG_OFF
@@ -6249,7 +6267,7 @@ static void mysql_init_variables(void)
#else
have_openssl=SHOW_OPTION_NO;
#endif
-#ifdef HAVE_BROKEN_REALPATH
+#if !defined(HAVE_REALPATH) || defined(HAVE_BROKEN_REALPATH)
have_symlink=SHOW_OPTION_NO;
#else
have_symlink=SHOW_OPTION_YES;
@@ -6795,6 +6813,17 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
fprintf(stderr, "Unknown option to tc-heuristic-recover: %s\n",argument);
exit(1);
}
+ }
+ case OPT_MYISAM_STATS_METHOD:
+ {
+ myisam_stats_method_str= argument;
+ int method;
+ if ((method=find_type(argument, &myisam_stats_method_typelib, 2)) <= 0)
+ {
+ fprintf(stderr, "Invalid value of myisam_stats_method: %s.\n", argument);
+ exit(1);
+ }
+ global_system_variables.myisam_stats_method= method-1;
break;
}
case OPT_SQL_MODE:
@@ -6930,7 +6959,7 @@ static void get_options(int argc,char **argv)
usage();
exit(0);
}
-#if defined(HAVE_BROKEN_REALPATH)
+#if !defined(HAVE_REALPATH) || defined(HAVE_BROKEN_REALPATH)
my_use_symdir=0;
my_disable_symlinks=1;
have_symlink=SHOW_OPTION_NO;
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index b69822d201b..2f4cf1c4752 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -750,10 +750,9 @@ int QUICK_RANGE_SELECT::init()
{
DBUG_ENTER("QUICK_RANGE_SELECT::init");
- if (file->inited == handler::NONE)
- DBUG_RETURN(error= file->ha_index_init(index, 1));
- error= 0;
- DBUG_RETURN(0);
+ if (file->inited != handler::NONE)
+ file->ha_index_or_rnd_end();
+ DBUG_RETURN(error= file->ha_index_init(index, 1));
}
@@ -3539,17 +3538,17 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
switch (cond_func->functype()) {
case Item_func::BETWEEN:
- if (cond_func->arguments()[0]->type() != Item::FIELD_ITEM)
+ if (cond_func->arguments()[0]->real_item()->type() != Item::FIELD_ITEM)
DBUG_RETURN(0);
- field_item= (Item_field*) (cond_func->arguments()[0]);
+ field_item= (Item_field*) (cond_func->arguments()[0]->real_item());
value= NULL;
break;
case Item_func::IN_FUNC:
{
Item_func_in *func=(Item_func_in*) cond_func;
- if (func->key_item()->type() != Item::FIELD_ITEM)
+ if (func->key_item()->real_item()->type() != Item::FIELD_ITEM)
DBUG_RETURN(0);
- field_item= (Item_field*) (func->key_item());
+ field_item= (Item_field*) (func->key_item()->real_item());
value= NULL;
break;
}
@@ -5123,6 +5122,8 @@ check_quick_select(PARAM *param,uint idx,SEL_ARG *tree)
if (cpk_scan)
param->is_ror_scan= TRUE;
}
+ if (param->table->file->index_flags(key, 0, TRUE) & HA_KEY_SCAN_NOT_ROR)
+ param->is_ror_scan= FALSE;
DBUG_PRINT("exit", ("Records: %lu", (ulong) records));
DBUG_RETURN(records);
}
diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc
index 9802bbddde6..2e87f9cf0db 100644
--- a/sql/opt_sum.cc
+++ b/sql/opt_sum.cc
@@ -80,6 +80,8 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
List_iterator_fast<Item> it(all_fields);
int const_result= 1;
bool recalc_const_item= 0;
+ longlong count= 1;
+ bool is_exact_count= TRUE;
table_map removed_tables= 0, outer_tables= 0, used_tables= 0;
table_map where_tables= 0;
Item *item;
@@ -88,9 +90,13 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
if (conds)
where_tables= conds->used_tables();
- /* Don't replace expression on a table that is part of an outer join */
+ /*
+ Analyze outer join dependencies, and, if possible, compute the number
+ of returned rows.
+ */
for (TABLE_LIST *tl= tables; tl; tl= tl->next_leaf)
{
+ /* Don't replace expression on a table that is part of an outer join */
if (tl->on_expr)
{
outer_tables|= tl->table->map;
@@ -106,11 +112,27 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
}
else
used_tables|= tl->table->map;
+
+ /*
+ If the storage manager of 'tl' gives exact row count, compute the total
+ number of rows. If there are no outer table dependencies, this count
+ may be used as the real count.
+ */
+ if (tl->table->file->table_flags() & HA_NOT_EXACT_COUNT)
+ {
+ is_exact_count= FALSE;
+ count= 1; // ensure count != 0
+ }
+ else
+ {
+ tl->table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
+ count*= tl->table->file->records;
+ }
}
/*
- Iterate through item is select part and replace COUNT(), MIN() and MAX()
- with constants (if possible)
+ Iterate through all items in the SELECT clause and replace
+ COUNT(), MIN() and MAX() with constants (if possible).
*/
while ((item= it++))
@@ -122,9 +144,11 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
case Item_sum::COUNT_FUNC:
/*
If the expr in count(expr) can never be null we can change this
- to the number of rows in the tables
+ to the number of rows in the tables if this number is exact and
+ there are no outer joins.
*/
- if (!conds && !((Item_sum_count*) item)->args[0]->maybe_null)
+ if (!conds && !((Item_sum_count*) item)->args[0]->maybe_null &&
+ !outer_tables && is_exact_count)
{
longlong count= 1;
TABLE_LIST *table;
@@ -210,12 +234,27 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
}
removed_tables|= table->map;
}
- else if (!expr->const_item()) // This is VERY seldom false
+ else if (!expr->const_item() || !is_exact_count)
{
+ /*
+ The optimization is not applicable in both cases:
+ (a) 'expr' is a non-constant expression. Then we can't
+ replace 'expr' by a constant.
+ (b) 'expr' is a costant. According to ANSI, MIN/MAX must return
+ NULL if the query does not return any rows. Thus, if we are not
+ able to determine if the query returns any rows, we can't apply
+ the optimization and replace MIN/MAX with a constant.
+ */
const_result= 0;
break;
}
- ((Item_sum_min*) item_sum)->reset();
+ if (!count)
+ {
+ /* If count == 0, then we know that is_exact_count == TRUE. */
+ ((Item_sum_min*) item_sum)->clear(); /* Set to NULL. */
+ }
+ else
+ ((Item_sum_min*) item_sum)->reset(); /* Set to the constant value. */
((Item_sum_min*) item_sum)->make_const();
recalc_const_item= 1;
break;
@@ -282,13 +321,28 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
}
removed_tables|= table->map;
}
- else if (!expr->const_item()) // This is VERY seldom false
+ else if (!expr->const_item() || !is_exact_count)
{
+ /*
+ The optimization is not applicable in both cases:
+ (a) 'expr' is a non-constant expression. Then we can't
+ replace 'expr' by a constant.
+ (b) 'expr' is a costant. According to ANSI, MIN/MAX must return
+ NULL if the query does not return any rows. Thus, if we are not
+ able to determine if the query returns any rows, we can't apply
+ the optimization and replace MIN/MAX with a constant.
+ */
const_result= 0;
break;
}
- ((Item_sum_min*) item_sum)->reset();
- ((Item_sum_min*) item_sum)->make_const();
+ if (!count)
+ {
+ /* If count != 1, then we know that is_exact_count == TRUE. */
+ ((Item_sum_max*) item_sum)->clear(); /* Set to NULL. */
+ }
+ else
+ ((Item_sum_max*) item_sum)->reset(); /* Set to the constant value. */
+ ((Item_sum_max*) item_sum)->make_const();
recalc_const_item= 1;
break;
}
diff --git a/sql/parse_file.cc b/sql/parse_file.cc
index 82ce2f2d7b5..5c7053e6e2a 100644
--- a/sql/parse_file.cc
+++ b/sql/parse_file.cc
@@ -333,6 +333,59 @@ err_w_file:
DBUG_RETURN(TRUE);
}
+/*
+ Renames a frm file (including backups) in same schema
+
+ SYNOPSIS
+ rename_in_schema_file
+ schema name of given schema
+ old_name original file name
+ new_name new file name
+ revision revision number
+ num_view_backups number of backups
+
+ RETURN
+ 0 - OK
+ 1 - Error (only if renaming of frm failed)
+
+*/
+my_bool rename_in_schema_file(const char *schema, const char *old_name,
+ const char *new_name, ulonglong revision,
+ uint num_view_backups)
+{
+ char old_path[FN_REFLEN], new_path[FN_REFLEN], arc_path[FN_REFLEN];
+
+ strxnmov(old_path, FN_REFLEN, mysql_data_home, "/", schema, "/",
+ old_name, reg_ext, NullS);
+ (void) unpack_filename(old_path, old_path);
+
+ strxnmov(new_path, FN_REFLEN, mysql_data_home, "/", schema, "/",
+ new_name, reg_ext, NullS);
+ (void) unpack_filename(new_path, new_path);
+
+ if (my_rename(old_path, new_path, MYF(MY_WME)))
+ return 1;
+
+ /* check if arc_dir exists */
+ strxnmov(arc_path, FN_REFLEN, mysql_data_home, "/", schema, "/arc", NullS);
+ (void) unpack_filename(arc_path, arc_path);
+
+ if (revision > 0 && !access(arc_path, F_OK))
+ {
+ ulonglong limit= (revision > num_view_backups) ? revision - num_view_backups : 0;
+ while (revision > limit) {
+ my_snprintf(old_path, FN_REFLEN, "%s/%s%s-%04lu",
+ arc_path, old_name, reg_ext, (ulong)revision);
+ (void) unpack_filename(old_path, old_path);
+ my_snprintf(new_path, FN_REFLEN, "%s/%s%s-%04lu",
+ arc_path, new_name, reg_ext, (ulong)revision);
+ (void) unpack_filename(new_path, new_path);
+ my_rename(old_path, new_path, MYF(0));
+ revision--;
+ }
+ }
+ return 0;
+}
/*
Prepare frm to parse (read to memory)
diff --git a/sql/parse_file.h b/sql/parse_file.h
index cc0aa6556f6..b4199e4fbf1 100644
--- a/sql/parse_file.h
+++ b/sql/parse_file.h
@@ -48,6 +48,9 @@ my_bool
sql_create_definition_file(const LEX_STRING *dir, const LEX_STRING *file_name,
const LEX_STRING *type,
gptr base, File_option *parameters, uint versions);
+my_bool rename_in_schema_file(const char *schema, const char *old_name,
+ const char *new_name, ulonglong revision,
+ uint num_view_backups);
class File_parser: public Sql_alloc
{
diff --git a/sql/password.c b/sql/password.c
index 60cc0ac0c97..aa05be8c740 100644
--- a/sql/password.c
+++ b/sql/password.c
@@ -318,8 +318,8 @@ void create_random_string(char *to, uint length, struct rand_struct *rand_st)
str, len IN the beginning and the length of the input string
*/
-static void
-octet2hex(char *to, const uint8 *str, uint len)
+void
+octet2hex(char *to, const unsigned char *str, uint len)
{
const uint8 *str_end= str + len;
for (; str != str_end; ++str)
diff --git a/sql/protocol.h b/sql/protocol.h
index 2717d2258fa..c00bbba4cc9 100644
--- a/sql/protocol.h
+++ b/sql/protocol.h
@@ -150,30 +150,6 @@ public:
virtual bool store(Field *field);
};
-class Protocol_cursor :public Protocol_simple
-{
-public:
- MEM_ROOT *alloc;
- MYSQL_FIELD *fields;
- MYSQL_ROWS *data;
- MYSQL_ROWS **prev_record;
- ulong row_count;
-
- Protocol_cursor() :data(NULL) {}
- Protocol_cursor(THD *thd_arg, MEM_ROOT *ini_alloc) :Protocol_simple(thd_arg), alloc(ini_alloc), data(NULL) {}
- bool prepare_for_send(List<Item> *item_list)
- {
- row_count= 0;
- fields= NULL;
- data= NULL;
- prev_record= &data;
- return Protocol_simple::prepare_for_send(item_list);
- }
- bool send_fields(List<Item> *list, uint flags);
- bool write();
- uint get_field_count() { return field_count; }
-};
-
void send_warning(THD *thd, uint sql_errno, const char *err=0);
void net_printf_error(THD *thd, uint sql_errno, ...);
void net_send_error(THD *thd, uint sql_errno=0, const char *err=0);
diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc
index a30776057b1..93aafbdc0e0 100644
--- a/sql/repl_failsafe.cc
+++ b/sql/repl_failsafe.cc
@@ -67,13 +67,11 @@ static int init_failsafe_rpl_thread(THD* thd)
this thread has no other error reporting method).
*/
thd->system_thread = thd->bootstrap = 1;
- thd->host_or_ip= "";
+ thd->security_ctx->skip_grants();
thd->client_capabilities = 0;
my_net_init(&thd->net, 0);
thd->net.read_timeout = slave_net_timeout;
thd->max_client_packet_length=thd->net.max_packet;
- thd->master_access= ~(ulong)0;
- thd->priv_user = 0;
pthread_mutex_lock(&LOCK_thread_count);
thd->thread_id = thread_id++;
pthread_mutex_unlock(&LOCK_thread_count);
diff --git a/sql/set_var.cc b/sql/set_var.cc
index e7adc7387c0..e1dc23f6032 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -270,6 +270,12 @@ sys_var_long_ptr sys_myisam_data_pointer_size("myisam_data_pointer_size",
sys_var_thd_ulonglong sys_myisam_max_sort_file_size("myisam_max_sort_file_size", &SV::myisam_max_sort_file_size, fix_myisam_max_sort_file_size, 1);
sys_var_thd_ulong sys_myisam_repair_threads("myisam_repair_threads", &SV::myisam_repair_threads);
sys_var_thd_ulong sys_myisam_sort_buffer_size("myisam_sort_buffer_size", &SV::myisam_sort_buff_size);
+
+sys_var_thd_enum sys_myisam_stats_method("myisam_stats_method",
+ &SV::myisam_stats_method,
+ &myisam_stats_method_typelib,
+ NULL);
+
sys_var_thd_ulong sys_net_buffer_length("net_buffer_length",
&SV::net_buffer_length);
sys_var_thd_ulong sys_net_read_timeout("net_read_timeout",
@@ -641,6 +647,7 @@ sys_var *sys_variables[]=
&sys_myisam_max_sort_file_size,
&sys_myisam_repair_threads,
&sys_myisam_sort_buffer_size,
+ &sys_myisam_stats_method,
&sys_net_buffer_length,
&sys_net_read_timeout,
&sys_net_retry_count,
@@ -912,6 +919,9 @@ struct show_var_st init_vars[]= {
{sys_myisam_repair_threads.name, (char*) &sys_myisam_repair_threads,
SHOW_SYS},
{sys_myisam_sort_buffer_size.name, (char*) &sys_myisam_sort_buffer_size, SHOW_SYS},
+
+ {sys_myisam_stats_method.name, (char*) &sys_myisam_stats_method, SHOW_SYS},
+
#ifdef __NT__
{"named_pipe", (char*) &opt_enable_named_pipe, SHOW_MY_BOOL},
#endif
@@ -1112,9 +1122,10 @@ static void sys_default_init_slave(THD* thd, enum_var_type type)
static int sys_check_ftb_syntax(THD *thd, set_var *var)
{
- if (thd->master_access & SUPER_ACL)
- return ft_boolean_check_syntax_string((byte*) var->value->str_value.c_ptr()) ?
- -1 : 0;
+ if (thd->security_ctx->master_access & SUPER_ACL)
+ return (ft_boolean_check_syntax_string((byte*)
+ var->value->str_value.c_ptr()) ?
+ -1 : 0);
else
{
my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER");
@@ -2709,7 +2720,7 @@ static bool set_option_autocommit(THD *thd, set_var *var)
static int check_log_update(THD *thd, set_var *var)
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (!(thd->master_access & SUPER_ACL))
+ if (!(thd->security_ctx->master_access & SUPER_ACL))
{
my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER");
return 1;
@@ -2755,7 +2766,7 @@ static int check_pseudo_thread_id(THD *thd, set_var *var)
{
var->save_result.ulonglong_value= var->value->val_int();
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (thd->master_access & SUPER_ACL)
+ if (thd->security_ctx->master_access & SUPER_ACL)
return 0;
else
{
@@ -3120,10 +3131,10 @@ int set_var_password::check(THD *thd)
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (!user->host.str)
{
- if (thd->priv_host != 0)
+ if (*thd->security_ctx->priv_host != 0)
{
- user->host.str= (char *) thd->priv_host;
- user->host.length= strlen(thd->priv_host);
+ user->host.str= (char *) thd->security_ctx->priv_host;
+ user->host.length= strlen(thd->security_ctx->priv_host);
}
else
{
diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt
index 61d89545d61..3aabc4e5b1f 100644
--- a/sql/share/errmsg.txt
+++ b/sql/share/errmsg.txt
@@ -5311,7 +5311,8 @@ ER_XAER_NOTA XAE04
ER_XAER_INVAL XAE05
eng "XAER_INVAL: Invalid arguments (or unsupported command)"
ER_XAER_RMFAIL XAE07
- eng "XAER_RMFAIL: The command cannot be executed in the %.64s state"
+ eng "XAER_RMFAIL: The command cannot be executed when global transaction is in the %.64s state"
+ rus "XAER_RMFAIL: ÜÔÕ ËÏÍÁÎÄÕ ÎÅÌØÚÑ ×ÙÐÏÌÎÑÔØ ËÏÇÄÁ ÇÌÏÂÁÌØÎÁÑ ÔÒÁÎÚÁËÃÉÑ ÎÁÈÏÄÉÔÓÑ × ÓÏÓÔÏÑÎÉÉ '%.64s'"
ER_XAER_OUTSIDE XAE09
eng "XAER_OUTSIDE: Some work is done outside global transaction"
ER_XAER_RMERR XAE03
@@ -5366,12 +5367,12 @@ ER_TOO_BIG_SCALE 42000 S1009
eng "Too big scale %d specified for column '%-.64s'. Maximum is %d."
ER_TOO_BIG_PRECISION 42000 S1009
eng "Too big precision %d specified for column '%-.64s'. Maximum is %d."
-ER_SCALE_BIGGER_THAN_PRECISION 42000 S1009
- eng "Scale may not be larger than the precision (column '%-.64s')."
+ER_M_BIGGER_THAN_D 42000 S1009
+ eng "For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column '%-.64s')."
ER_WRONG_LOCK_OF_SYSTEM_TABLE
eng "You can't combine write-locking of system '%-.64s.%-.64s' table with other tables"
ER_CONNECT_TO_FOREIGN_DATA_SOURCE
- eng "Unable to connect to foreign data source - database '%s'!"
+ eng "Unable to connect to foreign data source - database '%.64s'!"
ER_QUERY_ON_FOREIGN_DATA_SOURCE
eng "There was a problem processing the query on the foreign data source. Data source error: '%-.64s'"
ER_FOREIGN_DATA_SOURCE_DOESNT_EXIST
@@ -5400,11 +5401,11 @@ ER_DATETIME_FUNCTION_OVERFLOW 22008
ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG
eng "Can't update table '%-.64s' in stored function/trigger because it is already used by statement which invoked this stored function/trigger."
ER_VIEW_PREVENT_UPDATE
- eng "The definition of table '%-.64s' prevents operation %s on table '%-.64s'."
+ eng "The definition of table '%-.64s' prevents operation %.64s on table '%-.64s'."
ER_PS_NO_RECURSION
eng "The prepared statement contains a stored routine call that refers to that same statement. It's not allowed to execute a prepared statement in such a recursive manner"
ER_SP_CANT_SET_AUTOCOMMIT
- eng "Not allowed to set autocommit from a stored function or trigger"
+ eng "Not allowed to set autocommit from a stored function or trigger"
ER_NO_VIEW_USER
eng "View definer is not fully qualified"
ER_VIEW_FRM_NO_USER
@@ -5413,6 +5414,12 @@ ER_VIEW_OTHER_USER
eng "You need the SUPER privilege for creation view with %-.64s@%-.64s definer"
ER_NO_SUCH_USER
eng "There is not %-.64s@%-.64s registered"
+ER_FORBID_SCHEMA_CHANGE
+ eng "Changing schema from '%-.64s' to '%-.64s' is not allowed."
+ER_ROW_IS_REFERENCED_2 23000
+ eng "Cannot delete or update a parent row: a foreign key constraint fails (%.192s)"
+ER_NO_REFERENCED_ROW_2 23000
+ eng "Cannot add or update a child row: a foreign key constraint fails (%.192s)"
ER_PARTITION_REQUIRES_VALUES_ERROR
eng "%s PARTITIONING requires definition of VALUES %s for each partition"
swe "%s PARTITIONering kräver definition av VALUES %s för varje partition"
diff --git a/sql/slave.cc b/sql/slave.cc
index 757d8bc212d..fb7b9275d0d 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -37,7 +37,7 @@ typedef bool (*CHECK_KILLED_FUNC)(THD*,void*);
volatile bool slave_sql_running = 0, slave_io_running = 0;
char* slave_load_tmpdir = 0;
MASTER_INFO *active_mi;
-bool replicate_same_server_id;
+my_bool replicate_same_server_id;
ulonglong relay_log_space_limit = 0;
/*
@@ -2426,17 +2426,10 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
DBUG_ENTER("init_slave_thread");
thd->system_thread = (thd_type == SLAVE_THD_SQL) ?
SYSTEM_THREAD_SLAVE_SQL : SYSTEM_THREAD_SLAVE_IO;
- /*
- The two next lines are needed for replication of SP (CREATE PROCEDURE
- needs a valid user to store in mysql.proc).
- */
- thd->priv_user= (char *) "";
- thd->priv_host[0]= '\0';
- thd->host_or_ip= "";
+ thd->security_ctx->skip_grants();
thd->client_capabilities = 0;
my_net_init(&thd->net, 0);
thd->net.read_timeout = slave_net_timeout;
- thd->master_access= ~(ulong)0;
thd->slave_thread = 1;
set_slave_thread_options(thd);
/*
diff --git a/sql/slave.h b/sql/slave.h
index ead1aa87ce6..486bb3055f5 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -552,7 +552,7 @@ extern "C" pthread_handler_decl(handle_slave_sql,arg);
extern bool volatile abort_loop;
extern MASTER_INFO main_mi, *active_mi; /* active_mi for multi-master */
extern LIST master_list;
-extern bool replicate_same_server_id;
+extern my_bool replicate_same_server_id;
extern int disconnect_slave_event_count, abort_slave_event_count ;
diff --git a/sql/sp.cc b/sql/sp.cc
index e979921492f..18d94a85884 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -494,7 +494,8 @@ db_create_routine(THD *thd, int type, sp_head *sp)
else
{
restore_record(table, s->default_values); // Get default values for fields
- strxmov(definer, thd->priv_user, "@", thd->priv_host, NullS);
+ strxmov(definer, thd->security_ctx->priv_user, "@",
+ thd->security_ctx->priv_host, NullS);
if (table->s->fields != MYSQL_PROC_FIELD_COUNT)
{
@@ -569,7 +570,7 @@ db_create_routine(THD *thd, int type, sp_head *sp)
goto done;
}
}
- if (!(thd->master_access & SUPER_ACL))
+ if (!(thd->security_ctx->master_access & SUPER_ACL))
{
my_message(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER,
ER(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER), MYF(0));
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 1a7599d7bbc..671acbc2a0c 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -199,11 +199,18 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type,
Item *it= sp_prepare_func_item(thd, it_addr);
uint rsize;
Query_arena backup_arena;
+ Item *old_item_next, *old_free_list, **p_free_list;
DBUG_PRINT("info", ("type: %d", type));
if (!it)
- {
DBUG_RETURN(NULL);
+
+ if (reuse)
+ {
+ old_item_next= reuse->next;
+ p_free_list= use_callers_arena ? &thd->spcont->callers_arena->free_list :
+ &thd->free_list;
+ old_free_list= *p_free_list;
}
switch (sp_map_result_type(type)) {
@@ -312,15 +319,23 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type,
default:
DBUG_ASSERT(0);
}
- it->rsize= rsize;
-
- DBUG_RETURN(it);
+ goto end;
return_null_item:
CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_null(),
use_callers_arena, &backup_arena);
+end:
it->rsize= rsize;
+ if (reuse && it == reuse)
+ {
+ /*
+ The Item constructor registered itself in the arena free list,
+ while the item slot is reused, so we have to restore the list.
+ */
+ it->next= old_item_next;
+ *p_free_list= old_free_list;
+ }
DBUG_RETURN(it);
}
@@ -1000,7 +1015,7 @@ int sp_head::execute(THD *thd)
ip= hip;
ret= 0;
ctx->clear_handler();
- ctx->in_handler= TRUE;
+ ctx->enter_handler(hip);
thd->clear_error();
thd->killed= THD::NOT_KILLED;
continue;
@@ -1358,14 +1373,6 @@ int sp_head::execute_procedure(THD *thd, List<Item> *args)
uint offset= static_cast<Item_splocal *>(it)->get_offset();
Item *val= nctx->get_item(i);
Item *orig= octx->get_item(offset);
- Item *o_item_next;
- /* we'll use callers_arena in sp_eval_func_item */
- Item *o_free_list= thd->spcont->callers_arena->free_list;
-
- LINT_INIT(o_item_next);
-
- if (orig)
- o_item_next= orig->next;
/*
We might need to allocate new item if we weren't able to
@@ -1380,15 +1387,6 @@ int sp_head::execute_procedure(THD *thd, List<Item> *args)
}
if (copy != orig)
octx->set_item(offset, copy);
- if (orig && copy == orig)
- {
- /*
- A reused item slot, where the constructor put it in the
- free_list, so we have to restore the list.
- */
- thd->spcont->callers_arena->free_list= o_free_list;
- copy->next= o_item_next;
- }
}
else
{
@@ -1636,8 +1634,10 @@ bool check_show_routine_access(THD *thd, sp_head *sp, bool *full_access)
tables.db= (char*) "mysql";
tables.table_name= tables.alias= (char*) "proc";
*full_access= (!check_table_access(thd, SELECT_ACL, &tables, 1) ||
- (!strcmp(sp->m_definer_user.str, thd->priv_user) &&
- !strcmp(sp->m_definer_host.str, thd->priv_host)));
+ (!strcmp(sp->m_definer_user.str,
+ thd->security_ctx->priv_user) &&
+ !strcmp(sp->m_definer_host.str,
+ thd->security_ctx->priv_host)));
if (!*full_access)
return check_some_routine_access(thd, sp->m_db.str, sp->m_name.str,
sp->m_type == TYPE_ENUM_PROCEDURE);
@@ -2378,7 +2378,7 @@ sp_instr_hreturn::execute(THD *thd, uint *nextp)
thd->spcont->restore_variables(m_frame);
*nextp= thd->spcont->pop_hstack();
}
- thd->spcont->in_handler= FALSE;
+ thd->spcont->exit_handler();
DBUG_RETURN(0);
}
@@ -2476,6 +2476,10 @@ sp_instr_cpop::backpatch(uint dest, sp_pcontext *dst_ctx)
int
sp_instr_copen::execute(THD *thd, uint *nextp)
{
+ /*
+ We don't store a pointer to the cursor in the instruction to be
+ able to reuse the same instruction among different threads in future.
+ */
sp_cursor *c= thd->spcont->get_cursor(m_cursor);
int res;
DBUG_ENTER("sp_instr_copen::execute");
@@ -2484,41 +2488,33 @@ sp_instr_copen::execute(THD *thd, uint *nextp)
res= -1;
else
{
- sp_lex_keeper *lex_keeper= c->pre_open(thd);
- if (!lex_keeper) // cursor already open or OOM
- {
- res= -1;
- *nextp= m_ip+1;
- }
- else
- {
- Query_arena *old_arena= thd->stmt_arena;
+ sp_lex_keeper *lex_keeper= c->get_lex_keeper();
+ Query_arena *old_arena= thd->stmt_arena;
- /*
- Get the Query_arena from the cpush instruction, which contains
- the free_list of the query, so new items (if any) are stored in
- the right free_list, and we can cleanup after each open.
- */
- thd->stmt_arena= c->get_instr();
- res= lex_keeper->reset_lex_and_exec_core(thd, nextp, FALSE, this);
- /* Cleanup the query's items */
- if (thd->stmt_arena->free_list)
- cleanup_items(thd->stmt_arena->free_list);
- thd->stmt_arena= old_arena;
- /*
- Work around the fact that errors in selects are not returned properly
- (but instead converted into a warning), so if a condition handler
- caught, we have lost the result code.
- */
- if (!res)
- {
- uint dummy1, dummy2;
+ /*
+ Get the Query_arena from the cpush instruction, which contains
+ the free_list of the query, so new items (if any) are stored in
+ the right free_list, and we can cleanup after each open.
+ */
+ thd->stmt_arena= c->get_instr();
+ res= lex_keeper->reset_lex_and_exec_core(thd, nextp, FALSE, this);
+ /* Cleanup the query's items */
+ if (thd->stmt_arena->free_list)
+ cleanup_items(thd->stmt_arena->free_list);
+ thd->stmt_arena= old_arena;
+ /*
+ Work around the fact that errors in selects are not returned properly
+ (but instead converted into a warning), so if a condition handler
+ caught, we have lost the result code.
+ */
+ if (!res)
+ {
+ uint dummy1, dummy2;
- if (thd->spcont->found_handler(&dummy1, &dummy2))
- res= -1;
- }
- c->post_open(thd, res ? FALSE : TRUE);
+ if (thd->spcont->found_handler(&dummy1, &dummy2))
+ res= -1;
}
+ /* TODO: Assert here that we either have an error or a cursor */
}
DBUG_RETURN(res);
}
@@ -2527,7 +2523,8 @@ sp_instr_copen::execute(THD *thd, uint *nextp)
int
sp_instr_copen::exec_core(THD *thd, uint *nextp)
{
- int res= mysql_execute_command(thd);
+ sp_cursor *c= thd->spcont->get_cursor(m_cursor);
+ int res= c->open(thd);
*nextp= m_ip+1;
return res;
}
@@ -2582,14 +2579,7 @@ sp_instr_cfetch::execute(THD *thd, uint *nextp)
Query_arena backup_arena;
DBUG_ENTER("sp_instr_cfetch::execute");
- if (! c)
- res= -1;
- else
- {
- thd->set_n_backup_active_arena(thd->spcont->callers_arena, &backup_arena);
- res= c->fetch(thd, &m_varlist);
- thd->restore_active_arena(thd->spcont->callers_arena, &backup_arena);
- }
+ res= c ? c->fetch(thd, &m_varlist) : -1;
*nextp= m_ip+1;
DBUG_RETURN(res);
@@ -2645,54 +2635,36 @@ sp_instr_error::print(String *str)
*/
#ifndef NO_EMBEDDED_ACCESS_CHECKS
-void
-sp_change_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp)
-{
- ctxp->changed= (sp->m_chistics->suid != SP_IS_NOT_SUID &&
- (strcmp(sp->m_definer_user.str, thd->priv_user) ||
- strcmp(sp->m_definer_host.str, thd->priv_host)));
-
- if (ctxp->changed)
+bool
+sp_change_security_context(THD *thd, sp_head *sp, Security_context **backup)
+{
+ *backup= 0;
+ if (sp->m_chistics->suid != SP_IS_NOT_SUID &&
+ (strcmp(sp->m_definer_user.str,
+ thd->security_ctx->priv_user) ||
+ my_strcasecmp(system_charset_info, sp->m_definer_host.str,
+ thd->security_ctx->priv_host)))
{
- ctxp->master_access= thd->master_access;
- ctxp->db_access= thd->db_access;
- ctxp->priv_user= thd->priv_user;
- strncpy(ctxp->priv_host, thd->priv_host, sizeof(ctxp->priv_host));
- ctxp->user= thd->user;
- ctxp->host= thd->host;
- ctxp->ip= thd->ip;
-
- /* Change thise just to do the acl_getroot_no_password */
- thd->user= sp->m_definer_user.str;
- thd->host= thd->ip = sp->m_definer_host.str;
-
- if (acl_getroot_no_password(thd))
- { // Failed, run as invoker for now
- ctxp->changed= FALSE;
- thd->master_access= ctxp->master_access;
- thd->db_access= ctxp->db_access;
- thd->priv_user= ctxp->priv_user;
- strncpy(thd->priv_host, ctxp->priv_host, sizeof(thd->priv_host));
+ if (acl_getroot_no_password(&sp->m_security_ctx, sp->m_definer_user.str,
+ sp->m_definer_host.str,
+ sp->m_definer_host.str,
+ sp->m_db.str))
+ {
+ my_error(ER_NO_SUCH_USER, MYF(0), sp->m_definer_user.str,
+ sp->m_definer_host.str);
+ return TRUE;
}
-
- /* Restore these immiediately */
- thd->user= ctxp->user;
- thd->host= ctxp->host;
- thd->ip= ctxp->ip;
+ *backup= thd->security_ctx;
+ thd->security_ctx= &sp->m_security_ctx;
}
+ return FALSE;
}
void
-sp_restore_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp)
+sp_restore_security_context(THD *thd, Security_context *backup)
{
- if (ctxp->changed)
- {
- ctxp->changed= FALSE;
- thd->master_access= ctxp->master_access;
- thd->db_access= ctxp->db_access;
- thd->priv_user= ctxp->priv_user;
- strncpy(thd->priv_host, ctxp->priv_host, sizeof(thd->priv_host));
- }
+ if (backup)
+ thd->security_ctx= backup;
}
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
diff --git a/sql/sp_head.h b/sql/sp_head.h
index 9888fe74149..ed0f3987e01 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -151,6 +151,12 @@ public:
// Pointers set during parsing
uchar *m_param_begin, *m_param_end, *m_body_begin;
+ /*
+ Security context for stored routine which should be run under
+ definer privileges.
+ */
+ Security_context m_security_ctx;
+
static void *
operator new(size_t size);
@@ -860,6 +866,12 @@ public:
virtual void print(String *str);
+ /*
+ This call is used to cleanup the instruction when a sensitive
+ cursor is closed. For now stored procedures always use materialized
+ cursors and the call is not used.
+ */
+ virtual void cleanup_stmt() { /* no op */ }
private:
sp_lex_keeper m_lex_keeper;
@@ -1017,23 +1029,12 @@ private:
}; // class sp_instr_error : public sp_instr
-struct st_sp_security_context
-{
- bool changed;
- uint master_access;
- uint db_access;
- char *priv_user;
- char priv_host[MAX_HOSTNAME];
- char *user;
- char *host;
- char *ip;
-};
-
#ifndef NO_EMBEDDED_ACCESS_CHECKS
+bool
+sp_change_security_context(THD *thd, sp_head *sp,
+ Security_context **backup);
void
-sp_change_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp);
-void
-sp_restore_security_context(THD *thd, sp_head *sp,st_sp_security_context *ctxp);
+sp_restore_security_context(THD *thd, Security_context *backup);
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
TABLE_LIST *
@@ -1041,4 +1042,7 @@ sp_add_to_query_tables(THD *thd, LEX *lex,
const char *db, const char *name,
thr_lock_type locktype);
+Item *sp_eval_func_item(THD *thd, Item **it, enum_field_types type,
+ Item *reuse, bool use_callers_arena);
+
#endif /* _SP_HEAD_H_ */
diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc
index 748c09f56c7..252bd7e5cab 100644
--- a/sql/sp_rcontext.cc
+++ b/sql/sp_rcontext.cc
@@ -25,17 +25,18 @@
#include "mysql.h"
#include "sp_head.h"
+#include "sql_cursor.h"
#include "sp_rcontext.h"
#include "sp_pcontext.h"
sp_rcontext::sp_rcontext(uint fsize, uint hmax, uint cmax)
: m_count(0), m_fsize(fsize), m_result(NULL), m_hcount(0), m_hsp(0),
- m_hfound(-1), m_ccount(0)
+ m_ihsp(0), m_hfound(-1), m_ccount(0)
{
- in_handler= FALSE;
m_frame= (Item **)sql_alloc(fsize * sizeof(Item*));
m_handler= (sp_handler_t *)sql_alloc(hmax * sizeof(sp_handler_t));
m_hstack= (uint *)sql_alloc(hmax * sizeof(uint));
+ m_in_handler= (uint *)sql_alloc(hmax * sizeof(uint));
m_cstack= (sp_cursor **)sql_alloc(cmax * sizeof(sp_cursor *));
m_saved.empty();
}
@@ -45,31 +46,18 @@ int
sp_rcontext::set_item_eval(THD *thd, uint idx, Item **item_addr,
enum_field_types type)
{
- extern Item *sp_eval_func_item(THD *thd, Item **it, enum_field_types type,
- Item *reuse, bool use_callers_arena);
Item *it;
Item *reuse_it;
- Item *old_item_next;
/* sp_eval_func_item will use callers_arena */
- Item *old_free_list= thd->spcont->callers_arena->free_list;
int res;
- LINT_INIT(old_item_next);
- if ((reuse_it= get_item(idx)))
- old_item_next= reuse_it->next;
+ reuse_it= get_item(idx);
it= sp_eval_func_item(thd, item_addr, type, reuse_it, TRUE);
if (! it)
res= -1;
else
{
res= 0;
- if (reuse_it && it == reuse_it)
- {
- // A reused item slot, where the constructor put it in the free_list,
- // so we have to restore the list.
- thd->spcont->callers_arena->free_list= old_free_list;
- it->next= old_item_next;
- }
set_item(idx, it);
}
@@ -80,8 +68,6 @@ bool
sp_rcontext::find_handler(uint sql_errno,
MYSQL_ERROR::enum_warning_level level)
{
- if (in_handler)
- return 0; // Already executing a handler
if (m_hfound >= 0)
return 1; // Already got one
@@ -91,6 +77,13 @@ sp_rcontext::find_handler(uint sql_errno,
while (i--)
{
sp_cond_type_t *cond= m_handler[i].cond;
+ int j= m_ihsp;
+
+ while (j--)
+ if (m_in_handler[j] == m_handler[i].handler)
+ break;
+ if (j >= 0)
+ continue; // Already executing this handler
switch (cond->type)
{
@@ -170,7 +163,8 @@ sp_rcontext::pop_cursors(uint count)
*/
sp_cursor::sp_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i)
- :m_lex_keeper(lex_keeper), m_prot(NULL), m_isopen(0), m_current_row(NULL),
+ :m_lex_keeper(lex_keeper),
+ server_side_cursor(NULL),
m_i(i)
{
/*
@@ -182,59 +176,37 @@ sp_cursor::sp_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i)
/*
- pre_open cursor
+ Open an SP cursor
SYNOPSIS
- pre_open()
- THD Thread handler
+ open()
+ THD Thread handler
- NOTES
- We have to open cursor in two steps to make it easy for sp_instr_copen
- to reuse the sp_instr::exec_stmt() code.
- If this function returns 0, post_open should not be called
RETURN
- 0 ERROR
+ 0 in case of success, -1 otherwise
*/
-sp_lex_keeper*
-sp_cursor::pre_open(THD *thd)
+int
+sp_cursor::open(THD *thd)
{
- if (m_isopen)
+ if (server_side_cursor)
{
my_message(ER_SP_CURSOR_ALREADY_OPEN, ER(ER_SP_CURSOR_ALREADY_OPEN),
MYF(0));
- return NULL;
+ return -1;
}
- init_alloc_root(&m_mem_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
- if ((m_prot= new Protocol_cursor(thd, &m_mem_root)) == NULL)
- return NULL;
-
- /* Save for execution. Will be restored in post_open */
- m_oprot= thd->protocol;
- m_nseof= thd->net.no_send_eof;
-
- /* Change protocol for execution */
- thd->protocol= m_prot;
- thd->net.no_send_eof= TRUE;
- return m_lex_keeper;
-}
-
-
-void
-sp_cursor::post_open(THD *thd, my_bool was_opened)
-{
- thd->net.no_send_eof= m_nseof; // Restore the originals
- thd->protocol= m_oprot;
- if ((m_isopen= was_opened))
- m_current_row= m_prot->data;
+ if (mysql_open_cursor(thd, (uint) ALWAYS_MATERIALIZED_CURSOR, &result,
+ &server_side_cursor))
+ return -1;
+ return 0;
}
int
sp_cursor::close(THD *thd)
{
- if (! m_isopen)
+ if (! server_side_cursor)
{
my_message(ER_SP_CURSOR_NOT_OPEN, ER(ER_SP_CURSOR_NOT_OPEN), MYF(0));
return -1;
@@ -247,106 +219,82 @@ sp_cursor::close(THD *thd)
void
sp_cursor::destroy()
{
- if (m_prot)
- {
- delete m_prot;
- m_prot= NULL;
- free_root(&m_mem_root, MYF(0));
- }
- m_isopen= FALSE;
+ delete server_side_cursor;
+ server_side_cursor= 0;
}
+
int
sp_cursor::fetch(THD *thd, List<struct sp_pvar> *vars)
{
- List_iterator_fast<struct sp_pvar> li(*vars);
- sp_pvar_t *pv;
- MYSQL_ROW row;
- uint fldcount;
-
- if (! m_isopen)
+ if (! server_side_cursor)
{
my_message(ER_SP_CURSOR_NOT_OPEN, ER(ER_SP_CURSOR_NOT_OPEN), MYF(0));
return -1;
}
- if (m_current_row == NULL)
+ if (vars->elements != result.get_field_count())
{
- my_message(ER_SP_FETCH_NO_DATA, ER(ER_SP_FETCH_NO_DATA), MYF(0));
+ my_message(ER_SP_WRONG_NO_OF_FETCH_ARGS,
+ ER(ER_SP_WRONG_NO_OF_FETCH_ARGS), MYF(0));
return -1;
}
- row= m_current_row->data;
- for (fldcount= 0 ; (pv= li++) ; fldcount++)
- {
- Item *it;
- Item *reuse;
- uint rsize;
- Item *old_item_next;
- Item *old_free_list= thd->free_list;
- const char *s;
- LINT_INIT(old_item_next);
-
- if (fldcount >= m_prot->get_field_count())
- {
- my_message(ER_SP_WRONG_NO_OF_FETCH_ARGS,
- ER(ER_SP_WRONG_NO_OF_FETCH_ARGS), MYF(0));
- return -1;
- }
+ result.set_spvar_list(vars);
- if ((reuse= thd->spcont->get_item(pv->offset)))
- old_item_next= reuse->next;
+ /* Attempt to fetch one row */
+ if (server_side_cursor->is_open())
+ server_side_cursor->fetch(1);
- s= row[fldcount];
- if (!s)
- it= new(reuse, &rsize) Item_null();
- else
- {
- /*
- Length of data can be calculated as:
- pointer_to_next_not_null_object - s -1
- where the last -1 is to remove the end \0
- */
- uint len;
- MYSQL_ROW next= row+fldcount+1;
- while (!*next) // Skip nulls
- next++;
- len= (*next -s)-1;
- switch (sp_map_result_type(pv->type)) {
- case INT_RESULT:
- it= new(reuse, &rsize) Item_int(s);
- break;
- case REAL_RESULT:
- it= new(reuse, &rsize) Item_float(s, len);
- break;
- case DECIMAL_RESULT:
- it= new(reuse, &rsize) Item_decimal(s, len, thd->db_charset);
- break;
- case STRING_RESULT:
- /* TODO: Document why we do an extra copy of the string 's' here */
- it= new(reuse, &rsize) Item_string(thd->strmake(s, len), len,
- thd->db_charset);
- break;
- case ROW_RESULT:
- default:
- DBUG_ASSERT(0);
- }
- }
- it->rsize= rsize;
- if (reuse && it == reuse)
- {
- // A reused item slot, where the constructor put it in the free_list,
- // so we have to restore the list.
- thd->free_list= old_free_list;
- it->next= old_item_next;
- }
- thd->spcont->set_item(pv->offset, it);
- }
- if (fldcount < m_prot->get_field_count())
+ /*
+ If the cursor was pointing after the last row, the fetch will
+ close it instead of sending any rows.
+ */
+ if (! server_side_cursor->is_open())
{
- my_message(ER_SP_WRONG_NO_OF_FETCH_ARGS,
- ER(ER_SP_WRONG_NO_OF_FETCH_ARGS), MYF(0));
+ my_message(ER_SP_FETCH_NO_DATA, ER(ER_SP_FETCH_NO_DATA), MYF(0));
return -1;
}
- m_current_row= m_current_row->next;
+
return 0;
}
+
+
+/***************************************************************************
+ Select_fetch_into_spvars
+****************************************************************************/
+
+int Select_fetch_into_spvars::prepare(List<Item> &fields, SELECT_LEX_UNIT *u)
+{
+ /*
+ Cache the number of columns in the result set in order to easily
+ return an error if column count does not match value count.
+ */
+ field_count= fields.elements;
+ return select_result_interceptor::prepare(fields, u);
+}
+
+
+bool Select_fetch_into_spvars::send_data(List<Item> &items)
+{
+ List_iterator_fast<struct sp_pvar> pv_iter(*spvar_list);
+ List_iterator_fast<Item> item_iter(items);
+ sp_pvar_t *pv;
+ Item *item;
+
+ /* Must be ensured by the caller */
+ DBUG_ASSERT(spvar_list->elements == items.elements);
+
+ /*
+ Assign the row fetched from a server side cursor to stored
+ procedure variables.
+ */
+ for (; pv= pv_iter++, item= item_iter++; )
+ {
+ Item *reuse= thd->spcont->get_item(pv->offset);
+ /* Evaluate a new item on the arena of the calling instruction */
+ Item *it= sp_eval_func_item(thd, &item, pv->type, reuse, TRUE);
+
+ thd->spcont->set_item(pv->offset, it);
+ }
+ return FALSE;
+}
diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h
index 36380952e5d..22fa4f6e865 100644
--- a/sql/sp_rcontext.h
+++ b/sql/sp_rcontext.h
@@ -58,7 +58,6 @@ class sp_rcontext : public Sql_alloc
public:
- bool in_handler;
/*
Arena used to (re) allocate items on . E.g. reallocate INOUT/OUT
SP parameters when they don't fit into prealloced items. This
@@ -169,6 +168,18 @@ class sp_rcontext : public Sql_alloc
return m_hstack[--m_hsp];
}
+ inline void
+ enter_handler(int hid)
+ {
+ m_in_handler[m_ihsp++]= hid;
+ }
+
+ inline void
+ exit_handler()
+ {
+ m_ihsp-= 1;
+ }
+
// Save variables starting at fp and up
void
save_variables(uint fp);
@@ -203,12 +214,14 @@ private:
Item *m_result; // For FUNCTIONs
- sp_handler_t *m_handler;
- uint m_hcount;
- uint *m_hstack;
- uint m_hsp;
- int m_hfound; // Set by find_handler; -1 if not found
- List<Item> m_saved; // Saved variables
+ sp_handler_t *m_handler; // Visible handlers
+ uint m_hcount; // Stack pointer for m_handler
+ uint *m_hstack; // Return stack for continue handlers
+ uint m_hsp; // Stack pointer for m_hstack
+ uint *m_in_handler; // Active handler, for recursion check
+ uint m_ihsp; // Stack pointer for m_in_handler
+ int m_hfound; // Set by find_handler; -1 if not found
+ List<Item> m_saved; // Saved variables during handler exec.
sp_cursor **m_cstack;
uint m_ccount;
@@ -216,6 +229,27 @@ private:
}; // class sp_rcontext : public Sql_alloc
+/*
+ An interceptor of cursor result set used to implement
+ FETCH <cname> INTO <varlist>.
+*/
+
+class Select_fetch_into_spvars: public select_result_interceptor
+{
+ List<struct sp_pvar> *spvar_list;
+ uint field_count;
+public:
+ uint get_field_count() { return field_count; }
+ void set_spvar_list(List<struct sp_pvar> *vars) { spvar_list= vars; }
+
+ virtual bool send_eof() { return FALSE; }
+ virtual bool send_data(List<Item> &items);
+ virtual int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
+};
+
+
+/* A mediator between stored procedures and server side cursors */
+
class sp_cursor : public Sql_alloc
{
public:
@@ -227,12 +261,11 @@ public:
destroy();
}
- // We have split this in two to make it easy for sp_instr_copen
- // to reuse the sp_instr::exec_stmt() code.
sp_lex_keeper *
- pre_open(THD *thd);
- void
- post_open(THD *thd, my_bool was_opened);
+ get_lex_keeper() { return m_lex_keeper; }
+
+ int
+ open(THD *thd);
int
close(THD *thd);
@@ -240,7 +273,7 @@ public:
inline my_bool
is_open()
{
- return m_isopen;
+ return test(server_side_cursor);
}
int
@@ -251,18 +284,13 @@ public:
{
return m_i;
}
-
+
private:
- MEM_ROOT m_mem_root; // My own mem_root
+ Select_fetch_into_spvars result;
sp_lex_keeper *m_lex_keeper;
- Protocol_cursor *m_prot;
- my_bool m_isopen;
- my_bool m_nseof; // Original no_send_eof
- Protocol *m_oprot; // Original protcol
- MYSQL_ROWS *m_current_row;
+ Server_side_cursor *server_side_cursor;
sp_instr_cpush *m_i; // My push instruction
-
void
destroy();
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index c7a6387aab1..7a87f01258a 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -692,8 +692,8 @@ static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b)
SYNOPSIS
acl_getroot()
thd thread handle. If all checks are OK,
- thd->priv_user, thd->master_access are updated.
- thd->host, thd->ip, thd->user are used for checks.
+ thd->security_ctx->priv_user/master_access are updated.
+ thd->security_ctx->host/ip/user are used for checks.
mqh user resources; on success mqh is reset, else
unchanged
passwd scrambled & crypted password, received from client
@@ -718,6 +718,7 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh,
ulong user_access= NO_ACCESS;
int res= 1;
ACL_USER *acl_user= 0;
+ Security_context *sctx= thd->security_ctx;
DBUG_ENTER("acl_getroot");
if (!initialized)
@@ -725,9 +726,7 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh,
/*
here if mysqld's been started with --skip-grant-tables option.
*/
- thd->priv_user= (char *) ""; // privileges for
- *thd->priv_host= '\0'; // the user are unknown
- thd->master_access= ~NO_ACCESS; // everything is allowed
+ sctx->skip_grants();
bzero((char*) mqh, sizeof(*mqh));
DBUG_RETURN(0);
}
@@ -743,9 +742,9 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh,
for (uint i=0 ; i < acl_users.elements ; i++)
{
ACL_USER *acl_user_tmp= dynamic_element(&acl_users,i,ACL_USER*);
- if (!acl_user_tmp->user || !strcmp(thd->user, acl_user_tmp->user))
+ if (!acl_user_tmp->user || !strcmp(sctx->user, acl_user_tmp->user))
{
- if (compare_hostname(&acl_user_tmp->host, thd->host, thd->ip))
+ if (compare_hostname(&acl_user_tmp->host, sctx->host, sctx->ip))
{
/* check password: it should be empty or valid */
if (passwd_len == acl_user_tmp->salt_len)
@@ -892,14 +891,14 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh,
break;
#endif /* HAVE_OPENSSL */
}
- thd->master_access= user_access;
- thd->priv_user= acl_user->user ? thd->user : (char *) "";
+ sctx->master_access= user_access;
+ sctx->priv_user= acl_user->user ? sctx->user : (char *) "";
*mqh= acl_user->user_resource;
if (acl_user->host.hostname)
- strmake(thd->priv_host, acl_user->host.hostname, MAX_HOSTNAME);
+ strmake(sctx->priv_host, acl_user->host.hostname, MAX_HOSTNAME);
else
- *thd->priv_host= 0;
+ *sctx->priv_host= 0;
}
VOID(pthread_mutex_unlock(&acl_cache->lock));
DBUG_RETURN(res);
@@ -907,47 +906,62 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh,
/*
- * This is like acl_getroot() above, but it doesn't check password,
- * and we don't care about the user resources.
- * Used to get access rights for SQL SECURITY DEFINER invocation of
- * stored procedures.
- */
-int acl_getroot_no_password(THD *thd)
+ This is like acl_getroot() above, but it doesn't check password,
+ and we don't care about the user resources.
+
+ SYNOPSIS
+ acl_getroot_no_password()
+ sctx Context which should be initialized
+ user user name
+ host host name
+ ip IP
+ db current data base name
+
+ RETURN
+ FALSE OK
+ TRUE Error
+*/
+
+bool acl_getroot_no_password(Security_context *sctx, char *user, char *host,
+ char *ip, char *db)
{
int res= 1;
uint i;
ACL_USER *acl_user= 0;
DBUG_ENTER("acl_getroot_no_password");
+ sctx->user= user;
+ sctx->host= host;
+ sctx->ip= ip;
+ sctx->host_or_ip= host ? host : (ip ? ip : "");
+
if (!initialized)
{
- /*
+ /*
here if mysqld's been started with --skip-grant-tables option.
*/
- thd->priv_user= (char *) ""; // privileges for
- *thd->priv_host= '\0'; // the user are unknown
- thd->master_access= ~NO_ACCESS; // everything is allowed
- DBUG_RETURN(0);
+ sctx->skip_grants();
+ DBUG_RETURN(FALSE);
}
VOID(pthread_mutex_lock(&acl_cache->lock));
- thd->master_access= 0;
- thd->db_access= 0;
+ sctx->master_access= 0;
+ sctx->db_access= 0;
/*
Find acl entry in user database.
This is specially tailored to suit the check we do for CALL of
- a stored procedure; thd->user is set to what is actually a
+ a stored procedure; user is set to what is actually a
priv_user, which can be ''.
*/
for (i=0 ; i < acl_users.elements ; i++)
{
acl_user= dynamic_element(&acl_users,i,ACL_USER*);
- if ((!acl_user->user && (!thd->user || !thd->user[0])) ||
- (acl_user->user && strcmp(thd->user, acl_user->user) == 0))
+ if ((!acl_user->user && (!user || !user[0])) ||
+ (acl_user->user && strcmp(user, acl_user->user) == 0))
{
- if (compare_hostname(&acl_user->host, thd->host, thd->ip))
+ if (compare_hostname(&acl_user->host, host, ip))
{
res= 0;
break;
@@ -961,25 +975,25 @@ int acl_getroot_no_password(THD *thd)
{
ACL_DB *acl_db= dynamic_element(&acl_dbs, i, ACL_DB*);
if (!acl_db->user ||
- (thd->user && thd->user[0] && !strcmp(thd->user, acl_db->user)))
+ (user && user[0] && !strcmp(user, acl_db->user)))
{
- if (compare_hostname(&acl_db->host, thd->host, thd->ip))
+ if (compare_hostname(&acl_db->host, host, ip))
{
- if (!acl_db->db || (thd->db && !strcmp(acl_db->db, thd->db)))
+ if (!acl_db->db || (db && !strcmp(acl_db->db, db)))
{
- thd->db_access= acl_db->access;
+ sctx->db_access= acl_db->access;
break;
}
}
}
}
- thd->master_access= acl_user->access;
- thd->priv_user= acl_user->user ? thd->user : (char *) "";
+ sctx->master_access= acl_user->access;
+ sctx->priv_user= acl_user->user ? user : (char *) "";
if (acl_user->host.hostname)
- strmake(thd->priv_host, acl_user->host.hostname, MAX_HOSTNAME);
+ strmake(sctx->priv_host, acl_user->host.hostname, MAX_HOSTNAME);
else
- *thd->priv_host= 0;
+ *sctx->priv_host= 0;
}
VOID(pthread_mutex_unlock(&acl_cache->lock));
DBUG_RETURN(res);
@@ -1333,13 +1347,14 @@ bool check_change_password(THD *thd, const char *host, const char *user,
return(1);
}
if (!thd->slave_thread &&
- (strcmp(thd->user,user) ||
- my_strcasecmp(system_charset_info, host, thd->priv_host)))
+ (strcmp(thd->security_ctx->user, user) ||
+ my_strcasecmp(system_charset_info, host,
+ thd->security_ctx->priv_host)))
{
if (check_access(thd, UPDATE_ACL, "mysql",0,1,0,0))
return(1);
}
- if (!thd->slave_thread && !thd->user[0])
+ if (!thd->slave_thread && !thd->security_ctx->user[0])
{
my_message(ER_PASSWORD_ANONYMOUS_USER, ER(ER_PASSWORD_ANONYMOUS_USER),
MYF(0));
@@ -1472,7 +1487,7 @@ bool is_acl_user(const char *host, const char *user)
{
bool res;
VOID(pthread_mutex_lock(&acl_cache->lock));
- res= find_acl_user(host, user, TRUE);
+ res= find_acl_user(host, user, TRUE) != NULL;
VOID(pthread_mutex_unlock(&acl_cache->lock));
return res;
}
@@ -1645,9 +1660,10 @@ static bool update_user_table(THD *thd, TABLE *table,
static bool test_if_create_new_users(THD *thd)
{
- bool create_new_users= test(thd->master_access & INSERT_ACL) ||
+ Security_context *sctx= thd->security_ctx;
+ bool create_new_users= test(sctx->master_access & INSERT_ACL) ||
(!opt_safe_user_create &&
- test(thd->master_access & CREATE_USER_ACL));
+ test(sctx->master_access & CREATE_USER_ACL));
if (!create_new_users)
{
TABLE_LIST tl;
@@ -1657,8 +1673,8 @@ static bool test_if_create_new_users(THD *thd)
tl.table_name= (char*) "user";
create_new_users= 1;
- db_access=acl_get(thd->host, thd->ip,
- thd->priv_user, tl.db, 0);
+ db_access=acl_get(sctx->host, sctx->ip,
+ sctx->priv_user, tl.db, 0);
if (!(db_access & INSERT_ACL))
{
if (check_grant(thd, INSERT_ACL, &tl, 0, UINT_MAX, 1))
@@ -1737,7 +1753,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
else if (!can_create_user)
{
my_error(ER_CANT_CREATE_USER_WITH_GRANT, MYF(0),
- thd->user, thd->host_or_ip);
+ thd->security_ctx->user, thd->security_ctx->host_or_ip);
goto end;
}
old_row_exists = 0;
@@ -2449,7 +2465,8 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
byte user_key[MAX_KEY_LENGTH];
DBUG_ENTER("replace_table_table");
- strxmov(grantor, thd->user, "@", thd->host_or_ip, NullS);
+ strxmov(grantor, thd->security_ctx->user, "@",
+ thd->security_ctx->host_or_ip, NullS);
/*
The following should always succeed as new users are created before
@@ -2571,7 +2588,8 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name,
DBUG_RETURN(-1);
}
- strxmov(grantor, thd->user, "@", thd->host_or_ip, NullS);
+ strxmov(grantor, thd->security_ctx->user, "@",
+ thd->security_ctx->host_or_ip, NullS);
/*
The following should always succeed as new users are created before
@@ -2762,7 +2780,8 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list,
get_privilege_desc(command, sizeof(command),
table_list->grant.want_privilege);
my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0),
- command, thd->priv_user, thd->host_or_ip, table_list->alias);
+ command, thd->security_ctx->priv_user,
+ thd->security_ctx->host_or_ip, table_list->alias);
DBUG_RETURN(-1);
}
}
@@ -3486,11 +3505,11 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
uint show_table, uint number, bool no_errors)
{
TABLE_LIST *table;
- char *user = thd->priv_user;
+ Security_context *sctx= thd->security_ctx;
DBUG_ENTER("check_grant");
DBUG_ASSERT(number > 0);
- want_access&= ~thd->master_access;
+ want_access&= ~sctx->master_access;
if (!want_access)
DBUG_RETURN(0); // ok
@@ -3508,8 +3527,9 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
table->grant.want_privilege= 0;
continue; // Already checked
}
- if (!(grant_table= table_hash_search(thd->host,thd->ip,
- table->db,user, table->table_name,0)))
+ if (!(grant_table= table_hash_search(sctx->host, sctx->ip,
+ table->db, sctx->priv_user,
+ table->table_name,0)))
{
want_access &= ~table->grant.privilege;
goto err; // No grants
@@ -3543,8 +3563,8 @@ err:
get_privilege_desc(command, sizeof(command), want_access);
my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0),
command,
- thd->priv_user,
- thd->host_or_ip,
+ sctx->priv_user,
+ sctx->host_or_ip,
table ? table->table_name : "unknown");
}
DBUG_RETURN(1);
@@ -3555,6 +3575,7 @@ bool check_grant_column(THD *thd, GRANT_INFO *grant,
const char *db_name, const char *table_name,
const char *name, uint length, uint show_tables)
{
+ Security_context *sctx= thd->security_ctx;
GRANT_TABLE *grant_table;
GRANT_COLUMN *grant_column;
ulong want_access= grant->want_privilege & ~grant->privilege;
@@ -3571,8 +3592,8 @@ bool check_grant_column(THD *thd, GRANT_INFO *grant,
if (grant->version != grant_version)
{
grant->grant_table=
- table_hash_search(thd->host, thd->ip, db_name,
- thd->priv_user,
+ table_hash_search(sctx->host, sctx->ip, db_name,
+ sctx->priv_user,
table_name, 0); /* purecov: inspected */
grant->version= grant_version; /* purecov: inspected */
}
@@ -3601,8 +3622,8 @@ err:
get_privilege_desc(command, sizeof(command), want_access);
my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0),
command,
- thd->priv_user,
- thd->host_or_ip,
+ sctx->priv_user,
+ sctx->host_or_ip,
name,
table_name);
}
@@ -3614,6 +3635,7 @@ bool check_grant_all_columns(THD *thd, ulong want_access, GRANT_INFO *grant,
const char* db_name, const char *table_name,
Field_iterator *fields)
{
+ Security_context *sctx= thd->security_ctx;
GRANT_TABLE *grant_table;
GRANT_COLUMN *grant_column;
@@ -3630,8 +3652,8 @@ bool check_grant_all_columns(THD *thd, ulong want_access, GRANT_INFO *grant,
if (grant->version != grant_version)
{
grant->grant_table=
- table_hash_search(thd->host, thd->ip, db_name,
- thd->priv_user,
+ table_hash_search(sctx->host, sctx->ip, db_name,
+ sctx->priv_user,
table_name, 0); /* purecov: inspected */
grant->version= grant_version; /* purecov: inspected */
}
@@ -3657,8 +3679,8 @@ err2:
get_privilege_desc(command, sizeof(command), want_access);
my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0),
command,
- thd->priv_user,
- thd->host_or_ip,
+ sctx->priv_user,
+ sctx->host_or_ip,
fields->name(),
table_name);
return 1;
@@ -3673,11 +3695,12 @@ err2:
bool check_grant_db(THD *thd,const char *db)
{
+ Security_context *sctx= thd->security_ctx;
char helping [NAME_LEN+USERNAME_LENGTH+2];
uint len;
bool error= 1;
- len= (uint) (strmov(strmov(helping,thd->priv_user)+1,db)-helping)+ 1;
+ len= (uint) (strmov(strmov(helping, sctx->priv_user) + 1, db) - helping) + 1;
rw_rdlock(&LOCK_grant);
for (uint idx=0 ; idx < column_priv_hash.records ; idx++)
@@ -3686,7 +3709,7 @@ bool check_grant_db(THD *thd,const char *db)
idx);
if (len < grant_table->key_length &&
!memcmp(grant_table->hash_key,helping,len) &&
- compare_hostname(&grant_table->host, thd->host, thd->ip))
+ compare_hostname(&grant_table->host, sctx->host, sctx->ip))
{
error=0; // Found match
break;
@@ -3714,15 +3737,16 @@ bool check_grant_db(THD *thd,const char *db)
1 Error: User did not have the requested privielges
****************************************************************************/
-bool check_grant_routine(THD *thd, ulong want_access,
+bool check_grant_routine(THD *thd, ulong want_access,
TABLE_LIST *procs, bool is_proc, bool no_errors)
{
TABLE_LIST *table;
- char *user= thd->priv_user;
- char *host= thd->priv_host;
+ Security_context *sctx= thd->security_ctx;
+ char *user= sctx->priv_user;
+ char *host= sctx->priv_host;
DBUG_ENTER("check_grant_routine");
- want_access&= ~thd->master_access;
+ want_access&= ~sctx->master_access;
if (!want_access)
DBUG_RETURN(0); // ok
@@ -3730,7 +3754,7 @@ bool check_grant_routine(THD *thd, ulong want_access,
for (table= procs; table; table= table->next_global)
{
GRANT_NAME *grant_proc;
- if ((grant_proc= routine_hash_search(host,thd->ip, table->db, user,
+ if ((grant_proc= routine_hash_search(host, sctx->ip, table->db, user,
table->table_name, is_proc, 0)))
table->grant.privilege|= grant_proc->privs;
@@ -3785,9 +3809,12 @@ bool check_routine_level_acl(THD *thd, const char *db, const char *name,
if (grant_option)
{
GRANT_NAME *grant_proc;
+ Security_context *sctx= thd->security_ctx;
rw_rdlock(&LOCK_grant);
- if ((grant_proc= routine_hash_search(thd->priv_host, thd->ip, db,
- thd->priv_user, name, is_proc, 0)))
+ if ((grant_proc= routine_hash_search(sctx->priv_host,
+ sctx->ip, db,
+ sctx->priv_user,
+ name, is_proc, 0)))
no_routine_acl= !(grant_proc->privs & SHOW_PROC_ACLS);
rw_unlock(&LOCK_grant);
}
@@ -3802,7 +3829,7 @@ bool check_routine_level_acl(THD *thd, const char *db, const char *name,
ulong get_table_grant(THD *thd, TABLE_LIST *table)
{
ulong privilege;
- char *user = thd->priv_user;
+ Security_context *sctx= thd->security_ctx;
const char *db = table->db ? table->db : thd->db;
GRANT_TABLE *grant_table;
@@ -3810,7 +3837,7 @@ ulong get_table_grant(THD *thd, TABLE_LIST *table)
#ifdef EMBEDDED_LIBRARY
grant_table= NULL;
#else
- grant_table= table_hash_search(thd->host, thd->ip, db, user,
+ grant_table= table_hash_search(sctx->host, sctx->ip, db, sctx->priv_user,
table->table_name, 0);
#endif
table->grant.grant_table=grant_table; // Remember for column test
@@ -3853,9 +3880,10 @@ ulong get_column_grant(THD *thd, GRANT_INFO *grant,
/* reload table if someone has modified any grants */
if (grant->version != grant_version)
{
+ Security_context *sctx= thd->security_ctx;
grant->grant_table=
- table_hash_search(thd->host, thd->ip, db_name,
- thd->priv_user,
+ table_hash_search(sctx->host, sctx->ip,
+ db_name, sctx->priv_user,
table_name, 0); /* purecov: inspected */
grant->version= grant_version; /* purecov: inspected */
}
@@ -5425,22 +5453,24 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
bool is_proc)
{
+ Security_context *sctx= thd->security_ctx;
LEX_USER *combo;
TABLE_LIST tables[1];
List<LEX_USER> user_list;
bool result;
- DBUG_ENTER("sp_grant_privileges");
+ DBUG_ENTER("sp_grant_privileges");
if (!(combo=(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
DBUG_RETURN(TRUE);
- combo->user.str= thd->user;
+ combo->user.str= sctx->user;
- if (!find_acl_user(combo->host.str=(char*)thd->host_or_ip, combo->user.str,
+ if (!find_acl_user(combo->host.str=(char*)sctx->host_or_ip, combo->user.str,
+ FALSE) &&
+ !find_acl_user(combo->host.str=(char*)sctx->host, combo->user.str,
FALSE) &&
- !find_acl_user(combo->host.str=(char*)thd->host, combo->user.str,
+ !find_acl_user(combo->host.str=(char*)sctx->ip, combo->user.str,
FALSE) &&
- !find_acl_user(combo->host.str=(char*)thd->ip, combo->user.str, FALSE) &&
!find_acl_user(combo->host.str=(char*)"%", combo->user.str, FALSE))
DBUG_RETURN(TRUE);
@@ -5557,7 +5587,7 @@ int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
char buff[100];
TABLE *table= tables->table;
bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1,0);
- char *curr_host= thd->priv_host ? thd->priv_host : (char *) "%";
+ char *curr_host= thd->security_ctx->priv_host_name();
DBUG_ENTER("fill_schema_user_privileges");
for (counter=0 ; counter < acl_users.elements ; counter++)
@@ -5570,7 +5600,7 @@ int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
host= "";
if (no_global_access &&
- (strcmp(thd->priv_user, user) ||
+ (strcmp(thd->security_ctx->priv_user, user) ||
my_strcasecmp(system_charset_info, curr_host, host)))
continue;
@@ -5610,7 +5640,7 @@ int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
char buff[100];
TABLE *table= tables->table;
bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1,0);
- char *curr_host= thd->priv_host ? thd->priv_host : (char *) "%";
+ char *curr_host= thd->security_ctx->priv_host_name();
DBUG_ENTER("fill_schema_schema_privileges");
for (counter=0 ; counter < acl_dbs.elements ; counter++)
@@ -5624,7 +5654,7 @@ int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
host= "";
if (no_global_access &&
- (strcmp(thd->priv_user, user) ||
+ (strcmp(thd->security_ctx->priv_user, user) ||
my_strcasecmp(system_charset_info, curr_host, host)))
continue;
@@ -5665,7 +5695,7 @@ int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
char buff[100];
TABLE *table= tables->table;
bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1,0);
- char *curr_host= thd->priv_host ? thd->priv_host : (char *) "%";
+ char *curr_host= thd->security_ctx->priv_host_name();
DBUG_ENTER("fill_schema_table_privileges");
for (index=0 ; index < column_priv_hash.records ; index++)
@@ -5677,7 +5707,7 @@ int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
user= "";
if (no_global_access &&
- (strcmp(thd->priv_user, user) ||
+ (strcmp(thd->security_ctx->priv_user, user) ||
my_strcasecmp(system_charset_info, curr_host,
grant_table->host.hostname)))
continue;
@@ -5727,7 +5757,7 @@ int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
char buff[100];
TABLE *table= tables->table;
bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1,0);
- char *curr_host= thd->priv_host ? thd->priv_host : (char *) "%";
+ char *curr_host= thd->security_ctx->priv_host_name();
DBUG_ENTER("fill_schema_table_privileges");
for (index=0 ; index < column_priv_hash.records ; index++)
@@ -5739,7 +5769,7 @@ int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
user= "";
if (no_global_access &&
- (strcmp(thd->priv_user, user) ||
+ (strcmp(thd->security_ctx->priv_user, user) ||
my_strcasecmp(system_charset_info, curr_host,
grant_table->host.hostname)))
continue;
@@ -5803,6 +5833,7 @@ int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
const char *db, const char *table)
{
+ Security_context *sctx= thd->security_ctx;
/* --skip-grants */
if (!initialized)
{
@@ -5811,13 +5842,13 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
}
/* global privileges */
- grant->privilege= thd->master_access;
+ grant->privilege= sctx->master_access;
- if (!thd->priv_user)
+ if (!sctx->priv_user)
return; // it is slave
/* db privileges */
- grant->privilege|= acl_get(thd->host, thd->ip, thd->priv_user, db, 0);
+ grant->privilege|= acl_get(sctx->host, sctx->ip, sctx->priv_user, db, 0);
if (!grant_option)
return;
@@ -5827,8 +5858,8 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
{
rw_rdlock(&LOCK_grant);
grant->grant_table=
- table_hash_search(thd->host, thd->ip, db,
- thd->priv_user,
+ table_hash_search(sctx->host, sctx->ip, db,
+ sctx->priv_user,
table, 0); /* purecov: inspected */
grant->version= grant_version; /* purecov: inspected */
rw_unlock(&LOCK_grant);
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
index 0d739e860e9..0a9c6ba785f 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -182,7 +182,8 @@ ulong acl_get(const char *host, const char *ip,
const char *user, const char *db, my_bool db_is_pattern);
int acl_getroot(THD *thd, USER_RESOURCES *mqh, const char *passwd,
uint passwd_len);
-int acl_getroot_no_password(THD *thd);
+bool acl_getroot_no_password(Security_context *sctx, char *user, char *host,
+ char *ip, char *db);
bool acl_check_host(const char *host, const char *ip);
bool check_change_password(THD *thd, const char *host, const char *user,
char *password, uint password_len);
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 38a9d259d24..1de9411cad0 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -1327,6 +1327,8 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
table->keys_in_use_for_query= table->s->keys_in_use;
table->insert_values= 0;
table->used_keys= table->s->keys_for_keyread;
+ table->fulltext_searched= 0;
+ table->file->ft_handler= 0;
if (table->timestamp_field)
table->timestamp_field_type= table->timestamp_field->get_auto_set_type();
table_list->updatable= 1; // It is not derived table nor non-updatable VIEW
@@ -2146,7 +2148,7 @@ static bool check_lock_and_start_stmt(THD *thd, TABLE *table,
my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0),table->alias);
DBUG_RETURN(1);
}
- if ((error=table->file->start_stmt(thd)))
+ if ((error=table->file->start_stmt(thd, lock_type)))
{
table->file->print_error(error,MYF(0));
DBUG_RETURN(1);
@@ -2953,6 +2955,18 @@ find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
belongs - differs from 'table_list' only for
NATURAL_USING joins.
+ DESCRIPTION
+ Find a field in a table reference depending on the type of table
+ reference. There are three types of table references with respect
+ to the representation of their result columns:
+ - an array of Field_translator objects for MERGE views and some
+ information_schema tables,
+ - an array of Field objects (and possibly a name hash) for stored
+ tables,
+ - a list of Natural_join_column objects for NATURAL/USING joins.
+ This procedure detects the type of the table reference 'table_list'
+ and calls the corresponding search routine.
+
RETURN
0 field is not found
view_ref_found found value in VIEW (real result is in *ref)
@@ -2976,16 +2990,29 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
/*
Check that the table and database that qualify the current field name
- are the same as the table we are going to search for the field.
- This is done differently for NATURAL/USING joins or nested joins that
- are operands of NATURAL/USING joins because there we can't simply
- compare the qualifying table and database names with the ones of
- 'table_list' because each field in such a join may originate from a
- different table.
+ are the same as the table reference we are going to search for the field.
+
+ Exclude from the test below nested joins because the columns in a
+ nested join generally originate from different tables. Nested joins
+ also have no table name, except when a nested join is a merge view
+ or an information schema table.
+
+ We include explicitly table references with a 'field_translation' table,
+ because if there are views over natural joins we don't want to search
+ inside the view, but we want to search directly in the view columns
+ which are represented as a 'field_translation'.
+
TODO: Ensure that table_name, db_name and tables->db always points to
something !
*/
- if (!(table_list->nested_join && table_list->join_columns) &&
+ if (/* Exclude nested joins. */
+ (!table_list->nested_join ||
+ /* Include merge views and information schema tables. */
+ table_list->field_translation) &&
+ /*
+ Test if the field qualifiers match the table reference we plan
+ to search.
+ */
table_name && table_name[0] &&
(my_strcasecmp(table_alias_charset, table_list->alias, table_name) ||
(db_name && db_name[0] && table_list->db && table_list->db[0] &&
@@ -2993,25 +3020,45 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
DBUG_RETURN(0);
*actual_table= NULL;
+
if (table_list->field_translation)
{
+ /* 'table_list' is a view or an information schema table. */
if ((fld= find_field_in_view(thd, table_list, name, item_name, length,
ref, check_grants_view,
register_tree_change)))
*actual_table= table_list;
}
- else if (table_list->nested_join && table_list->join_columns)
+ else if (!table_list->nested_join)
+ {
+ /* 'table_list' is a stored table. */
+ DBUG_ASSERT(table_list->table);
+ if ((fld= find_field_in_table(thd, table_list->table, name, length,
+ check_grants_table, allow_rowid,
+ cached_field_index_ptr)))
+ *actual_table= table_list;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ /* check for views with temporary table algorithm */
+ if (check_grants_view && table_list->view &&
+ fld && fld != WRONG_GRANT &&
+ check_grant_column(thd, &table_list->grant,
+ table_list->view_db.str,
+ table_list->view_name.str,
+ name, length))
+ fld= WRONG_GRANT;
+#endif
+ }
+ else
{
/*
- If this is a NATURAL/USING join, or an operand of such join which is a
- join itself, and the field name is qualified, then search for the field
- in the operands of the join.
+ 'table_list' is a NATURAL/USING join, or an operand of such join that
+ is a nested join itself.
+
+ If the field name we search for is qualified, then search for the field
+ in the table references used by NATURAL/USING the join.
*/
if (table_name && table_name[0])
{
- /*
- Qualified field; Search for it in the tables used by the natural join.
- */
List_iterator<TABLE_LIST> it(table_list->nested_join->join_list);
TABLE_LIST *table;
while ((table= it++))
@@ -3037,23 +3084,6 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
check_grants_table || check_grants_view,
register_tree_change, actual_table);
}
- else
- {
- if ((fld= find_field_in_table(thd, table_list->table, name, length,
- check_grants_table, allow_rowid,
- cached_field_index_ptr)))
- *actual_table= table_list;
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- /* check for views with temporary table algorithm */
- if (check_grants_view && table_list->view &&
- fld && fld != WRONG_GRANT &&
- check_grant_column(thd, &table_list->grant,
- table_list->view_db.str,
- table_list->view_name.str,
- name, length))
- fld= WRONG_GRANT;
-#endif
- }
DBUG_RETURN(fld);
}
@@ -3364,9 +3394,9 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
for (uint i= 0; (item=li++); i++)
{
- if (field_name && item->type() == Item::FIELD_ITEM)
+ if (field_name && item->real_item()->type() == Item::FIELD_ITEM)
{
- Item_field *item_field= (Item_field*) item;
+ Item_ident *item_field= (Item_ident*) item;
/*
In case of group_concat() with ORDER BY condition in the QUERY
@@ -3466,7 +3496,7 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
}
}
}
- else if (!table_name && (item->eq(find,0) ||
+ else if (!table_name && (find->eq(item,0) ||
find->name && item->name &&
!my_strcasecmp(system_charset_info,
item->name,find->name)))
@@ -4617,7 +4647,8 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
VIEW_ANY_ACL)))
{
my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), "ANY",
- thd->priv_user, thd->host_or_ip,
+ thd->security_ctx->priv_user,
+ thd->security_ctx->host_or_ip,
fld->field_name, field_table_name);
DBUG_RETURN(TRUE);
}
@@ -4805,9 +4836,6 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
}
DBUG_RETURN(test(thd->net.report_error));
-err:
- if (arena)
- thd->restore_active_arena(arena, &backup);
err_no_arena:
DBUG_RETURN(1);
}
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 1ca9db44cc7..f17825e6d2c 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -1299,7 +1299,8 @@ void Query_cache::invalidate_locked_for_write(TABLE_LIST *tables_used)
DUMP(this);
for (; tables_used; tables_used= tables_used->next_local)
{
- if (tables_used->lock_type & (TL_WRITE_LOW_PRIORITY | TL_WRITE))
+ if (tables_used->lock_type & (TL_WRITE_LOW_PRIORITY | TL_WRITE) &&
+ tables_used->table)
invalidate_table(tables_used->table);
}
}
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 2699a4fa628..fc7ea6a2794 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -181,9 +181,10 @@ THD::THD()
spcont(NULL)
{
stmt_arena= this;
- host= user= priv_user= db= ip= 0;
+ db= 0;
catalog= (char*)"std"; // the only catalog we have for now
- host_or_ip= "connecting host";
+ main_security_ctx.init();
+ security_ctx= &main_security_ctx;
locked=some_tables_deleted=no_errors=password= 0;
query_start_used= 0;
count_cuted_fields= CHECK_FIELD_IGNORE;
@@ -236,9 +237,6 @@ THD::THD()
server_id = ::server_id;
slave_net = 0;
command=COM_CONNECT;
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- db_access=NO_ACCESS;
-#endif
*scramble= '\0';
init();
@@ -426,12 +424,8 @@ THD::~THD()
ha_close_connection(this);
- DBUG_PRINT("info", ("freeing host"));
- if (host != my_localhost) // If not pointer to constant
- safeFree(host);
- if (user != delayed_user)
- safeFree(user);
- safeFree(ip);
+ DBUG_PRINT("info", ("freeing security context"));
+ main_security_ctx.destroy();
safeFree(db);
free_root(&warn_root,MYF(0));
#ifdef USING_TRANSACTIONS
@@ -1544,6 +1538,19 @@ void Query_arena::free_items()
}
+void Query_arena::set_query_arena(Query_arena *set)
+{
+ mem_root= set->mem_root;
+ free_list= set->free_list;
+ state= set->state;
+}
+
+
+void Query_arena::cleanup_stmt()
+{
+ DBUG_ASSERT("Query_arena::cleanup_stmt()" == "not implemented");
+}
+
/*
Statement functions
*/
@@ -1601,12 +1608,6 @@ void Statement::restore_backup_statement(Statement *stmt, Statement *backup)
}
-void Statement::close_cursor()
-{
- DBUG_ASSERT("Statement::close_cursor()" == "not implemented");
-}
-
-
void THD::end_statement()
{
/* Cleanup SQL processing state to resuse this statement in next query. */
@@ -1648,13 +1649,6 @@ void THD::restore_active_arena(Query_arena *set, Query_arena *backup)
DBUG_VOID_RETURN;
}
-void Query_arena::set_query_arena(Query_arena *set)
-{
- mem_root= set->mem_root;
- free_list= set->free_list;
- state= set->state;
-}
-
Statement::~Statement()
{
/*
@@ -1723,9 +1717,11 @@ int Statement_map::insert(Statement *statement)
void Statement_map::close_transient_cursors()
{
+#ifdef TO_BE_IMPLEMENTED
Statement *stmt;
while ((stmt= transient_cursor_list.head()))
stmt->close_cursor(); /* deletes itself from the list */
+#endif
}
@@ -1827,6 +1823,38 @@ void THD::set_status_var_init()
bzero((char*) &status_var, sizeof(status_var));
}
+
+void Security_context::init()
+{
+ host= user= priv_user= ip= 0;
+ host_or_ip= "connecting host";
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ db_access= NO_ACCESS;
+#endif
+}
+
+
+void Security_context::destroy()
+{
+ // If not pointer to constant
+ if (host != my_localhost)
+ safeFree(host);
+ if (user != delayed_user)
+ safeFree(user);
+ safeFree(ip);
+}
+
+
+void Security_context::skip_grants()
+{
+ /* privileges for the user are unknown everything is allowed */
+ host_or_ip= (char *)"";
+ master_access= ~NO_ACCESS;
+ priv_user= (char *)"";
+ *priv_host= '\0';
+}
+
+
/****************************************************************************
Handling of open and locked tables states.
@@ -1954,8 +1982,8 @@ HASH xid_cache;
static byte *xid_get_hash_key(const byte *ptr,uint *length,
my_bool not_used __attribute__((unused)))
{
- *length=((XID_STATE*)ptr)->xid.length();
- return (byte *)&((XID_STATE*)ptr)->xid;
+ *length=((XID_STATE*)ptr)->xid.key_length();
+ return ((XID_STATE*)ptr)->xid.key();
}
static void xid_free_hash (void *ptr)
@@ -1983,7 +2011,7 @@ void xid_cache_free()
XID_STATE *xid_cache_search(XID *xid)
{
pthread_mutex_lock(&LOCK_xid_cache);
- XID_STATE *res=(XID_STATE *)hash_search(&xid_cache, (byte *)xid, xid->length());
+ XID_STATE *res=(XID_STATE *)hash_search(&xid_cache, xid->key(), xid->key_length());
pthread_mutex_unlock(&LOCK_xid_cache);
return res;
}
@@ -1994,7 +2022,7 @@ bool xid_cache_insert(XID *xid, enum xa_states xa_state)
XID_STATE *xs;
my_bool res;
pthread_mutex_lock(&LOCK_xid_cache);
- if (hash_search(&xid_cache, (byte *)xid, xid->length()))
+ if (hash_search(&xid_cache, xid->key(), xid->key_length()))
res=0;
else if (!(xs=(XID_STATE *)my_malloc(sizeof(*xs), MYF(MY_WME))))
res=1;
@@ -2013,8 +2041,8 @@ bool xid_cache_insert(XID *xid, enum xa_states xa_state)
bool xid_cache_insert(XID_STATE *xid_state)
{
pthread_mutex_lock(&LOCK_xid_cache);
- DBUG_ASSERT(hash_search(&xid_cache, (byte *)&xid_state->xid,
- xid_state->xid.length())==0);
+ DBUG_ASSERT(hash_search(&xid_cache, xid_state->xid.key(),
+ xid_state->xid.key_length())==0);
my_bool res=my_hash_insert(&xid_cache, (byte*)xid_state);
pthread_mutex_unlock(&LOCK_xid_cache);
return res;
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 59b51a702aa..727ed282836 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -510,6 +510,7 @@ struct system_variables
ulong multi_range_count;
ulong myisam_repair_threads;
ulong myisam_sort_buff_size;
+ ulong myisam_stats_method;
ulong net_buffer_length;
ulong net_interactive_timeout;
ulong net_read_timeout;
@@ -742,10 +743,12 @@ public:
void set_query_arena(Query_arena *set);
void free_items();
+ /* Close the active state associated with execution of this statement */
+ virtual void cleanup_stmt();
};
-class Cursor;
+class Server_side_cursor;
/*
State of a single command executed against this connection.
@@ -828,7 +831,7 @@ public:
*/
char *query;
uint32 query_length; // current query length
- Cursor *cursor;
+ Server_side_cursor *cursor;
public:
@@ -845,8 +848,6 @@ public:
void restore_backup_statement(Statement *stmt, Statement *backup);
/* return class type */
virtual Type type() const;
- /* Close the cursor open for this statement, if there is one */
- virtual void close_cursor();
};
@@ -898,9 +899,6 @@ public:
}
hash_delete(&st_hash, (byte *) statement);
}
- void add_transient_cursor(Statement *stmt)
- { transient_cursor_list.append(stmt); }
- void erase_transient_cursor(Statement *stmt) { stmt->unlink(); }
/*
Close all cursors of this connection that use tables of a storage
engine that has transaction-specific state and therefore can not
@@ -953,6 +951,34 @@ bool xid_cache_insert(XID *xid, enum xa_states xa_state);
bool xid_cache_insert(XID_STATE *xid_state);
void xid_cache_delete(XID_STATE *xid_state);
+
+class Security_context {
+public:
+ /*
+ host - host of the client
+ user - user of the client, set to NULL until the user has been read from
+ the connection
+ priv_user - The user privilege we are using. May be "" for anonymous user.
+ ip - client IP
+ */
+ char *host, *user, *priv_user, *ip;
+ /* The host privilege we are using */
+ char priv_host[MAX_HOSTNAME];
+ /* points to host if host is available, otherwise points to ip */
+ const char *host_or_ip;
+ ulong master_access; /* Global privileges from mysql.user */
+ ulong db_access; /* Privileges for current db */
+
+ void init();
+ void destroy();
+ void skip_grants();
+ inline char *priv_host_name()
+ {
+ return (*priv_host ? priv_host : (char *)"%");
+ }
+};
+
+
/*
A registry for item tree transformations performed during
query optimization. We register only those changes which require
@@ -1125,13 +1151,8 @@ public:
char *thread_stack;
/*
- host - host of the client
- user - user of the client, set to NULL until the user has been read from
- the connection
- priv_user - The user privilege we are using. May be '' for anonymous user.
db - currently selected database
catalog - currently selected catalog
- ip - client IP
WARNING: some members of THD (currently 'db', 'catalog' and 'query') are
set and alloced by the slave SQL thread (for the THD of that thread); that
thread is (and must remain, for now) the only responsible for freeing these
@@ -1140,8 +1161,10 @@ public:
properly. For details see the 'err:' label of the pthread_handler_decl of
the slave SQL thread, in sql/slave.cc.
*/
- char *host,*user,*priv_user,*db,*catalog,*ip;
- char priv_host[MAX_HOSTNAME];
+ char *db, *catalog;
+ Security_context main_security_ctx;
+ Security_context *security_ctx;
+
/* remote (peer) port */
uint16 peer_port;
/*
@@ -1150,13 +1173,9 @@ public:
a time-consuming piece that MySQL can get stuck in for a long time.
*/
const char *proc_info;
- /* points to host if host is available, otherwise points to ip */
- const char *host_or_ip;
ulong client_capabilities; /* What the client supports */
ulong max_client_packet_length;
- ulong master_access; /* Global privileges from mysql.user */
- ulong db_access; /* Privileges for current db */
HASH handler_tables_hash;
/*
@@ -1824,18 +1843,21 @@ public:
}
};
-class select_union :public select_result_interceptor {
- public:
- TABLE *table;
+class select_union :public select_result_interceptor
+{
TMP_TABLE_PARAM tmp_table_param;
+public:
+ TABLE *table;
- select_union(TABLE *table_par);
- ~select_union();
+ select_union() :table(0) {}
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
bool send_data(List<Item> &items);
bool send_eof();
bool flush();
- void set_table(TABLE *tbl) { table= tbl; }
+
+ bool create_result_table(THD *thd, List<Item> *column_types,
+ bool is_distinct, ulonglong options,
+ const char *alias);
};
/* Base subselect interface class */
diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc
new file mode 100644
index 00000000000..e8da691ea18
--- /dev/null
+++ b/sql/sql_cursor.cc
@@ -0,0 +1,660 @@
+/* Copyright (C) 2005 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
+#ifdef USE_PRAGMA_IMPLEMENTATION
+#pragma implementation /* gcc class implementation */
+#endif
+
+#include "mysql_priv.h"
+#include "sql_cursor.h"
+#include "sql_select.h"
+
+/****************************************************************************
+ Declarations.
+****************************************************************************/
+
+/*
+ Sensitive_cursor -- a sensitive non-materialized server side
+ cursor An instance of this class cursor has its own runtime
+ state -- list of used items and memory root for runtime memory,
+ open and locked tables, change list for the changes of the
+ parsed tree. This state is freed when the cursor is closed.
+*/
+
+class Sensitive_cursor: public Server_side_cursor
+{
+ MEM_ROOT main_mem_root;
+ Query_arena *stmt_arena;
+ JOIN *join;
+ TABLE *open_tables;
+ MYSQL_LOCK *lock;
+ TABLE *derived_tables;
+ /* List of items created during execution */
+ query_id_t query_id;
+ struct Engine_info
+ {
+ const handlerton *ht;
+ void *read_view;
+ };
+ Engine_info ht_info[MAX_HA];
+ Item_change_list change_list;
+ my_bool close_at_commit;
+ THR_LOCK_OWNER lock_id;
+private:
+ /* bzero cursor state in THD */
+ void reset_thd(THD *thd);
+public:
+ Sensitive_cursor(THD *thd, select_result *result_arg);
+
+ THR_LOCK_OWNER *get_lock_id() { return &lock_id; }
+ /* Save THD state into cursor */
+ void post_open(THD *thd);
+
+ virtual bool is_open() const { return join != 0; }
+ virtual int open(JOIN *join);
+ virtual void fetch(ulong num_rows);
+ virtual void close();
+ virtual ~Sensitive_cursor();
+};
+
+
+/*
+ Materialized_cursor -- an insensitive materialized server-side
+ cursor. The result set of this cursor is saved in a temporary
+ table at open. The cursor itself is simply an interface for the
+ handler of the temporary table.
+*/
+
+class Materialized_cursor: public Server_side_cursor
+{
+ MEM_ROOT main_mem_root;
+ /* A fake unit to supply to select_send when fetching */
+ SELECT_LEX_UNIT fake_unit;
+ TABLE *table;
+ List<Item> item_list;
+ ulong fetch_limit;
+ ulong fetch_count;
+public:
+ Materialized_cursor(select_result *result, TABLE *table);
+
+ virtual bool is_open() const { return table != 0; }
+ virtual int open(JOIN *join __attribute__((unused)));
+ virtual void fetch(ulong num_rows);
+ virtual void close();
+ virtual ~Materialized_cursor();
+};
+
+
+/*
+ Select_materialize -- a mediator between a cursor query and the
+ protocol. In case we were not able to open a non-materialzed
+ cursor, it creates an internal temporary HEAP table, and insert
+ all rows into it. When the table reaches max_heap_table_size,
+ it's converted to a MyISAM table. Later this table is used to
+ create a Materialized_cursor.
+*/
+
+class Select_materialize: public select_union
+{
+ select_result *result; /* the result object of the caller (PS or SP) */
+public:
+ Select_materialize(select_result *result_arg) :result(result_arg) {}
+ virtual bool send_fields(List<Item> &list, uint flags);
+};
+
+
+/**************************************************************************/
+
+/*
+ Attempt to open a materialized or non-materialized cursor.
+
+ SYNOPSIS
+ mysql_open_cursor()
+ thd thread handle
+ flags [in] create a materialized cursor or not
+ result [in] result class of the caller used as a destination
+ for the rows fetched from the cursor
+ pcursor [out] a pointer to store a pointer to cursor in
+
+ RETURN VALUE
+ 0 the query has been successfully executed; in this
+ case pcursor may or may not contain
+ a pointer to an open cursor.
+ non-zero an error, 'pcursor' has been left intact.
+*/
+
+int mysql_open_cursor(THD *thd, uint flags, select_result *result,
+ Server_side_cursor **pcursor)
+{
+ Sensitive_cursor *sensitive_cursor;
+ select_result *save_result;
+ Select_materialize *result_materialize;
+ LEX *lex= thd->lex;
+ int rc;
+
+ /*
+ The lifetime of the sensitive cursor is the same or less as the
+ lifetime of the runtime memory of the statement it's opened for.
+ */
+ if (! (result_materialize= new (thd->mem_root) Select_materialize(result)))
+ return 1;
+
+ if (! (sensitive_cursor= new (thd->mem_root) Sensitive_cursor(thd, result)))
+ {
+ delete result;
+ return 1;
+ }
+
+ save_result= lex->result;
+
+ lex->result= result_materialize;
+ if (! (flags & (uint) ALWAYS_MATERIALIZED_CURSOR))
+ {
+ thd->lock_id= sensitive_cursor->get_lock_id();
+ thd->cursor= sensitive_cursor;
+ }
+
+ rc= mysql_execute_command(thd);
+
+ lex->result= save_result;
+ thd->lock_id= &thd->main_lock_id;
+ thd->cursor= 0;
+
+ /*
+ Possible options here:
+ - a sensitive cursor is open. In this case rc is 0 and
+ result_materialize->table is NULL, or
+ - a materialized cursor is open. In this case rc is 0 and
+ result_materialize->table is not NULL
+ - an error occured during materializaton.
+ result_materialize->table is not NULL, but rc != 0
+ - successful completion of mysql_execute_command without
+ a cursor: rc is 0, result_materialize->table is NULL,
+ sensitive_cursor is not open.
+ This is possible if some command writes directly to the
+ network, bypassing select_result mechanism. An example of
+ such command is SHOW VARIABLES or SHOW STATUS.
+ */
+ if (rc)
+ goto err_open;
+
+ if (sensitive_cursor->is_open())
+ {
+ DBUG_ASSERT(!result_materialize->table);
+ /*
+ It's safer if we grab THD state after mysql_execute_command
+ is finished and not in Sensitive_cursor::open(), because
+ currently the call to Sensitive_cursor::open is buried deep
+ in JOIN::exec of the top level join.
+ */
+ sensitive_cursor->post_open(thd);
+ *pcursor= sensitive_cursor;
+ goto end;
+ }
+ else if (result_materialize->table)
+ {
+ Materialized_cursor *materialized_cursor;
+ TABLE *table= result_materialize->table;
+ MEM_ROOT *mem_root= &table->mem_root;
+
+ if (!(materialized_cursor= new (mem_root)
+ Materialized_cursor(result, table)))
+ {
+ rc= 1;
+ goto err_open;
+ }
+
+ if ((rc= materialized_cursor->open(0)))
+ {
+ delete materialized_cursor;
+ goto err_open;
+ }
+
+ *pcursor= materialized_cursor;
+ thd->stmt_arena->cleanup_stmt();
+ goto end;
+ }
+
+err_open:
+ DBUG_ASSERT(! (sensitive_cursor && sensitive_cursor->is_open()));
+ delete sensitive_cursor;
+ if (result_materialize->table)
+ free_tmp_table(thd, result_materialize->table);
+end:
+ delete result_materialize;
+ return rc;
+}
+
+/****************************************************************************
+ Server_side_cursor
+****************************************************************************/
+
+Server_side_cursor::~Server_side_cursor()
+{
+}
+
+
+void Server_side_cursor::operator delete(void *ptr, size_t size)
+{
+ Server_side_cursor *cursor= (Server_side_cursor*) ptr;
+ MEM_ROOT own_root= *cursor->mem_root;
+
+ DBUG_ENTER("Server_side_cursor::operator delete");
+ TRASH(ptr, size);
+ /*
+ If this cursor has never been opened mem_root is empty. Otherwise
+ mem_root points to the memory the cursor object was allocated in.
+ In this case it's important to call free_root last, and free a copy
+ instead of *mem_root to avoid writing into freed memory.
+ */
+ free_root(&own_root, MYF(0));
+ DBUG_VOID_RETURN;
+}
+
+/****************************************************************************
+ Sensitive_cursor
+****************************************************************************/
+
+Sensitive_cursor::Sensitive_cursor(THD *thd, select_result *result_arg)
+ :Server_side_cursor(&main_mem_root, result_arg),
+ stmt_arena(0),
+ join(0),
+ close_at_commit(FALSE)
+{
+ /* We will overwrite it at open anyway. */
+ init_sql_alloc(&main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
+ thr_lock_owner_init(&lock_id, &thd->lock_info);
+ bzero((void*) ht_info, sizeof(ht_info));
+}
+
+
+void
+Sensitive_cursor::post_open(THD *thd)
+{
+ Engine_info *info;
+ /*
+ We need to save and reset thd->mem_root, otherwise it'll be
+ freed later in mysql_parse.
+
+ We can't just change thd->mem_root here as we want to keep the
+ things that are already allocated in thd->mem_root for
+ Sensitive_cursor::fetch()
+ */
+ *mem_root= *thd->mem_root;
+ stmt_arena= thd->stmt_arena;
+ state= stmt_arena->state;
+ /* Allocate a new memory root for thd */
+ init_sql_alloc(thd->mem_root,
+ thd->variables.query_alloc_block_size,
+ thd->variables.query_prealloc_size);
+
+ /*
+ Save tables and zero THD pointers to prevent table close in
+ close_thread_tables.
+ */
+ derived_tables= thd->derived_tables;
+ open_tables= thd->open_tables;
+ lock= thd->lock;
+ query_id= thd->query_id;
+ free_list= thd->free_list;
+ change_list= thd->change_list;
+ reset_thd(thd);
+ /* Now we have an active cursor and can cause a deadlock */
+ thd->lock_info.n_cursors++;
+
+ close_at_commit= FALSE; /* reset in case we're reusing the cursor */
+ info= &ht_info[0];
+ for (handlerton **pht= thd->transaction.stmt.ht; *pht; pht++)
+ {
+ const handlerton *ht= *pht;
+ close_at_commit|= test(ht->flags & HTON_CLOSE_CURSORS_AT_COMMIT);
+ if (ht->create_cursor_read_view)
+ {
+ info->ht= ht;
+ info->read_view= (ht->create_cursor_read_view)();
+ ++info;
+ }
+ }
+ /*
+ XXX: thd->locked_tables is not changed.
+ What problems can we have with it if cursor is open?
+ TODO: must be fixed because of the prelocked mode.
+ */
+}
+
+
+void
+Sensitive_cursor::reset_thd(THD *thd)
+{
+ thd->derived_tables= 0;
+ thd->open_tables= 0;
+ thd->lock= 0;
+ thd->free_list= 0;
+ thd->change_list.empty();
+}
+
+
+int
+Sensitive_cursor::open(JOIN *join_arg)
+{
+ join= join_arg;
+ THD *thd= join->thd;
+ /* First non-constant table */
+ JOIN_TAB *join_tab= join->join_tab + join->const_tables;
+ DBUG_ENTER("Sensitive_cursor::open");
+
+ join->change_result(result);
+ /*
+ Send fields description to the client; server_status is sent
+ in 'EOF' packet, which follows send_fields().
+ We don't simply use SEND_EOF flag of send_fields because we also
+ want to flush the network buffer, which is done only in a standalone
+ send_eof().
+ */
+ result->send_fields(*join->fields, Protocol::SEND_NUM_ROWS);
+ thd->server_status|= SERVER_STATUS_CURSOR_EXISTS;
+ result->send_eof();
+ thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS;
+
+ /* Prepare JOIN for reading rows. */
+ join->tmp_table= 0;
+ join->join_tab[join->tables-1].next_select= setup_end_select_func(join);
+ join->send_records= 0;
+ join->fetch_limit= join->unit->offset_limit_cnt;
+
+ /* Disable JOIN CACHE as it is not working with cursors yet */
+ for (JOIN_TAB *tab= join_tab;
+ tab != join->join_tab + join->tables - 1;
+ tab++)
+ {
+ if (tab->next_select == sub_select_cache)
+ tab->next_select= sub_select;
+ }
+
+ DBUG_ASSERT(join_tab->table->reginfo.not_exists_optimize == 0);
+ DBUG_ASSERT(join_tab->not_used_in_distinct == 0);
+ /*
+ null_row is set only if row not found and it's outer join: should never
+ happen for the first table in join_tab list
+ */
+ DBUG_ASSERT(join_tab->table->null_row == 0);
+ DBUG_RETURN(0);
+}
+
+
+/*
+ SYNOPSIS
+ Sensitive_cursor::fetch()
+ num_rows fetch up to this number of rows (maybe less)
+
+ DESCRIPTION
+ Fetch next num_rows rows from the cursor and send them to the client
+
+ Precondition:
+ Sensitive_cursor is open
+
+ RETURN VALUES:
+ none, this function will send OK to the clinet or set an error
+ message in THD
+*/
+
+void
+Sensitive_cursor::fetch(ulong num_rows)
+{
+ THD *thd= join->thd;
+ JOIN_TAB *join_tab= join->join_tab + join->const_tables;
+ enum_nested_loop_state error= NESTED_LOOP_OK;
+ Query_arena backup_arena;
+ Engine_info *info;
+ DBUG_ENTER("Sensitive_cursor::fetch");
+ DBUG_PRINT("enter",("rows: %lu", num_rows));
+
+ DBUG_ASSERT(thd->derived_tables == 0 && thd->open_tables == 0 &&
+ thd->lock == 0);
+
+ thd->derived_tables= derived_tables;
+ thd->open_tables= open_tables;
+ thd->lock= lock;
+ thd->query_id= query_id;
+ thd->change_list= change_list;
+ /* save references to memory allocated during fetch */
+ thd->set_n_backup_active_arena(this, &backup_arena);
+
+ for (info= ht_info; info->read_view ; info++)
+ (info->ht->set_cursor_read_view)(info->read_view);
+
+ join->fetch_limit+= num_rows;
+
+ error= sub_select(join, join_tab, 0);
+ if (error == NESTED_LOOP_OK || error == NESTED_LOOP_NO_MORE_ROWS)
+ error= sub_select(join,join_tab,1);
+ if (error == NESTED_LOOP_QUERY_LIMIT)
+ error= NESTED_LOOP_OK; /* select_limit used */
+ if (error == NESTED_LOOP_CURSOR_LIMIT)
+ join->resume_nested_loop= TRUE;
+
+#ifdef USING_TRANSACTIONS
+ ha_release_temporary_latches(thd);
+#endif
+ /* Grab free_list here to correctly free it in close */
+ thd->restore_active_arena(this, &backup_arena);
+
+ change_list= thd->change_list;
+ reset_thd(thd);
+
+ for (info= ht_info; info->read_view; info++)
+ (info->ht->set_cursor_read_view)(0);
+
+ if (error == NESTED_LOOP_CURSOR_LIMIT)
+ {
+ /* Fetch limit worked, possibly more rows are there */
+ thd->server_status|= SERVER_STATUS_CURSOR_EXISTS;
+ result->send_eof();
+ thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS;
+ }
+ else
+ {
+ close();
+ if (error == NESTED_LOOP_OK)
+ {
+ thd->server_status|= SERVER_STATUS_LAST_ROW_SENT;
+ result->send_eof();
+ thd->server_status&= ~SERVER_STATUS_LAST_ROW_SENT;
+ }
+ else if (error != NESTED_LOOP_KILLED)
+ my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+void
+Sensitive_cursor::close()
+{
+ THD *thd= join->thd;
+ DBUG_ENTER("Sensitive_cursor::close");
+
+ for (Engine_info *info= ht_info; info->read_view; info++)
+ {
+ (info->ht->close_cursor_read_view)(info->read_view);
+ info->read_view= 0;
+ info->ht= 0;
+ }
+
+ thd->change_list= change_list;
+ {
+ /*
+ XXX: Another hack: we need to set THD state as if in a fetch to be
+ able to call stmt close.
+ */
+ DBUG_ASSERT(lock || open_tables || derived_tables);
+
+ TABLE *tmp_derived_tables= thd->derived_tables;
+ MYSQL_LOCK *tmp_lock= thd->lock;
+
+ thd->open_tables= open_tables;
+ thd->derived_tables= derived_tables;
+ thd->lock= lock;
+
+ /* Is expected to at least close tables and empty thd->change_list */
+ stmt_arena->cleanup_stmt();
+
+ thd->open_tables= tmp_derived_tables;
+ thd->derived_tables= tmp_derived_tables;
+ thd->lock= tmp_lock;
+ }
+ thd->lock_info.n_cursors--; /* Decrease the number of active cursors */
+ join= 0;
+ stmt_arena= 0;
+ free_items();
+ change_list.empty();
+ DBUG_VOID_RETURN;
+}
+
+
+Sensitive_cursor::~Sensitive_cursor()
+{
+ if (is_open())
+ close();
+}
+
+/***************************************************************************
+ Materialized_cursor
+****************************************************************************/
+
+Materialized_cursor::Materialized_cursor(select_result *result_arg,
+ TABLE *table_arg)
+ :Server_side_cursor(&table_arg->mem_root, result_arg),
+ table(table_arg),
+ fetch_limit(0),
+ fetch_count(0)
+{
+ fake_unit.init_query();
+ fake_unit.thd= table->in_use;
+}
+
+
+int Materialized_cursor::open(JOIN *join __attribute__((unused)))
+{
+ THD *thd= fake_unit.thd;
+ int rc;
+ Query_arena backup_arena;
+
+ thd->set_n_backup_active_arena(this, &backup_arena);
+ /* Create a list of fields and start sequential scan */
+ rc= (table->fill_item_list(&item_list) ||
+ result->prepare(item_list, &fake_unit) ||
+ table->file->ha_rnd_init(TRUE));
+ thd->restore_active_arena(this, &backup_arena);
+ return rc;
+}
+
+
+/*
+ Fetch up to the given number of rows from a materialized cursor.
+
+ DESCRIPTION
+ Precondition: the cursor is open.
+
+ If the cursor points after the last row, the fetch will automatically
+ close the cursor and not send any data (except the 'EOF' packet
+ with SERVER_STATUS_LAST_ROW_SENT). This is an extra round trip
+ and probably should be improved to return
+ SERVER_STATUS_LAST_ROW_SENT along with the last row.
+
+ RETURN VALUE
+ none, in case of success the row is sent to the client, otherwise
+ an error message is set in THD
+*/
+
+void Materialized_cursor::fetch(ulong num_rows)
+{
+ THD *thd= table->in_use;
+
+ int res= 0;
+ for (fetch_limit+= num_rows; fetch_count < fetch_limit; fetch_count++)
+ {
+ if ((res= table->file->rnd_next(table->record[0])))
+ break;
+ /* Send data only if the read was successful. */
+ result->send_data(item_list);
+ }
+
+ switch (res) {
+ case 0:
+ thd->server_status|= SERVER_STATUS_CURSOR_EXISTS;
+ result->send_eof();
+ thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS;
+ break;
+ case HA_ERR_END_OF_FILE:
+ thd->server_status|= SERVER_STATUS_LAST_ROW_SENT;
+ result->send_eof();
+ thd->server_status&= ~SERVER_STATUS_LAST_ROW_SENT;
+ close();
+ break;
+ default:
+ table->file->print_error(res, MYF(0));
+ close();
+ break;
+ }
+}
+
+
+void Materialized_cursor::close()
+{
+ /* Free item_list items */
+ free_items();
+ (void) table->file->ha_rnd_end();
+ /*
+ We need to grab table->mem_root to prevent free_tmp_table from freeing:
+ the cursor object was allocated in this memory.
+ */
+ main_mem_root= table->mem_root;
+ mem_root= &main_mem_root;
+ clear_alloc_root(&table->mem_root);
+ free_tmp_table(table->in_use, table);
+ table= 0;
+}
+
+
+Materialized_cursor::~Materialized_cursor()
+{
+ if (is_open())
+ close();
+}
+
+
+/***************************************************************************
+ Select_materialize
+****************************************************************************/
+
+bool Select_materialize::send_fields(List<Item> &list, uint flags)
+{
+ bool rc;
+ DBUG_ASSERT(table == 0);
+ if (create_result_table(unit->thd, unit->get_unit_column_types(),
+ FALSE, thd->options | TMP_TABLE_ALL_COLUMNS, ""))
+ return TRUE;
+ /*
+ We can't simply supply SEND_EOF flag to send_fields, because send_fields
+ doesn't flush the network buffer.
+ */
+ rc= result->send_fields(list, Protocol::SEND_NUM_ROWS);
+ thd->server_status|= SERVER_STATUS_CURSOR_EXISTS;
+ result->send_eof();
+ thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS;
+ return rc;
+}
+
diff --git a/sql/sql_cursor.h b/sql/sql_cursor.h
new file mode 100644
index 00000000000..d1156dfba8d
--- /dev/null
+++ b/sql/sql_cursor.h
@@ -0,0 +1,65 @@
+#ifndef _sql_cursor_h_
+#define _sql_cursor_h_
+/* Copyright (C) 2005 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
+
+#ifdef USE_PRAGMA_INTERFACE
+#pragma interface /* gcc class interface */
+#endif
+
+/*
+ Declarations for implementation of server side cursors. Only
+ read-only non-scrollable cursors are currently implemented.
+*/
+
+/*
+ Server_side_cursor -- an interface for materialized and
+ sensitive (non-materialized) implementation of cursors. All
+ cursors are self-contained (created in their own memory root).
+ For that reason they must be deleted only using a pointer to
+ Server_side_cursor, not to its base class.
+*/
+
+class Server_side_cursor: protected Query_arena, public Sql_alloc
+{
+protected:
+ /* Row destination used for fetch */
+ select_result *result;
+public:
+ Server_side_cursor(MEM_ROOT *mem_root_arg, select_result *result_arg)
+ :Query_arena(mem_root_arg, INITIALIZED), result(result_arg)
+ {}
+
+ virtual bool is_open() const= 0;
+
+ virtual int open(JOIN *top_level_join)= 0;
+ virtual void fetch(ulong num_rows)= 0;
+ virtual void close()= 0;
+ virtual ~Server_side_cursor();
+
+ static void operator delete(void *ptr, size_t size);
+};
+
+
+int mysql_open_cursor(THD *thd, uint flags,
+ select_result *result,
+ Server_side_cursor **res);
+
+/* Possible values for flags */
+
+enum { ANY_CURSOR= 1, ALWAYS_MATERIALIZED_CURSOR= 2 };
+
+#endif /* _sql_cusor_h_ */
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index e8fb8d9ce16..a5dabc8140c 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -1094,6 +1094,7 @@ bool mysql_change_db(THD *thd, const char *name, bool no_access_check)
bool system_db= 0;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
ulong db_access;
+ Security_context *sctx= thd->security_ctx;
#endif
DBUG_ENTER("mysql_change_db");
DBUG_PRINT("enter",("name: '%s'",name));
@@ -1131,22 +1132,20 @@ bool mysql_change_db(THD *thd, const char *name, bool no_access_check)
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (!no_access_check)
{
- if (test_all_bits(thd->master_access,DB_ACLS))
+ if (test_all_bits(sctx->master_access, DB_ACLS))
db_access=DB_ACLS;
else
- db_access= (acl_get(thd->host,thd->ip, thd->priv_user,dbname,0) |
- thd->master_access);
+ 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),
- thd->priv_user,
- thd->priv_host,
+ sctx->priv_user,
+ sctx->priv_host,
dbname);
- mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR),
- thd->priv_user,
- thd->priv_host,
- dbname);
+ mysql_log.write(thd, COM_INIT_DB, ER(ER_DBACCESS_DENIED_ERROR),
+ sctx->priv_user, sctx->priv_host, dbname);
my_free(dbname,MYF(0));
DBUG_RETURN(1);
}
@@ -1168,7 +1167,7 @@ end:
thd->db_length=db_length;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (!no_access_check)
- thd->db_access=db_access;
+ sctx->db_access= db_access;
#endif
if (system_db)
{
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 00d82bcdfda..584601fe202 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -266,19 +266,12 @@ cleanup:
delete select;
transactional_table= table->file->has_transactions();
- /*
- We write to the binary log even if we deleted no row, because maybe the
- user is using this command to ensure that a table is clean on master *and
- on slave*. Think of the case of a user having played separately with the
- master's table and slave's table and wanting to take a fresh identical
- start now.
- error < 0 means "really no error". error <= 0 means "maybe some error".
- */
- if ((deleted || (error < 0)) && (error <= 0 || !transactional_table))
+ /* See similar binlogging code in sql_update.cc, for comments */
+ if ((error < 0) || (deleted && !transactional_table))
{
if (mysql_bin_log.is_open())
{
- if (error <= 0)
+ if (error < 0)
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
transactional_table, FALSE);
@@ -328,6 +321,7 @@ bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
SELECT_LEX *select_lex= &thd->lex->select_lex;
DBUG_ENTER("mysql_prepare_delete");
+ thd->allow_sum_func= 0;
if (setup_tables(thd, &thd->lex->select_lex.context,
&thd->lex->select_lex.top_join_list,
table_list, conds, &select_lex->leaf_tables,
@@ -736,6 +730,9 @@ bool multi_delete::send_eof()
/* Does deletes for the last n - 1 tables, returns 0 if ok */
int local_error= do_deletes(); // returns 0 if success
+ /* compute a total error to know if something failed */
+ local_error= local_error || error;
+
/* reset used flags */
thd->proc_info="end";
@@ -748,19 +745,11 @@ bool multi_delete::send_eof()
query_cache_invalidate3(thd, delete_tables, 1);
}
- /*
- Write the SQL statement to the binlog if we deleted
- rows and we succeeded, or also in an error case when there
- was a non-transaction-safe table involved, since
- modifications in it cannot be rolled back.
- Note that if we deleted nothing we don't write to the binlog (TODO:
- fix this).
- */
- if (deleted && ((error <= 0 && !local_error) || normal_tables))
+ if ((local_error == 0) || (deleted && normal_tables))
{
if (mysql_bin_log.is_open())
{
- if (error <= 0 && !local_error)
+ if (local_error == 0)
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
transactional_tables, FALSE);
@@ -816,7 +805,7 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
TABLE *table= *table_ptr;
table->file->info(HA_STATUS_AUTO | HA_STATUS_NO_LOCK);
db_type table_type= table->s->db_type;
- if (!ha_supports_generate(table_type))
+ if (!ha_check_storage_engine_flag(table_type, HTON_CAN_RECREATE))
goto trunc_by_del;
strmov(path, table->s->path);
*table_ptr= table->next; // Unlink table from list
@@ -847,7 +836,8 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
table_list->db, table_list->table_name);
DBUG_RETURN(TRUE);
}
- if (!ha_supports_generate(table_type) || thd->lex->sphead)
+ if (!ha_check_storage_engine_flag(table_type, HTON_CAN_RECREATE)
+ || thd->lex->sphead)
goto trunc_by_del;
if (lock_and_wait_for_table_name(thd, table_list))
DBUG_RETURN(TRUE);
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index 7b9191cd841..74b239e1637 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -27,7 +27,7 @@
/*
- call given derived table processor (preparing or filling tables)
+ Call given derived table processor (preparing or filling tables)
SYNOPSIS
mysql_handle_derived()
@@ -36,7 +36,6 @@
RETURN
0 ok
- -1 Error
1 Error and error message given
*/
@@ -97,14 +96,14 @@ out:
RETURN
0 ok
- 1 Error
- -1 Error and error message given
- */
+ 1 Error and an error message was given
+*/
int mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
{
SELECT_LEX_UNIT *unit= orig_table_list->derived;
int res= 0;
+ ulonglong create_options;
DBUG_ENTER("mysql_derived_prepare");
if (unit)
{
@@ -118,21 +117,18 @@ int mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
for (SELECT_LEX *sl= first_select; sl; sl= sl->next_select())
sl->context.outer_context= 0;
- if (!(derived_result= new select_union(0)))
+ if (!(derived_result= new select_union))
DBUG_RETURN(1); // out of memory
// st_select_lex_unit::prepare correctly work for single select
- if ((res= unit->prepare(thd, derived_result, 0, orig_table_list->alias)))
+ if ((res= unit->prepare(thd, derived_result, 0)))
goto exit;
- if (check_duplicate_names(unit->types, 0))
- {
- res= -1;
+ if ((res= check_duplicate_names(unit->types, 0)))
goto exit;
- }
- derived_result->tmp_table_param.init();
- derived_result->tmp_table_param.field_count= unit->types.elements;
+ create_options= (first_select->options | thd->options |
+ TMP_TABLE_ALL_COLUMNS);
/*
Temp table is created so that it hounours if UNION without ALL is to be
processed
@@ -143,18 +139,12 @@ int mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
!unit->union_distinct->next_select() (i.e. it is union and last distinct
SELECT is last SELECT of UNION).
*/
- if (!(table= create_tmp_table(thd, &derived_result->tmp_table_param,
- unit->types, (ORDER*) 0,
- FALSE, 1,
- (first_select->options | thd->options |
- TMP_TABLE_ALL_COLUMNS),
- HA_POS_ERROR,
- orig_table_list->alias)))
- {
- res= -1;
+ if ((res= derived_result->create_result_table(thd, &unit->types, FALSE,
+ create_options,
+ orig_table_list->alias)))
goto exit;
- }
- derived_result->set_table(table);
+
+ table= derived_result->table;
exit:
/* Hide "Unknown column" or "Unknown function" error */
@@ -231,9 +221,8 @@ exit:
RETURN
0 ok
- 1 Error
- -1 Error and error message given
- */
+ 1 Error and an error message was given
+*/
int mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
{
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 3d7ca8059b9..d1122cf2ac4 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -285,7 +285,8 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
By default, both logs are enabled (this won't cause problems if the server
runs without --log-update or --log-bin).
*/
- bool log_on= (thd->options & OPTION_BIN_LOG) || (!(thd->master_access & SUPER_ACL));
+ bool log_on= (thd->options & OPTION_BIN_LOG) ||
+ (!(thd->security_ctx->master_access & SUPER_ACL));
bool transactional_table;
uint value_count;
ulong counter = 1;
@@ -1277,8 +1278,8 @@ public:
table(0),tables_in_use(0),stacked_inserts(0), status(0), dead(0),
group_count(0)
{
- thd.user=thd.priv_user=(char*) delayed_user;
- thd.host=(char*) my_localhost;
+ thd.security_ctx->user=thd.security_ctx->priv_user=(char*) delayed_user;
+ thd.security_ctx->host=(char*) my_localhost;
thd.current_tablenr=0;
thd.version=refresh_version;
thd.command=COM_DELAYED_INSERT;
@@ -1288,7 +1289,7 @@ public:
bzero((char*) &thd.net, sizeof(thd.net)); // Safety
bzero((char*) &table_list, sizeof(table_list)); // Safety
thd.system_thread= SYSTEM_THREAD_DELAYED_INSERT;
- thd.host_or_ip= "";
+ thd.security_ctx->host_or_ip= "";
bzero((char*) &info,sizeof(info));
pthread_mutex_init(&mutex,MY_MUTEX_INIT_FAST);
pthread_cond_init(&cond,NULL);
@@ -1311,7 +1312,7 @@ public:
pthread_cond_destroy(&cond_client);
thd.unlink(); // Must be unlinked under lock
x_free(thd.query);
- thd.user=thd.host=0;
+ thd.security_ctx->user= thd.security_ctx->host=0;
thread_count--;
delayed_insert_threads--;
VOID(pthread_mutex_unlock(&LOCK_thread_count));
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 381d6573a09..7640b6eb569 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -54,7 +54,7 @@ enum enum_sql_command {
SQLCOM_SHOW_DATABASES, SQLCOM_SHOW_TABLES, SQLCOM_SHOW_FIELDS,
SQLCOM_SHOW_KEYS, SQLCOM_SHOW_VARIABLES, SQLCOM_SHOW_LOGS, SQLCOM_SHOW_STATUS,
- SQLCOM_SHOW_INNODB_STATUS, SQLCOM_SHOW_MUTEX_STATUS,
+ SQLCOM_SHOW_INNODB_STATUS, SQLCOM_SHOW_NDBCLUSTER_STATUS, SQLCOM_SHOW_MUTEX_STATUS,
SQLCOM_SHOW_PROCESSLIST, SQLCOM_SHOW_MASTER_STAT, SQLCOM_SHOW_SLAVE_STAT,
SQLCOM_SHOW_GRANTS, SQLCOM_SHOW_CREATE, SQLCOM_SHOW_CHARSETS,
SQLCOM_SHOW_COLLATIONS, SQLCOM_SHOW_CREATE_DB, SQLCOM_SHOW_TABLE_STATUS,
@@ -433,10 +433,6 @@ public:
{
return my_reinterpret_cast(st_select_lex*)(slave);
}
- st_select_lex* first_select_in_union()
- {
- return my_reinterpret_cast(st_select_lex*)(slave);
- }
st_select_lex_unit* next_unit()
{
return my_reinterpret_cast(st_select_lex_unit*)(next);
@@ -446,8 +442,7 @@ public:
void exclude_tree();
/* UNION methods */
- bool prepare(THD *thd, select_result *result, ulong additional_options,
- const char *tmp_table_alias);
+ bool prepare(THD *thd, select_result *result, ulong additional_options);
bool exec();
bool cleanup();
inline void unclean() { cleaned= 0; }
@@ -463,7 +458,10 @@ public:
friend void lex_start(THD *thd, uchar *buf, uint length);
friend int subselect_union_engine::exec();
+
+ List<Item> *get_unit_column_types();
};
+
typedef class st_select_lex_unit SELECT_LEX_UNIT;
/*
diff --git a/sql/sql_list.h b/sql/sql_list.h
index e4a34cc0aa1..285f1d6e501 100644
--- a/sql/sql_list.h
+++ b/sql/sql_list.h
@@ -32,6 +32,8 @@ public:
{
return (void*) sql_alloc((uint) size);
}
+ static void *operator new[](size_t size, MEM_ROOT *mem_root)
+ { return (void*) alloc_root(mem_root, (uint) size); }
static void *operator new(size_t size, MEM_ROOT *mem_root)
{ return (void*) alloc_root(mem_root, (uint) size); }
static void operator delete(void *ptr, size_t size) { TRASH(ptr, size); }
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index 8eec970b4df..895065241f4 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -147,6 +147,10 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
MYF(0));
DBUG_RETURN(TRUE);
}
+ /*
+ This needs to be done before external_lock
+ */
+ ha_enable_transaction(thd, FALSE);
if (open_and_lock_tables(thd, table_list))
DBUG_RETURN(TRUE);
if (setup_tables(thd, &thd->lex->select_lex.context,
@@ -363,7 +367,6 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
if (ignore ||
handle_duplicates == DUP_REPLACE)
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
- ha_enable_transaction(thd, FALSE);
table->file->start_bulk_insert((ha_rows) 0);
table->copy_blobs=1;
@@ -383,10 +386,10 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
*enclosed, skip_lines, ignore);
if (table->file->end_bulk_insert())
error=1; /* purecov: inspected */
- ha_enable_transaction(thd, TRUE);
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
table->next_number_field=0;
}
+ ha_enable_transaction(thd, TRUE);
if (file >= 0)
my_close(file,MYF(0));
free_blobs(table); /* if pack_blob was used */
@@ -552,6 +555,8 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
while ((sql_field= (Item_field*) it++))
{
Field *field= sql_field->field;
+ if (field == table->next_number_field)
+ table->auto_increment_field_not_null= TRUE;
/*
No fields specified in fields_vars list can be null in this format.
Mark field as not null, we should do this for each row because of
@@ -570,6 +575,8 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
{
uint length;
byte save_chr;
+ if (field == table->next_number_field)
+ table->auto_increment_field_not_null= TRUE;
if ((length=(uint) (read_info.row_end-pos)) >
field->field_length)
length=field->field_length;
@@ -692,6 +699,8 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
Field *field= ((Item_field *)item)->field;
field->reset();
field->set_null();
+ if (field == table->next_number_field)
+ table->auto_increment_field_not_null= TRUE;
if (!field->maybe_null())
{
if (field->type() == FIELD_TYPE_TIMESTAMP)
@@ -709,9 +718,12 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
if (item->type() == Item::FIELD_ITEM)
{
+
Field *field= ((Item_field *)item)->field;
field->set_notnull();
read_info.row_end[0]=0; // Safe to change end marker
+ if (field == table->next_number_field)
+ table->auto_increment_field_not_null= TRUE;
field->store((char*) pos, length, read_info.read_charset);
}
else
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index d9f5c178370..48dc8f68707 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -26,6 +26,10 @@
#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"
@@ -131,6 +135,12 @@ static bool end_active_trans(THD *thd)
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))
{
@@ -180,13 +190,8 @@ static bool begin_trans(THD *thd)
*/
inline bool all_tables_not_ok(THD *thd, TABLE_LIST *tables)
{
- return (rpl_filter->is_on() && tables &&
- !(thd->spcont || rpl_filter->tables_ok(thd->db, tables)) &&
- ((thd->lex->sql_command != SQLCOM_DELETE_MULTI) ||
- !(thd->spcont ||
- rpl_filter->tables_ok(thd->db,
- (TABLE_LIST *)
- thd->lex->auxilliary_table_list.first))));
+ return rpl_filter->is_on() && tables &&
+ !rpl_filter->tables_ok(thd->db, tables);
}
#endif
@@ -249,7 +254,7 @@ end:
SYNOPSIS
check_user()
- thd thread handle, thd->{host,user,ip} are used
+ 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.
@@ -264,8 +269,8 @@ end:
are 'IN'.
RETURN VALUE
- 0 OK; thd->user, thd->master_access, thd->priv_user, thd->db and
- thd->db_access are updated; OK is sent to client;
+ 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
*/
@@ -277,7 +282,7 @@ int check_user(THD *thd, enum enum_server_command command,
DBUG_ENTER("check_user");
#ifdef NO_EMBEDDED_ACCESS_CHECKS
- thd->master_access= GLOBAL_ACLS; // Full rights
+ thd->main_security_ctx.master_access= GLOBAL_ACLS; // Full rights
/* Change database if necessary */
if (db && db[0])
{
@@ -344,15 +349,17 @@ int check_user(THD *thd, enum enum_server_command command,
if (opt_secure_auth_local)
{
net_printf_error(thd, ER_SERVER_IS_IN_SECURE_AUTH_MODE,
- thd->user, thd->host_or_ip);
+ 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->user, thd->host_or_ip);
+ 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);
}
@@ -364,22 +371,27 @@ int check_user(THD *thd, enum enum_server_command command,
/* here res is always >= 0 */
if (res == 0)
{
- if (!(thd->master_access & NO_ACCESS)) // authentication is OK
+ if (!(thd->main_security_ctx.master_access &
+ NO_ACCESS)) // authentication is OK
{
DBUG_PRINT("info",
("Capabilities: %d packet_length: %ld Host: '%s' "
"Login user: '%s' Priv_user: '%s' Using password: %s "
"Access: %u db: '%s'",
- thd->client_capabilities, thd->max_client_packet_length,
- thd->host_or_ip, thd->user, thd->priv_user,
+ 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->master_access, thd->db ? thd->db : "*none*"));
+ 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->master_access & SUPER_ACL);
+ || (thd->main_security_ctx.master_access & SUPER_ACL);
VOID(pthread_mutex_unlock(&LOCK_thread_count));
if (!count_ok)
{ // too many connections
@@ -389,11 +401,13 @@ int check_user(THD *thd, enum enum_server_command command,
}
/* Why logging is performed before all checks've passed? */
- mysql_log.write(thd,command,
- (thd->priv_user == thd->user ?
+ 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->user, thd->host_or_ip,
+ thd->main_security_ctx.user,
+ thd->main_security_ctx.host_or_ip,
db ? db : (char*) "");
/*
@@ -401,14 +415,16 @@ int check_user(THD *thd, enum enum_server_command command,
set to 0 here because we don't have an active database yet (and we
may not have an active database to set.
*/
- thd->db_access=0;
+ 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->user : thd->priv_user,
- opt_old_style_user_limits ? thd->host_or_ip : thd->priv_host,
+ (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 &&
@@ -443,12 +459,12 @@ int check_user(THD *thd, enum enum_server_command command,
DBUG_RETURN(-1);
}
net_printf_error(thd, ER_ACCESS_DENIED_ERROR,
- thd->user,
- thd->host_or_ip,
+ 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->user,
- thd->host_or_ip,
+ 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 */
@@ -772,41 +788,45 @@ static int check_connection(THD *thd)
DBUG_PRINT("info",
("New connection received on %s", vio_description(net->vio)));
- if (!thd->host) // If TCP/IP connection
+ 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->ip= my_strdup(ip,MYF(0))))
+ if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(0))))
return (ER_OUT_OF_RESOURCES);
- thd->host_or_ip= thd->ip;
+ 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->host=ip_to_hostname(&thd->remote.sin_addr,&connect_errors);
+ thd->main_security_ctx.host=
+ ip_to_hostname(&thd->remote.sin_addr, &connect_errors);
/* Cut very long hostnames to avoid possible overflows */
- if (thd->host)
+ if (thd->main_security_ctx.host)
{
- if (thd->host != my_localhost)
- thd->host[min(strlen(thd->host), HOSTNAME_LENGTH)]= 0;
- thd->host_or_ip= thd->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->host ? thd->host : "unknown host",
- thd->ip ? thd->ip : "unknown ip"));
- if (acl_check_host(thd->host,thd->ip))
+ (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->host));
- thd->host_or_ip= thd->host;
- thd->ip= 0;
+ 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));
}
@@ -989,9 +1009,9 @@ static int check_connection(THD *thd)
thd->charset(), &dummy_errors)]= '\0';
user= user_buff;
- if (thd->user)
- x_free(thd->user);
- if (!(thd->user= my_strdup(user, MYF(0))))
+ 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);
}
@@ -1079,13 +1099,14 @@ pthread_handler_decl(handle_one_connection,arg)
{
int error;
NET *net= &thd->net;
+ Security_context *sctx= thd->security_ctx;
thd->thread_stack= (char*) &thd;
net->no_send_error= 0;
if ((error=check_connection(thd)))
{ // Wrong permissions
if (error > 0)
- net_printf_error(thd, error, thd->host_or_ip);
+ 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() */
@@ -1094,7 +1115,7 @@ pthread_handler_decl(handle_one_connection,arg)
goto end_thread;
}
#ifdef __NETWARE__
- netware_reg_user(thd->ip, thd->user, "MySQL");
+ netware_reg_user(sctx->ip, sctx->user, "MySQL");
#endif
if (thd->variables.max_join_size == HA_POS_ERROR)
thd->options |= OPTION_BIG_SELECTS;
@@ -1107,7 +1128,7 @@ pthread_handler_decl(handle_one_connection,arg)
thd->set_time();
thd->init_for_queries();
- if (sys_init_connect.value_length && !(thd->master_access & SUPER_ACL))
+ 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)
@@ -1131,8 +1152,8 @@ pthread_handler_decl(handle_one_connection,arg)
if (!thd->killed && thd->variables.log_warnings > 1)
sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
thd->thread_id,(thd->db ? thd->db : "unconnected"),
- thd->user ? thd->user : "unauthenticated",
- thd->host_or_ip,
+ 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);
@@ -1195,7 +1216,8 @@ extern "C" pthread_handler_decl(handle_bootstrap,arg)
thd->proc_info=0;
thd->version=refresh_version;
- thd->priv_user=thd->user=(char*) my_strdup("boot", MYF(MY_WME));
+ thd->security_ctx->priv_user=
+ thd->security_ctx->user= (char*) my_strdup("boot", MYF(MY_WME));
buff= (char*) thd->net.buff;
thd->init_for_queries();
@@ -1354,6 +1376,12 @@ int end_trans(THD *thd, enum enum_mysql_completiontype completion)
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:
/*
@@ -1590,17 +1618,14 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
db= db_buff;
/* Save user and privileges */
- uint save_master_access= thd->master_access;
- uint save_db_access= thd->db_access;
uint save_db_length= thd->db_length;
- char *save_user= thd->user;
- char *save_priv_user= thd->priv_user;
char *save_db= thd->db;
+ Security_context save_security_ctx= *thd->security_ctx;
USER_CONN *save_user_connect= thd->user_connect;
-
- if (!(thd->user= my_strdup(user, MYF(0))))
+
+ if (!(thd->security_ctx->user= my_strdup(user, MYF(0))))
{
- thd->user= save_user;
+ thd->security_ctx->user= save_security_ctx.user;
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
break;
}
@@ -1614,12 +1639,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
/* 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->user);
- thd->user= save_user;
- thd->priv_user= save_priv_user;
+ x_free(thd->security_ctx->user);
+ *thd->security_ctx= save_security_ctx;
thd->user_connect= save_user_connect;
- thd->master_access= save_master_access;
- thd->db_access= save_db_access;
thd->db= save_db;
thd->db_length= save_db_length;
}
@@ -1629,7 +1651,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if (save_user_connect)
decrease_user_connections(save_user_connect);
x_free((gptr) save_db);
- x_free((gptr) save_user);
+ x_free((gptr) save_security_ctx.user);
}
break;
}
@@ -1971,12 +1993,13 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
case COM_PROCESS_INFO:
statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_PROCESSLIST],
&LOCK_status);
- if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL))
+ 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->master_access & PROCESS_ACL ?
- NullS : thd->priv_user, 0);
+ thd->security_ctx->master_access & PROCESS_ACL ?
+ NullS : thd->security_ctx->priv_user, 0);
break;
case COM_PROCESS_KILL:
{
@@ -2144,7 +2167,8 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
if (!thd->col_access && check_grant_db(thd,db))
{
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
- thd->priv_user, thd->priv_host, db);
+ thd->security_ctx->priv_user, thd->security_ctx->priv_host,
+ db);
DBUG_RETURN(1);
}
/*
@@ -2402,7 +2426,8 @@ mysql_execute_command(THD *thd)
Except for the replication thread and the 'super' users.
*/
if (opt_readonly &&
- !(thd->slave_thread || (thd->master_access & SUPER_ACL)) &&
+ !(thd->slave_thread ||
+ (thd->security_ctx->master_access & SUPER_ACL)) &&
uc_update_queries[lex->sql_command])
{
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
@@ -2673,6 +2698,13 @@ mysql_execute_command(THD *thd)
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:
{
@@ -3381,11 +3413,14 @@ end_with_restore_list:
res = mysql_drop_index(thd, first_table, &lex->alter_info);
break;
case SQLCOM_SHOW_PROCESSLIST:
- if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL))
+ if (!thd->security_ctx->priv_user[0] &&
+ check_global_access(thd,PROCESS_ACL))
break;
mysqld_list_processes(thd,
- thd->master_access & PROCESS_ACL ? NullS :
- thd->priv_user,lex->verbose);
+ (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);
@@ -3723,7 +3758,7 @@ end_with_restore_list:
select_lex->db ? is_schema_db(select_lex->db) : 0))
goto error;
- if (thd->user) // If not replication
+ if (thd->security_ctx->user) // If not replication
{
LEX_USER *user;
uint counter;
@@ -3739,9 +3774,9 @@ end_with_restore_list:
user->host.str);
// Are we trying to change a password of another user
DBUG_ASSERT(user->host.str != 0);
- if (strcmp(thd->user, user->user.str) ||
+ if (strcmp(thd->security_ctx->user, user->user.str) ||
my_strcasecmp(system_charset_info,
- user->host.str, thd->host_or_ip))
+ user->host.str, thd->security_ctx->host_or_ip))
{
// TODO: use check_change_password()
if (check_acl_user(user, &counter) && user->password.str &&
@@ -3868,8 +3903,8 @@ end_with_restore_list:
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
case SQLCOM_SHOW_GRANTS:
- if ((thd->priv_user &&
- !strcmp(thd->priv_user,lex->grant_user->user.str)) ||
+ if ((thd->security_ctx->priv_user &&
+ !strcmp(thd->security_ctx->priv_user, lex->grant_user->user.str)) ||
!check_access(thd, SELECT_ACL, "mysql",0,1,0,0))
{
res = mysql_show_grants(thd,lex->grant_user);
@@ -3905,6 +3940,12 @@ end_with_restore_list:
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);
@@ -4143,7 +4184,7 @@ end_with_restore_list:
else
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- st_sp_security_context save_ctx;
+ Security_context *save_ctx;
#endif
ha_rows select_limit;
/* bits that should be cleared in thd->server_status */
@@ -4189,23 +4230,23 @@ end_with_restore_list:
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (check_routine_access(thd, EXECUTE_ACL,
- sp->m_db.str, sp->m_name.str, TRUE, 0))
+ if (check_routine_access(thd, EXECUTE_ACL,
+ sp->m_db.str, sp->m_name.str, TRUE, 0) ||
+ sp_change_security_context(thd, sp, &save_ctx))
{
#ifndef EMBEDDED_LIBRARY
thd->net.no_send_ok= nsok;
#endif
goto error;
}
- sp_change_security_context(thd, sp, &save_ctx);
- if (save_ctx.changed &&
- check_routine_access(thd, EXECUTE_ACL,
- sp->m_db.str, sp->m_name.str, TRUE, 0))
+ if (save_ctx &&
+ check_routine_access(thd, EXECUTE_ACL,
+ sp->m_db.str, sp->m_name.str, TRUE, 0))
{
#ifndef EMBEDDED_LIBRARY
thd->net.no_send_ok= nsok;
#endif
- sp_restore_security_context(thd, sp, &save_ctx);
+ sp_restore_security_context(thd, save_ctx);
goto error;
}
@@ -4245,7 +4286,7 @@ end_with_restore_list:
thd->variables.select_limit= select_limit;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- sp_restore_security_context(thd, sp, &save_ctx);
+ sp_restore_security_context(thd, save_ctx);
#endif
#ifndef EMBEDDED_LIBRARY
@@ -4477,10 +4518,10 @@ end_with_restore_list:
mysql_bin_log.is_open())
{
String buff;
- LEX_STRING command[3]=
- {{STRING_WITH_LEN("CREATE ")},
- {STRING_WITH_LEN("ALTER ")},
- {STRING_WITH_LEN("CREATE OR REPLACE ")}};
+ const LEX_STRING command[3]=
+ {{(char *)STRING_WITH_LEN("CREATE ")},
+ {(char *)STRING_WITH_LEN("ALTER ")},
+ {(char *)STRING_WITH_LEN("CREATE OR REPLACE ")}};
thd->clear_error();
buff.append(command[thd->lex->create_view_mode].str,
@@ -4807,6 +4848,7 @@ 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);
@@ -4815,7 +4857,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
const char *db_name;
DBUG_ENTER("check_access");
DBUG_PRINT("enter",("db: %s want_access: %lu master_access: %lu",
- db ? db : "", want_access, thd->master_access));
+ db ? db : "", want_access, sctx->master_access));
if (save_priv)
*save_priv=0;
else
@@ -4837,7 +4879,8 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
{
if (!no_errors)
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
- thd->priv_user, thd->priv_host, db_name);
+ sctx->priv_user,
+ sctx->priv_host, db_name);
DBUG_RETURN(TRUE);
}
else
@@ -4850,28 +4893,29 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
#ifdef NO_EMBEDDED_ACCESS_CHECKS
DBUG_RETURN(0);
#else
- if ((thd->master_access & want_access) == want_access)
+ 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= thd->db_access;
- if (!(thd->master_access & SELECT_ACL) &&
+ 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(thd->host, thd->ip, thd->priv_user, db, db_is_pattern);
- *save_priv=thd->master_access | db_access;
+ 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 & ~thd->master_access) & ~(DB_ACLS | EXTRA_ACL)) ||
+ 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),
- thd->priv_user,
- thd->priv_host,
+ sctx->priv_user,
+ sctx->priv_host,
(thd->password ?
ER(ER_YES) :
ER(ER_NO))); /* purecov: tested */
@@ -4882,15 +4926,16 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
DBUG_RETURN(FALSE); // Allow select on anything
if (db && (!thd->db || db_is_pattern || strcmp(db,thd->db)))
- db_access=acl_get(thd->host, thd->ip, thd->priv_user, db, db_is_pattern);
+ db_access= acl_get(sctx->host, sctx->ip, sctx->priv_user, db,
+ db_is_pattern);
else
- db_access=thd->db_access;
+ db_access= sctx->db_access;
DBUG_PRINT("info",("db_access: %lu", db_access));
/* Remove SHOW attribute and access rights we already have */
- want_access &= ~(thd->master_access | EXTRA_ACL);
+ 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 | thd->master_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 ||
@@ -4901,8 +4946,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
DBUG_PRINT("error",("Access denied"));
if (!no_errors)
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
- thd->priv_user,
- thd->priv_host,
+ sctx->priv_user, sctx->priv_host,
(db ? db : (thd->db ?
thd->db :
"unknown"))); /* purecov: tested */
@@ -4936,7 +4980,7 @@ bool check_global_access(THD *thd, ulong want_access)
return 0;
#else
char command[128];
- if ((thd->master_access & want_access))
+ 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);
@@ -4964,7 +5008,7 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
{
if (!no_errors)
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
- thd->priv_user, thd->priv_host,
+ thd->security_ctx->priv_user, thd->security_ctx->priv_host,
information_schema_name.str);
return TRUE;
}
@@ -4973,7 +5017,8 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
my_tz_check_n_skip_implicit_tables(&tables,
thd->lex->time_zone_tables_used))
continue;
- if ((thd->master_access & want_access) == (want_access & ~EXTRA_ACL) &&
+ if ((thd->security_ctx->master_access & want_access) ==
+ (want_access & ~EXTRA_ACL) &&
thd->db)
tables->grant.privilege= want_access;
else if (tables->db && tables->db == thd->db)
@@ -5010,7 +5055,8 @@ check_routine_access(THD *thd, ulong want_access,char *db, char *name,
tables->db= db;
tables->table_name= tables->alias= name;
- if ((thd->master_access & want_access) == want_access && !thd->db)
+ if ((thd->security_ctx->master_access & want_access) == want_access &&
+ !thd->db)
tables->grant.privilege= want_access;
else if (check_access(thd,want_access,db,&tables->grant.privilege,
0, no_errors, test(tables->schema_table)))
@@ -5043,7 +5089,7 @@ bool check_some_routine_access(THD *thd, const char *db, const char *name,
bool is_proc)
{
ulong save_priv;
- if (thd->master_access & SHOW_PROC_ACLS)
+ if (thd->security_ctx->master_access & SHOW_PROC_ACLS)
return FALSE;
/*
There are no routines in information_schema db. So we can safely
@@ -5240,6 +5286,7 @@ void mysql_reset_thd_for_next_command(THD *thd)
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)
{
@@ -5617,8 +5664,7 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
and so on, the display width is ignored.
*/
char buf[32];
- my_snprintf(buf, sizeof(buf),
- "TIMESTAMP(%s)", length, system_charset_info);
+ 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),
@@ -5724,7 +5770,7 @@ new_create_field(THD *thd, char *field_name, enum_field_types type,
}
if (new_field->length < new_field->decimals)
{
- my_error(ER_SCALE_BIGGER_THAN_PRECISION, MYF(0), field_name);
+ my_error(ER_M_BIGGER_THAN_D, MYF(0), field_name);
DBUG_RETURN(NULL);
}
new_field->length=
@@ -5787,19 +5833,31 @@ new_create_field(THD *thd, char *field_name, enum_field_types type,
new_field->decimals= NOT_FIXED_DEC;
break;
}
- if (!length)
+ if (!length && !decimals)
{
new_field->length = FLT_DIG+6;
new_field->decimals= NOT_FIXED_DEC;
}
+ if (new_field->length < new_field->decimals &&
+ new_field->decimals != NOT_FIXED_DEC)
+ {
+ my_error(ER_M_BIGGER_THAN_D, MYF(0), field_name);
+ DBUG_RETURN(NULL);
+ }
break;
case FIELD_TYPE_DOUBLE:
allowed_type_modifier= AUTO_INCREMENT_FLAG;
- if (!length)
+ if (!length && !decimals)
{
new_field->length = DBL_DIG+7;
new_field->decimals=NOT_FIXED_DEC;
}
+ if (new_field->length < new_field->decimals &&
+ new_field->decimals != NOT_FIXED_DEC)
+ {
+ my_error(ER_M_BIGGER_THAN_D, MYF(0), field_name);
+ DBUG_RETURN(NULL);
+ }
break;
case FIELD_TYPE_TIMESTAMP:
if (!length)
@@ -6764,8 +6822,8 @@ void kill_one_thread(THD *thd, ulong id, bool only_kill_query)
VOID(pthread_mutex_unlock(&LOCK_thread_count));
if (tmp)
{
- if ((thd->master_access & SUPER_ACL) ||
- !strcmp(thd->user,tmp->user))
+ 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;
@@ -7182,6 +7240,12 @@ bool multi_delete_set_locks_and_link_aux_tables(LEX *lex)
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
}
@@ -7390,7 +7454,7 @@ Item *negate_expression(THD *thd, Item *expr)
SYNOPSIS
default_definer()
- thd thread handler
+ Secytity_context current decurity context
definer structure where it should be assigned
RETURN
@@ -7398,14 +7462,14 @@ Item *negate_expression(THD *thd, Item *expr)
TRUE Error
*/
-bool default_view_definer(THD *thd, st_lex_user *definer)
+bool default_view_definer(Security_context *sctx, st_lex_user *definer)
{
- definer->user.str= thd->priv_user;
- definer->user.length= strlen(thd->priv_user);
- if (*thd->priv_host != 0)
+ definer->user.str= sctx->priv_user;
+ definer->user.length= strlen(sctx->priv_user);
+ if (*sctx->priv_host != 0)
{
- definer->host.str= thd->priv_host;
- definer->host.length= strlen(thd->priv_host);
+ definer->host.str= sctx->priv_host;
+ definer->host.length= strlen(sctx->priv_host);
}
else
{
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 4cda4ed108a..16433e42e3c 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -71,6 +71,7 @@ When one supplies long data for a placeholder:
#include "mysql_priv.h"
#include "sql_select.h" // for JOIN
+#include "sql_cursor.h"
#include "sp_head.h"
#include "sp.h"
#include "sp_cache.h"
@@ -81,6 +82,18 @@ When one supplies long data for a placeholder:
#include <mysql_com.h>
#endif
+/* A result class used to send cursor rows using the binary protocol. */
+
+class Select_fetch_protocol_prep: public select_send
+{
+ Protocol_prep protocol;
+public:
+ Select_fetch_protocol_prep(THD *thd);
+ virtual bool send_fields(List<Item> &list, uint flags);
+ virtual bool send_data(List<Item> &items);
+ virtual bool send_eof();
+};
+
/******************************************************************************
Prepared_statement: a statement that can contain placeholders
******************************************************************************/
@@ -89,6 +102,7 @@ class Prepared_statement: public Statement
{
public:
THD *thd;
+ Select_fetch_protocol_prep result;
Protocol *protocol;
Item_param **param_array;
uint param_count;
@@ -109,8 +123,9 @@ public:
virtual ~Prepared_statement();
void setup_set_params();
virtual Query_arena::Type type() const;
- virtual void close_cursor();
+ virtual void cleanup_stmt();
bool set_name(LEX_STRING *name);
+ inline void close_cursor() { delete cursor; cursor= 0; }
bool prepare(const char *packet, uint packet_length);
bool execute(String *expanded_query, bool open_cursor);
@@ -140,8 +155,6 @@ inline bool is_param_null(const uchar *pos, ulong param_no)
return pos[param_no/8] & (1 << (param_no & 7));
}
-enum { STMT_QUERY_LOG_LENGTH= 8192 };
-
/*
Find a prepared statement in the statement map by id.
@@ -1264,7 +1277,7 @@ static int mysql_test_select(Prepared_statement *stmt,
It is not SELECT COMMAND for sure, so setup_tables will be called as
usual, and we pass 0 as setup_tables_done_option
*/
- if (unit->prepare(thd, 0, 0, ""))
+ if (unit->prepare(thd, 0, 0))
goto error;
if (!lex->describe && !text_protocol)
{
@@ -1395,7 +1408,7 @@ static bool select_like_stmt_test(Prepared_statement *stmt,
thd->used_tables= 0; // Updated by setup_fields
/* Calls JOIN::prepare */
- DBUG_RETURN(lex->unit.prepare(thd, 0, setup_tables_done_option, ""));
+ DBUG_RETURN(lex->unit.prepare(thd, 0, setup_tables_done_option));
}
/*
@@ -1785,19 +1798,6 @@ static bool init_param_array(Prepared_statement *stmt)
}
-/* Cleanup PS after execute/prepare and restore THD state */
-
-static void cleanup_stmt_and_thd_after_use(Statement *stmt, THD *thd)
-{
- DBUG_ENTER("cleanup_stmt_and_thd_after_use");
- stmt->lex->unit.cleanup();
- cleanup_items(stmt->free_list);
- thd->rollback_item_tree_changes();
- thd->cleanup_after_query();
- DBUG_VOID_RETURN;
-}
-
-
/*
COM_STMT_PREPARE handler.
@@ -2129,8 +2129,8 @@ void reinit_stmt_before_use(THD *thd, LEX *lex)
lex->result->cleanup();
lex->result->set_thd(thd);
}
-
- DBUG_VOID_RETURN;
+ thd->allow_sum_func= 0;
+ DBUG_VOID_RETURN;
}
@@ -2221,16 +2221,14 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
test(flags & (ulong) CURSOR_TYPE_READ_ONLY));
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(), WAIT_PRIOR);
- if (rc)
- goto err;
- mysql_log.write(thd, COM_STMT_EXECUTE, "[%lu] %s", stmt->id, thd->query);
+ if (rc == 0)
+ mysql_log.write(thd, COM_STMT_EXECUTE, "[%lu] %s", stmt->id, thd->query);
DBUG_VOID_RETURN;
set_params_data_err:
my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_stmt_execute");
-err:
reset_stmt_params(stmt);
DBUG_VOID_RETURN;
}
@@ -2285,14 +2283,16 @@ void mysql_sql_stmt_execute(THD *thd)
if (stmt->set_params_from_vars(stmt, lex->prepared_stmt_params,
&expanded_query))
- {
- my_error(ER_WRONG_ARGUMENTS, MYF(0), "EXECUTE");
- DBUG_VOID_RETURN;
- }
+ goto set_params_data_err;
(void) stmt->execute(&expanded_query, FALSE);
DBUG_VOID_RETURN;
+
+set_params_data_err:
+ my_error(ER_WRONG_ARGUMENTS, MYF(0), "EXECUTE");
+ reset_stmt_params(stmt);
+ DBUG_VOID_RETURN;
}
@@ -2313,7 +2313,7 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length)
ulong num_rows= uint4korr(packet+4);
Prepared_statement *stmt;
Statement stmt_backup;
- Cursor *cursor;
+ Server_side_cursor *cursor;
DBUG_ENTER("mysql_stmt_fetch");
statistic_increment(thd->status_var.com_stmt_fetch, &LOCK_status);
@@ -2321,7 +2321,7 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length)
DBUG_VOID_RETURN;
cursor= stmt->cursor;
- if (!cursor || !cursor->is_open())
+ if (!cursor)
{
my_error(ER_STMT_HAS_NO_OPEN_CURSOR, MYF(0), stmt_id);
DBUG_VOID_RETURN;
@@ -2333,25 +2333,16 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length)
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(), QUERY_PRIOR);
- thd->protocol= stmt->protocol; // Switch to binary protocol
cursor->fetch(num_rows);
- thd->protocol= &thd->protocol_simple; // Use normal protocol
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(), WAIT_PRIOR);
if (!cursor->is_open())
{
- /* We're done with the fetch: reset PS for next execution */
- cleanup_stmt_and_thd_after_use(stmt, thd);
+ stmt->close_cursor();
+ thd->cursor= 0;
reset_stmt_params(stmt);
- /*
- Must be the last, as some memory is still needed for
- the previous calls.
- */
- free_root(cursor->mem_root, MYF(0));
- if (cursor->close_at_commit)
- thd->stmt_map.erase_transient_cursor(stmt);
}
thd->restore_backup_statement(stmt, &stmt_backup);
@@ -2384,14 +2375,19 @@ void mysql_stmt_reset(THD *thd, char *packet)
/* There is always space for 4 bytes in buffer */
ulong stmt_id= uint4korr(packet);
Prepared_statement *stmt;
- Cursor *cursor;
DBUG_ENTER("mysql_stmt_reset");
statistic_increment(thd->status_var.com_stmt_reset, &LOCK_status);
if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_reset")))
DBUG_VOID_RETURN;
- stmt->close_cursor(); /* will reset statement params */
+ stmt->close_cursor();
+
+ /*
+ Clear parameters from data which could be set by
+ mysql_stmt_send_long_data() call.
+ */
+ reset_stmt_params(stmt);
stmt->state= Query_arena::PREPARED;
@@ -2533,11 +2529,65 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
}
+/***************************************************************************
+ Select_fetch_protocol_prep
+****************************************************************************/
+
+Select_fetch_protocol_prep::Select_fetch_protocol_prep(THD *thd)
+ :protocol(thd)
+{}
+
+bool Select_fetch_protocol_prep::send_fields(List<Item> &list, uint flags)
+{
+ bool rc;
+ Protocol *save_protocol= thd->protocol;
+
+ /*
+ Protocol::send_fields caches the information about column types:
+ this information is later used to send data. Therefore, the same
+ dedicated Protocol object must be used for all operations with
+ a cursor.
+ */
+ thd->protocol= &protocol;
+ rc= select_send::send_fields(list, flags);
+ thd->protocol= save_protocol;
+
+ return rc;
+}
+
+bool Select_fetch_protocol_prep::send_eof()
+{
+ Protocol *save_protocol= thd->protocol;
+
+ thd->protocol= &protocol;
+ ::send_eof(thd);
+ thd->protocol= save_protocol;
+ return FALSE;
+}
+
+
+bool
+Select_fetch_protocol_prep::send_data(List<Item> &fields)
+{
+ Protocol *save_protocol= thd->protocol;
+ bool rc;
+
+ thd->protocol= &protocol;
+ rc= select_send::send_data(fields);
+ thd->protocol= save_protocol;
+ return rc;
+}
+
+/***************************************************************************
+ Prepared_statement
+****************************************************************************/
+
Prepared_statement::Prepared_statement(THD *thd_arg, Protocol *protocol_arg)
:Statement(INITIALIZED, ++thd_arg->statement_id_counter,
thd_arg->variables.query_alloc_block_size,
thd_arg->variables.query_prealloc_size),
thd(thd_arg),
+ result(thd_arg),
protocol(protocol_arg),
param_array(0),
param_count(0),
@@ -2585,17 +2635,7 @@ Prepared_statement::~Prepared_statement()
{
DBUG_ENTER("Prepared_statement::~Prepared_statement");
DBUG_PRINT("enter",("stmt: %p cursor: %p", this, cursor));
- if (cursor)
- {
- if (cursor->is_open())
- {
- cursor->close(FALSE);
- cleanup_items(free_list);
- thd->rollback_item_tree_changes();
- free_root(cursor->mem_root, MYF(0));
- }
- cursor->Cursor::~Cursor();
- }
+ delete cursor;
/*
We have to call free on the items even if cleanup is called as some items,
like Item_param, don't free everything until free_items()
@@ -2612,25 +2652,18 @@ Query_arena::Type Prepared_statement::type() const
}
-void Prepared_statement::close_cursor()
+void Prepared_statement::cleanup_stmt()
{
- DBUG_ENTER("Prepared_statement::close_cursor");
+ DBUG_ENTER("Prepared_statement::cleanup_stmt");
DBUG_PRINT("enter",("stmt: %p", this));
- if (cursor && cursor->is_open())
- {
- thd->change_list= cursor->change_list;
- cursor->close(FALSE);
- cleanup_stmt_and_thd_after_use(this, thd);
- free_root(cursor->mem_root, MYF(0));
- if (cursor->close_at_commit)
- thd->stmt_map.erase_transient_cursor(this);
- }
- /*
- Clear parameters from data which could be set by
- mysql_stmt_send_long_data() call.
- */
- reset_stmt_params(this);
+ /* The order is important */
+ lex->unit.cleanup();
+ cleanup_items(free_list);
+ thd->cleanup_after_query();
+ close_thread_tables(thd);
+ thd->rollback_item_tree_changes();
+
DBUG_VOID_RETURN;
}
@@ -2734,14 +2767,13 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
if (rc == 0)
rc= check_prepared_statement(this, name.str != 0);
- if (rc && thd->lex->sphead)
+ if (rc && lex->sphead)
{
- delete thd->lex->sphead;
- thd->lex->sphead= NULL;
+ delete lex->sphead;
+ lex->sphead= NULL;
}
lex_end(lex);
- close_thread_tables(thd);
- cleanup_stmt_and_thd_after_use(this, thd);
+ cleanup_stmt();
thd->restore_backup_statement(this, &stmt_backup);
thd->stmt_arena= old_stmt_arena;
@@ -2781,7 +2813,7 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
Statement stmt_backup;
Query_arena *old_stmt_arena;
Item *old_free_list;
- bool rc= 1;
+ bool rc= TRUE;
statistic_increment(thd->status_var.com_stmt_execute, &LOCK_status);
@@ -2789,18 +2821,35 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
if (state == Query_arena::ERROR)
{
my_message(last_errno, last_error, MYF(0));
- return 1;
+ return TRUE;
}
if (flags & IS_IN_USE)
{
my_error(ER_PS_NO_RECURSION, MYF(0));
- return 1;
+ return TRUE;
}
+
+ /*
+ For SHOW VARIABLES lex->result is NULL, as it's a non-SELECT
+ command. For such queries we don't return an error and don't
+ open a cursor -- the client library will recognize this case and
+ materialize the result set.
+ For SELECT statements lex->result is created in
+ check_prepared_statement. lex->result->simple_select() is FALSE
+ in INSERT ... SELECT and similar commands.
+ */
+
+ if (open_cursor && lex->result && !lex->result->simple_select())
+ {
+ DBUG_PRINT("info",("Cursor asked for not SELECT stmt"));
+ my_error(ER_SP_BAD_CURSOR_QUERY, MYF(0));
+ return TRUE;
+ }
+
/* In case the command has a call to SP which re-uses this statement name */
flags|= IS_IN_USE;
- if (cursor && cursor->is_open())
- close_cursor();
+ close_cursor();
/*
If the free_list is not empty, we'll wrongly free some externally
@@ -2808,32 +2857,6 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
*/
DBUG_ASSERT(thd->change_list.is_empty());
DBUG_ASSERT(thd->free_list == NULL);
- if (open_cursor)
- {
- if (!lex->result || !lex->result->simple_select())
- {
- DBUG_PRINT("info",("Cursor asked for not SELECT stmt"));
- /*
- If lex->result is set in the parser, this is not a SELECT
- statement: we can't open a cursor for it.
- */
- my_error(ER_SP_BAD_CURSOR_QUERY, MYF(0));
- goto error;
- }
-
- DBUG_PRINT("info",("Using READ_ONLY cursor"));
- if (!cursor && !(cursor= new (mem_root) Cursor(thd)))
- goto error;
- /* If lex->result is set, mysql_execute_command will use it */
- lex->result= &cursor->result;
- protocol= &cursor->protocol;
- thd->lock_id= &cursor->lock_id;
- /*
- Currently cursors can be used only from C API, so
- we don't have to create an own memory root for them:
- the one in THD is clean and can be used.
- */
- }
thd->set_n_backup_statement(this, &stmt_backup);
if (expanded_query->length() &&
alloc_query(thd, (char*) expanded_query->ptr(),
@@ -2862,38 +2885,27 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
reinit_stmt_before_use(thd, lex);
thd->protocol= protocol; /* activate stmt protocol */
- mysql_execute_command(thd);
+ rc= open_cursor ? mysql_open_cursor(thd, (uint) ALWAYS_MATERIALIZED_CURSOR,
+ &result, &cursor) :
+ mysql_execute_command(thd);
thd->protocol= &thd->protocol_simple; /* use normal protocol */
- if (cursor && cursor->is_open())
- {
- /*
- It's safer if we grab THD state after mysql_execute_command is
- finished and not in Cursor::open(), because currently the call to
- Cursor::open is buried deep in JOIN::exec of the top level join.
- */
- cursor->init_from_thd(thd);
+ /* Assert that if an error, no cursor is open */
+ DBUG_ASSERT(! (rc && cursor));
- if (cursor->close_at_commit)
- thd->stmt_map.add_transient_cursor(this);
- }
- else
+ if (! cursor)
{
- close_thread_tables(thd);
- cleanup_stmt_and_thd_after_use(this, thd);
+ cleanup_stmt();
reset_stmt_params(this);
}
thd->set_statement(&stmt_backup);
- thd->lock_id= &thd->main_lock_id;
thd->stmt_arena= old_stmt_arena;
if (state == Query_arena::PREPARED)
state= Query_arena::EXECUTED;
- rc= 0;
error:
- thd->lock_id= &thd->main_lock_id;
flags&= ~IS_IN_USE;
return rc;
}
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc
index 3880aa428b9..154e828b47e 100644
--- a/sql/sql_rename.cc
+++ b/sql/sql_rename.cc
@@ -133,11 +133,12 @@ static TABLE_LIST *
rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error)
{
TABLE_LIST *ren_table,*new_table;
+ frm_type_enum frm_type;
DBUG_ENTER("rename_tables");
for (ren_table= table_list; ren_table; ren_table= new_table->next_local)
{
- db_type table_type;
+ int rc= 1;
char name[FN_REFLEN];
const char *new_alias, *old_alias;
@@ -164,19 +165,36 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error)
ren_table->db, old_alias,
reg_ext);
unpack_filename(name, name);
- if ((table_type=get_table_type(thd, name)) == DB_TYPE_UNKNOWN)
- {
- my_error(ER_FILE_NOT_FOUND, MYF(0), name, my_errno);
- if (!skip_error)
- DBUG_RETURN(ren_table);
- }
- else if (mysql_rename_table(table_type,
- ren_table->db, old_alias,
- new_table->db, new_alias))
+
+ frm_type= mysql_frm_type(name);
+ switch (frm_type)
{
- if (!skip_error)
- DBUG_RETURN(ren_table);
+ case FRMTYPE_TABLE:
+ {
+ db_type table_type;
+ if ((table_type= get_table_type(thd, name)) == DB_TYPE_UNKNOWN)
+ my_error(ER_FILE_NOT_FOUND, MYF(0), name, my_errno);
+ else
+ rc= mysql_rename_table(table_type, ren_table->db, old_alias,
+ new_table->db, new_alias);
+ break;
+ }
+ case FRMTYPE_VIEW:
+ /* change of schema is not allowed */
+ if (strcmp(ren_table->db, new_table->db))
+ my_error(ER_FORBID_SCHEMA_CHANGE, MYF(0), ren_table->db,
+ new_table->db);
+ else
+ rc= mysql_rename_view(thd, new_alias, ren_table);
+ break;
+ default:
+ DBUG_ASSERT(0); // should never happen
+ case FRMTYPE_ERROR:
+ my_error(ER_FILE_NOT_FOUND, MYF(0), name, my_errno);
+ break;
}
+ if (rc && !skip_error)
+ DBUG_RETURN(ren_table);
}
DBUG_RETURN(0);
}
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index b8f9d30faab..a02a61b7a86 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -23,6 +23,7 @@
#include "mysql_priv.h"
#include "sql_select.h"
+#include "sql_cursor.h"
#include <m_ctype.h>
#include <hash.h>
@@ -107,20 +108,15 @@ static bool const_expression_in_where(COND *conds,Item *item, Item **comp_item);
static bool open_tmp_table(TABLE *table);
static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
ulong options);
-static Next_select_func setup_end_select_func(JOIN *join);
static int do_select(JOIN *join,List<Item> *fields,TABLE *tmp_table,
Procedure *proc);
static enum_nested_loop_state
-sub_select_cache(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
-static enum_nested_loop_state
evaluate_join_record(JOIN *join, JOIN_TAB *join_tab,
int error, my_bool *report_error);
static enum_nested_loop_state
evaluate_null_complemented_join_record(JOIN *join, JOIN_TAB *join_tab);
static enum_nested_loop_state
-sub_select(JOIN *join,JOIN_TAB *join_tab, bool end_of_records);
-static enum_nested_loop_state
flush_cached_records(JOIN *join, JOIN_TAB *join_tab, bool skip_last);
static enum_nested_loop_state
end_send(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
@@ -1728,262 +1724,6 @@ JOIN::destroy()
DBUG_RETURN(error);
}
-
-/************************* Cursor ******************************************/
-
-Cursor::Cursor(THD *thd)
- :Query_arena(&main_mem_root, INITIALIZED),
- join(0), unit(0),
- protocol(thd),
- close_at_commit(FALSE)
-{
- /* We will overwrite it at open anyway. */
- init_sql_alloc(&main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
- thr_lock_owner_init(&lock_id, &thd->lock_info);
- bzero((void*) ht_info, sizeof(ht_info));
-}
-
-
-void
-Cursor::init_from_thd(THD *thd)
-{
- Engine_info *info;
- /*
- We need to save and reset thd->mem_root, otherwise it'll be freed
- later in mysql_parse.
-
- We can't just change the thd->mem_root here as we want to keep the
- things that are already allocated in thd->mem_root for Cursor::fetch()
- */
- main_mem_root= *thd->mem_root;
- state= thd->stmt_arena->state;
- /* Allocate new memory root for thd */
- init_sql_alloc(thd->mem_root,
- thd->variables.query_alloc_block_size,
- thd->variables.query_prealloc_size);
-
- /*
- The same is true for open tables and lock: save tables and zero THD
- pointers to prevent table close in close_thread_tables (This is a part
- of the temporary solution to make cursors work with minimal changes to
- the current source base).
- */
- derived_tables= thd->derived_tables;
- open_tables= thd->open_tables;
- lock= thd->lock;
- query_id= thd->query_id;
- free_list= thd->free_list;
- change_list= thd->change_list;
- reset_thd(thd);
- /* Now we have an active cursor and can cause a deadlock */
- thd->lock_info.n_cursors++;
-
- close_at_commit= FALSE; /* reset in case we're reusing the cursor */
- info= &ht_info[0];
- for (handlerton **pht= thd->transaction.stmt.ht; *pht; pht++)
- {
- const handlerton *ht= *pht;
- close_at_commit|= test(ht->flags & HTON_CLOSE_CURSORS_AT_COMMIT);
- if (ht->create_cursor_read_view)
- {
- info->ht= ht;
- info->read_view= (ht->create_cursor_read_view)();
- ++info;
- }
- }
- /*
- XXX: thd->locked_tables is not changed.
- What problems can we have with it if cursor is open?
- TODO: must be fixed because of the prelocked mode.
- */
-}
-
-
-void
-Cursor::reset_thd(THD *thd)
-{
- thd->derived_tables= 0;
- thd->open_tables= 0;
- thd->lock= 0;
- thd->free_list= 0;
- thd->change_list.empty();
-}
-
-
-int
-Cursor::open(JOIN *join_arg)
-{
- join= join_arg;
- THD *thd= join->thd;
- /* First non-constant table */
- JOIN_TAB *join_tab= join->join_tab + join->const_tables;
- DBUG_ENTER("Cursor::open");
-
- /*
- Send fields description to the client; server_status is sent
- in 'EOF' packet, which ends send_fields().
- */
- thd->server_status|= SERVER_STATUS_CURSOR_EXISTS;
- join->result->send_fields(*join->fields, Protocol::SEND_NUM_ROWS);
- ::send_eof(thd);
- thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS;
-
- /* Prepare JOIN for reading rows. */
- join->tmp_table= 0;
- join->join_tab[join->tables-1].next_select= setup_end_select_func(join);
- join->send_records= 0;
- join->fetch_limit= join->unit->offset_limit_cnt;
-
- /* Disable JOIN CACHE as it is not working with cursors yet */
- for (JOIN_TAB *tab= join_tab;
- tab != join->join_tab + join->tables - 1;
- tab++)
- {
- if (tab->next_select == sub_select_cache)
- tab->next_select= sub_select;
- }
-
- DBUG_ASSERT(join_tab->table->reginfo.not_exists_optimize == 0);
- DBUG_ASSERT(join_tab->not_used_in_distinct == 0);
- /*
- null_row is set only if row not found and it's outer join: should never
- happen for the first table in join_tab list
- */
- DBUG_ASSERT(join_tab->table->null_row == 0);
- DBUG_RETURN(0);
-}
-
-
-/*
- DESCRIPTION
- Fetch next num_rows rows from the cursor and sent them to the client
- PRECONDITION:
- Cursor is open
- RETURN VALUES:
- none, this function will send error or OK to network if necessary.
-*/
-
-void
-Cursor::fetch(ulong num_rows)
-{
- THD *thd= join->thd;
- JOIN_TAB *join_tab= join->join_tab + join->const_tables;
- enum_nested_loop_state error= NESTED_LOOP_OK;
- Query_arena backup_arena;
- Engine_info *info;
- DBUG_ENTER("Cursor::fetch");
- DBUG_PRINT("enter",("rows: %lu", num_rows));
-
- DBUG_ASSERT(thd->derived_tables == 0 && thd->open_tables == 0 &&
- thd->lock == 0);
-
- thd->derived_tables= derived_tables;
- thd->open_tables= open_tables;
- thd->lock= lock;
- thd->query_id= query_id;
- thd->change_list= change_list;
- /* save references to memory, allocated during fetch */
- thd->set_n_backup_active_arena(this, &backup_arena);
-
- for (info= ht_info; info->read_view ; info++)
- (info->ht->set_cursor_read_view)(info->read_view);
-
- join->fetch_limit+= num_rows;
-
- error= sub_select(join, join_tab, 0);
- if (error == NESTED_LOOP_OK || error == NESTED_LOOP_NO_MORE_ROWS)
- error= sub_select(join,join_tab,1);
- if (error == NESTED_LOOP_QUERY_LIMIT)
- error= NESTED_LOOP_OK; /* select_limit used */
- if (error == NESTED_LOOP_CURSOR_LIMIT)
- join->resume_nested_loop= TRUE;
-
-#ifdef USING_TRANSACTIONS
- ha_release_temporary_latches(thd);
-#endif
- /* Grab free_list here to correctly free it in close */
- thd->restore_active_arena(this, &backup_arena);
-
- for (info= ht_info; info->read_view; info++)
- (info->ht->set_cursor_read_view)(0);
-
- if (error == NESTED_LOOP_CURSOR_LIMIT)
- {
- /* Fetch limit worked, possibly more rows are there */
- thd->server_status|= SERVER_STATUS_CURSOR_EXISTS;
- ::send_eof(thd);
- thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS;
- change_list= thd->change_list;
- reset_thd(thd);
- }
- else
- {
- close(TRUE);
- if (error == NESTED_LOOP_OK)
- {
- thd->server_status|= SERVER_STATUS_LAST_ROW_SENT;
- ::send_eof(thd);
- thd->server_status&= ~SERVER_STATUS_LAST_ROW_SENT;
- }
- else if (error != NESTED_LOOP_KILLED)
- my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
- }
- DBUG_VOID_RETURN;
-}
-
-
-void
-Cursor::close(bool is_active)
-{
- THD *thd= join->thd;
- DBUG_ENTER("Cursor::close");
-
- /*
- In case of UNIONs JOIN is freed inside of unit->cleanup(),
- otherwise in select_lex->cleanup().
- */
- if (unit)
- (void) unit->cleanup();
- else
- (void) join->select_lex->cleanup();
-
- for (Engine_info *info= ht_info; info->read_view; info++)
- {
- (info->ht->close_cursor_read_view)(info->read_view);
- info->read_view= 0;
- info->ht= 0;
- }
-
- if (is_active)
- close_thread_tables(thd);
- else
- {
- /* XXX: Another hack: closing tables used in the cursor */
- DBUG_ASSERT(lock || open_tables || derived_tables);
-
- TABLE *tmp_derived_tables= thd->derived_tables;
- MYSQL_LOCK *tmp_lock= thd->lock;
-
- thd->open_tables= open_tables;
- thd->derived_tables= derived_tables;
- thd->lock= lock;
- close_thread_tables(thd);
-
- thd->open_tables= tmp_derived_tables;
- thd->derived_tables= tmp_derived_tables;
- thd->lock= tmp_lock;
- }
- thd->lock_info.n_cursors--; /* Decrease the number of active cursors */
- join= 0;
- unit= 0;
- free_items();
- change_list.empty();
- DBUG_VOID_RETURN;
-}
-
-
-/*********************************************************************/
-
/*
An entry point to single-unit select (a select without UNION).
@@ -2063,9 +1803,9 @@ mysql_select(THD *thd, Item ***rref_pointer_array,
}
else
{
- if (join->prepare(rref_pointer_array, tables, wild_num,
- conds, og_num, order, group, having, proc_param,
- select_lex, unit))
+ if (err= join->prepare(rref_pointer_array, tables, wild_num,
+ conds, og_num, order, group, having, proc_param,
+ select_lex, unit))
{
goto err;
}
@@ -2080,9 +1820,9 @@ mysql_select(THD *thd, Item ***rref_pointer_array,
DBUG_RETURN(TRUE);
thd->proc_info="init";
thd->used_tables=0; // Updated by setup_fields
- if (join->prepare(rref_pointer_array, tables, wild_num,
- conds, og_num, order, group, having, proc_param,
- select_lex, unit))
+ if (err= join->prepare(rref_pointer_array, tables, wild_num,
+ conds, og_num, order, group, having, proc_param,
+ select_lex, unit))
{
goto err;
}
@@ -2124,7 +1864,7 @@ err:
if (free_join)
{
thd->proc_info="end";
- err= select_lex->cleanup();
+ err|= select_lex->cleanup();
DBUG_RETURN(err || thd->net.report_error);
}
DBUG_RETURN(join->error);
@@ -2658,7 +2398,6 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end,
field Field used in comparision
eq_func True if we used =, <=> or IS NULL
value Value used for comparison with field
- Is NULL for BETWEEN and IN
usable_tables Tables which can be used for key optimization
NOTES
@@ -2682,6 +2421,7 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond,
!field->table->maybe_null || field->null_ptr)
return; // Not a key. Skip it
exists_optimize= KEY_OPTIMIZE_EXISTS;
+ DBUG_ASSERT(num_values == 1);
}
else
{
@@ -2733,7 +2473,26 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond,
eq_func is NEVER true when num_values > 1
*/
if (!eq_func)
- return;
+ {
+ /*
+ Additional optimization: if we're processing
+ "t.key BETWEEN c1 AND c1" then proceed as if we were processing
+ "t.key = c1".
+ TODO: This is a very limited fix. A more generic fix is possible.
+ There are 2 options:
+ A) Make equality propagation code be able to handle BETWEEN
+ (including cases like t1.key BETWEEN t2.key AND t3.key)
+ B) Make range optimizer to infer additional "t.key = c" equalities
+ and use them in equality propagation process (see details in
+ OptimizerKBAndTodo)
+ */
+ if ((cond->functype() == Item_func::BETWEEN) &&
+ value[0]->eq(value[1], field->binary()))
+ eq_func= TRUE;
+ else
+ return;
+ }
+
if (field->result_type() == STRING_RESULT)
{
if ((*value)->result_type() != STRING_RESULT)
@@ -2760,7 +2519,6 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond,
}
}
}
- DBUG_ASSERT(num_values == 1);
/*
For the moment eq_func is always true. This slot is reserved for future
extensions where we want to remembers other things than just eq comparisons
@@ -5991,7 +5749,7 @@ void JOIN::join_free(bool full)
cleanup(full);
for (unit= select_lex->first_inner_unit(); unit; unit= unit->next_unit())
- for (sl= unit->first_select_in_union(); sl; sl= sl->next_select())
+ for (sl= unit->first_select(); sl; sl= sl->next_select())
{
JOIN *join= sl->join;
if (join)
@@ -8092,18 +7850,24 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
if (field->maybe_null && !field->field->maybe_null())
{
result= create_tmp_field_from_item(thd, item, table, NULL,
- modify_item, convert_blob_length);
+ modify_item, convert_blob_length);
*from_field= field->field;
if (result && modify_item)
- ((Item_field*)item)->result_field= result;
+ field->result_field= result;
}
- else if (table_cant_handle_bit_fields && field->field->type() == FIELD_TYPE_BIT)
+ else if (table_cant_handle_bit_fields && field->field->type() ==
+ FIELD_TYPE_BIT)
+ {
+ *from_field= field->field;
result= create_tmp_field_from_item(thd, item, table, copy_func,
modify_item, convert_blob_length);
+ if (result && modify_item)
+ field->result_field= result;
+ }
else
result= create_tmp_field_from_field(thd, (*from_field= field->field),
item->name, table,
- modify_item ? (Item_field*) item :
+ modify_item ? field :
NULL,
convert_blob_length);
if (orig_type == Item::REF_ITEM && orig_modify)
@@ -8137,9 +7901,31 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
/*
Create a temp table according to a field list.
- Set distinct if duplicates could be removed
- Given fields field pointers are changed to point at tmp_table
- for send_fields
+
+ SYNOPSIS
+ create_tmp_table()
+ thd thread handle
+ param a description used as input to create the table
+ fields list of items that will be used to define
+ column types of the table (also see NOTES)
+ group TODO document
+ distinct should table rows be distinct
+ save_sum_fields see NOTES
+ select_options
+ rows_limit
+ table_alias possible name of the temporary table that can be used
+ for name resolving; can be "".
+
+ DESCRIPTION
+ Given field pointers are changed to point at tmp_table for
+ send_fields. The table object is self contained: it's
+ allocated in its own memory root, as well as Field objects
+ created for table columns.
+ This function will replace Item_sum items in 'fields' list with
+ corresponding Item_field items, pointing at the fields in the
+ temporary table, unless this was prohibited by TRUE
+ value of argument save_sum_fields. The Item_field objects
+ are created in THD memory root.
*/
#define STRING_TOTAL_LENGTH_TO_PACK_ROWS 128
@@ -8153,6 +7939,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
ulonglong select_options, ha_rows rows_limit,
char *table_alias)
{
+ MEM_ROOT *mem_root_save, own_root;
TABLE *table;
uint i,field_count,null_count,null_pack_length;
uint hidden_null_count, hidden_null_pack_length, hidden_field_count;
@@ -8217,29 +8004,33 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
field_count=param->field_count+param->func_count+param->sum_func_count;
hidden_field_count=param->hidden_field_count;
- if (!my_multi_malloc(MYF(MY_WME),
- &table,sizeof(*table),
- &reg_field, sizeof(Field*)*(field_count+1),
- &blob_field, sizeof(uint)*(field_count+1),
- &from_field, sizeof(Field*)*field_count,
- &copy_func,sizeof(*copy_func)*(param->func_count+1),
- &param->keyinfo,sizeof(*param->keyinfo),
- &key_part_info,
- sizeof(*key_part_info)*(param->group_parts+1),
- &param->start_recinfo,
- sizeof(*param->recinfo)*(field_count*2+4),
- &tmpname,(uint) strlen(path)+1,
- &group_buff,group && ! using_unique_constraint ?
- param->group_length : 0,
- NullS))
+
+ init_sql_alloc(&own_root, TABLE_ALLOC_BLOCK_SIZE, 0);
+
+ if (!multi_alloc_root(&own_root,
+ &table, sizeof(*table),
+ &reg_field, sizeof(Field*) * (field_count+1),
+ &blob_field, sizeof(uint)*(field_count+1),
+ &from_field, sizeof(Field*)*field_count,
+ &copy_func, sizeof(*copy_func)*(param->func_count+1),
+ &param->keyinfo, sizeof(*param->keyinfo),
+ &key_part_info,
+ sizeof(*key_part_info)*(param->group_parts+1),
+ &param->start_recinfo,
+ sizeof(*param->recinfo)*(field_count*2+4),
+ &tmpname, (uint) strlen(path)+1,
+ &group_buff, group && ! using_unique_constraint ?
+ param->group_length : 0,
+ NullS))
{
bitmap_lock_clear_bit(&temp_pool, temp_pool_slot);
DBUG_RETURN(NULL); /* purecov: inspected */
}
- if (!(param->copy_field=copy=new Copy_field[field_count]))
+ /* Copy_field belongs to TMP_TABLE_PARAM, allocate it in THD mem_root */
+ if (!(param->copy_field= copy= new (thd->mem_root) Copy_field[field_count]))
{
bitmap_lock_clear_bit(&temp_pool, temp_pool_slot);
- my_free((gptr) table,MYF(0)); /* purecov: inspected */
+ free_root(&own_root, MYF(0)); /* purecov: inspected */
DBUG_RETURN(NULL); /* purecov: inspected */
}
param->items_to_copy= copy_func;
@@ -8249,6 +8040,11 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
bzero((char*) table,sizeof(*table));
bzero((char*) reg_field,sizeof(Field*)*(field_count+1));
bzero((char*) from_field,sizeof(Field*)*field_count);
+
+ table->mem_root= own_root;
+ mem_root_save= thd->mem_root;
+ thd->mem_root= &table->mem_root;
+
table->field=reg_field;
table->alias= table_alias;
table->reginfo.lock_type=TL_WRITE; /* Will be updated */
@@ -8315,7 +8111,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
Field *new_field=
create_tmp_field(thd, table, arg, arg->type(), &copy_func,
tmp_from_field, group != 0,not_all_columns,
- group || distinct,
+ distinct,
param->convert_blob_length);
if (!new_field)
goto err; // Should be OOM
@@ -8326,6 +8122,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
*blob_field++= (uint) (reg_field - table->field);
blob_count++;
}
+ if (new_field->type() == FIELD_TYPE_BIT)
+ total_uneven_bit_length+= new_field->field_length & 7;
new_field->field_index= (uint) (reg_field - table->field);
*(reg_field++)= new_field;
if (new_field->real_type() == MYSQL_TYPE_STRING ||
@@ -8334,7 +8132,9 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
string_count++;
string_total_length+= new_field->pack_length();
}
+ thd->mem_root= mem_root_save;
thd->change_item_tree(argp, new Item_field(new_field));
+ thd->mem_root= &table->mem_root;
if (!(new_field->flags & NOT_NULL_FLAG))
{
null_count++;
@@ -8360,12 +8160,16 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
write rows to the temporary table.
We here distinguish between UNION and multi-table-updates by the fact
that in the later case group is set to the row pointer.
+
+ The test for item->marker == 4 is ensure we don't create a group-by
+ key over a bit field as heap tables can't handle that.
*/
Field *new_field= (param->schema_table) ?
create_tmp_field_for_schema(thd, item, table) :
create_tmp_field(thd, table, item, type, &copy_func,
tmp_from_field, group != 0,
- not_all_columns || group != 0, 0,
+ not_all_columns || group != 0,
+ item->marker == 4,
param->convert_blob_length);
if (!new_field)
@@ -8398,7 +8202,14 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
*(reg_field++) =new_field;
}
if (!--hidden_field_count)
+ {
+ /*
+ This was the last hidden field; Remember how many hidden fields could
+ have null
+ */
hidden_null_count=null_count;
+ null_count= 0;
+ }
}
DBUG_ASSERT(field_count >= (uint) (reg_field - table->field));
field_count= (uint) (reg_field - table->field);
@@ -8438,8 +8249,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
null_count++;
}
hidden_null_pack_length=(hidden_null_count+7)/8;
- null_pack_length= hidden_null_count +
- (null_count + total_uneven_bit_length + 7) / 8;
+ null_pack_length= (hidden_null_pack_length +
+ (null_count + total_uneven_bit_length + 7) / 8);
reclength+=null_pack_length;
if (!reclength)
reclength=1; // Dummy select
@@ -8454,7 +8265,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
{
uint alloc_length=ALIGN_SIZE(reclength+MI_UNIQUE_HASH_LENGTH+1);
table->s->rec_buff_length= alloc_length;
- if (!(table->record[0]= (byte *) my_malloc(alloc_length*3, MYF(MY_WME))))
+ if (!(table->record[0]= (byte*)
+ alloc_root(&table->mem_root, alloc_length*3)))
goto err;
table->record[1]= table->record[0]+alloc_length;
table->s->default_values= table->record[1]+alloc_length;
@@ -8640,8 +8452,10 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
table->s->uniques= 1;
}
if (!(key_part_info= (KEY_PART_INFO*)
- sql_calloc((keyinfo->key_parts)*sizeof(KEY_PART_INFO))))
+ alloc_root(&table->mem_root,
+ keyinfo->key_parts * sizeof(KEY_PART_INFO))))
goto err;
+ bzero((void*) key_part_info, keyinfo->key_parts * sizeof(KEY_PART_INFO));
table->key_info=keyinfo;
keyinfo->key_part=key_part_info;
keyinfo->flags=HA_NOSAME | HA_NULL_ARE_EQUAL;
@@ -8689,10 +8503,15 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
if (create_myisam_tmp_table(table,param,select_options))
goto err;
}
- if (!open_tmp_table(table))
- DBUG_RETURN(table);
+ if (open_tmp_table(table))
+ goto err;
- err:
+ thd->mem_root= mem_root_save;
+
+ DBUG_RETURN(table);
+
+err:
+ thd->mem_root= mem_root_save;
free_tmp_table(thd,table); /* purecov: inspected */
bitmap_lock_clear_bit(&temp_pool, temp_pool_slot);
DBUG_RETURN(NULL); /* purecov: inspected */
@@ -8837,11 +8656,12 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
if (table->s->keys)
{ // Get keys for ni_create
bool using_unique_constraint=0;
- HA_KEYSEG *seg= (HA_KEYSEG*) sql_calloc(sizeof(*seg) *
- keyinfo->key_parts);
+ HA_KEYSEG *seg= (HA_KEYSEG*) alloc_root(&table->mem_root,
+ sizeof(*seg) * keyinfo->key_parts);
if (!seg)
goto err;
+ bzero(seg, sizeof(*seg) * keyinfo->key_parts);
if (keyinfo->key_length >= table->file->max_key_length() ||
keyinfo->key_parts > table->file->max_key_parts() ||
table->s->uniques)
@@ -8938,13 +8758,14 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
void
free_tmp_table(THD *thd, TABLE *entry)
{
+ MEM_ROOT own_root= entry->mem_root;
const char *save_proc_info;
DBUG_ENTER("free_tmp_table");
DBUG_PRINT("enter",("table: %s",entry->alias));
save_proc_info=thd->proc_info;
thd->proc_info="removing tmp table";
- free_blobs(entry);
+
if (entry->file)
{
if (entry->db_stat)
@@ -8965,12 +8786,11 @@ free_tmp_table(THD *thd, TABLE *entry)
/* free blobs */
for (Field **ptr=entry->field ; *ptr ; ptr++)
(*ptr)->free();
- my_free((gptr) entry->record[0],MYF(0));
free_io_cache(entry);
bitmap_lock_clear_bit(&temp_pool, entry->temp_pool_slot);
- my_free((gptr) entry,MYF(0));
+ free_root(&own_root, MYF(0)); /* the table is allocated in its own root */
thd->proc_info=save_proc_info;
DBUG_VOID_RETURN;
@@ -9090,7 +8910,7 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
end_select function to use. This function can't fail.
*/
-static Next_select_func setup_end_select_func(JOIN *join)
+Next_select_func setup_end_select_func(JOIN *join)
{
TABLE *table= join->tmp_table;
Next_select_func end_select;
@@ -9245,7 +9065,7 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
}
-static enum_nested_loop_state
+enum_nested_loop_state
sub_select_cache(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
{
enum_nested_loop_state rc;
@@ -9386,7 +9206,7 @@ sub_select_cache(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
return one of enum_nested_loop_state, except NESTED_LOOP_NO_MORE_ROWS.
*/
-static enum_nested_loop_state
+enum_nested_loop_state
sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
{
join_tab->table->null_row=0;
@@ -12409,6 +12229,11 @@ calc_group_buffer(JOIN *join,ORDER *group)
key_length+=MAX_BLOB_WIDTH; // Can't be used as a key
else if (field->type() == MYSQL_TYPE_VARCHAR)
key_length+= field->field_length + HA_KEY_BLOB_LENGTH;
+ else if (field->type() == FIELD_TYPE_BIT)
+ {
+ /* Bit is usually stored as a longlong key for group fields */
+ key_length+= 8; // Big enough
+ }
else
key_length+= field->pack_length();
}
@@ -13813,8 +13638,7 @@ bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
unit->fake_select_lex->select_number= UINT_MAX; // jost for initialization
unit->fake_select_lex->type= "UNION RESULT";
unit->fake_select_lex->options|= SELECT_DESCRIBE;
- if (!(res= unit->prepare(thd, result, SELECT_NO_UNLOCK | SELECT_DESCRIBE,
- "")))
+ if (!(res= unit->prepare(thd, result, SELECT_NO_UNLOCK | SELECT_DESCRIBE)))
res= unit->exec();
res|= unit->cleanup();
}
diff --git a/sql/sql_select.h b/sql/sql_select.h
index ce40f657a8e..be51851e760 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -101,7 +101,7 @@ enum enum_nested_loop_state
typedef enum_nested_loop_state
(*Next_select_func)(JOIN *, struct st_join_table *, bool);
typedef int (*Read_record_func)(struct st_join_table *tab);
-
+Next_select_func setup_end_select_func(JOIN *join);
typedef struct st_join_table {
TABLE *table;
@@ -141,6 +141,11 @@ typedef struct st_join_table {
void cleanup();
} JOIN_TAB;
+enum_nested_loop_state sub_select_cache(JOIN *join, JOIN_TAB *join_tab, bool
+ end_of_records);
+enum_nested_loop_state sub_select(JOIN *join,JOIN_TAB *join_tab, bool
+ end_of_records);
+
typedef struct st_position /* Used in find_best */
{
@@ -373,58 +378,6 @@ class JOIN :public Sql_alloc
};
-/*
- Server-side cursor (now stands only for basic read-only cursor)
- See class implementation in sql_select.cc
- A cursor has its own runtime state - list of used items and memory root of
- used memory - which is different from Prepared statement runtime: it must
- be different at least for the purpose of reusing the same prepared
- statement for many cursors.
-*/
-
-class Cursor: public Sql_alloc, public Query_arena
-{
- MEM_ROOT main_mem_root;
- JOIN *join;
- SELECT_LEX_UNIT *unit;
-
- TABLE *open_tables;
- MYSQL_LOCK *lock;
- TABLE *derived_tables;
- /* List of items created during execution */
- query_id_t query_id;
- struct Engine_info
- {
- const handlerton *ht;
- void *read_view;
- };
- Engine_info ht_info[MAX_HA];
-public:
- Protocol_prep protocol;
- Item_change_list change_list;
- select_send result;
- THR_LOCK_OWNER lock_id;
- my_bool close_at_commit;
-
- /* Temporary implementation as now we replace THD state by value */
- /* Save THD state into cursor */
- void init_from_thd(THD *thd);
- /* bzero cursor state in THD */
- void reset_thd(THD *thd);
-
- int open(JOIN *join);
- void fetch(ulong num_rows);
- void reset() { join= 0; }
- bool is_open() const { return join != 0; }
-
- void close(bool is_active);
-
- void set_unit(SELECT_LEX_UNIT *unit_arg) { unit= unit_arg; }
- Cursor(THD *thd);
- ~Cursor() {}
-};
-
-
typedef struct st_select_check {
uint const_ref,reg_ref;
} SELECT_CHECK;
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index c0bb29e035b..24acb1fb6d1 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -67,18 +67,18 @@ bool mysqld_show_storage_engines(THD *thd)
const char *default_type_name=
ha_get_storage_engine((enum db_type)thd->variables.table_type);
- show_table_type_st *types;
- for (types= sys_table_types; types->type; types++)
+ handlerton **types;
+ for (types= sys_table_types; *types; types++)
{
protocol->prepare_for_resend();
- protocol->store(types->type, system_charset_info);
- const char *option_name= show_comp_option_name[(int) *types->value];
+ protocol->store((*types)->name, system_charset_info);
+ const char *option_name= show_comp_option_name[(int) (*types)->state];
- if (*types->value == SHOW_OPTION_YES &&
- !my_strcasecmp(system_charset_info, default_type_name, types->type))
+ 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);
+ protocol->store((*types)->comment, system_charset_info);
if (protocol->write())
DBUG_RETURN(TRUE);
}
@@ -415,8 +415,9 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
bool mysqld_show_create_db(THD *thd, char *dbname,
HA_CREATE_INFO *create_info)
{
+ Security_context *sctx= thd->security_ctx;
int length;
- char path[FN_REFLEN];
+ char path[FN_REFLEN];
char buff[2048];
String buffer(buff, sizeof(buff), system_charset_info);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -435,17 +436,17 @@ bool mysqld_show_create_db(THD *thd, char *dbname,
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (test_all_bits(thd->master_access,DB_ACLS))
+ if (test_all_bits(sctx->master_access, DB_ACLS))
db_access=DB_ACLS;
else
- db_access= (acl_get(thd->host,thd->ip, thd->priv_user,dbname,0) |
- thd->master_access);
+ 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),
- thd->priv_user, thd->host_or_ip, dbname);
+ sctx->priv_user, sctx->host_or_ip, dbname);
mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR),
- thd->priv_user, thd->host_or_ip, dbname);
+ sctx->priv_user, sctx->host_or_ip, dbname);
DBUG_RETURN(TRUE);
}
#endif
@@ -793,7 +794,8 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet)
field->sql_type(type);
packet->append(type.ptr(), type.length(), system_charset_info);
- if (field->has_charset() && !limited_mysql_mode && !foreign_db_mode)
+ if (field->has_charset() &&
+ !(thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)))
{
if (field->charset() != share->table_charset)
{
@@ -832,7 +834,7 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet)
has_default= (field->type() != FIELD_TYPE_BLOB &&
!(field->flags & NO_DEFAULT_VALUE_FLAG) &&
field->unireg_check != Field::NEXT_NUMBER &&
- !((foreign_db_mode || limited_mysql_mode) &&
+ !((thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)) &&
has_now_default));
if (has_default)
@@ -862,12 +864,13 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet)
packet->append(tmp);
}
- if (!foreign_db_mode && !limited_mysql_mode &&
+ if (!(thd->variables.sql_mode & MODE_NO_FIELD_OPTIONS) &&
table->timestamp_field == field &&
field->unireg_check != Field::TIMESTAMP_DN_FIELD)
packet->append(" on update CURRENT_TIMESTAMP",28);
- if (field->unireg_check == Field::NEXT_NUMBER && !foreign_db_mode)
+ if (field->unireg_check == Field::NEXT_NUMBER &&
+ !(thd->variables.sql_mode & MODE_NO_FIELD_OPTIONS))
packet->append(" auto_increment", 15 );
if (field->comment.length)
@@ -1210,24 +1213,26 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
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->user && !strcmp(tmp->user,user))))
+ (!user || (tmp_sctx->user && !strcmp(tmp_sctx->user, user))))
{
- thread_info *thd_info=new thread_info;
+ thread_info *thd_info= new thread_info;
thd_info->thread_id=tmp->thread_id;
- thd_info->user=thd->strdup(tmp->user ? tmp->user :
- (tmp->system_thread ?
- "system user" : "unauthenticated user"));
- if (tmp->peer_port && (tmp->host || tmp->ip) && thd->host_or_ip[0])
+ 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->host_or_ip, tmp->peer_port);
+ "%s:%u", tmp_sctx->host_or_ip, tmp->peer_port);
}
else
- thd_info->host= thd->strdup(tmp->host_or_ip);
+ thd_info->host= thd->strdup(tmp_sctx->host_or_ip);
if ((thd_info->db=tmp->db)) // Safe test
thd_info->db=thd->strdup(thd_info->db);
thd_info->command=(int) tmp->command;
@@ -1278,6 +1283,9 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
VOID(pthread_mutex_unlock(&LOCK_thread_count));
thread_info *thd_info;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ Security_context *sctx;
+#endif
time_t now= time(0);
while ((thd_info=thread_infos.get()))
{
@@ -2014,7 +2022,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
enum enum_schema_tables schema_table_idx;
List<char> bases;
List_iterator_fast<char> it(bases);
- COND *partial_cond;
+ COND *partial_cond;
+ Security_context *sctx= thd->security_ctx;
uint derived_tables= lex->derived_tables;
int error= 1;
Open_tables_state open_tables_state_backup;
@@ -2086,8 +2095,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (!check_access(thd,SELECT_ACL, base_name,
&thd->col_access, 0, 1, with_i_schema) ||
- thd->master_access & (DB_ACLS | SHOW_DB_ACL) ||
- acl_get(thd->host, thd->ip, thd->priv_user, base_name,0) ||
+ 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
{
@@ -2219,6 +2228,7 @@ int fill_schema_shemata(THD *thd, TABLE_LIST *tables, COND *cond)
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,
@@ -2237,8 +2247,8 @@ int fill_schema_shemata(THD *thd, TABLE_LIST *tables, COND *cond)
continue;
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (thd->master_access & (DB_ACLS | SHOW_DB_ACL) ||
- acl_get(thd->host, thd->ip, thd->priv_user, file_name,0) ||
+ 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
{
@@ -2839,7 +2849,8 @@ int fill_schema_proc(THD *thd, TABLE_LIST *tables, COND *cond)
Open_tables_state open_tables_state_backup;
DBUG_ENTER("fill_schema_proc");
- strxmov(definer, thd->priv_user, "@", thd->priv_host, NullS);
+ 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";
@@ -2977,7 +2988,7 @@ static int get_schema_views_record(THD *thd, struct st_table_list *tables,
CHARSET_INFO *cs= system_charset_info;
DBUG_ENTER("get_schema_views_record");
char definer[HOSTNAME_LENGTH + USERNAME_LENGTH + 2];
- uint defiler_len;
+ uint definer_len;
if (!res)
{
if (tables->view)
@@ -3002,9 +3013,9 @@ static int get_schema_views_record(THD *thd, struct st_table_list *tables,
table->field[5]->store(STRING_WITH_LEN("YES"), cs);
else
table->field[5]->store(STRING_WITH_LEN("NO"), cs);
- defiler_len= (strxmov(definer, tables->definer.user.str, "@",
- tables->definer.host.str, NullS) - definer) - 1;
- table->field[6]->store(definer, defiler_len, 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
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 59e23f8b972..a1f2be7e11c 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -3867,6 +3867,16 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
if (create_info->row_type == ROW_TYPE_NOT_USED)
create_info->row_type= table->s->row_type;
+ DBUG_PRINT("info", ("old type: %d new type: %d", old_db_type, new_db_type));
+ if (ha_check_storage_engine_flag(old_db_type, HTON_ALTER_NOT_SUPPORTED)
+ || ha_check_storage_engine_flag(new_db_type, HTON_ALTER_NOT_SUPPORTED))
+ {
+ DBUG_PRINT("info", ("doesn't support alter"));
+ my_error(ER_ILLEGAL_HA, MYF(0), table_name);
+ DBUG_RETURN(TRUE);
+ }
+ DBUG_PRINT("info", ("supports alter"));
+
thd->proc_info="setup";
if (!(alter_info->flags & ~(ALTER_RENAME | ALTER_KEYS_ONOFF)) &&
!table->s->tmp_table) // no need to touch frm
@@ -4880,7 +4890,7 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, HA_CHECK_OPT *check_opt)
strxmov(table_name, table->db ,".", table->table_name, NullS);
- t= table->table= open_ltable(thd, table, TL_READ_NO_INSERT);
+ t= table->table= open_ltable(thd, table, TL_READ);
thd->clear_error(); // these errors shouldn't get client
protocol->prepare_for_resend();
@@ -4906,6 +4916,7 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, HA_CHECK_OPT *check_opt)
{
/* calculating table's checksum */
ha_checksum crc= 0;
+ uchar null_mask=256 - (1 << t->s->last_null_bit_pos);
/*
Set all bits in read set and inform InnoDB that we are reading all
@@ -4927,9 +4938,15 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, HA_CHECK_OPT *check_opt)
continue;
break;
}
- if (t->record[0] != (byte*) t->field[0]->ptr)
- row_crc= my_checksum(row_crc, t->record[0],
- ((byte*) t->field[0]->ptr) - t->record[0]);
+ if (t->s->null_bytes)
+ {
+ /* fix undefined null bits */
+ t->record[0][t->s->null_bytes-1] |= null_mask;
+ if (!(t->s->db_create_options & HA_OPTION_PACK_RECORD))
+ t->record[0][0] |= 1;
+
+ row_crc= my_checksum(row_crc, t->record[0], t->s->null_bytes);
+ }
for (uint i= 0; i < t->s->fields; i++ )
{
@@ -4973,9 +4990,9 @@ static bool check_engine(THD *thd, const char *table_name,
enum db_type *new_engine)
{
enum db_type req_engine= *new_engine;
- bool no_substitution=
+ bool no_substitution=
test(thd->variables.sql_mode & MODE_NO_ENGINE_SUBSTITUTION);
- if ((*new_engine=
+ if ((*new_engine=
ha_checktype(thd, req_engine, no_substitution, 1)) == DB_TYPE_UNKNOWN)
return TRUE;
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index 7342c146045..df8de59508d 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -172,7 +172,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
stronger test will be removed, the test below will hold.
*/
if (!trust_routine_creators && mysql_bin_log.is_open() &&
- !(thd->master_access & SUPER_ACL))
+ !(thd->security_ctx->master_access & SUPER_ACL))
{
my_message(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER,
ER(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER), MYF(0));
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 556493f4fc8..951248e8cd8 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -23,6 +23,7 @@
#include "mysql_priv.h"
#include "sql_select.h"
+#include "sql_cursor.h"
bool mysql_union(THD *thd, LEX *lex, select_result *result,
SELECT_LEX_UNIT *unit, ulong setup_tables_done_option)
@@ -30,13 +31,9 @@ bool mysql_union(THD *thd, LEX *lex, select_result *result,
DBUG_ENTER("mysql_union");
bool res;
if (!(res= unit->prepare(thd, result, SELECT_NO_UNLOCK |
- setup_tables_done_option, "")))
+ setup_tables_done_option)))
res= unit->exec();
- if (!res && thd->cursor && thd->cursor->is_open())
- {
- thd->cursor->set_unit(unit);
- }
- else
+ if (res || !thd->cursor || !thd->cursor->is_open())
res|= unit->cleanup();
DBUG_RETURN(res);
}
@@ -46,16 +43,6 @@ bool mysql_union(THD *thd, LEX *lex, select_result *result,
** store records in temporary table for UNION
***************************************************************************/
-select_union::select_union(TABLE *table_par)
- :table(table_par)
-{
-}
-
-select_union::~select_union()
-{
-}
-
-
int select_union::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
{
unit= u;
@@ -103,6 +90,45 @@ bool select_union::flush()
return 0;
}
+/*
+ Create a temporary table to store the result of select_union.
+
+ SYNOPSIS
+ select_union::create_result_table()
+ thd thread handle
+ column_types a list of items used to define columns of the
+ temporary table
+ is_union_distinct if set, the temporary table will eliminate
+ duplicates on insert
+ options create options
+
+ DESCRIPTION
+ Create a temporary table that is used to store the result of a UNION,
+ derived table, or a materialized cursor.
+
+ RETURN VALUE
+ 0 The table has been created successfully.
+ 1 create_tmp_table failed.
+*/
+
+bool
+select_union::create_result_table(THD *thd, List<Item> *column_types,
+ bool is_union_distinct, ulonglong options,
+ const char *alias)
+{
+ DBUG_ASSERT(table == 0);
+ tmp_table_param.init();
+ tmp_table_param.field_count= column_types->elements;
+
+ if (! (table= create_tmp_table(thd, &tmp_table_param, *column_types,
+ (ORDER*) 0, is_union_distinct, 1,
+ options, HA_POS_ERROR, (char*) alias)))
+ return TRUE;
+ table->file->extra(HA_EXTRA_WRITE_CACHE);
+ table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
+ return FALSE;
+}
+
/*
initialization procedures before fake_select_lex preparation()
@@ -133,11 +159,10 @@ st_select_lex_unit::init_prepare_fake_select_lex(THD *thd)
bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
- ulong additional_options,
- const char *tmp_table_alias)
+ ulong additional_options)
{
SELECT_LEX *lex_select_save= thd_arg->lex->current_select;
- SELECT_LEX *sl, *first_select;
+ SELECT_LEX *sl, *first_sl= first_select();
select_result *tmp_result;
bool is_union;
TABLE *empty_table= 0;
@@ -156,7 +181,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
if (describe)
{
/* fast reinit for EXPLAIN */
- for (sl= first_select_in_union(); sl; sl= sl->next_select())
+ for (sl= first_sl; sl; sl= sl->next_select())
{
sl->join->result= result;
select_limit_cnt= HA_POS_ERROR;
@@ -175,17 +200,16 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
prepared= 1;
res= FALSE;
- thd_arg->lex->current_select= sl= first_select= first_select_in_union();
- found_rows_for_union= first_select->options & OPTION_FOUND_ROWS;
- is_union= test(first_select->next_select());
+ thd_arg->lex->current_select= sl= first_sl;
+ found_rows_for_union= first_sl->options & OPTION_FOUND_ROWS;
+ is_union= test(first_sl->next_select());
/* Global option */
if (is_union)
{
- if (!(tmp_result= union_result= new select_union(0)))
+ if (!(tmp_result= union_result= new select_union))
goto err;
- union_result->tmp_table_param.init();
if (describe)
tmp_result= sel_result;
}
@@ -238,8 +262,8 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
information about fields lengths and exact types
*/
if (!is_union)
- types= first_select_in_union()->item_list;
- else if (sl == first_select)
+ types= first_sl->item_list;
+ else if (sl == first_sl)
{
/*
We need to create an empty table object. It is used
@@ -287,7 +311,6 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
all collations together for UNION.
*/
List_iterator_fast<Item> tp(types);
- Query_arena *arena= thd->stmt_arena;
Item *type;
ulonglong create_options;
@@ -301,7 +324,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
}
}
- create_options= (first_select_in_union()->options | thd_arg->options |
+ create_options= (first_sl->options | thd_arg->options |
TMP_TABLE_ALL_COLUMNS);
/*
Force the temporary table to be a MyISAM table if we're going to use
@@ -312,47 +335,35 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
if (global_parameters->ftfunc_list->elements)
create_options= create_options | TMP_TABLE_FORCE_MYISAM;
- union_result->tmp_table_param.field_count= types.elements;
- if (!(table= create_tmp_table(thd_arg,
- &union_result->tmp_table_param, types,
- (ORDER*) 0, (bool) union_distinct, 1,
- create_options, HA_POS_ERROR,
- (char *) tmp_table_alias)))
+ if (union_result->create_result_table(thd, &types, test(union_distinct),
+ create_options, ""))
goto err;
- table->file->extra(HA_EXTRA_WRITE_CACHE);
- table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
bzero((char*) &result_table_list, sizeof(result_table_list));
result_table_list.db= (char*) "";
result_table_list.table_name= result_table_list.alias= (char*) "union";
- result_table_list.table= table;
- union_result->set_table(table);
+ result_table_list.table= table= union_result->table;
thd_arg->lex->current_select= lex_select_save;
if (!item_list.elements)
{
- Field **field;
- Query_arena *tmp_arena,backup;
- tmp_arena= thd->activate_stmt_arena_if_needed(&backup);
+ Query_arena *arena, backup_arena;
- for (field= table->field; *field; field++)
- {
- Item_field *item= new Item_field(*field);
- if (!item || item_list.push_back(item))
- {
- if (tmp_arena)
- thd->restore_active_arena(tmp_arena, &backup);
- DBUG_RETURN(TRUE);
- }
- }
- if (tmp_arena)
- thd->restore_active_arena(tmp_arena, &backup);
- if (arena->is_stmt_prepare_or_first_sp_execute())
+ arena= thd->activate_stmt_arena_if_needed(&backup_arena);
+
+ res= table->fill_item_list(&item_list);
+
+ if (arena)
+ thd->restore_active_arena(arena, &backup_arena);
+
+ if (res)
+ goto err;
+
+ if (thd->stmt_arena->is_stmt_prepare())
{
- /* prepare fake select to initialize it correctly */
+ /* Validate the global parameters of this union */
+
init_prepare_fake_select_lex(thd);
- /*
- Should be done only once (the only item_list per statement).
- */
+ /* Should be done only once (the only item_list per statement) */
DBUG_ASSERT(fake_select_lex->join == 0);
if (!(fake_select_lex->join= new JOIN(thd, item_list, thd->options,
result)))
@@ -375,19 +386,14 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
fake_select_lex->table_list.empty();
}
}
- else if (!arena->is_conventional())
+ else
{
+ DBUG_ASSERT(!thd->stmt_arena->is_conventional());
/*
We're in execution of a prepared statement or stored procedure:
reset field items to point at fields from the created temporary table.
*/
- List_iterator_fast<Item> it(item_list);
- for (Field **field= table->field; *field; field++)
- {
- Item_field *item_field= (Item_field*) it++;
- DBUG_ASSERT(item_field != 0);
- item_field->reset_field(*field);
- }
+ table->reset_item_list(&item_list);
}
}
@@ -404,7 +410,7 @@ err:
bool st_select_lex_unit::exec()
{
SELECT_LEX *lex_select_save= thd->lex->current_select;
- SELECT_LEX *select_cursor=first_select_in_union();
+ SELECT_LEX *select_cursor=first_select();
ulonglong add_rows=0;
ha_rows examined_rows= 0;
DBUG_ENTER("st_select_lex_unit::exec");
@@ -595,7 +601,7 @@ bool st_select_lex_unit::cleanup()
table= 0; // Safety
}
- for (SELECT_LEX *sl= first_select_in_union(); sl; sl= sl->next_select())
+ for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
error|= sl->cleanup();
if (fake_select_lex)
@@ -652,7 +658,7 @@ bool st_select_lex_unit::change_result(select_subselect *result,
select_subselect *old_result)
{
bool res= FALSE;
- for (SELECT_LEX *sl= first_select_in_union(); sl; sl= sl->next_select())
+ for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
{
if (sl->join && sl->join->result == old_result)
if (sl->join->change_result(result))
@@ -663,6 +669,36 @@ bool st_select_lex_unit::change_result(select_subselect *result,
return (res);
}
+/*
+ Get column type information for this unit.
+
+ SYNOPSIS
+ st_select_lex_unit::get_unit_column_types()
+
+ DESCRIPTION
+ For a single-select the column types are taken
+ from the list of selected items. For a union this function
+ assumes that st_select_lex_unit::prepare has been called
+ and returns the type holders that were created for unioned
+ column types of all selects.
+
+ NOTES
+ The implementation of this function should be in sync with
+ st_select_lex_unit::prepare()
+*/
+
+List<Item> *st_select_lex_unit::get_unit_column_types()
+{
+ bool is_union= test(first_select()->next_select());
+
+ if (is_union)
+ {
+ DBUG_ASSERT(prepared);
+ /* Types are generated during prepare */
+ return &types;
+ }
+ return &first_select()->item_list;
+}
bool st_select_lex::cleanup()
{
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 7e20817c7c7..72a8eef9a55 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -580,11 +580,20 @@ int mysql_update(THD *thd,
query_cache_invalidate3(thd, table_list, 1);
}
- if ((updated || (error < 0)) && (error <= 0 || !transactional_table))
+ /*
+ error < 0 means really no error at all: we processed all rows until the
+ last one without error. error > 0 means an error (e.g. unique key
+ violation and no IGNORE or REPLACE). error == 0 is also an error (if
+ preparing the record or invoking before triggers fails). See
+ ha_autocommit_or_rollback(error>=0) and DBUG_RETURN(error>=0) below.
+ Sometimes we want to binlog even if we updated no rows, in case user used
+ it to be sure master and slave are in same state.
+ */
+ if ((error < 0) || (updated && !transactional_table))
{
if (mysql_bin_log.is_open())
{
- if (error <= 0)
+ if (error < 0)
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
transactional_table, FALSE);
@@ -667,6 +676,7 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
bzero((char*) &tables,sizeof(tables)); // For ORDER BY
tables.table= table;
tables.alias= table_list->alias;
+ thd->allow_sum_func= 0;
if (setup_tables(thd, &select_lex->context, &select_lex->top_join_list,
table_list, conds, &select_lex->leaf_tables,
@@ -1544,16 +1554,14 @@ bool multi_update::send_eof()
/*
Write the SQL statement to the binlog if we updated
rows and we succeeded or if we updated some non
- transacational tables.
- Note that if we updated nothing we don't write to the binlog (TODO:
- fix this).
+ transactional tables.
*/
- if (updated && (local_error <= 0 || !trans_safe))
+ if ((local_error == 0) || (updated && !trans_safe))
{
if (mysql_bin_log.is_open())
{
- if (local_error <= 0)
+ if (local_error == 0)
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
transactional_tables, FALSE);
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index c26f9cc4d71..f956d9d4928 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -214,12 +214,13 @@ bool mysql_create_view(THD *thd,
- same as current user
- current user has SUPER_ACL
*/
- if (strcmp(lex->create_view_definer->user.str, thd->priv_user) != 0 ||
+ if (strcmp(lex->create_view_definer->user.str,
+ thd->security_ctx->priv_user) != 0 ||
my_strcasecmp(system_charset_info,
lex->create_view_definer->host.str,
- thd->priv_host) != 0)
+ thd->security_ctx->priv_host) != 0)
{
- if (!(thd->master_access & SUPER_ACL))
+ if (!(thd->security_ctx->master_access & SUPER_ACL))
{
my_error(ER_VIEW_OTHER_USER, MYF(0), lex->create_view_definer->user.str,
lex->create_view_definer->host.str);
@@ -275,7 +276,8 @@ bool mysql_create_view(THD *thd,
if (check_some_access(thd, VIEW_ANY_ACL, tbl))
{
my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0),
- "ANY", thd->priv_user, thd->host_or_ip, tbl->table_name);
+ "ANY", thd->security_ctx->priv_user,
+ thd->security_ctx->priv_host, tbl->table_name);
res= TRUE;
goto err;
}
@@ -378,7 +380,7 @@ bool mysql_create_view(THD *thd,
/* prepare select to resolve all fields */
lex->view_prepare_mode= 1;
- if (unit->prepare(thd, 0, 0, view->view_name.str))
+ if (unit->prepare(thd, 0, 0))
{
/*
some errors from prepare are reported to user, if is not then
@@ -441,7 +443,8 @@ bool mysql_create_view(THD *thd,
{
/* VIEW column has more privileges */
my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0),
- "create view", thd->priv_user, thd->host_or_ip, item->name,
+ "create view", thd->security_ctx->priv_user,
+ thd->security_ctx->priv_host, item->name,
view->table_name);
res= TRUE;
goto err;
@@ -481,6 +484,8 @@ err:
static const int revision_number_position= 8;
/* index of last required parameter for making view */
static const int required_view_parameters= 10;
+/* number of backups */
+static const int num_view_backups= 3;
/*
table of VIEW .frm field descriptors
@@ -708,7 +713,7 @@ loop_out:
}
if (sql_create_definition_file(&dir, &file, view_file_type,
- (gptr)view, view_parameters, 3))
+ (gptr)view, view_parameters, num_view_backups))
{
DBUG_RETURN(thd->net.report_error? -1 : 1);
}
@@ -786,7 +791,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_VIEW_FRM_NO_USER, ER(ER_VIEW_FRM_NO_USER),
table->db, table->table_name);
- if (default_view_definer(thd, &table->definer))
+ if (default_view_definer(thd->security_ctx, &table->definer))
goto err;
}
@@ -1165,7 +1170,7 @@ frm_type_enum mysql_frm_type(char *path)
int length;
DBUG_ENTER("mysql_frm_type");
- if ((file= my_open(path, O_RDONLY | O_SHARE, MYF(MY_WME))) < 0)
+ if ((file= my_open(path, O_RDONLY | O_SHARE, MYF(0))) < 0)
{
DBUG_RETURN(FRMTYPE_ERROR);
}
@@ -1369,3 +1374,94 @@ int view_checksum(THD *thd, TABLE_LIST *view)
HA_ADMIN_WRONG_CHECKSUM :
HA_ADMIN_OK);
}
+
+/*
+ rename view
+
+ Synopsis:
+ renames a view
+
+ Parameters:
+ thd thread handler
+ new_name new name of view
+ view view
+
+ Return values:
+ FALSE Ok
+ TRUE Error
+*/
+bool
+mysql_rename_view(THD *thd,
+ const char *new_name,
+ TABLE_LIST *view)
+{
+ LEX_STRING pathstr, file;
+ File_parser *parser;
+ char view_path[FN_REFLEN];
+ bool error= TRUE;
+
+ DBUG_ENTER("mysql_rename_view");
+
+ strxnmov(view_path, FN_REFLEN, mysql_data_home, "/", view->db, "/",
+ view->table_name, reg_ext, NullS);
+ (void) unpack_filename(view_path, view_path);
+
+ pathstr.str= (char *)view_path;
+ pathstr.length= strlen(view_path);
+
+ if ((parser= sql_parse_prepare(&pathstr, thd->mem_root, 1)) &&
+ is_equal(&view_type, parser->type()))
+ {
+ TABLE_LIST view_def;
+ char dir_buff[FN_REFLEN], file_buff[FN_REFLEN];
+
+ /*
+ To be PS-friendly we should either to restore state of
+ TABLE_LIST object pointed by 'view' after using it for
+ view definition parsing or use temporary 'view_def'
+ object for it.
+ */
+ bzero(&view_def, sizeof(view_def));
+ view_def.timestamp.str= view_def.timestamp_buffer;
+ view_def.view_suid= TRUE;
+
+ /* get view definition and source */
+ if (parser->parse((gptr)&view_def, thd->mem_root, view_parameters,
+ sizeof(view_parameters)/sizeof(view_parameters[0])-1))
+ goto err;
+
+ /* rename view and it's backups */
+ if (rename_in_schema_file(view->db, view->table_name, new_name,
+ view_def.revision - 1, num_view_backups))
+ goto err;
+
+ strxnmov(dir_buff, FN_REFLEN, mysql_data_home, "/", view->db, "/", NullS);
+ (void) unpack_filename(dir_buff, dir_buff);
+
+ pathstr.str= (char*)dir_buff;
+ pathstr.length= strlen(dir_buff);
+
+ file.str= file_buff;
+ file.length= (strxnmov(file_buff, FN_REFLEN, new_name, reg_ext, NullS)
+ - file_buff);
+
+ if (sql_create_definition_file(&pathstr, &file, view_file_type,
+ (gptr)&view_def, view_parameters,
+ num_view_backups))
+ {
+ /* restore renamed view in case of error */
+ rename_in_schema_file(view->db, new_name, view->table_name,
+ view_def.revision - 1, num_view_backups);
+ goto err;
+ }
+ } else
+ DBUG_RETURN(1);
+
+ /* remove cache entries */
+ query_cache_invalidate3(thd, view, 0);
+ sp_cache_invalidate();
+ error= FALSE;
+
+err:
+ DBUG_RETURN(error);
+}
diff --git a/sql/sql_view.h b/sql/sql_view.h
index 9d961feb143..4cc9eb454fb 100644
--- a/sql/sql_view.h
+++ b/sql/sql_view.h
@@ -34,6 +34,7 @@ int view_checksum(THD *thd, TABLE_LIST *view);
extern TYPELIB updatable_views_with_limit_typelib;
bool check_duplicate_names(List<Item>& item_list, bool gen_unique_view_names);
+bool mysql_rename_view(THD *thd, const char *new_name, TABLE_LIST *view);
#define VIEW_ANY_ACL (SELECT_ACL | UPDATE_ACL | INSERT_ACL | DELETE_ACL)
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 49c385dd1be..77c1a37e16e 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -5370,27 +5370,48 @@ simple_expr:
$$= new Item_func_sp(Lex->current_context(), name);
lex->safe_to_cache_query=0;
}
- | IDENT_sys '(' udf_expr_list ')'
+ | IDENT_sys '('
{
#ifdef HAVE_DLOPEN
- udf_func *udf;
+ udf_func *udf= 0;
+ if (using_udf_functions &&
+ (udf= find_udf($1.str, $1.length)) &&
+ udf->type == UDFTYPE_AGGREGATE)
+ {
+ LEX *lex= Lex;
+ if (lex->current_select->inc_in_sum_expr())
+ {
+ yyerror(ER(ER_SYNTAX_ERROR));
+ YYABORT;
+ }
+ }
+ $<udf>$= udf;
+#endif
+ }
+ udf_expr_list ')'
+ {
+#ifdef HAVE_DLOPEN
+ udf_func *udf= $<udf>3;
SELECT_LEX *sel= Select;
- if (using_udf_functions && (udf=find_udf($1.str, $1.length)))
+ if (udf)
{
+ if (udf->type == UDFTYPE_AGGREGATE)
+ Select->in_sum_expr--;
+
switch (udf->returns) {
case STRING_RESULT:
if (udf->type == UDFTYPE_FUNCTION)
{
- if ($3 != NULL)
- $$ = new Item_func_udf_str(udf, *$3);
+ if ($4 != NULL)
+ $$ = new Item_func_udf_str(udf, *$4);
else
$$ = new Item_func_udf_str(udf);
}
else
{
- if ($3 != NULL)
- $$ = new Item_sum_udf_str(udf, *$3);
+ if ($4 != NULL)
+ $$ = new Item_sum_udf_str(udf, *$4);
else
$$ = new Item_sum_udf_str(udf);
}
@@ -5398,15 +5419,15 @@ simple_expr:
case REAL_RESULT:
if (udf->type == UDFTYPE_FUNCTION)
{
- if ($3 != NULL)
- $$ = new Item_func_udf_float(udf, *$3);
+ if ($4 != NULL)
+ $$ = new Item_func_udf_float(udf, *$4);
else
$$ = new Item_func_udf_float(udf);
}
else
{
- if ($3 != NULL)
- $$ = new Item_sum_udf_float(udf, *$3);
+ if ($4 != NULL)
+ $$ = new Item_sum_udf_float(udf, *$4);
else
$$ = new Item_sum_udf_float(udf);
}
@@ -5414,15 +5435,15 @@ simple_expr:
case INT_RESULT:
if (udf->type == UDFTYPE_FUNCTION)
{
- if ($3 != NULL)
- $$ = new Item_func_udf_int(udf, *$3);
+ if ($4 != NULL)
+ $$ = new Item_func_udf_int(udf, *$4);
else
$$ = new Item_func_udf_int(udf);
}
else
{
- if ($3 != NULL)
- $$ = new Item_sum_udf_int(udf, *$3);
+ if ($4 != NULL)
+ $$ = new Item_sum_udf_int(udf, *$4);
else
$$ = new Item_sum_udf_int(udf);
}
@@ -5430,15 +5451,15 @@ simple_expr:
case DECIMAL_RESULT:
if (udf->type == UDFTYPE_FUNCTION)
{
- if ($3 != NULL)
- $$ = new Item_func_udf_decimal(udf, *$3);
+ if ($4 != NULL)
+ $$ = new Item_func_udf_decimal(udf, *$4);
else
$$ = new Item_func_udf_decimal(udf);
}
else
{
- if ($3 != NULL)
- $$ = new Item_sum_udf_decimal(udf, *$3);
+ if ($4 != NULL)
+ $$ = new Item_sum_udf_decimal(udf, *$4);
else
$$ = new Item_sum_udf_decimal(udf);
}
@@ -5454,8 +5475,8 @@ simple_expr:
sp_name *name= sp_name_current_db_new(YYTHD, $1);
sp_add_used_routine(lex, YYTHD, name, TYPE_ENUM_FUNCTION);
- if ($3)
- $$= new Item_func_sp(Lex->current_context(), name, *$3);
+ if ($4)
+ $$= new Item_func_sp(Lex->current_context(), name, *$4);
else
$$= new Item_func_sp(Lex->current_context(), name);
lex->safe_to_cache_query=0;
@@ -7145,15 +7166,16 @@ show_param:
LEX *lex=Lex;
lex->sql_command= SQLCOM_SHOW_GRANTS;
THD *thd= lex->thd;
+ Security_context *sctx= thd->security_ctx;
LEX_USER *curr_user;
if (!(curr_user= (LEX_USER*) thd->alloc(sizeof(st_lex_user))))
YYABORT;
- curr_user->user.str= thd->priv_user;
- curr_user->user.length= strlen(thd->priv_user);
- if (*thd->priv_host != 0)
+ curr_user->user.str= sctx->priv_user;
+ curr_user->user.length= strlen(sctx->priv_user);
+ if (*sctx->priv_host != 0)
{
- curr_user->host.str= thd->priv_host;
- curr_user->host.length= strlen(thd->priv_host);
+ curr_user->host.str= sctx->priv_host;
+ curr_user->host.length= strlen(sctx->priv_host);
}
else
{
@@ -7239,6 +7261,9 @@ show_engine_param:
STATUS_SYM
{
switch (Lex->create_info.db_type) {
+ case DB_TYPE_NDBCLUSTER:
+ Lex->sql_command = SQLCOM_SHOW_NDBCLUSTER_STATUS;
+ break;
case DB_TYPE_INNODB:
Lex->sql_command = SQLCOM_SHOW_INNODB_STATUS;
break;
@@ -8054,14 +8079,15 @@ user:
| CURRENT_USER optional_braces
{
THD *thd= YYTHD;
+ Security_context *sctx= thd->security_ctx;
if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
YYABORT;
- $$->user.str= thd->priv_user;
- $$->user.length= strlen(thd->priv_user);
- if (*thd->priv_host != 0)
+ $$->user.str= sctx->priv_user;
+ $$->user.length= strlen(sctx->priv_user);
+ if (*sctx->priv_host != 0)
{
- $$->host.str= thd->priv_host;
- $$->host.length= strlen(thd->priv_host);
+ $$->host.str= sctx->priv_host;
+ $$->host.length= strlen(sctx->priv_host);
}
else
{
@@ -8588,7 +8614,7 @@ option_value:
if (!(user=(LEX_USER*) thd->alloc(sizeof(LEX_USER))))
YYABORT;
user->host=null_lex_str;
- user->user.str=thd->priv_user;
+ user->user.str=thd->security_ctx->priv_user;
thd->lex->var_list.push_back(new set_var_password(user, $3));
}
| PASSWORD FOR_SYM user equal text_or_password
@@ -9521,7 +9547,8 @@ view_user:
if (!(thd->lex->create_view_definer=
(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
YYABORT;
- if (default_view_definer(thd, thd->lex->create_view_definer))
+ if (default_view_definer(thd->security_ctx,
+ thd->lex->create_view_definer))
YYABORT;
}
| CURRENT_USER optional_braces
@@ -9530,7 +9557,8 @@ view_user:
if (!(thd->lex->create_view_definer=
(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
YYABORT;
- if (default_view_definer(thd, thd->lex->create_view_definer))
+ if (default_view_definer(thd->security_ctx,
+ thd->lex->create_view_definer))
YYABORT;
}
| DEFINER_SYM EQ ident_or_text '@' ident_or_text
diff --git a/sql/table.cc b/sql/table.cc
index 9d91cb51ee1..d3f7d2b3b9f 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -290,8 +290,6 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
keynames=(char*) key_part;
strpos+= (strmov(keynames, (char *) strpos) - keynames)+1;
- share->null_bytes= null_pos - (uchar*) outparam->null_flags + (null_bit_pos + 7) / 8;
-
share->reclength = uint2korr((head+16));
if (*(head+26) == 1)
share->system= 1; /* one-record-database */
@@ -351,7 +349,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
char *buff;
if (!(buff= alloc_root(&outparam->mem_root, n_length)))
goto err;
- if (my_pread(file, buff, n_length, record_offset + share->reclength,
+ if (my_pread(file, (byte*)buff, n_length, record_offset + share->reclength,
MYF(MY_NABP)))
goto err;
share->connect_string.length= uint2korr(buff);
@@ -473,6 +471,9 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
{
outparam->null_flags=null_pos=(uchar*) record+1;
null_bit_pos= (db_create_options & HA_OPTION_PACK_RECORD) ? 0 : 1;
+ /* null_bytes below is only correct under the condition that
+ there are no bit fields. Correct values is set below after the
+ table struct is initialized */
share->null_bytes= (share->null_fields + null_bit_pos + 7) / 8;
}
else
@@ -885,6 +886,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
(*save++)= i;
}
}
+
if (outparam->file->ha_allocate_read_write_set(share->fields))
goto err;
@@ -895,6 +897,10 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
#endif
goto err;
+ /* the correct null_bytes can now be set, since bitfields have been taken into account */
+ share->null_bytes= null_pos - (uchar*) outparam->null_flags + (null_bit_pos + 7) / 8;
+ share->last_null_bit_pos= null_bit_pos;
+
/* The table struct is now initialized; Open the table */
error=2;
if (db_stat)
@@ -1725,6 +1731,63 @@ db_type get_table_type(THD *thd, const char *name)
DBUG_RETURN(ha_checktype(thd,(enum db_type) (uint) *(head+3),0,0));
}
+/*
+ Create Item_field for each column in the table.
+
+ SYNPOSIS
+ st_table::fill_item_list()
+ item_list a pointer to an empty list used to store items
+
+ DESCRIPTION
+ Create Item_field object for each column in the table and
+ initialize it with the corresponding Field. New items are
+ created in the current THD memory root.
+
+ RETURN VALUE
+ 0 success
+ 1 out of memory
+*/
+
+bool st_table::fill_item_list(List<Item> *item_list) const
+{
+ /*
+ All Item_field's created using a direct pointer to a field
+ are fixed in Item_field constructor.
+ */
+ for (Field **ptr= field; *ptr; ptr++)
+ {
+ Item_field *item= new Item_field(*ptr);
+ if (!item || item_list->push_back(item))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ Reset an existing list of Item_field items to point to the
+ Fields of this table.
+
+ SYNPOSIS
+ st_table::fill_item_list()
+ item_list a non-empty list with Item_fields
+
+ DESCRIPTION
+ This is a counterpart of fill_item_list used to redirect
+ Item_fields to the fields of a newly created table.
+ The caller must ensure that number of items in the item_list
+ is the same as the number of columns in the table.
+*/
+
+void st_table::reset_item_list(List<Item> *item_list) const
+{
+ List_iterator_fast<Item> it(*item_list);
+ for (Field **ptr= field; *ptr; ptr++)
+ {
+ Item_field *item_field= (Item_field*) it++;
+ DBUG_ASSERT(item_field != 0);
+ item_field->reset_field(*ptr);
+ }
+}
/*
calculate md5 of query
@@ -2268,8 +2331,10 @@ TABLE_LIST *st_table_list::first_leaf_for_name_resolution()
List_iterator_fast<TABLE_LIST> it(cur_nested_join->join_list);
cur_table_ref= it++;
/*
- If 'this' is a RIGHT JOIN, the operands in 'join_list' are in reverse
- order, thus the first operand is already at the front of the list.
+ If the current nested join is a RIGHT JOIN, the operands in
+ 'join_list' are in reverse order, thus the first operand is
+ already at the front of the list. Otherwise the first operand
+ is in the end of the list of join operands.
*/
if (!(cur_table_ref->outer_join & JOIN_TYPE_RIGHT))
{
@@ -2320,9 +2385,11 @@ TABLE_LIST *st_table_list::last_leaf_for_name_resolution()
cur_nested_join;
cur_nested_join= cur_table_ref->nested_join)
{
+ cur_table_ref= cur_nested_join->join_list.head();
/*
- If 'this' is a RIGHT JOIN, the operands in 'join_list' are in reverse
- order, thus the last operand is in the end of the list.
+ If the current nested is a RIGHT JOIN, the operands in
+ 'join_list' are in reverse order, thus the last operand is in the
+ end of the list.
*/
if ((cur_table_ref->outer_join & JOIN_TYPE_RIGHT))
{
@@ -2332,8 +2399,6 @@ TABLE_LIST *st_table_list::last_leaf_for_name_resolution()
while ((next= it++))
cur_table_ref= next;
}
- else
- cur_table_ref= cur_nested_join->join_list.head();
if (cur_table_ref->is_leaf_for_name_resolution())
break;
}
@@ -2401,22 +2466,6 @@ Field *Natural_join_column::field()
const char *Natural_join_column::table_name()
{
return table_ref->alias;
- /*
- TODO:
- I think that it is sufficient to return just
- table->alias, which is correctly set to either
- the view name, the table name, or the alias to
- the table reference (view or stored table).
- */
-#ifdef NOT_YET
- if (view_field)
- return table_ref->view_name.str;
-
- DBUG_ASSERT(!strcmp(table_ref->table_name,
- table_ref->table->s->table_name));
- return table_ref->table_name;
-}
-#endif
}
@@ -2552,7 +2601,7 @@ Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref,
DBUG_RETURN(field);
}
Item *item= new Item_direct_view_ref(&view->view->select_lex.context,
- field_ref, view->view_name.str,
+ field_ref, view->alias,
name);
DBUG_RETURN(item);
}
diff --git a/sql/table.h b/sql/table.h
index f3f1444a797..c1de61ef273 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -145,7 +145,7 @@ typedef struct st_table_share
enum tmp_table_type tmp_table;
uint blob_ptr_size; /* 4 or 8 */
- uint null_bytes;
+ uint null_bytes, last_null_bit_pos;
uint key_length; /* Length of table_cache_key */
uint fields; /* Number of fields */
uint rec_buff_length; /* Size of table->record[] buffer */
@@ -274,6 +274,9 @@ struct st_table {
GRANT_INFO grant;
FILESORT_INFO sort;
TABLE_SHARE share_not_to_be_used; /* To be deleted when true shares */
+
+ bool fill_item_list(List<Item> *item_list) const;
+ void reset_item_list(List<Item> *item_list) const;
};
diff --git a/sql/unireg.cc b/sql/unireg.cc
index 0279f224940..592093350f1 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -167,8 +167,8 @@ bool mysql_create_frm(THD *thd, my_string file_name,
{
char buff[2];
int2store(buff,create_info->connect_string.length);
- if (my_write(file, buff, sizeof(buff), MYF(MY_NABP)) ||
- my_write(file, create_info->connect_string.str,
+ if (my_write(file, (const byte*)buff, sizeof(buff), MYF(MY_NABP)) ||
+ my_write(file, (const byte*)create_info->connect_string.str,
create_info->connect_string.length, MYF(MY_NABP)))
goto err;
}