diff options
| -rw-r--r-- | CMakeLists.txt | 8 | ||||
| -rw-r--r-- | Makefile.am | 3 | ||||
| -rw-r--r-- | configure.ac | 68 | ||||
| -rw-r--r-- | m4/ac_mysql.m4 | 96 | ||||
| -rw-r--r-- | src/Makefile.am | 8 | ||||
| -rw-r--r-- | table_sizes.cc (renamed from src/table_sizes.cc) | 345 |
6 files changed, 115 insertions, 413 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index e468c80..7392af9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
| @@ -1,5 +1,9 @@ | |||
| 1 | INCLUDE_DIRECTORIES(SYSTEM ${BOOST_PATCHES_DIR} ${BOOST_INCLUDE_DIR}) | 1 | INCLUDE_DIRECTORIES(SYSTEM ${BOOST_PATCHES_DIR} ${BOOST_INCLUDE_DIR}) |
| 2 | 2 | ||
| 3 | MYSQL_ADD_PLUGIN(table_sizes src/table_sizes.cc | 3 | MYSQL_ADD_PLUGIN(table_sizes |
| 4 | MODULE_ONLY MODULE_OUTPUT_NAME "table_sizes") | 4 | table_sizes.cc |
| 5 | MODULE_ONLY MODULE_OUTPUT_NAME "table_sizes" | ||
| 6 | LINK_LIBRARIES extra::rapidjson | ||
| 7 | ) | ||
| 5 | 8 | ||
| 9 | ADD_DEFINITIONS(-DMYSQL_SERVER) | ||
diff --git a/Makefile.am b/Makefile.am deleted file mode 100644 index 3cb8f22..0000000 --- a/Makefile.am +++ /dev/null | |||
| @@ -1,3 +0,0 @@ | |||
| 1 | AUTOMAKE_OPTIONS = foreign no-dependencies | ||
| 2 | ACLOCAL_AMFLAGS = -I m4 | ||
| 3 | SUBDIRS = src | ||
diff --git a/configure.ac b/configure.ac deleted file mode 100644 index 48857f8..0000000 --- a/configure.ac +++ /dev/null | |||
| @@ -1,68 +0,0 @@ | |||
| 1 | # Process this file with autoconf to produce a configure script. | ||
| 2 | |||
| 3 | AC_PREREQ(2.59) | ||
| 4 | AC_INIT(mysql-table-sizes-plugin, [dev]) | ||
| 5 | AC_CANONICAL_TARGET | ||
| 6 | AC_CONFIG_MACRO_DIR([m4]) | ||
| 7 | |||
| 8 | AM_INIT_AUTOMAKE | ||
| 9 | |||
| 10 | AC_CONFIG_SRCDIR([src/table_sizes.cc]) | ||
| 11 | AC_CONFIG_HEADER([src/config.h]) | ||
| 12 | |||
| 13 | AC_DEFUN([CHECK_DEBUG], [ | ||
| 14 | AC_ARG_ENABLE([debug], | ||
| 15 | AS_HELP_STRING([--enable-debug], [turn on debugging, default: no])) | ||
| 16 | |||
| 17 | AC_MSG_CHECKING(whether to enable debugging) | ||
| 18 | AS_IF([test "x$enable_debug" = "xyes"], | ||
| 19 | [ | ||
| 20 | CPPFLAGS="$CPPFLAGS -g -D_DEBUG" | ||
| 21 | AC_MSG_RESULT(yes) | ||
| 22 | ], | ||
| 23 | [ | ||
| 24 | CPPFLAGS="$CPPFLAGS -g -O2 -DDBUG_OFF" | ||
| 25 | AC_MSG_RESULT(no) | ||
| 26 | ] | ||
| 27 | ) | ||
| 28 | ]) | ||
| 29 | |||
| 30 | |||
| 31 | dnl Run tests using C++ compiler | ||
| 32 | dnl AC_LANG(C++) | ||
| 33 | |||
| 34 | CHECK_DEBUG | ||
| 35 | |||
| 36 | #check for mysql src | ||
| 37 | MYSQL_SRC_TEST | ||
| 38 | MYSQL_PLUGIN_DIR_TEST | ||
| 39 | #MYSQL_LIB_SERVICES_TEST | ||
| 40 | AC_SUBST(MYSQL_INC) | ||
| 41 | AC_SUBST(MYSQL_PLUGIN_DIR) | ||
| 42 | #AC_SUBST(MYSQL_LIBSERVICES) | ||
| 43 | |||
| 44 | #check for programs | ||
| 45 | AC_PROG_CC | ||
| 46 | AC_PROG_LIBTOOL | ||
| 47 | AC_PROG_CXX | ||
| 48 | AC_PROG_CPP | ||
| 49 | |||
| 50 | #we can add the following flags for better error catching: -Werror | ||
| 51 | CPPFLAGS="$CPPFLAGS -Werror" | ||
| 52 | # From MySQL: Disable exceptions as they seams to create problems with gcc and threads. | ||
| 53 | CXXFLAGS="$CXXFLAGS -fno-exceptions -fno-rtti" | ||
| 54 | |||
| 55 | #make sure we have const | ||
| 56 | AC_C_CONST | ||
| 57 | AC_TYPE_SIZE_T | ||
| 58 | |||
| 59 | #subst the relevant variables | ||
| 60 | AC_SUBST(CPPFLAGS) | ||
| 61 | AC_SUBST(CXXLAGS) | ||
| 62 | AC_SUBST(CFLAGS) | ||
| 63 | |||
| 64 | AC_CONFIG_FILES([ | ||
| 65 | Makefile | ||
| 66 | src/Makefile | ||
| 67 | ]) | ||
| 68 | AC_OUTPUT | ||
diff --git a/m4/ac_mysql.m4 b/m4/ac_mysql.m4 deleted file mode 100644 index b5a5c0c..0000000 --- a/m4/ac_mysql.m4 +++ /dev/null | |||
| @@ -1,96 +0,0 @@ | |||
| 1 | dnl --------------------------------------------------------------------------- | ||
| 2 | dnl Macro: MYSQL_SRC_TEST | ||
| 3 | dnl --------------------------------------------------------------------------- | ||
| 4 | |||
| 5 | dir_resolve() dnl {{{ | ||
| 6 | { | ||
| 7 | pwd=`pwd` | ||
| 8 | cd "$1" 2>/dev/null || cd "${pwd}/${1}" 2>/dev/null | ||
| 9 | if test "$?" = "0" | ||
| 10 | then | ||
| 11 | echo `pwd -P` | ||
| 12 | else | ||
| 13 | echo "$1" | ||
| 14 | fi | ||
| 15 | } | ||
| 16 | dnl }}} | ||
| 17 | |||
| 18 | AC_DEFUN([MYSQL_SRC_TEST], [ | ||
| 19 | AC_MSG_CHECKING(for mysql source code) | ||
| 20 | AC_ARG_WITH(mysql, | ||
| 21 | [AS_HELP_STRING([--with-mysql=PATH], [MySQL src directory required to build.])], | ||
| 22 | [ | ||
| 23 | ac_mysql_source_dir=`readlink -e "$withval"` | ||
| 24 | HEADERS="include/my_dir.h include/mysql/plugin.h include/mysql.h include/mysql_version.h include/config.h include/my_config.h" | ||
| 25 | for file in $HEADERS | ||
| 26 | do | ||
| 27 | if ! test -r "$ac_mysql_source_dir/$file" | ||
| 28 | then | ||
| 29 | AC_MSG_ERROR([Failed to find required header file $ac_mysql_source_dir/$file, check the path and make sure you've run './configure ..<options>.. && cd include && make' in MySQL 5.1 sources dir or 'cmake . && make' in MySQL 5.5 sources dir.]) | ||
| 30 | fi | ||
| 31 | done | ||
| 32 | AC_DEFINE([MYSQL_SRC], [1], [Source directory for MySQL]) | ||
| 33 | MYSQL_INC="-I$ac_mysql_source_dir/sql -I$ac_mysql_source_dir/include -I$ac_mysql_source_dir/regex -I$ac_mysql_source_dir -I$ac_mysql_source_dir/libbinlogevents/export -I$ac_mysql_source_dir/libbinlogevents/include -I$ac_mysql_source_dir/sql/auth" | ||
| 34 | AC_MSG_RESULT(["$ac_mysql_source_dir"]) | ||
| 35 | ], | ||
| 36 | [ | ||
| 37 | AC_MSG_ERROR(["No mysql source provided. Please specify --with-mysql=<mysql source dir>!"]) | ||
| 38 | ] | ||
| 39 | ) | ||
| 40 | ]) | ||
| 41 | |||
| 42 | dnl --------------------------------------------------------------------------- | ||
| 43 | dnl Macro: MYSQL_PLUGIN_DIR_TEST | ||
| 44 | dnl --------------------------------------------------------------------------- | ||
| 45 | |||
| 46 | AC_DEFUN([MYSQL_PLUGIN_DIR_TEST], [ | ||
| 47 | AC_MSG_CHECKING([for mysql plugin dir]) | ||
| 48 | ac_mysql_plugin_dir= | ||
| 49 | AC_ARG_WITH([mysql-plugindir], | ||
| 50 | [AS_HELP_STRING([--with-mysql-plugindir=PATH], [MySQL plugin directory where plugin is to be copied to])], | ||
| 51 | [ | ||
| 52 | ac_mysql_plugin_dir=`readlink -m "$withval"` | ||
| 53 | MYSQL_PLUGIN_DIR="$ac_mysql_plugin_dir" | ||
| 54 | ], | ||
| 55 | [ | ||
| 56 | ac_mysql_plugin_dir="/usr/lib/mysql/plugin" | ||
| 57 | MYSQL_PLUGIN_DIR="$ac_mysql_plugin_dir" | ||
| 58 | AC_MSG_RESULT([--with-mysql-plugindir was not set. Using $ac_mysql_plugin_dir]) | ||
| 59 | ] | ||
| 60 | ) | ||
| 61 | ]) | ||
| 62 | |||
| 63 | dnl --------------------------------------------------------------------------- | ||
| 64 | dnl Macro: MYSQL_LIB_SERVICES : 5.5 services lib to add to linker | ||
| 65 | dnl --------------------------------------------------------------------------- | ||
| 66 | |||
| 67 | dnl AC_DEFUN([MYSQL_LIB_SERVICES_TEST], [ | ||
| 68 | dnl AC_MSG_CHECKING([for mysql libmysqlservices]) | ||
| 69 | dnl ac_mysql_libservices= | ||
| 70 | dnl AC_ARG_WITH([mysql-libservices], | ||
| 71 | dnl [AS_HELP_STRING([--with-mysql-libservices=PATH], [MySQL libmysqlservices.a location (relevant for 5.5 only)])], | ||
| 72 | dnl [ | ||
| 73 | dnl ac_mysql_libservices=`readlink -e "$withval"` | ||
| 74 | dnl if test -f "$ac_mysql_libservices" | ||
| 75 | dnl then | ||
| 76 | dnl MYSQL_LIBSERVICES="$ac_mysql_libservices" | ||
| 77 | dnl AC_MSG_RESULT([yes: Using $ac_mysql_libservices]) | ||
| 78 | dnl else | ||
| 79 | dnl AC_MSG_ERROR([invalid MySQL libmysqlservices : $ac_mysql_libservices]) | ||
| 80 | dnl fi | ||
| 81 | dnl ], | ||
| 82 | dnl [ | ||
| 83 | dnl if test -f "$ac_mysql_source_dir/VERSION" | ||
| 84 | dnl then | ||
| 85 | dnl source "$ac_mysql_source_dir/VERSION" | ||
| 86 | dnl if test "$MYSQL_VERSION_MAJOR.$MYSQL_VERSION_MINOR" = "5.5" | ||
| 87 | dnl then | ||
| 88 | dnl AC_MSG_ERROR([no mysql-libservices. Required for MySQL 5.5]) | ||
| 89 | dnl fi | ||
| 90 | dnl fi | ||
| 91 | dnl ac_mysql_libservices="" | ||
| 92 | dnl MYSQL_LIBSERVICES="$ac_mysql_libservices" | ||
| 93 | dnl AC_MSG_RESULT([--with-mysql-libservices was not set.]) | ||
| 94 | dnl ] | ||
| 95 | dnl ) | ||
| 96 | dnl ]) | ||
diff --git a/src/Makefile.am b/src/Makefile.am deleted file mode 100644 index 7965ee4..0000000 --- a/src/Makefile.am +++ /dev/null | |||
| @@ -1,8 +0,0 @@ | |||
| 1 | INCLUDES = $(MYSQL_INC) $(DEPS_CFLAGS) | ||
| 2 | |||
| 3 | pkgplugindir = $(MYSQL_PLUGIN_DIR) | ||
| 4 | |||
| 5 | pkgplugin_LTLIBRARIES = table_sizes.la | ||
| 6 | table_sizes_la_SOURCES = table_sizes.cc | ||
| 7 | table_sizes_la_LIBADD = $(DEPS_LIBS) | ||
| 8 | table_sizes_la_LDFLAGS = -module | ||
diff --git a/src/table_sizes.cc b/table_sizes.cc index 40d5090..ec8efc0 100644 --- a/src/table_sizes.cc +++ b/table_sizes.cc | |||
| @@ -18,10 +18,9 @@ | |||
| 18 | 18 | ||
| 19 | #include "sql/mysqld.h" | 19 | #include "sql/mysqld.h" |
| 20 | #include "sql/sql_base.h" | 20 | #include "sql/sql_base.h" |
| 21 | #include "sql/sql_show.h" | ||
| 22 | #include "sql/sql_class.h" // THD | 21 | #include "sql/sql_class.h" // THD |
| 23 | #include "sql/sql_table.h" // filename_to_tablename | 22 | #include "sql/sql_table.h" // filename_to_tablename |
| 24 | #include "sql/strfunc.h" // make_lex_string_root | 23 | #include "sql/strfunc.h" // casedn |
| 25 | #include "sql/sql_parse.h" // sql_command_flags | 24 | #include "sql/sql_parse.h" // sql_command_flags |
| 26 | #include "sql/sql_lex.h" // LEX | 25 | #include "sql/sql_lex.h" // LEX |
| 27 | #include "sql/item_func.h" // Item_Func | 26 | #include "sql/item_func.h" // Item_Func |
| @@ -156,25 +155,13 @@ struct LOOKUP_FIELD_VALUES { | |||
| 156 | /** | 155 | /** |
| 157 | Value of a TABLE_SCHEMA clause. | 156 | Value of a TABLE_SCHEMA clause. |
| 158 | Note that this value length may exceed @c NAME_LEN. | 157 | Note that this value length may exceed @c NAME_LEN. |
| 159 | @sa wild_db_value | ||
| 160 | */ | 158 | */ |
| 161 | boost::optional<dd::String_type> db_value; | 159 | boost::optional<dd::String_type> db_value; |
| 162 | /** | 160 | /** |
| 163 | Value of a TABLE_NAME clause. | 161 | Value of a TABLE_NAME clause. |
| 164 | Note that this value length may exceed @c NAME_LEN. | 162 | Note that this value length may exceed @c NAME_LEN. |
| 165 | @sa wild_table_value | ||
| 166 | */ | 163 | */ |
| 167 | boost::optional<dd::String_type> table_value; | 164 | boost::optional<dd::String_type> table_value; |
| 168 | /** | ||
| 169 | True when @c db_value is a LIKE clause, | ||
| 170 | false when @c db_value is an '=' clause. | ||
| 171 | */ | ||
| 172 | bool wild_db_value = {false}; | ||
| 173 | /** | ||
| 174 | True when @c table_value is a LIKE clause, | ||
| 175 | false when @c table_value is an '=' clause. | ||
| 176 | */ | ||
| 177 | bool wild_table_value = {false}; | ||
| 178 | }; | 165 | }; |
| 179 | 166 | ||
| 180 | /** | 167 | /** |
| @@ -195,19 +182,11 @@ struct LOOKUP_FIELD_VALUES { | |||
| 195 | 1 error, there can be no matching records for the condition | 182 | 1 error, there can be no matching records for the condition |
| 196 | */ | 183 | */ |
| 197 | 184 | ||
| 198 | static bool get_lookup_value(Item_func *item_func, TABLE_LIST *table, | 185 | static bool get_lookup_value(Item_func *item_func, Table_ref *table, |
| 199 | LOOKUP_FIELD_VALUES *lookup_field_vals) | 186 | LOOKUP_FIELD_VALUES *lookup_field_vals) |
| 200 | { | 187 | { |
| 201 | ST_SCHEMA_TABLE *schema_table = table->schema_table; | 188 | ST_SCHEMA_TABLE *schema_table = table->schema_table; |
| 202 | ST_FIELD_INFO *field_info = schema_table->fields_info; | 189 | ST_FIELD_INFO *field_info = schema_table->fields_info; |
| 203 | const char *field_name1 = | ||
| 204 | schema_table->idx_field1 >= 0 | ||
| 205 | ? field_info[schema_table->idx_field1].field_name | ||
| 206 | : ""; | ||
| 207 | const char *field_name2 = | ||
| 208 | schema_table->idx_field2 >= 0 | ||
| 209 | ? field_info[schema_table->idx_field2].field_name | ||
| 210 | : ""; | ||
| 211 | 190 | ||
| 212 | if (item_func->functype() == Item_func::EQ_FUNC || | 191 | if (item_func->functype() == Item_func::EQ_FUNC || |
| 213 | item_func->functype() == Item_func::EQUAL_FUNC) { | 192 | item_func->functype() == Item_func::EQUAL_FUNC) { |
| @@ -236,15 +215,16 @@ static bool get_lookup_value(Item_func *item_func, TABLE_LIST *table, | |||
| 236 | if (!tmp_str) return 1; | 215 | if (!tmp_str) return 1; |
| 237 | 216 | ||
| 238 | /* Lookup value is database name */ | 217 | /* Lookup value is database name */ |
| 239 | if (!cs->coll->strnncollsp(cs, (uchar *)field_name1, strlen(field_name1), | 218 | if (!cs->coll->strnncollsp(cs, (const uchar *)field_info[0].field_name, |
| 240 | (uchar *)item_field->field_name, | 219 | strlen(field_info[0].field_name), |
| 220 | (const uchar *)item_field->field_name, | ||
| 241 | strlen(item_field->field_name))) { | 221 | strlen(item_field->field_name))) { |
| 242 | lookup_field_vals->db_value.emplace(tmp_str->ptr(), tmp_str->length()); | 222 | lookup_field_vals->db_value.emplace(tmp_str->ptr(), tmp_str->length()); |
| 243 | } | 223 | } |
| 244 | /* Lookup value is table name */ | 224 | /* Lookup value is table name */ |
| 245 | else if (!cs->coll->strnncollsp(cs, (uchar *)field_name2, | 225 | else if (!cs->coll->strnncollsp(cs, (const uchar *)field_info[1].field_name, |
| 246 | strlen(field_name2), | 226 | strlen(field_info[1].field_name), |
| 247 | (uchar *)item_field->field_name, | 227 | (const uchar *)item_field->field_name, |
| 248 | strlen(item_field->field_name))) { | 228 | strlen(item_field->field_name))) { |
| 249 | lookup_field_vals->table_value.emplace(tmp_str->ptr(), tmp_str->length()); | 229 | lookup_field_vals->table_value.emplace(tmp_str->ptr(), tmp_str->length()); |
| 250 | } | 230 | } |
| @@ -270,7 +250,7 @@ static bool get_lookup_value(Item_func *item_func, TABLE_LIST *table, | |||
| 270 | */ | 250 | */ |
| 271 | 251 | ||
| 272 | static bool calc_lookup_values_from_cond(Item *cond, | 252 | static bool calc_lookup_values_from_cond(Item *cond, |
| 273 | TABLE_LIST *table, LOOKUP_FIELD_VALUES *lookup_field_vals) | 253 | Table_ref *table, LOOKUP_FIELD_VALUES *lookup_field_vals) |
| 274 | { | 254 | { |
| 275 | if (!cond) return 0; | 255 | if (!cond) return 0; |
| 276 | 256 | ||
| @@ -299,62 +279,32 @@ static bool calc_lookup_values_from_cond(Item *cond, | |||
| 299 | @brief Calculate lookup values(database name, table name) | 279 | @brief Calculate lookup values(database name, table name) |
| 300 | 280 | ||
| 301 | @details This function calculates lookup values(database name, table name) | 281 | @details This function calculates lookup values(database name, table name) |
| 302 | from 'WHERE' condition or wild values (for 'SHOW' commands only) | 282 | from 'WHERE' condition and fill lookup_field_vals struct field |
| 303 | from LEX struct and fill lookup_field_vals struct field | ||
| 304 | with these values. | 283 | with these values. |
| 305 | 284 | ||
| 306 | @param[in] thd thread handler | 285 | @param[in] cond WHERE condition |
| 307 | @param[in] cond WHERE condition | 286 | @param[in] tables I_S table |
| 308 | @param[in] tables I_S table | 287 | @param[in, out] lookup_field_vals Struct which holds lookup values |
| 309 | @param[in, out] lookup_field_values Struct which holds lookup values | ||
| 310 | 288 | ||
| 311 | @return | 289 | @return |
| 312 | 0 success | 290 | 0 success |
| 313 | 1 error, there can be no matching records for the condition | 291 | 1 error, there can be no matching records for the condition |
| 314 | */ | 292 | */ |
| 315 | 293 | ||
| 316 | static bool get_lookup_field_values(THD *thd, Item *cond, TABLE_LIST *tables, | 294 | static bool get_lookup_field_values(Item *cond, Table_ref *tables, |
| 317 | LOOKUP_FIELD_VALUES *lookup_field_values) | 295 | LOOKUP_FIELD_VALUES *lookup_field_vals) |
| 318 | { | 296 | { |
| 319 | LEX *lex = thd->lex; | 297 | bool rc = calc_lookup_values_from_cond(cond, tables, lookup_field_vals); |
| 320 | const char *wild = lex->wild ? lex->wild->ptr() : NullS; | ||
| 321 | bool rc = 0; | ||
| 322 | |||
| 323 | switch (lex->sql_command) { | ||
| 324 | case SQLCOM_SHOW_DATABASES: | ||
| 325 | if (wild) { | ||
| 326 | lookup_field_values->db_value = wild; | ||
| 327 | lookup_field_values->wild_db_value = true; | ||
| 328 | } | ||
| 329 | break; | ||
| 330 | case SQLCOM_SHOW_TABLES: | ||
| 331 | case SQLCOM_SHOW_TABLE_STATUS: | ||
| 332 | case SQLCOM_SHOW_TRIGGERS: | ||
| 333 | case SQLCOM_SHOW_EVENTS: | ||
| 334 | lookup_field_values->db_value = lex->select_lex->db; | ||
| 335 | if (wild) { | ||
| 336 | lookup_field_values->table_value = wild; | ||
| 337 | lookup_field_values->wild_table_value = true; | ||
| 338 | } | ||
| 339 | break; | ||
| 340 | default: | ||
| 341 | /* | ||
| 342 | The "default" is for queries over I_S. | ||
| 343 | All previous cases handle SHOW commands. | ||
| 344 | */ | ||
| 345 | rc = calc_lookup_values_from_cond(cond, tables, lookup_field_values); | ||
| 346 | break; | ||
| 347 | } | ||
| 348 | 298 | ||
| 349 | if (lower_case_table_names && !rc) { | 299 | if (lower_case_table_names && !rc) { |
| 350 | /* | 300 | /* |
| 351 | We can safely do in-place upgrades here since all of the above cases | 301 | We can safely do in-place upgrades here since all of the above cases |
| 352 | are allocating a new memory buffer for these strings. | 302 | are allocating a new memory buffer for these strings. |
| 353 | */ | 303 | */ |
| 354 | if (lookup_field_values->db_value && !lookup_field_values->db_value->empty()) | 304 | if (lookup_field_vals->db_value && !lookup_field_vals->db_value->empty()) |
| 355 | casedn(system_charset_info, *lookup_field_values->db_value); | 305 | casedn(system_charset_info, *lookup_field_vals->db_value); |
| 356 | if (lookup_field_values->table_value && !lookup_field_values->table_value->empty()) | 306 | if (lookup_field_vals->table_value && !lookup_field_vals->table_value->empty()) |
| 357 | casedn(system_charset_info, *lookup_field_values->table_value); | 307 | casedn(system_charset_info, *lookup_field_vals->table_value); |
| 358 | } | 308 | } |
| 359 | 309 | ||
| 360 | return rc; | 310 | return rc; |
| @@ -369,8 +319,16 @@ static bool is_special_db(const dd::String_type &db_name) | |||
| 369 | || is_perfschema_db(db_name.c_str(), db_name.size()); | 319 | || is_perfschema_db(db_name.c_str(), db_name.size()); |
| 370 | } | 320 | } |
| 371 | 321 | ||
| 372 | static int | 322 | /** |
| 373 | make_db_list(THD *thd, std::vector<dd::String_type> *db_names, | 323 | Return either single or all schemas |
| 324 | |||
| 325 | @param[in] thd thread handler | ||
| 326 | @param[out] db_names list of schemas | ||
| 327 | @param[in] lookup_field_vals Struct which holds lookup values | ||
| 328 | |||
| 329 | @return true if error, false otherwise | ||
| 330 | */ | ||
| 331 | static int make_db_list(THD *thd, std::vector<dd::String_type> *db_names, | ||
| 374 | LOOKUP_FIELD_VALUES *lookup_field_vals) | 332 | LOOKUP_FIELD_VALUES *lookup_field_vals) |
| 375 | { | 333 | { |
| 376 | /* | 334 | /* |
| @@ -405,53 +363,45 @@ make_db_list(THD *thd, std::vector<dd::String_type> *db_names, | |||
| 405 | 363 | ||
| 406 | /*----------------------------------------------------------------------------*/ | 364 | /*----------------------------------------------------------------------------*/ |
| 407 | 365 | ||
| 408 | /* | 366 | /** |
| 409 | SYNOPSIS | 367 | Find files in a given directory. |
| 410 | thd thread handler | 368 | |
| 411 | tables put found tables and their size in this list | 369 | @param thd thread handler |
| 412 | db database name to set in TABLE_LIST structure | 370 | @param tables put found files in this list |
| 413 | path path to database | 371 | @param db_name filter for found files |
| 414 | wild filter for found files | 372 | @param wild filter for found files |
| 415 | 373 | ||
| 416 | RETURN | 374 | @return true if error, false otherwise |
| 417 | FIND_FILES_OK success | ||
| 418 | FIND_FILES_OOM out of memory error | ||
| 419 | FIND_FILES_DIR no such directory, or directory can't be read | ||
| 420 | */ | 375 | */ |
| 421 | typedef std::map<dd::String_type, size_t> Table_sizes_map; | 376 | typedef std::map<dd::String_type, size_t> Table_sizes_map; |
| 422 | static find_files_result | 377 | bool find_tables(THD *thd, Table_sizes_map &tables, |
| 423 | find_tables(THD *thd, Table_sizes_map &tables, const char *db, | 378 | Table_ref &db_data, boost::optional<dd::String_type> &wild) |
| 424 | const char *path, boost::optional<dd::String_type> &wild, | ||
| 425 | MEM_ROOT *tmp_mem_root) | ||
| 426 | { | 379 | { |
| 427 | MY_DIR *dirp; | 380 | MY_DIR *dirp; |
| 428 | MEM_ROOT **save_mem_root_ptr = THR_MALLOC; | ||
| 429 | uint col_access = thd->col_access; | ||
| 430 | DBUG_ENTER("find_files"); | 381 | DBUG_ENTER("find_files"); |
| 431 | 382 | ||
| 383 | char path[FN_REFLEN + 1]; | ||
| 384 | build_table_filename(path, sizeof(path) - 1, db_data.db, "", "", 0); | ||
| 385 | |||
| 432 | if (!(dirp = my_dir(path, MYF(MY_WANT_STAT)))) | 386 | if (!(dirp = my_dir(path, MYF(MY_WANT_STAT)))) |
| 433 | { | 387 | { |
| 434 | if (my_errno() == ENOENT) | 388 | if (my_errno() == ENOENT) |
| 435 | my_error(ER_BAD_DB_ERROR, MYF(0), db); | 389 | my_error(ER_BAD_DB_ERROR, MYF(0), db_data.db); |
| 436 | else | 390 | else |
| 437 | { | 391 | { |
| 438 | char errbuf[MYSYS_STRERROR_SIZE]; | 392 | char errbuf[MYSYS_STRERROR_SIZE]; |
| 439 | my_error(ER_CANT_READ_DIR, MYF(0), path, | 393 | my_error(ER_CANT_READ_DIR, MYF(0), path, |
| 440 | my_errno(), my_strerror(errbuf, sizeof(errbuf), my_errno())); | 394 | my_errno(), my_strerror(errbuf, sizeof(errbuf), my_errno())); |
| 441 | } | 395 | } |
| 442 | DBUG_RETURN(FIND_FILES_DIR); | 396 | return true; |
| 443 | } | 397 | } |
| 444 | 398 | ||
| 445 | if (tmp_mem_root) | ||
| 446 | THR_MALLOC = &tmp_mem_root; | ||
| 447 | |||
| 448 | char uname[NAME_LEN + 1]; /* Unencoded name */ | 399 | char uname[NAME_LEN + 1]; /* Unencoded name */ |
| 449 | dd::String_type fts_schema_name, fts_table_name; /* FTS lookup */ | 400 | dd::String_type fts_schema_name, fts_table_name; /* FTS lookup */ |
| 450 | std::map<dd::Object_id, dd::String_type> fts_cache; | 401 | std::map<dd::Object_id, dd::String_type> fts_cache; |
| 451 | tables.clear(); | 402 | tables.clear(); |
| 452 | for (uint i = 0; i < dirp->number_off_files; i++) | 403 | for (uint i = 0; i < dirp->number_off_files; i++) |
| 453 | { | 404 | { |
| 454 | |||
| 455 | FILEINFO *file = dirp->dir_entry + i; | 405 | FILEINFO *file = dirp->dir_entry + i; |
| 456 | /* skip '.', '..' and temp files. */ | 406 | /* skip '.', '..' and temp files. */ |
| 457 | if ((file->name[0] == '.' && | 407 | if ((file->name[0] == '.' && |
| @@ -508,18 +458,14 @@ find_tables(THD *thd, Table_sizes_map &tables, const char *db, | |||
| 508 | continue; | 458 | continue; |
| 509 | } | 459 | } |
| 510 | 460 | ||
| 511 | /* Don't show tables where we don't have any privileges */ | 461 | /* |
| 512 | if (db && !(col_access & TABLE_ACLS)) | 462 | Check_grant will grant access if there is any column privileges on |
| 513 | { | 463 | all of the tables thanks to the fourth parameter (bool show_table). |
| 514 | TABLE_LIST table_list; | 464 | */ |
| 515 | table_list.db = db; | 465 | db_data.table_name = uname; |
| 516 | table_list.db_length = strlen(db); | 466 | db_data.table_name_length = file_name_len; |
| 517 | table_list.table_name = uname; | 467 | if (check_grant(thd, SELECT_ACL, &db_data, true, 1, true)) |
| 518 | table_list.table_name_length = file_name_len; | 468 | continue; |
| 519 | table_list.grant.privilege = col_access; | ||
| 520 | if (check_grant(thd, TABLE_ACLS, &table_list, true, 1, true)) | ||
| 521 | continue; | ||
| 522 | } | ||
| 523 | 469 | ||
| 524 | tables.emplace(uname, file->mystat->st_size); | 470 | tables.emplace(uname, file->mystat->st_size); |
| 525 | } | 471 | } |
| @@ -527,167 +473,94 @@ find_tables(THD *thd, Table_sizes_map &tables, const char *db, | |||
| 527 | DBUG_PRINT("info", ("found: %ld files", tables.size())); | 473 | DBUG_PRINT("info", ("found: %ld files", tables.size())); |
| 528 | my_dirend(dirp); | 474 | my_dirend(dirp); |
| 529 | 475 | ||
| 530 | if (tmp_mem_root) | 476 | return false; |
| 531 | THR_MALLOC = save_mem_root_ptr; | ||
| 532 | |||
| 533 | DBUG_RETURN(FIND_FILES_OK); | ||
| 534 | } | 477 | } |
| 535 | 478 | ||
| 536 | static int | 479 | static bool make_table_list(THD *thd, Table_sizes_map &table_names, |
| 537 | make_table_list(THD *thd, Table_sizes_map &table_names, LEX *lex, | 480 | LOOKUP_FIELD_VALUES *lookup_field_vals, Table_ref &db_data) |
| 538 | LOOKUP_FIELD_VALUES *lookup_field_vals, const dd::String_type &db_name, | ||
| 539 | MEM_ROOT *tmp_mem_root) | ||
| 540 | { | 481 | { |
| 541 | char path[FN_REFLEN + 1]; | ||
| 542 | build_table_filename(path, sizeof(path) - 1, db_name.c_str(), "", "", 0); | ||
| 543 | |||
| 544 | const dd::Schema *sch_obj = NULL; | 482 | const dd::Schema *sch_obj = NULL; |
| 545 | if (thd->dd_client()->acquire(db_name.c_str(), &sch_obj)) | 483 | if (thd->dd_client()->acquire(db_data.db, &sch_obj) || !sch_obj) |
| 546 | return 1; | 484 | return 1; |
| 547 | if (!sch_obj) | ||
| 548 | { | ||
| 549 | /* | ||
| 550 | Report missing database only if it is a 'SHOW' command. | ||
| 551 | Another thread may have dropped the database after we | ||
| 552 | got its name from the DD. | ||
| 553 | */ | ||
| 554 | if (sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) | ||
| 555 | { | ||
| 556 | my_error(ER_BAD_DB_ERROR, MYF(0), db_name.c_str()); | ||
| 557 | return 1; | ||
| 558 | } | ||
| 559 | return 2; | ||
| 560 | } | ||
| 561 | 485 | ||
| 562 | find_files_result res = find_tables(thd, table_names, db_name.c_str(), path, | 486 | return find_tables(thd, table_names, db_data, lookup_field_vals->table_value); |
| 563 | lookup_field_vals->table_value, tmp_mem_root); | ||
| 564 | return (res == FIND_FILES_OK) ? 0 : 2; | ||
| 565 | } | 487 | } |
| 566 | 488 | ||
| 567 | /*----------------------------------------------------------------------------*/ | 489 | /*----------------------------------------------------------------------------*/ |
| 568 | 490 | ||
| 569 | static struct st_mysql_information_schema info = | ||
| 570 | { MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION }; | ||
| 571 | |||
| 572 | static ST_FIELD_INFO fields_info[] = | 491 | static ST_FIELD_INFO fields_info[] = |
| 573 | { | 492 | { |
| 574 | {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, | 493 | {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, 0}, |
| 575 | {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Name", | 494 | {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Name", 0}, |
| 576 | SKIP_OPEN_TABLE}, | ||
| 577 | {"TABLE_SIZE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, | 495 | {"TABLE_SIZE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, |
| 578 | MY_I_S_UNSIGNED, "Table_size", SKIP_OPEN_TABLE}, | 496 | MY_I_S_UNSIGNED, "Table_size", 0}, |
| 579 | {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE} | 497 | {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0} |
| 580 | }; | 498 | }; |
| 581 | 499 | ||
| 582 | static int fill_table(THD *thd, TABLE_LIST *tables, Item *cond) | 500 | static int fill_table(THD *thd, Table_ref *tables, Item *cond) |
| 583 | { | 501 | { |
| 584 | LEX *lex = thd->lex; | ||
| 585 | TABLE *table = tables->table; | 502 | TABLE *table = tables->table; |
| 586 | LOOKUP_FIELD_VALUES lookup_field_vals; | 503 | LOOKUP_FIELD_VALUES lookup_field_vals; |
| 587 | Security_context *sctx = thd->security_context(); | ||
| 588 | std::vector<dd::String_type> db_names; | 504 | std::vector<dd::String_type> db_names; |
| 589 | int error = 1; | ||
| 590 | 505 | ||
| 591 | DBUG_ENTER("fill_table"); | 506 | DBUG_ENTER("fill_table"); |
| 592 | 507 | ||
| 593 | MEM_ROOT tmp_mem_root; | 508 | if (get_lookup_field_values(cond, tables, &lookup_field_vals)) |
| 594 | init_sql_alloc(key_memory_get_all_tables, &tmp_mem_root, | 509 | return 0; |
| 595 | TABLE_ALLOC_BLOCK_SIZE, 0); | ||
| 596 | |||
| 597 | if (get_lookup_field_values(thd, cond, tables, &lookup_field_vals)) | ||
| 598 | { | ||
| 599 | error = 0; | ||
| 600 | goto err; | ||
| 601 | } | ||
| 602 | 510 | ||
| 603 | #define STR_OR_NIL(S) ((S) ? (S->c_str()) : "<nil>") | 511 | #define STR_OR_NIL(S) ((S) ? (S->c_str()) : "<nil>") |
| 604 | DBUG_PRINT("INDEX VALUES", ("db_name='%s', table_name='%s'", | 512 | DBUG_PRINT("INDEX VALUES", ("db_name='%s', table_name='%s'", |
| 605 | STR_OR_NIL(lookup_field_vals.db_value), | 513 | STR_OR_NIL(lookup_field_vals.db_value), |
| 606 | STR_OR_NIL(lookup_field_vals.table_value))); | 514 | STR_OR_NIL(lookup_field_vals.table_value))); |
| 607 | 515 | ||
| 608 | if (!lookup_field_vals.wild_db_value && !lookup_field_vals.wild_table_value) | 516 | /* EXPLAIN SELECT */ |
| 609 | { | 517 | if (thd->lex->is_explain()) |
| 610 | /* | 518 | return 0; |
| 611 | if lookup value is empty string then | ||
| 612 | it's impossible table name or db name | ||
| 613 | */ | ||
| 614 | if ((lookup_field_vals.db_value | ||
| 615 | && lookup_field_vals.db_value->empty()) | ||
| 616 | || (lookup_field_vals.table_value | ||
| 617 | && lookup_field_vals.table_value->empty())) | ||
| 618 | { | ||
| 619 | error = 0; | ||
| 620 | goto err; | ||
| 621 | } | ||
| 622 | } | ||
| 623 | |||
| 624 | if (lookup_field_vals.db_value && !lookup_field_vals.db_value->empty() | ||
| 625 | && !lookup_field_vals.wild_db_value) | ||
| 626 | tables->has_db_lookup_value = true; | ||
| 627 | if (lookup_field_vals.table_value && !lookup_field_vals.table_value->empty() | ||
| 628 | && !lookup_field_vals.wild_table_value) | ||
| 629 | tables->has_table_lookup_value = true; | ||
| 630 | |||
| 631 | if (lex->is_explain()) | ||
| 632 | { | ||
| 633 | /* EXPLAIN SELECT */ | ||
| 634 | error = 0; | ||
| 635 | goto err; | ||
| 636 | } | ||
| 637 | 519 | ||
| 638 | if (make_db_list(thd, &db_names, &lookup_field_vals)) | 520 | if (make_db_list(thd, &db_names, &lookup_field_vals)) |
| 639 | goto err; | 521 | return 1; |
| 640 | 522 | ||
| 641 | for (auto &db_name : db_names) | 523 | for (auto &db_name : db_names) |
| 642 | { | 524 | { |
| 643 | bool have_db_privileges = false; | 525 | Table_ref db_data; |
| 644 | if (sctx->get_active_roles()->size() > 0) { | 526 | memset(reinterpret_cast<char *>(&db_data), 0, sizeof(db_data)); |
| 645 | LEX_CSTRING const_db_name = { db_name.c_str(), db_name.size() }; | 527 | db_data.db = db_name.c_str(); |
| 646 | have_db_privileges = sctx->db_acl(const_db_name) > 0 ? true : false; | 528 | db_data.db_length = db_name.length(); |
| 647 | } | 529 | db_data.grant.privilege = 0; |
| 648 | if (!(check_access(thd, SELECT_ACL, db_name.c_str(), &thd->col_access, NULL, 0, 1) | 530 | |
| 649 | || (!thd->col_access && check_grant_db(thd, db_name.c_str()))) | 531 | // Get user's global and db-level privileges. |
| 650 | || sctx->check_access(DB_ACLS | SHOW_DB_ACL, true) | 532 | if (check_access(thd, SELECT_ACL, db_data.db, &db_data.grant.privilege, NULL, false, true)) |
| 651 | || have_db_privileges | 533 | continue; |
| 652 | || acl_get(thd, sctx->host().str, sctx->ip().str, | ||
| 653 | sctx->priv_user().str, db_name.c_str(), 0)) | ||
| 654 | { | ||
| 655 | // We must make sure the schema is released and unlocked in the right | ||
| 656 | // order. Fail if we are unable to get a meta data lock on the schema | ||
| 657 | // name. | ||
| 658 | dd::Schema_MDL_locker mdl_handler(thd); | ||
| 659 | if (mdl_handler.ensure_locked(db_name.c_str())) | ||
| 660 | goto err; | ||
| 661 | |||
| 662 | dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client()); | ||
| 663 | Table_sizes_map tables; | ||
| 664 | int res = make_table_list(thd, tables, lex, &lookup_field_vals, | ||
| 665 | db_name, &tmp_mem_root); | ||
| 666 | if (res) | ||
| 667 | { | ||
| 668 | if (res == 2) /* Not fatal error, continue */ | ||
| 669 | continue; | ||
| 670 | goto err; | ||
| 671 | } | ||
| 672 | 534 | ||
| 673 | for (auto &table_data : tables) | 535 | // Now check, if user has access on global level or to any of database/ |
| 674 | { | 536 | // table/column/routine. |
| 675 | table->field[0]->store(db_name.c_str(), db_name.size(), | 537 | if (!(db_data.grant.privilege & DB_OP_ACLS) && check_grant_db(thd, db_data.db)) |
| 676 | system_charset_info); | 538 | continue; |
| 677 | table->field[1]->store(table_data.first.c_str(), table_data.first.size(), | ||
| 678 | system_charset_info); | ||
| 679 | table->field[2]->store(table_data.second, true); | ||
| 680 | if (schema_table_store_record(thd, table)) | ||
| 681 | goto err; | ||
| 682 | } | ||
| 683 | } | ||
| 684 | } | ||
| 685 | 539 | ||
| 686 | error = 0; | 540 | // We must make sure the schema is released and unlocked in the right |
| 541 | // order. Fail if we are unable to get a meta data lock on the schema | ||
| 542 | // name. | ||
| 543 | dd::Schema_MDL_locker mdl_handler(thd); | ||
| 544 | if (mdl_handler.ensure_locked(db_data.db)) | ||
| 545 | return 1; | ||
| 687 | 546 | ||
| 688 | err: | 547 | dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client()); |
| 689 | free_root(&tmp_mem_root, MYF(0)); | 548 | Table_sizes_map tables_data; |
| 690 | DBUG_RETURN(error); | 549 | int res = make_table_list(thd, tables_data, &lookup_field_vals, db_data); |
| 550 | if (res) | ||
| 551 | continue; | ||
| 552 | |||
| 553 | for (auto &table_data : tables_data) | ||
| 554 | { | ||
| 555 | table->field[0]->store(db_data.db, db_data.db_length, | ||
| 556 | system_charset_info); | ||
| 557 | table->field[1]->store(table_data.first.c_str(), table_data.first.size(), | ||
| 558 | system_charset_info); | ||
| 559 | table->field[2]->store(table_data.second, true); | ||
| 560 | if (schema_table_store_record(thd, table)) | ||
| 561 | return 1; | ||
| 562 | } | ||
| 563 | } | ||
| 691 | 564 | ||
| 692 | return 0; | 565 | return 0; |
| 693 | } | 566 | } |
| @@ -698,12 +571,12 @@ static int init(void *ptr) | |||
| 698 | 571 | ||
| 699 | schema_table->fields_info = fields_info; | 572 | schema_table->fields_info = fields_info; |
| 700 | schema_table->fill_table = fill_table; | 573 | schema_table->fill_table = fill_table; |
| 701 | schema_table->idx_field1 = 0; | ||
| 702 | schema_table->idx_field2 = 1; | ||
| 703 | schema_table->i_s_requested_object = OPTIMIZE_I_S_TABLE; | ||
| 704 | return 0; | 574 | return 0; |
| 705 | } | 575 | } |
| 706 | 576 | ||
| 577 | static struct st_mysql_information_schema info = | ||
| 578 | { MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION }; | ||
| 579 | |||
| 707 | mysql_declare_plugin(table_sizes) | 580 | mysql_declare_plugin(table_sizes) |
| 708 | { | 581 | { |
| 709 | MYSQL_INFORMATION_SCHEMA_PLUGIN, | 582 | MYSQL_INFORMATION_SCHEMA_PLUGIN, |
