diff options
Diffstat (limited to 'src/table_sizes.cc')
| -rw-r--r-- | src/table_sizes.cc | 647 |
1 files changed, 489 insertions, 158 deletions
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. */ | ||
| 40 | struct 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 */ | ||
| 54 | bool 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 | */ | ||
| 155 | struct 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 | ||
| 25 | typedef 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 | |||
| 198 | static 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 | |||
| 272 | static 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 | |||
| 316 | static 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 | ||
| 31 | bool 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 | ||
| 365 | static 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 | |||
| 36 | static int | 372 | static int |
| 37 | make_db_list(THD *thd, List<LEX_STRING> *db_names, | 373 | make_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 | ||
| 61 | struct 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 | */ |
| 421 | typedef std::map<dd::String_type, size_t> Table_sizes_map; | ||
| 80 | static find_files_result | 422 | static find_files_result |
| 81 | find_tables(THD *thd, List<TABLE_DATA> *tables, const char *db, | 423 | find_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 | ||
| 207 | static int | 536 | static int |
| 208 | make_table_list(THD *thd, List<TABLE_DATA> *table_names, LEX *lex, | 537 | make_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 */ |
