summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--src/mysql_inc.h16
-rw-r--r--src/table_sizes.cc647
3 files changed, 491 insertions, 174 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4eeccdd..e468c80 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,3 +1,5 @@
1INCLUDE_DIRECTORIES(SYSTEM ${BOOST_PATCHES_DIR} ${BOOST_INCLUDE_DIR})
2
1MYSQL_ADD_PLUGIN(table_sizes src/table_sizes.cc 3MYSQL_ADD_PLUGIN(table_sizes src/table_sizes.cc
2 MODULE_ONLY MODULE_OUTPUT_NAME "table_sizes") 4 MODULE_ONLY MODULE_OUTPUT_NAME "table_sizes")
3 5
diff --git a/src/mysql_inc.h b/src/mysql_inc.h
deleted file mode 100644
index 4912682..0000000
--- a/src/mysql_inc.h
+++ /dev/null
@@ -1,16 +0,0 @@
1#ifndef MYSQL_INCL_H
2#define MYSQL_INCL_H
3
4#ifndef HAVE_CONFIG_H
5#define HAVE_CONFIG_H
6#endif
7
8#ifndef MYSQL_DYNAMIC_PLUGIN
9#define MYSQL_DYNAMIC_PLUGIN
10#endif
11
12#define MYSQL_SERVER 1
13
14#include <mysql_version.h>
15
16#endif
diff --git a/src/table_sizes.cc b/src/table_sizes.cc
index b1b38bb..40d5090 100644
--- a/src/table_sizes.cc
+++ b/src/table_sizes.cc
@@ -12,31 +12,366 @@
12 along with this program; if not, write to the Free Software 12 along with this program; if not, write to the Free Software
13 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 13 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
14*/ 14*/
15#include "mysql_inc.h"
16#include <sql_base.h>
17#include <sql_show.h>
18#include <sql_table.h>
19#include <sql_parse.h>
20#include <sql_db.h>
21#include <auth_common.h>
22 15
23#define STR_OR_NIL(S) ((S) ? (S) : "<nil>") 16#include <mysql/plugin.h>
17#include <boost/optional/optional.hpp>
18
19#include "sql/mysqld.h"
20#include "sql/sql_base.h"
21#include "sql/sql_show.h"
22#include "sql/sql_class.h" // THD
23#include "sql/sql_table.h" // filename_to_tablename
24#include "sql/strfunc.h" // make_lex_string_root
25#include "sql/sql_parse.h" // sql_command_flags
26#include "sql/sql_lex.h" // LEX
27#include "sql/item_func.h" // Item_Func
28#include "sql/item_cmpfunc.h" // Item_cond
29#include "sql/dd/cache/dictionary_client.h" // dd::cache::Dictionary_client
30#include "sql/dd/dd_schema.h" // dd::Schema_MDL_locker
31#include "sql/dd/string_type.h" // dd::String_type
32#include "sql/dd/sdi_file.h" // dd::sdi_file
33#include "sql/auth/auth_acls.h" // *_ACLS
34#include "sql/auth/auth_common.h" // check_grant_db
35#include "mf_wcomp.h" // wild_compare,wild_one,wild_many
36#include "my_dir.h" // MY_DIR
37
38// InnoDB FTS
39/** For storing table info when checking for orphaned tables. */
40struct fts_aux_table_t
41{
42 /** Parent table id */
43 uint64_t parent_id;
44
45 /** Table FT index id */
46 uint64_t index_id;
47};
48
49/** Check if a table is an FTS auxiliary table name.
50@param[out] table FTS table info
51@param[in] name Table name
52@param[in] len Length of table name
53@return true if the name matches an auxiliary table name pattern */
54bool fts_is_aux_table_name(fts_aux_table_t *table, const char *name,
55 int len)
56{
57 /** FTS auxiliary table prefix that are common to all FT indexes.*/
58 const char *FTS_PREFIX = "fts_";
59 const char *FTS_PREFIX_5_7 = "FTS_";
60
61 /** FTS auxiliary table suffixes that are common to all FT indexes. */
62 const char *fts_common_tables[] = {"being_deleted", "being_deleted_cache",
63 "config", "deleted",
64 "deleted_cache", NULL};
65 const char *fts_common_tables_5_7[] = {"BEING_DELETED", "BEING_DELETED_CACHE",
66 "CONFIG", "DELETED",
67 "DELETED_CACHE", NULL};
68
69 /** FTS auxiliary INDEX split intervals. */
70 const char *fts_index_selector[] = {"index_1", "index_2", "index_3", "index_4",
71 "index_5", "index_6", NULL};
72 const char *fts_index_selector_5_7[] = {"INDEX_1", "INDEX_2", "INDEX_3", "INDEX_4",
73 "INDEX_5", "INDEX_6", NULL};
74
75 const char *ptr = name;
76 const char *end = name + len;
77
78 /* All auxiliary tables are prefixed with "FTS_" and the name
79 length will be at the very least greater than 20 bytes. */
80 if (ptr != NULL && len > 20 &&
81 (strncmp(ptr, FTS_PREFIX, 4) == 0 ||
82 strncmp(ptr, FTS_PREFIX_5_7, 4) == 0))
83 {
84 /* Skip the prefix. */
85 ptr += 4;
86 len -= 4;
87
88 /* Try and read the table id. */
89 if (sscanf(ptr, "%016" PRIx64, &table->parent_id) != 1)
90 return false;
91
92 /* Skip the table id. */
93 ptr = static_cast<const char *>(memchr(ptr, '_', len));
94 if (ptr == NULL)
95 return false;
96
97 /* Skip the underscore. */
98 ++ptr;
99 len = end - ptr;
100
101 /* First search the common table suffix array. */
102 for (int i = 0; fts_common_tables[i] != NULL; ++i) {
103 if (strncmp(ptr, fts_common_tables[i], len) == 0 ||
104 strncmp(ptr, fts_common_tables_5_7[i], len) == 0) {
105 return true;
106 }
107 }
108
109 /* Could be obsolete common tables. */
110 if (native_strncasecmp(ptr, "ADDED", len) == 0 ||
111 native_strncasecmp(ptr, "STOPWORDS", len) == 0) {
112 return true;
113 }
114
115 /* Try and read the index id. */
116 if (sscanf(ptr, "%016" PRIx64, &table->index_id) != 1)
117 return false;
118
119 /* Skip the index id. */
120 ptr = static_cast<const char *>(memchr(ptr, '_', len));
121
122 if (ptr == NULL)
123 return false;
124
125 /* Skip the underscore. */
126 ++ptr;
127 len = end - ptr;
128
129 /* Search the FT index specific array. */
130 for (int i = 0; fts_index_selector[i] != NULL; ++i) {
131 if (strncmp(ptr, fts_index_selector[i], len) == 0 ||
132 strncmp(ptr, fts_index_selector_5_7[i], len) == 0) {
133 return true;
134 }
135 }
136
137 /* Other FT index specific table(s). */
138 if (native_strncasecmp(ptr, "DOC_ID", len) == 0)
139 return true;
140 }
141
142 return false;
143}
144
145/*----------------------------------------------------------------------------*/
146
147/**
148 Condition pushdown used for INFORMATION_SCHEMA / SHOW queries.
149 This structure is to implement an optimization when
150 accessing data dictionary data in the INFORMATION_SCHEMA
151 or SHOW commands.
152 When the query contain a TABLE_SCHEMA or TABLE_NAME clause,
153 narrow the search for data based on the constraints given.
154*/
155struct LOOKUP_FIELD_VALUES {
156 /**
157 Value of a TABLE_SCHEMA clause.
158 Note that this value length may exceed @c NAME_LEN.
159 @sa wild_db_value
160 */
161 boost::optional<dd::String_type> db_value;
162 /**
163 Value of a TABLE_NAME clause.
164 Note that this value length may exceed @c NAME_LEN.
165 @sa wild_table_value
166 */
167 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};
179
180/**
181 @brief Get lookup value from the part of 'WHERE' condition
182
183 @details This function gets lookup value from
184 the part of 'WHERE' condition if it's possible and
185 fill appropriate lookup_field_vals struct field
186 with this value.
24 187
25typedef struct st_lookup_field_values 188 @param[in] thd thread handler
189 @param[in] item_func part of WHERE condition
190 @param[in] table I_S table
191 @param[in, out] lookup_field_vals Struct which holds lookup values
192
193 @return
194 0 success
195 1 error, there can be no matching records for the condition
196*/
197
198static bool get_lookup_value(Item_func *item_func, TABLE_LIST *table,
199 LOOKUP_FIELD_VALUES *lookup_field_vals)
200{
201 ST_SCHEMA_TABLE *schema_table = table->schema_table;
202 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
212 if (item_func->functype() == Item_func::EQ_FUNC ||
213 item_func->functype() == Item_func::EQUAL_FUNC) {
214 int idx_field, idx_val;
215 char tmp[MAX_FIELD_WIDTH];
216 String *tmp_str, str_buff(tmp, sizeof(tmp), system_charset_info);
217 Item_field *item_field;
218 CHARSET_INFO *cs = system_charset_info;
219
220 if (item_func->arguments()[0]->type() == Item::FIELD_ITEM &&
221 item_func->arguments()[1]->const_item()) {
222 idx_field = 0;
223 idx_val = 1;
224 } else if (item_func->arguments()[1]->type() == Item::FIELD_ITEM &&
225 item_func->arguments()[0]->const_item()) {
226 idx_field = 1;
227 idx_val = 0;
228 } else
229 return 0;
230
231 item_field = (Item_field *)item_func->arguments()[idx_field];
232 if (table->table != item_field->field->table) return 0;
233 tmp_str = item_func->arguments()[idx_val]->val_str(&str_buff);
234
235 /* impossible value */
236 if (!tmp_str) return 1;
237
238 /* Lookup value is database name */
239 if (!cs->coll->strnncollsp(cs, (uchar *)field_name1, strlen(field_name1),
240 (uchar *)item_field->field_name,
241 strlen(item_field->field_name))) {
242 lookup_field_vals->db_value.emplace(tmp_str->ptr(), tmp_str->length());
243 }
244 /* Lookup value is table name */
245 else if (!cs->coll->strnncollsp(cs, (uchar *)field_name2,
246 strlen(field_name2),
247 (uchar *)item_field->field_name,
248 strlen(item_field->field_name))) {
249 lookup_field_vals->table_value.emplace(tmp_str->ptr(), tmp_str->length());
250 }
251 }
252 return 0;
253}
254
255/**
256 @brief Calculates lookup values from 'WHERE' condition
257
258 @details This function calculates lookup value(database name, table name)
259 from 'WHERE' condition if it's possible and
260 fill lookup_field_vals struct fields with these values.
261
262 @param[in] thd thread handler
263 @param[in] cond WHERE condition
264 @param[in] table I_S table
265 @param[in, out] lookup_field_vals Struct which holds lookup values
266
267 @return
268 0 success
269 1 error, there can be no matching records for the condition
270*/
271
272static bool calc_lookup_values_from_cond(Item *cond,
273 TABLE_LIST *table, LOOKUP_FIELD_VALUES *lookup_field_vals)
274{
275 if (!cond) return 0;
276
277 if (cond->type() == Item::COND_ITEM) {
278 if (((Item_cond *)cond)->functype() == Item_func::COND_AND_FUNC) {
279 List_iterator<Item> li(*((Item_cond *)cond)->argument_list());
280 Item *item;
281 while ((item = li++)) {
282 if (item->type() == Item::FUNC_ITEM) {
283 if (get_lookup_value((Item_func *)item, table, lookup_field_vals))
284 return 1;
285 } else {
286 if (calc_lookup_values_from_cond(item, table, lookup_field_vals))
287 return 1;
288 }
289 }
290 }
291 return 0;
292 } else if (cond->type() == Item::FUNC_ITEM &&
293 get_lookup_value((Item_func *)cond, table, lookup_field_vals))
294 return 1;
295 return 0;
296}
297
298/**
299 @brief Calculate lookup values(database name, table name)
300
301 @details This function calculates lookup values(database name, table name)
302 from 'WHERE' condition or wild values (for 'SHOW' commands only)
303 from LEX struct and fill lookup_field_vals struct field
304 with these values.
305
306 @param[in] thd thread handler
307 @param[in] cond WHERE condition
308 @param[in] tables I_S table
309 @param[in, out] lookup_field_values Struct which holds lookup values
310
311 @return
312 0 success
313 1 error, there can be no matching records for the condition
314*/
315
316static bool get_lookup_field_values(THD *thd, Item *cond, TABLE_LIST *tables,
317 LOOKUP_FIELD_VALUES *lookup_field_values)
26{ 318{
27 LEX_STRING db_value, table_value; 319 LEX *lex = thd->lex;
28 bool wild_db_value, wild_table_value; 320 const char *wild = lex->wild ? lex->wild->ptr() : NullS;
29} LOOKUP_FIELD_VALUES; 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 }
30 348
31bool get_lookup_field_values(THD *thd, Item *cond, TABLE_LIST *table, 349 if (lower_case_table_names && !rc) {
32 LOOKUP_FIELD_VALUES *lookup_field_vals); 350 /*
351 We can safely do in-place upgrades here since all of the above cases
352 are allocating a new memory buffer for these strings.
353 */
354 if (lookup_field_values->db_value && !lookup_field_values->db_value->empty())
355 casedn(system_charset_info, *lookup_field_values->db_value);
356 if (lookup_field_values->table_value && !lookup_field_values->table_value->empty())
357 casedn(system_charset_info, *lookup_field_values->table_value);
358 }
359
360 return rc;
361}
33 362
34/*----------------------------------------------------------------------------*/ 363/*----------------------------------------------------------------------------*/
35 364
365static bool is_special_db(const dd::String_type &db_name)
366{
367 /* I_S does not exist and we hide P_S */
368 return is_infoschema_db(db_name.c_str(), db_name.size())
369 || is_perfschema_db(db_name.c_str(), db_name.size());
370}
371
36static int 372static int
37make_db_list(THD *thd, List<LEX_STRING> *db_names, 373make_db_list(THD *thd, std::vector<dd::String_type> *db_names,
38 LOOKUP_FIELD_VALUES *lookup_field_vals, 374 LOOKUP_FIELD_VALUES *lookup_field_vals)
39 MEM_ROOT *tmp_mem_root)
40{ 375{
41 /* 376 /*
42 If we have db lookup value we just add it to list and 377 If we have db lookup value we just add it to list and
@@ -44,26 +379,32 @@ make_db_list(THD *thd, List<LEX_STRING> *db_names,
44 We don't do this for database names longer than the maximum 379 We don't do this for database names longer than the maximum
45 path length. 380 path length.
46 */ 381 */
47 if (lookup_field_vals->db_value.str 382 if (lookup_field_vals->db_value
48 && lookup_field_vals->db_value.length <= NAME_LEN) 383 && lookup_field_vals->db_value->length() <= NAME_LEN)
49 { 384 {
50 if (db_names->push_back(&lookup_field_vals->db_value)) 385 const dd::String_type &db_name = lookup_field_vals->db_value.get();
51 return 1; 386 if (!is_special_db(db_name))
387 db_names->push_back(db_name);
52 return 0; 388 return 0;
53 } 389 }
54 390
55 return (find_files(thd, db_names, NullS, 391 dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client());
56 mysql_data_home, NullS, TRUE, tmp_mem_root) != FIND_FILES_OK); 392 std::vector<const dd::Schema *> schemas;
393 if (thd->dd_client()->fetch_global_components(&schemas))
394 return 1;
395
396 for (const dd::Schema *schema_obj : schemas)
397 {
398 const dd::String_type &db_name = schema_obj->name();
399 if (is_special_db(db_name))
400 continue;
401 db_names->push_back(db_name);
402 }
403 return 0;
57} 404}
58 405
59/*----------------------------------------------------------------------------*/ 406/*----------------------------------------------------------------------------*/
60 407
61struct TABLE_DATA
62{
63 LEX_STRING name;
64 longlong size;
65};
66
67/* 408/*
68 SYNOPSIS 409 SYNOPSIS
69 thd thread handler 410 thd thread handler
@@ -77,30 +418,17 @@ struct TABLE_DATA
77 FIND_FILES_OOM out of memory error 418 FIND_FILES_OOM out of memory error
78 FIND_FILES_DIR no such directory, or directory can't be read 419 FIND_FILES_DIR no such directory, or directory can't be read
79*/ 420*/
421typedef std::map<dd::String_type, size_t> Table_sizes_map;
80static find_files_result 422static find_files_result
81find_tables(THD *thd, List<TABLE_DATA> *tables, const char *db, 423find_tables(THD *thd, Table_sizes_map &tables, const char *db,
82 const char *path, const char *wild, MEM_ROOT *tmp_mem_root) 424 const char *path, boost::optional<dd::String_type> &wild,
425 MEM_ROOT *tmp_mem_root)
83{ 426{
84 MY_DIR *dirp; 427 MY_DIR *dirp;
85 MEM_ROOT **root_ptr = NULL, *old_root = NULL; 428 MEM_ROOT **save_mem_root_ptr = THR_MALLOC;
86#ifndef NO_EMBEDDED_ACCESS_CHECKS
87 uint col_access = thd->col_access; 429 uint col_access = thd->col_access;
88#endif
89 size_t wild_length = 0;
90 TABLE_LIST table_list;
91 TABLE_DATA *table_data = NULL;
92 DBUG_ENTER("find_files"); 430 DBUG_ENTER("find_files");
93 431
94 if (wild)
95 {
96 if (!wild[0])
97 wild = 0;
98 else
99 wild_length = strlen(wild);
100 }
101
102 memset(&table_list, 0, sizeof(table_list));
103
104 if (!(dirp = my_dir(path, MYF(MY_WANT_STAT)))) 432 if (!(dirp = my_dir(path, MYF(MY_WANT_STAT))))
105 { 433 {
106 if (my_errno() == ENOENT) 434 if (my_errno() == ENOENT)
@@ -115,40 +443,55 @@ find_tables(THD *thd, List<TABLE_DATA> *tables, const char *db,
115 } 443 }
116 444
117 if (tmp_mem_root) 445 if (tmp_mem_root)
118 { 446 THR_MALLOC = &tmp_mem_root;
119 root_ptr = my_thread_get_THR_MALLOC();
120 old_root = *root_ptr;
121 *root_ptr = tmp_mem_root;
122 }
123 447
448 char uname[NAME_LEN + 1]; /* Unencoded name */
449 dd::String_type fts_schema_name, fts_table_name; /* FTS lookup */
450 std::map<dd::Object_id, dd::String_type> fts_cache;
451 tables.clear();
124 for (uint i = 0; i < dirp->number_off_files; i++) 452 for (uint i = 0; i < dirp->number_off_files; i++)
125 { 453 {
126 char uname[NAME_LEN + 1]; /* Unencoded name */
127 FILEINFO *file;
128 size_t file_name_len;
129 char *ext;
130 454
131 file = dirp->dir_entry + i; 455 FILEINFO *file = dirp->dir_entry + i;
132 /* skip '.', '..', db.opt and temp files. */ 456 /* skip '.', '..' and temp files. */
133 if ((file->name[0] == '.' && 457 if ((file->name[0] == '.' &&
134 (!file->name[1] || (file->name[1] == '.' && !file->name[2]))) 458 (!file->name[1] || (file->name[1] == '.' && !file->name[2])))
135 || !my_strcasecmp(files_charset_info, file->name, MY_DB_OPT_FILE)
136 || is_prefix(file->name, tmp_file_prefix)) 459 || is_prefix(file->name, tmp_file_prefix))
137 continue; 460 continue;
138 461
462 char *ext;
139 if ((ext = strrchr(file->name, '.'))) 463 if ((ext = strrchr(file->name, '.')))
464 {
465 // sdi files are small and their name is truncated
466 // lookup by id is possible but not worth the effort
467 if (!strcmp(ext, dd::sdi_file::EXT.c_str()))
468 continue;
140 *ext = 0; 469 *ext = 0;
141 file_name_len = filename_to_tablename(file->name, uname, sizeof(uname)); 470 ++ext;
471 }
142 472
143 if (table_data != NULL) 473 size_t file_name_len;
474 fts_aux_table_t fts_table;
475 if (ext && !strcmp(ext, "ibd")
476 && fts_is_aux_table_name(&fts_table, file->name, strlen(file->name)))
144 { 477 {
145 if (!my_strcasecmp(files_charset_info, uname, table_data->name.str)) 478 auto entry = fts_cache.find(fts_table.parent_id);
146 { 479 if (entry != fts_cache.end())
147 table_data->size += file->mystat->st_size; 480 fts_table_name = entry->second;
481 else if (thd->dd_client()->get_table_name_by_se_private_id("InnoDB",
482 fts_table.parent_id, &fts_schema_name, &fts_table_name))
148 continue; 483 continue;
149 } 484
150 else 485 file_name_len = (my_stpnmov(uname, fts_table_name.c_str(), sizeof(uname)) - uname);
151 table_data = NULL; 486 }
487 else
488 file_name_len = filename_to_tablename(file->name, uname, sizeof(uname));
489
490 auto table_data = tables.find(uname);
491 if (table_data != tables.end())
492 {
493 table_data->second += file->mystat->st_size;
494 continue;
152 } 495 }
153 496
154 if (wild) 497 if (wild)
@@ -157,81 +500,68 @@ find_tables(THD *thd, List<TABLE_DATA> *tables, const char *db,
157 { 500 {
158 if (my_wildcmp(files_charset_info, 501 if (my_wildcmp(files_charset_info,
159 uname, uname + file_name_len, 502 uname, uname + file_name_len,
160 wild, wild + wild_length, 503 wild->c_str(), wild->c_str() + wild->length(),
161 wild_prefix, wild_one, wild_many)) 504 wild_prefix, wild_one, wild_many))
162 continue; 505 continue;
163 } 506 }
164 else if (wild_compare(uname, wild, 0)) 507 else if (wild_compare(uname, file_name_len, wild->c_str(), wild->length(), 0))
165 continue; 508 continue;
166 } 509 }
167 510
168#ifndef NO_EMBEDDED_ACCESS_CHECKS
169 /* Don't show tables where we don't have any privileges */ 511 /* Don't show tables where we don't have any privileges */
170 if (db && !(col_access & TABLE_ACLS)) 512 if (db && !(col_access & TABLE_ACLS))
171 { 513 {
514 TABLE_LIST table_list;
172 table_list.db = db; 515 table_list.db = db;
173 table_list.db_length = strlen(db); 516 table_list.db_length = strlen(db);
174 table_list.table_name = uname; 517 table_list.table_name = uname;
175 table_list.table_name_length = file_name_len; 518 table_list.table_name_length = file_name_len;
176 table_list.grant.privilege = col_access; 519 table_list.grant.privilege = col_access;
177 if (check_grant(thd, TABLE_ACLS, &table_list, TRUE, 1, TRUE)) 520 if (check_grant(thd, TABLE_ACLS, &table_list, true, 1, true))
178 continue; 521 continue;
179 } 522 }
180#endif 523
181 524 tables.emplace(uname, file->mystat->st_size);
182 table_data = new TABLE_DATA();
183 table_data->size = file->mystat->st_size;
184 if (!(tmp_mem_root
185 ? make_lex_string_root(tmp_mem_root, &table_data->name, uname,
186 file_name_len, FALSE)
187 : thd->make_lex_string(&table_data->name, uname,
188 file_name_len, FALSE))
189 || tables->push_back(table_data))
190 {
191 my_dirend(dirp);
192 DBUG_RETURN(FIND_FILES_OOM);
193 }
194 } 525 }
195 526
196 DBUG_PRINT("info", ("found: %d files", tables->elements)); 527 DBUG_PRINT("info", ("found: %ld files", tables.size()));
197 my_dirend(dirp); 528 my_dirend(dirp);
198 529
199 //(void)ha_find_files(thd, db, path, wild, dir, files);
200
201 if (tmp_mem_root) 530 if (tmp_mem_root)
202 *root_ptr = old_root; 531 THR_MALLOC = save_mem_root_ptr;
203 532
204 DBUG_RETURN(FIND_FILES_OK); 533 DBUG_RETURN(FIND_FILES_OK);
205} 534}
206 535
207static int 536static int
208make_table_list(THD *thd, List<TABLE_DATA> *table_names, LEX *lex, 537make_table_list(THD *thd, Table_sizes_map &table_names, LEX *lex,
209 LOOKUP_FIELD_VALUES *lookup_field_vals, LEX_STRING *db_name, 538 LOOKUP_FIELD_VALUES *lookup_field_vals, const dd::String_type &db_name,
210 MEM_ROOT *tmp_mem_root) 539 MEM_ROOT *tmp_mem_root)
211{ 540{
212 char path[FN_REFLEN + 1]; 541 char path[FN_REFLEN + 1];
213 build_table_filename(path, sizeof(path) - 1, db_name->str, "", "", 0); 542 build_table_filename(path, sizeof(path) - 1, db_name.c_str(), "", "", 0);
214 543
215 find_files_result res = find_tables(thd, table_names, db_name->str, path, 544 const dd::Schema *sch_obj = NULL;
216 lookup_field_vals->table_value.str, tmp_mem_root); 545 if (thd->dd_client()->acquire(db_name.c_str(), &sch_obj))
217 if (res != FIND_FILES_OK) 546 return 1;
547 if (!sch_obj)
218 { 548 {
219 /* 549 /*
220 Downgrade errors about problems with database directory to 550 Report missing database only if it is a 'SHOW' command.
221 warnings if this is not a 'SHOW' command. Another thread 551 Another thread may have dropped the database after we
222 may have dropped database, and we may still have a name 552 got its name from the DD.
223 for that directory.
224 */ 553 */
225 if (res == FIND_FILES_DIR) 554 if (sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND)
226 { 555 {
227 if (sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) 556 my_error(ER_BAD_DB_ERROR, MYF(0), db_name.c_str());
228 return 1; 557 return 1;
229 thd->clear_error();
230 return 2;
231 } 558 }
232 return 1; 559 return 2;
233 } 560 }
234 return 0; 561
562 find_files_result res = find_tables(thd, table_names, db_name.c_str(), path,
563 lookup_field_vals->table_value, tmp_mem_root);
564 return (res == FIND_FILES_OK) ? 0 : 2;
235} 565}
236 566
237/*----------------------------------------------------------------------------*/ 567/*----------------------------------------------------------------------------*/
@@ -254,11 +584,8 @@ static int fill_table(THD *thd, TABLE_LIST *tables, Item *cond)
254 LEX *lex = thd->lex; 584 LEX *lex = thd->lex;
255 TABLE *table = tables->table; 585 TABLE *table = tables->table;
256 LOOKUP_FIELD_VALUES lookup_field_vals; 586 LOOKUP_FIELD_VALUES lookup_field_vals;
257#ifndef NO_EMBEDDED_ACCESS_CHECKS
258 Security_context *sctx = thd->security_context(); 587 Security_context *sctx = thd->security_context();
259#endif 588 std::vector<dd::String_type> db_names;
260 List<LEX_STRING> db_names;
261 List_iterator_fast<LEX_STRING> it(db_names);
262 int error = 1; 589 int error = 1;
263 590
264 DBUG_ENTER("fill_table"); 591 DBUG_ENTER("fill_table");
@@ -273,9 +600,10 @@ static int fill_table(THD *thd, TABLE_LIST *tables, Item *cond)
273 goto err; 600 goto err;
274 } 601 }
275 602
603#define STR_OR_NIL(S) ((S) ? (S->c_str()) : "<nil>")
276 DBUG_PRINT("INDEX VALUES", ("db_name='%s', table_name='%s'", 604 DBUG_PRINT("INDEX VALUES", ("db_name='%s', table_name='%s'",
277 STR_OR_NIL(lookup_field_vals.db_value.str), 605 STR_OR_NIL(lookup_field_vals.db_value),
278 STR_OR_NIL(lookup_field_vals.table_value.str))); 606 STR_OR_NIL(lookup_field_vals.table_value)));
279 607
280 if (!lookup_field_vals.wild_db_value && !lookup_field_vals.wild_table_value) 608 if (!lookup_field_vals.wild_db_value && !lookup_field_vals.wild_table_value)
281 { 609 {
@@ -283,74 +611,76 @@ static int fill_table(THD *thd, TABLE_LIST *tables, Item *cond)
283 if lookup value is empty string then 611 if lookup value is empty string then
284 it's impossible table name or db name 612 it's impossible table name or db name
285 */ 613 */
286 if ((lookup_field_vals.db_value.str 614 if ((lookup_field_vals.db_value
287 && !lookup_field_vals.db_value.str[0]) 615 && lookup_field_vals.db_value->empty())
288 || (lookup_field_vals.table_value.str 616 || (lookup_field_vals.table_value
289 && !lookup_field_vals.table_value.str[0])) 617 && lookup_field_vals.table_value->empty()))
290 { 618 {
291 error= 0; 619 error = 0;
292 goto err; 620 goto err;
293 } 621 }
294 } 622 }
295 623
296 /* NOTE: doesn't change the output of EXPLAIN - maybe sometimes later */ 624 if (lookup_field_vals.db_value && !lookup_field_vals.db_value->empty()
297 if (lookup_field_vals.db_value.length
298 && !lookup_field_vals.wild_db_value) 625 && !lookup_field_vals.wild_db_value)
299 tables->has_db_lookup_value = TRUE; 626 tables->has_db_lookup_value = true;
300 if (lookup_field_vals.table_value.length 627 if (lookup_field_vals.table_value && !lookup_field_vals.table_value->empty()
301 && !lookup_field_vals.wild_table_value) 628 && !lookup_field_vals.wild_table_value)
302 tables->has_table_lookup_value = TRUE; 629 tables->has_table_lookup_value = true;
303 630
304 if (lex->describe) 631 if (lex->is_explain())
305 { 632 {
306 /* EXPLAIN SELECT */ 633 /* EXPLAIN SELECT */
307 error = 0; 634 error = 0;
308 goto err; 635 goto err;
309 } 636 }
310 637
311 if (make_db_list(thd, &db_names, &lookup_field_vals, &tmp_mem_root)) 638 if (make_db_list(thd, &db_names, &lookup_field_vals))
312 goto err; 639 goto err;
313 640
314 LEX_STRING *db_name; 641 for (auto &db_name : db_names)
315 it.rewind(); /* To get access to new elements in basis list */
316 while ((db_name = it++))
317 { 642 {
318#ifndef NO_EMBEDDED_ACCESS_CHECKS 643 bool have_db_privileges = false;
319 if ((check_access(thd, SELECT_ACL, db_name->str, &thd->col_access, NULL, 0, 1) 644 if (sctx->get_active_roles()->size() > 0) {
320 || (!thd->col_access && check_grant_db(thd, db_name->str))) 645 LEX_CSTRING const_db_name = { db_name.c_str(), db_name.size() };
321 && !sctx->check_access(DB_ACLS | SHOW_DB_ACL, true) 646 have_db_privileges = sctx->db_acl(const_db_name) > 0 ? true : false;
322 && !acl_get(sctx->host().str, sctx->ip().str,
323 sctx->priv_user().str, db_name->str, 0))
324 continue;
325#endif
326
327 List<TABLE_DATA> tables;
328 int res = make_table_list(thd, &tables, lex, &lookup_field_vals,
329 db_name, &tmp_mem_root);
330 if (res)
331 {
332 tables.delete_elements();
333 if (res == 2) /* Not fatal error, continue */
334 continue;
335 goto err;
336 } 647 }
337 648 if (!(check_access(thd, SELECT_ACL, db_name.c_str(), &thd->col_access, NULL, 0, 1)
338 TABLE_DATA *table_data; 649 || (!thd->col_access && check_grant_db(thd, db_name.c_str())))
339 List_iterator_fast<TABLE_DATA> it_tables(tables); 650 || sctx->check_access(DB_ACLS | SHOW_DB_ACL, true)
340 while ((table_data = it_tables++)) 651 || have_db_privileges
652 || acl_get(thd, sctx->host().str, sctx->ip().str,
653 sctx->priv_user().str, db_name.c_str(), 0))
341 { 654 {
342 table->field[0]->store(db_name->str, db_name->length, 655 // We must make sure the schema is released and unlocked in the right
343 system_charset_info); 656 // order. Fail if we are unable to get a meta data lock on the schema
344 table->field[1]->store(table_data->name.str, table_data->name.length, 657 // name.
345 system_charset_info); 658 dd::Schema_MDL_locker mdl_handler(thd);
346 table->field[2]->store(table_data->size, TRUE); 659 if (mdl_handler.ensure_locked(db_name.c_str()))
347 if (schema_table_store_record(thd, table)) 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)
348 { 667 {
349 tables.delete_elements(); 668 if (res == 2) /* Not fatal error, continue */
669 continue;
350 goto err; 670 goto err;
351 } 671 }
672
673 for (auto &table_data : tables)
674 {
675 table->field[0]->store(db_name.c_str(), db_name.size(),
676 system_charset_info);
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 }
352 } 683 }
353 tables.delete_elements();
354 } 684 }
355 685
356 error = 0; 686 error = 0;
@@ -384,7 +714,8 @@ mysql_declare_plugin(table_sizes)
384 PLUGIN_LICENSE_GPL, /* license type */ 714 PLUGIN_LICENSE_GPL, /* license type */
385 init, /* init function */ 715 init, /* init function */
386 NULL, 716 NULL,
387 0x0507, /* version = 5.7 */ 717 NULL,
718 0x0800, /* version = 8.0 */
388 NULL, /* no status variables */ 719 NULL, /* no status variables */
389 NULL, /* no system variables */ 720 NULL, /* no system variables */
390 NULL, /* no reserved information */ 721 NULL, /* no reserved information */