diff options
| author | manuel <manuel@mausz.at> | 2025-02-11 10:41:08 +0100 |
|---|---|---|
| committer | manuel <manuel@mausz.at> | 2025-02-11 10:41:08 +0100 |
| commit | 552a69076f8c93c3e3c57c0a26388faa162f9f46 (patch) | |
| tree | 226980b1cdd01ddce50f61219514f3b4c54a4104 | |
| parent | 5f13291f5e395eb45f792dbd769e0758cfd34e51 (diff) | |
| download | mysql-table_sizes-552a69076f8c93c3e3c57c0a26388faa162f9f46.tar.gz mysql-table_sizes-552a69076f8c93c3e3c57c0a26388faa162f9f46.tar.bz2 mysql-table_sizes-552a69076f8c93c3e3c57c0a26388faa162f9f46.zip | |
| -rw-r--r-- | CMakeLists.txt | 3 | ||||
| -rw-r--r-- | table_sizes.cc | 418 |
2 files changed, 211 insertions, 210 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 7392af9..e195e8d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
| @@ -1,5 +1,3 @@ | |||
| 1 | INCLUDE_DIRECTORIES(SYSTEM ${BOOST_PATCHES_DIR} ${BOOST_INCLUDE_DIR}) | ||
| 2 | |||
| 3 | MYSQL_ADD_PLUGIN(table_sizes | 1 | MYSQL_ADD_PLUGIN(table_sizes |
| 4 | table_sizes.cc | 2 | table_sizes.cc |
| 5 | MODULE_ONLY MODULE_OUTPUT_NAME "table_sizes" | 3 | MODULE_ONLY MODULE_OUTPUT_NAME "table_sizes" |
| @@ -7,3 +5,4 @@ MYSQL_ADD_PLUGIN(table_sizes | |||
| 7 | ) | 5 | ) |
| 8 | 6 | ||
| 9 | ADD_DEFINITIONS(-DMYSQL_SERVER) | 7 | ADD_DEFINITIONS(-DMYSQL_SERVER) |
| 8 | ADD_DEFINITIONS(-DLOG_COMPONENT_TAG="TABLE_SIZES") | ||
diff --git a/table_sizes.cc b/table_sizes.cc index ec8efc0..ef12d19 100644 --- a/table_sizes.cc +++ b/table_sizes.cc | |||
| @@ -13,8 +13,9 @@ | |||
| 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 | 15 | ||
| 16 | #include <mysql/plugin.h> | 16 | #include "mysql/components/my_service.h" |
| 17 | #include <boost/optional/optional.hpp> | 17 | #include "mysql/components/services/log_builtins.h" |
| 18 | #include "mysql/plugin.h" | ||
| 18 | 19 | ||
| 19 | #include "sql/mysqld.h" | 20 | #include "sql/mysqld.h" |
| 20 | #include "sql/sql_base.h" | 21 | #include "sql/sql_base.h" |
| @@ -30,10 +31,19 @@ | |||
| 30 | #include "sql/dd/string_type.h" // dd::String_type | 31 | #include "sql/dd/string_type.h" // dd::String_type |
| 31 | #include "sql/dd/sdi_file.h" // dd::sdi_file | 32 | #include "sql/dd/sdi_file.h" // dd::sdi_file |
| 32 | #include "sql/auth/auth_acls.h" // *_ACLS | 33 | #include "sql/auth/auth_acls.h" // *_ACLS |
| 33 | #include "sql/auth/auth_common.h" // check_grant_db | 34 | #include "sql/auth/auth_common.h" // check_access + check_grant_db |
| 34 | #include "mf_wcomp.h" // wild_compare,wild_one,wild_many | 35 | #include "mf_wcomp.h" // wild_compare,wild_one,wild_many |
| 35 | #include "my_dir.h" // MY_DIR | 36 | #include "my_dir.h" // MY_DIR |
| 36 | 37 | ||
| 38 | // MySQL 8.0 logger service interface | ||
| 39 | static SERVICE_TYPE(registry) *reg_srv = nullptr; | ||
| 40 | SERVICE_TYPE(log_builtins) *log_bi = nullptr; | ||
| 41 | SERVICE_TYPE(log_builtins_string) *log_bs = nullptr; | ||
| 42 | |||
| 43 | namespace table_sizes { | ||
| 44 | |||
| 45 | static const char *IS_TABLE_NAME = "TABLE_SIZES"; | ||
| 46 | |||
| 37 | // InnoDB FTS | 47 | // InnoDB FTS |
| 38 | /** For storing table info when checking for orphaned tables. */ | 48 | /** For storing table info when checking for orphaned tables. */ |
| 39 | struct fts_aux_table_t | 49 | struct fts_aux_table_t |
| @@ -60,23 +70,23 @@ bool fts_is_aux_table_name(fts_aux_table_t *table, const char *name, | |||
| 60 | /** FTS auxiliary table suffixes that are common to all FT indexes. */ | 70 | /** FTS auxiliary table suffixes that are common to all FT indexes. */ |
| 61 | const char *fts_common_tables[] = {"being_deleted", "being_deleted_cache", | 71 | const char *fts_common_tables[] = {"being_deleted", "being_deleted_cache", |
| 62 | "config", "deleted", | 72 | "config", "deleted", |
| 63 | "deleted_cache", NULL}; | 73 | "deleted_cache", nullptr}; |
| 64 | const char *fts_common_tables_5_7[] = {"BEING_DELETED", "BEING_DELETED_CACHE", | 74 | const char *fts_common_tables_5_7[] = {"BEING_DELETED", "BEING_DELETED_CACHE", |
| 65 | "CONFIG", "DELETED", | 75 | "CONFIG", "DELETED", |
| 66 | "DELETED_CACHE", NULL}; | 76 | "DELETED_CACHE", nullptr}; |
| 67 | 77 | ||
| 68 | /** FTS auxiliary INDEX split intervals. */ | 78 | /** FTS auxiliary INDEX split intervals. */ |
| 69 | const char *fts_index_selector[] = {"index_1", "index_2", "index_3", "index_4", | 79 | const char *fts_index_selector[] = {"index_1", "index_2", "index_3", "index_4", |
| 70 | "index_5", "index_6", NULL}; | 80 | "index_5", "index_6", nullptr}; |
| 71 | const char *fts_index_selector_5_7[] = {"INDEX_1", "INDEX_2", "INDEX_3", "INDEX_4", | 81 | const char *fts_index_selector_5_7[] = {"INDEX_1", "INDEX_2", "INDEX_3", "INDEX_4", |
| 72 | "INDEX_5", "INDEX_6", NULL}; | 82 | "INDEX_5", "INDEX_6", nullptr}; |
| 73 | 83 | ||
| 74 | const char *ptr = name; | 84 | const char *ptr = name; |
| 75 | const char *end = name + len; | 85 | const char *end = name + len; |
| 76 | 86 | ||
| 77 | /* All auxiliary tables are prefixed with "FTS_" and the name | 87 | /* All auxiliary tables are prefixed with "FTS_" and the name |
| 78 | length will be at the very least greater than 20 bytes. */ | 88 | length will be at the very least greater than 20 bytes. */ |
| 79 | if (ptr != NULL && len > 20 && | 89 | if (ptr != nullptr && len > 20 && |
| 80 | (strncmp(ptr, FTS_PREFIX, 4) == 0 || | 90 | (strncmp(ptr, FTS_PREFIX, 4) == 0 || |
| 81 | strncmp(ptr, FTS_PREFIX_5_7, 4) == 0)) | 91 | strncmp(ptr, FTS_PREFIX_5_7, 4) == 0)) |
| 82 | { | 92 | { |
| @@ -90,15 +100,19 @@ bool fts_is_aux_table_name(fts_aux_table_t *table, const char *name, | |||
| 90 | 100 | ||
| 91 | /* Skip the table id. */ | 101 | /* Skip the table id. */ |
| 92 | ptr = static_cast<const char *>(memchr(ptr, '_', len)); | 102 | ptr = static_cast<const char *>(memchr(ptr, '_', len)); |
| 93 | if (ptr == NULL) | 103 | if (ptr == nullptr) |
| 94 | return false; | 104 | return false; |
| 95 | 105 | ||
| 96 | /* Skip the underscore. */ | 106 | /* Skip the underscore. */ |
| 97 | ++ptr; | 107 | ++ptr; |
| 98 | len = end - ptr; | 108 | len = end - ptr; |
| 99 | 109 | ||
| 110 | /* It's not enough to be a FTS auxiliary table name */ | ||
| 111 | if (len == 0) | ||
| 112 | return false; | ||
| 113 | |||
| 100 | /* First search the common table suffix array. */ | 114 | /* First search the common table suffix array. */ |
| 101 | for (int i = 0; fts_common_tables[i] != NULL; ++i) { | 115 | for (int i = 0; fts_common_tables[i] != nullptr; ++i) { |
| 102 | if (strncmp(ptr, fts_common_tables[i], len) == 0 || | 116 | if (strncmp(ptr, fts_common_tables[i], len) == 0 || |
| 103 | strncmp(ptr, fts_common_tables_5_7[i], len) == 0) { | 117 | strncmp(ptr, fts_common_tables_5_7[i], len) == 0) { |
| 104 | return true; | 118 | return true; |
| @@ -118,15 +132,19 @@ bool fts_is_aux_table_name(fts_aux_table_t *table, const char *name, | |||
| 118 | /* Skip the index id. */ | 132 | /* Skip the index id. */ |
| 119 | ptr = static_cast<const char *>(memchr(ptr, '_', len)); | 133 | ptr = static_cast<const char *>(memchr(ptr, '_', len)); |
| 120 | 134 | ||
| 121 | if (ptr == NULL) | 135 | if (ptr == nullptr) |
| 122 | return false; | 136 | return false; |
| 123 | 137 | ||
| 124 | /* Skip the underscore. */ | 138 | /* Skip the underscore. */ |
| 125 | ++ptr; | 139 | ++ptr; |
| 126 | len = end - ptr; | 140 | len = end - ptr; |
| 127 | 141 | ||
| 142 | /* It's not enough to be a FTS auxiliary table name */ | ||
| 143 | if (len == 0) | ||
| 144 | return false; | ||
| 145 | |||
| 128 | /* Search the FT index specific array. */ | 146 | /* Search the FT index specific array. */ |
| 129 | for (int i = 0; fts_index_selector[i] != NULL; ++i) { | 147 | for (int i = 0; fts_index_selector[i] != nullptr; ++i) { |
| 130 | if (strncmp(ptr, fts_index_selector[i], len) == 0 || | 148 | if (strncmp(ptr, fts_index_selector[i], len) == 0 || |
| 131 | strncmp(ptr, fts_index_selector_5_7[i], len) == 0) { | 149 | strncmp(ptr, fts_index_selector_5_7[i], len) == 0) { |
| 132 | return true; | 150 | return true; |
| @@ -143,58 +161,27 @@ bool fts_is_aux_table_name(fts_aux_table_t *table, const char *name, | |||
| 143 | 161 | ||
| 144 | /*----------------------------------------------------------------------------*/ | 162 | /*----------------------------------------------------------------------------*/ |
| 145 | 163 | ||
| 146 | /** | ||
| 147 | Condition pushdown used for INFORMATION_SCHEMA / SHOW queries. | ||
| 148 | This structure is to implement an optimization when | ||
| 149 | accessing data dictionary data in the INFORMATION_SCHEMA | ||
| 150 | or SHOW commands. | ||
| 151 | When the query contain a TABLE_SCHEMA or TABLE_NAME clause, | ||
| 152 | narrow the search for data based on the constraints given. | ||
| 153 | */ | ||
| 154 | struct LOOKUP_FIELD_VALUES { | 164 | struct LOOKUP_FIELD_VALUES { |
| 155 | /** | 165 | std::map<dd::String_type, bool> db_values; |
| 156 | Value of a TABLE_SCHEMA clause. | 166 | std::map<dd::String_type, bool> table_values; |
| 157 | Note that this value length may exceed @c NAME_LEN. | ||
| 158 | */ | ||
| 159 | boost::optional<dd::String_type> db_value; | ||
| 160 | /** | ||
| 161 | Value of a TABLE_NAME clause. | ||
| 162 | Note that this value length may exceed @c NAME_LEN. | ||
| 163 | */ | ||
| 164 | boost::optional<dd::String_type> table_value; | ||
| 165 | }; | 167 | }; |
| 166 | 168 | ||
| 167 | /** | 169 | static bool get_lookup_value(THD *thd, Item_func *item_func, Table_ref *table, |
| 168 | @brief Get lookup value from the part of 'WHERE' condition | ||
| 169 | |||
| 170 | @details This function gets lookup value from | ||
| 171 | the part of 'WHERE' condition if it's possible and | ||
| 172 | fill appropriate lookup_field_vals struct field | ||
| 173 | with this value. | ||
| 174 | |||
| 175 | @param[in] thd thread handler | ||
| 176 | @param[in] item_func part of WHERE condition | ||
| 177 | @param[in] table I_S table | ||
| 178 | @param[in, out] lookup_field_vals Struct which holds lookup values | ||
| 179 | |||
| 180 | @return | ||
| 181 | 0 success | ||
| 182 | 1 error, there can be no matching records for the condition | ||
| 183 | */ | ||
| 184 | |||
| 185 | static bool get_lookup_value(Item_func *item_func, Table_ref *table, | ||
| 186 | LOOKUP_FIELD_VALUES *lookup_field_vals) | 170 | LOOKUP_FIELD_VALUES *lookup_field_vals) |
| 187 | { | 171 | { |
| 188 | ST_SCHEMA_TABLE *schema_table = table->schema_table; | 172 | ST_SCHEMA_TABLE *schema_table = table->schema_table; |
| 189 | ST_FIELD_INFO *field_info = schema_table->fields_info; | 173 | ST_FIELD_INFO *field_info = schema_table->fields_info; |
| 190 | 174 | ||
| 175 | String foo; | ||
| 176 | item_func->print(thd, &foo, QT_ORDINARY); | ||
| 177 | |||
| 191 | if (item_func->functype() == Item_func::EQ_FUNC || | 178 | if (item_func->functype() == Item_func::EQ_FUNC || |
| 192 | item_func->functype() == Item_func::EQUAL_FUNC) { | 179 | item_func->functype() == Item_func::EQUAL_FUNC || |
| 180 | item_func->functype() == Item_func::LIKE_FUNC) { | ||
| 193 | int idx_field, idx_val; | 181 | int idx_field, idx_val; |
| 194 | char tmp[MAX_FIELD_WIDTH]; | 182 | char tmp[MAX_FIELD_WIDTH]; |
| 195 | String *tmp_str, str_buff(tmp, sizeof(tmp), system_charset_info); | 183 | String *tmp_str, str_buf(tmp, sizeof(tmp), system_charset_info); |
| 196 | Item_field *item_field; | 184 | bool is_wildcard = (item_func->functype() == Item_func::LIKE_FUNC); |
| 197 | CHARSET_INFO *cs = system_charset_info; | ||
| 198 | 185 | ||
| 199 | if (item_func->arguments()[0]->type() == Item::FIELD_ITEM && | 186 | if (item_func->arguments()[0]->type() == Item::FIELD_ITEM && |
| 200 | item_func->arguments()[1]->const_item()) { | 187 | item_func->arguments()[1]->const_item()) { |
| @@ -207,109 +194,93 @@ static bool get_lookup_value(Item_func *item_func, Table_ref *table, | |||
| 207 | } else | 194 | } else |
| 208 | return 0; | 195 | return 0; |
| 209 | 196 | ||
| 210 | item_field = (Item_field *)item_func->arguments()[idx_field]; | 197 | Item_field *item_field = (Item_field *)item_func->arguments()[idx_field]; |
| 211 | if (table->table != item_field->field->table) return 0; | 198 | if (table->table != item_field->field->table) |
| 212 | tmp_str = item_func->arguments()[idx_val]->val_str(&str_buff); | 199 | return 0; |
| 213 | 200 | ||
| 214 | /* impossible value */ | 201 | tmp_str = item_func->arguments()[idx_val]->val_str(&str_buf); |
| 215 | if (!tmp_str) return 1; | 202 | if (!tmp_str || !tmp_str->length()) |
| 203 | return 0; | ||
| 204 | if (lower_case_table_names && files_charset_info->casedn_multiply == 1) | ||
| 205 | my_casedn_str(files_charset_info, tmp_str->c_ptr_quick()); | ||
| 216 | 206 | ||
| 217 | /* Lookup value is database name */ | 207 | if (my_strcasecmp(system_charset_info, item_field->field_name, |
| 218 | if (!cs->coll->strnncollsp(cs, (const uchar *)field_info[0].field_name, | 208 | field_info[0].field_name) == 0) { |
| 219 | strlen(field_info[0].field_name), | 209 | /* Lookup value is database name */ |
| 220 | (const uchar *)item_field->field_name, | 210 | lookup_field_vals->db_values[dd::String_type(tmp_str->ptr(), tmp_str->length())] = is_wildcard; |
| 221 | strlen(item_field->field_name))) { | ||
| 222 | lookup_field_vals->db_value.emplace(tmp_str->ptr(), tmp_str->length()); | ||
| 223 | } | 211 | } |
| 224 | /* Lookup value is table name */ | 212 | else if (my_strcasecmp(system_charset_info, item_field->field_name, |
| 225 | else if (!cs->coll->strnncollsp(cs, (const uchar *)field_info[1].field_name, | 213 | field_info[1].field_name) == 0) { |
| 226 | strlen(field_info[1].field_name), | 214 | /* Lookup value is table name */ |
| 227 | (const uchar *)item_field->field_name, | 215 | lookup_field_vals->table_values[dd::String_type(tmp_str->ptr(), tmp_str->length())] = is_wildcard; |
| 228 | strlen(item_field->field_name))) { | ||
| 229 | lookup_field_vals->table_value.emplace(tmp_str->ptr(), tmp_str->length()); | ||
| 230 | } | 216 | } |
| 231 | } | 217 | } |
| 232 | return 0; | 218 | else if (item_func->functype() == Item_func::IN_FUNC) |
| 233 | } | 219 | { |
| 220 | Item_func_in *in_func = static_cast<Item_func_in *>(item_func); | ||
| 221 | char tmp[MAX_FIELD_WIDTH]; | ||
| 222 | String *tmp_str, str_buf(tmp, sizeof(tmp), system_charset_info); | ||
| 223 | |||
| 224 | if (in_func->arguments()[0]->type() != Item::FIELD_ITEM) | ||
| 225 | return 0; | ||
| 226 | |||
| 227 | Item_field *item_field = (Item_field *)in_func->arguments()[0]; | ||
| 228 | if (table->table != item_field->field->table) | ||
| 229 | return 0; | ||
| 234 | 230 | ||
| 235 | /** | 231 | for (uint i = 1; i < in_func->arg_count; ++i) |
| 236 | @brief Calculates lookup values from 'WHERE' condition | 232 | { |
| 233 | if (in_func->arguments()[i] == nullptr) | ||
| 234 | continue; | ||
| 237 | 235 | ||
| 238 | @details This function calculates lookup value(database name, table name) | 236 | tmp_str = in_func->arguments()[i]->val_str(&str_buf); |
| 239 | from 'WHERE' condition if it's possible and | 237 | if (!tmp_str || !tmp_str->length()) |
| 240 | fill lookup_field_vals struct fields with these values. | 238 | continue; |
| 239 | if (lower_case_table_names && files_charset_info->casedn_multiply == 1) | ||
| 240 | my_casedn_str(files_charset_info, tmp_str->c_ptr_quick()); | ||
| 241 | 241 | ||
| 242 | @param[in] thd thread handler | 242 | /* Lookup value is database name */ |
| 243 | @param[in] cond WHERE condition | 243 | if (my_strcasecmp(system_charset_info, item_field->field_name, |
| 244 | @param[in] table I_S table | 244 | field_info[0].field_name) == 0) { |
| 245 | @param[in, out] lookup_field_vals Struct which holds lookup values | 245 | lookup_field_vals->db_values[dd::String_type(tmp_str->ptr(), tmp_str->length())] = false; |
| 246 | } | ||
| 247 | else if (my_strcasecmp(system_charset_info, item_field->field_name, | ||
| 248 | field_info[1].field_name) == 0) { | ||
| 249 | lookup_field_vals->table_values[dd::String_type(tmp_str->ptr(), tmp_str->length())] = false; | ||
| 250 | } | ||
| 251 | } | ||
| 252 | } | ||
| 246 | 253 | ||
| 247 | @return | 254 | return 0; |
| 248 | 0 success | 255 | } |
| 249 | 1 error, there can be no matching records for the condition | ||
| 250 | */ | ||
| 251 | 256 | ||
| 252 | static bool calc_lookup_values_from_cond(Item *cond, | 257 | static bool calc_lookup_values_from_cond(THD *thd, Item *cond, |
| 253 | Table_ref *table, LOOKUP_FIELD_VALUES *lookup_field_vals) | 258 | Table_ref *table, LOOKUP_FIELD_VALUES *lookup_field_vals) |
| 254 | { | 259 | { |
| 255 | if (!cond) return 0; | 260 | if (!cond) return 0; |
| 256 | 261 | ||
| 257 | if (cond->type() == Item::COND_ITEM) { | 262 | if (cond->type() == Item::COND_ITEM) { |
| 258 | if (((Item_cond *)cond)->functype() == Item_func::COND_AND_FUNC) { | 263 | auto func_type = ((Item_cond *)cond)->functype(); |
| 264 | if (func_type == Item_func::COND_AND_FUNC) { | ||
| 259 | List_iterator<Item> li(*((Item_cond *)cond)->argument_list()); | 265 | List_iterator<Item> li(*((Item_cond *)cond)->argument_list()); |
| 260 | Item *item; | 266 | Item *item; |
| 261 | while ((item = li++)) { | 267 | while ((item = li++)) { |
| 262 | if (item->type() == Item::FUNC_ITEM) { | 268 | if (item->type() == Item::FUNC_ITEM) { |
| 263 | if (get_lookup_value((Item_func *)item, table, lookup_field_vals)) | 269 | if (get_lookup_value(thd, (Item_func *)item, table, lookup_field_vals)) |
| 264 | return 1; | 270 | return 1; |
| 265 | } else { | 271 | } else { |
| 266 | if (calc_lookup_values_from_cond(item, table, lookup_field_vals)) | 272 | if (calc_lookup_values_from_cond(thd, item, table, lookup_field_vals)) |
| 267 | return 1; | 273 | return 1; |
| 268 | } | 274 | } |
| 269 | } | 275 | } |
| 270 | } | 276 | } |
| 271 | return 0; | 277 | return 0; |
| 272 | } else if (cond->type() == Item::FUNC_ITEM && | 278 | } else if (cond->type() == Item::FUNC_ITEM && |
| 273 | get_lookup_value((Item_func *)cond, table, lookup_field_vals)) | 279 | get_lookup_value(thd, (Item_func *)cond, table, lookup_field_vals)) |
| 274 | return 1; | 280 | return 1; |
| 275 | return 0; | 281 | return 0; |
| 276 | } | 282 | } |
| 277 | 283 | ||
| 278 | /** | ||
| 279 | @brief Calculate lookup values(database name, table name) | ||
| 280 | |||
| 281 | @details This function calculates lookup values(database name, table name) | ||
| 282 | from 'WHERE' condition and fill lookup_field_vals struct field | ||
| 283 | with these values. | ||
| 284 | |||
| 285 | @param[in] cond WHERE condition | ||
| 286 | @param[in] tables I_S table | ||
| 287 | @param[in, out] lookup_field_vals Struct which holds lookup values | ||
| 288 | |||
| 289 | @return | ||
| 290 | 0 success | ||
| 291 | 1 error, there can be no matching records for the condition | ||
| 292 | */ | ||
| 293 | |||
| 294 | static bool get_lookup_field_values(Item *cond, Table_ref *tables, | ||
| 295 | LOOKUP_FIELD_VALUES *lookup_field_vals) | ||
| 296 | { | ||
| 297 | bool rc = calc_lookup_values_from_cond(cond, tables, lookup_field_vals); | ||
| 298 | |||
| 299 | if (lower_case_table_names && !rc) { | ||
| 300 | /* | ||
| 301 | We can safely do in-place upgrades here since all of the above cases | ||
| 302 | are allocating a new memory buffer for these strings. | ||
| 303 | */ | ||
| 304 | if (lookup_field_vals->db_value && !lookup_field_vals->db_value->empty()) | ||
| 305 | casedn(system_charset_info, *lookup_field_vals->db_value); | ||
| 306 | if (lookup_field_vals->table_value && !lookup_field_vals->table_value->empty()) | ||
| 307 | casedn(system_charset_info, *lookup_field_vals->table_value); | ||
| 308 | } | ||
| 309 | |||
| 310 | return rc; | ||
| 311 | } | ||
| 312 | |||
| 313 | /*----------------------------------------------------------------------------*/ | 284 | /*----------------------------------------------------------------------------*/ |
| 314 | 285 | ||
| 315 | static bool is_special_db(const dd::String_type &db_name) | 286 | static bool is_special_db(const dd::String_type &db_name) |
| @@ -319,33 +290,9 @@ static bool is_special_db(const dd::String_type &db_name) | |||
| 319 | || is_perfschema_db(db_name.c_str(), db_name.size()); | 290 | || is_perfschema_db(db_name.c_str(), db_name.size()); |
| 320 | } | 291 | } |
| 321 | 292 | ||
| 322 | /** | ||
| 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, | 293 | static int make_db_list(THD *thd, std::vector<dd::String_type> *db_names, |
| 332 | LOOKUP_FIELD_VALUES *lookup_field_vals) | 294 | LOOKUP_FIELD_VALUES *lookup_field_vals) |
| 333 | { | 295 | { |
| 334 | /* | ||
| 335 | If we have db lookup value we just add it to list and | ||
| 336 | exit from the function. | ||
| 337 | We don't do this for database names longer than the maximum | ||
| 338 | path length. | ||
| 339 | */ | ||
| 340 | if (lookup_field_vals->db_value | ||
| 341 | && lookup_field_vals->db_value->length() <= NAME_LEN) | ||
| 342 | { | ||
| 343 | const dd::String_type &db_name = lookup_field_vals->db_value.get(); | ||
| 344 | if (!is_special_db(db_name)) | ||
| 345 | db_names->push_back(db_name); | ||
| 346 | return 0; | ||
| 347 | } | ||
| 348 | |||
| 349 | dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client()); | 296 | dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client()); |
| 350 | std::vector<const dd::Schema *> schemas; | 297 | std::vector<const dd::Schema *> schemas; |
| 351 | if (thd->dd_client()->fetch_global_components(&schemas)) | 298 | if (thd->dd_client()->fetch_global_components(&schemas)) |
| @@ -354,28 +301,34 @@ static int make_db_list(THD *thd, std::vector<dd::String_type> *db_names, | |||
| 354 | for (const dd::Schema *schema_obj : schemas) | 301 | for (const dd::Schema *schema_obj : schemas) |
| 355 | { | 302 | { |
| 356 | const dd::String_type &db_name = schema_obj->name(); | 303 | const dd::String_type &db_name = schema_obj->name(); |
| 357 | if (is_special_db(db_name)) | 304 | if (db_name.length() > NAME_LEN || is_special_db(db_name)) |
| 358 | continue; | 305 | continue; |
| 359 | db_names->push_back(db_name); | 306 | bool match = true; |
| 307 | for (auto &db_value : lookup_field_vals->db_values) | ||
| 308 | { | ||
| 309 | dd::String_type wildx = db_value.first; | ||
| 310 | match = (db_value.second) | ||
| 311 | ? (lower_case_table_names) | ||
| 312 | ? !my_wildcmp(files_charset_info, | ||
| 313 | db_name.c_str(), db_name.c_str() + db_name.length(), | ||
| 314 | wildx.c_str(), wildx.c_str() + wildx.length(), | ||
| 315 | wild_prefix, wild_one, wild_many) | ||
| 316 | : !wild_compare(db_name.c_str(), db_name.length(), wildx.c_str(), wildx.length(), 0) | ||
| 317 | : (my_strcasecmp(files_charset_info, db_name.c_str(), wildx.c_str()) == 0); | ||
| 318 | if (match) | ||
| 319 | break; | ||
| 320 | } | ||
| 321 | if (match) | ||
| 322 | db_names->push_back(db_name); | ||
| 360 | } | 323 | } |
| 361 | return 0; | 324 | return 0; |
| 362 | } | 325 | } |
| 363 | 326 | ||
| 364 | /*----------------------------------------------------------------------------*/ | 327 | /*----------------------------------------------------------------------------*/ |
| 365 | 328 | ||
| 366 | /** | ||
| 367 | Find files in a given directory. | ||
| 368 | |||
| 369 | @param thd thread handler | ||
| 370 | @param tables put found files in this list | ||
| 371 | @param db_name filter for found files | ||
| 372 | @param wild filter for found files | ||
| 373 | |||
| 374 | @return true if error, false otherwise | ||
| 375 | */ | ||
| 376 | typedef std::map<dd::String_type, size_t> Table_sizes_map; | 329 | typedef std::map<dd::String_type, size_t> Table_sizes_map; |
| 377 | bool find_tables(THD *thd, Table_sizes_map &tables, | 330 | static bool find_tables(THD *thd, Table_sizes_map &tables, |
| 378 | Table_ref &db_data, boost::optional<dd::String_type> &wild) | 331 | Table_ref &db_data, std::map<dd::String_type, bool> &wild) |
| 379 | { | 332 | { |
| 380 | MY_DIR *dirp; | 333 | MY_DIR *dirp; |
| 381 | DBUG_ENTER("find_files"); | 334 | DBUG_ENTER("find_files"); |
| @@ -396,6 +349,10 @@ bool find_tables(THD *thd, Table_sizes_map &tables, | |||
| 396 | return true; | 349 | return true; |
| 397 | } | 350 | } |
| 398 | 351 | ||
| 352 | /* check global privilege */ | ||
| 353 | bool has_global_show = (thd->security_context() | ||
| 354 | ->master_access(db_data.db) & (DB_OP_ACLS | SHOW_DB_ACL)); | ||
| 355 | |||
| 399 | char uname[NAME_LEN + 1]; /* Unencoded name */ | 356 | char uname[NAME_LEN + 1]; /* Unencoded name */ |
| 400 | dd::String_type fts_schema_name, fts_table_name; /* FTS lookup */ | 357 | dd::String_type fts_schema_name, fts_table_name; /* FTS lookup */ |
| 401 | std::map<dd::Object_id, dd::String_type> fts_cache; | 358 | std::map<dd::Object_id, dd::String_type> fts_cache; |
| @@ -444,19 +401,23 @@ bool find_tables(THD *thd, Table_sizes_map &tables, | |||
| 444 | continue; | 401 | continue; |
| 445 | } | 402 | } |
| 446 | 403 | ||
| 447 | if (wild) | 404 | bool match = true; |
| 405 | for (auto &wild_entry : wild) | ||
| 448 | { | 406 | { |
| 449 | if (lower_case_table_names) | 407 | dd::String_type wildx = wild_entry.first; |
| 450 | { | 408 | match = (wild_entry.second) |
| 451 | if (my_wildcmp(files_charset_info, | 409 | ? (lower_case_table_names) |
| 452 | uname, uname + file_name_len, | 410 | ? !my_wildcmp(files_charset_info, |
| 453 | wild->c_str(), wild->c_str() + wild->length(), | 411 | uname, uname + file_name_len, |
| 454 | wild_prefix, wild_one, wild_many)) | 412 | wildx.c_str(), wildx.c_str() + wildx.length(), |
| 455 | continue; | 413 | wild_prefix, wild_one, wild_many) |
| 456 | } | 414 | : !wild_compare(uname, file_name_len, wildx.c_str(), wildx.length(), 0) |
| 457 | else if (wild_compare(uname, file_name_len, wild->c_str(), wild->length(), 0)) | 415 | : (my_strcasecmp(files_charset_info, uname, wildx.c_str()) == 0); |
| 458 | continue; | 416 | if (match) |
| 417 | break; | ||
| 459 | } | 418 | } |
| 419 | if (!match) | ||
| 420 | continue; | ||
| 460 | 421 | ||
| 461 | /* | 422 | /* |
| 462 | Check_grant will grant access if there is any column privileges on | 423 | Check_grant will grant access if there is any column privileges on |
| @@ -464,7 +425,7 @@ bool find_tables(THD *thd, Table_sizes_map &tables, | |||
| 464 | */ | 425 | */ |
| 465 | db_data.table_name = uname; | 426 | db_data.table_name = uname; |
| 466 | db_data.table_name_length = file_name_len; | 427 | db_data.table_name_length = file_name_len; |
| 467 | if (check_grant(thd, SELECT_ACL, &db_data, true, 1, true)) | 428 | if (!has_global_show && check_grant(thd, SELECT_ACL, &db_data, true, 1, true)) |
| 468 | continue; | 429 | continue; |
| 469 | 430 | ||
| 470 | tables.emplace(uname, file->mystat->st_size); | 431 | tables.emplace(uname, file->mystat->st_size); |
| @@ -479,11 +440,11 @@ bool find_tables(THD *thd, Table_sizes_map &tables, | |||
| 479 | static bool make_table_list(THD *thd, Table_sizes_map &table_names, | 440 | static bool make_table_list(THD *thd, Table_sizes_map &table_names, |
| 480 | LOOKUP_FIELD_VALUES *lookup_field_vals, Table_ref &db_data) | 441 | LOOKUP_FIELD_VALUES *lookup_field_vals, Table_ref &db_data) |
| 481 | { | 442 | { |
| 482 | const dd::Schema *sch_obj = NULL; | 443 | const dd::Schema *sch_obj = nullptr; |
| 483 | if (thd->dd_client()->acquire(db_data.db, &sch_obj) || !sch_obj) | 444 | if (thd->dd_client()->acquire(db_data.db, &sch_obj) || !sch_obj) |
| 484 | return 1; | 445 | return 1; |
| 485 | 446 | ||
| 486 | return find_tables(thd, table_names, db_data, lookup_field_vals->table_value); | 447 | return find_tables(thd, table_names, db_data, lookup_field_vals->table_values); |
| 487 | } | 448 | } |
| 488 | 449 | ||
| 489 | /*----------------------------------------------------------------------------*/ | 450 | /*----------------------------------------------------------------------------*/ |
| @@ -497,22 +458,39 @@ static ST_FIELD_INFO fields_info[] = | |||
| 497 | {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0} | 458 | {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0} |
| 498 | }; | 459 | }; |
| 499 | 460 | ||
| 461 | static bool can_access_database(THD *thd, Table_ref &db_data) | ||
| 462 | { | ||
| 463 | Security_context *sctx = thd->security_context(); | ||
| 464 | |||
| 465 | /* check global privileges */ | ||
| 466 | if (sctx->master_access(db_data.db) & (DB_OP_ACLS | SHOW_DB_ACL)) | ||
| 467 | return true; | ||
| 468 | |||
| 469 | /* check db privileges */ | ||
| 470 | Access_bitmask db_access = sctx->check_db_level_access(thd, db_data.db, db_data.db_length); | ||
| 471 | //if (check_access(thd, SELECT_ACL, db_data.db, &db_access, nullptr, false, true)) | ||
| 472 | // return false; | ||
| 473 | if (db_access) { | ||
| 474 | db_data.grant.privilege = db_access; | ||
| 475 | return true; | ||
| 476 | } | ||
| 477 | |||
| 478 | /* check specific table privileges */ | ||
| 479 | if (!check_grant_db(thd, db_data.db)) | ||
| 480 | return true; | ||
| 481 | |||
| 482 | return false; | ||
| 483 | } | ||
| 484 | |||
| 500 | static int fill_table(THD *thd, Table_ref *tables, Item *cond) | 485 | static int fill_table(THD *thd, Table_ref *tables, Item *cond) |
| 501 | { | 486 | { |
| 502 | TABLE *table = tables->table; | 487 | TABLE *table = tables->table; |
| 503 | LOOKUP_FIELD_VALUES lookup_field_vals; | 488 | LOOKUP_FIELD_VALUES lookup_field_vals = {}; |
| 504 | std::vector<dd::String_type> db_names; | 489 | std::vector<dd::String_type> db_names; |
| 505 | 490 | ||
| 506 | DBUG_ENTER("fill_table"); | 491 | if (calc_lookup_values_from_cond(thd, cond, tables, &lookup_field_vals)) |
| 507 | |||
| 508 | if (get_lookup_field_values(cond, tables, &lookup_field_vals)) | ||
| 509 | return 0; | 492 | return 0; |
| 510 | 493 | ||
| 511 | #define STR_OR_NIL(S) ((S) ? (S->c_str()) : "<nil>") | ||
| 512 | DBUG_PRINT("INDEX VALUES", ("db_name='%s', table_name='%s'", | ||
| 513 | STR_OR_NIL(lookup_field_vals.db_value), | ||
| 514 | STR_OR_NIL(lookup_field_vals.table_value))); | ||
| 515 | |||
| 516 | /* EXPLAIN SELECT */ | 494 | /* EXPLAIN SELECT */ |
| 517 | if (thd->lex->is_explain()) | 495 | if (thd->lex->is_explain()) |
| 518 | return 0; | 496 | return 0; |
| @@ -528,13 +506,7 @@ static int fill_table(THD *thd, Table_ref *tables, Item *cond) | |||
| 528 | db_data.db_length = db_name.length(); | 506 | db_data.db_length = db_name.length(); |
| 529 | db_data.grant.privilege = 0; | 507 | db_data.grant.privilege = 0; |
| 530 | 508 | ||
| 531 | // Get user's global and db-level privileges. | 509 | if (!can_access_database(thd, db_data)) |
| 532 | if (check_access(thd, SELECT_ACL, db_data.db, &db_data.grant.privilege, NULL, false, true)) | ||
| 533 | continue; | ||
| 534 | |||
| 535 | // Now check, if user has access on global level or to any of database/ | ||
| 536 | // table/column/routine. | ||
| 537 | if (!(db_data.grant.privilege & DB_OP_ACLS) && check_grant_db(thd, db_data.db)) | ||
| 538 | continue; | 510 | continue; |
| 539 | 511 | ||
| 540 | // We must make sure the schema is released and unlocked in the right | 512 | // We must make sure the schema is released and unlocked in the right |
| @@ -565,33 +537,63 @@ static int fill_table(THD *thd, Table_ref *tables, Item *cond) | |||
| 565 | return 0; | 537 | return 0; |
| 566 | } | 538 | } |
| 567 | 539 | ||
| 568 | static int init(void *ptr) | 540 | static int view_init(void *ptr) |
| 569 | { | 541 | { |
| 542 | if (init_logging_service_for_plugin(®_srv, &log_bi, &log_bs)) | ||
| 543 | return 1; | ||
| 544 | |||
| 545 | LogErr(INFORMATION_LEVEL, ER_LOG_PRINTF_MSG, | ||
| 546 | "Plugin table_sizes initializing..."); | ||
| 547 | |||
| 548 | if (reg_srv == nullptr) | ||
| 549 | { | ||
| 550 | LogPluginErrMsg(ERROR_LEVEL, ER_LOG_PRINTF_MSG, "reg_srv is NULL in init"); | ||
| 551 | return 1; | ||
| 552 | } | ||
| 553 | |||
| 570 | ST_SCHEMA_TABLE *schema_table = (ST_SCHEMA_TABLE*)ptr; | 554 | ST_SCHEMA_TABLE *schema_table = (ST_SCHEMA_TABLE*)ptr; |
| 571 | 555 | ||
| 572 | schema_table->fields_info = fields_info; | 556 | schema_table->table_name = IS_TABLE_NAME; |
| 573 | schema_table->fill_table = fill_table; | 557 | schema_table->fields_info = fields_info; |
| 558 | schema_table->fill_table = fill_table; | ||
| 559 | schema_table->old_format = nullptr; | ||
| 560 | schema_table->process_table = nullptr; | ||
| 561 | return 0; | ||
| 562 | } | ||
| 563 | |||
| 564 | static int view_deinit(void *) | ||
| 565 | { | ||
| 566 | LogPluginErrMsg(INFORMATION_LEVEL, ER_LOG_PRINTF_MSG, | ||
| 567 | "Plugin table_sizes de-initializing..."); | ||
| 568 | |||
| 569 | if (reg_srv == nullptr) | ||
| 570 | LogPluginErrMsg(ERROR_LEVEL, ER_LOG_PRINTF_MSG, "reg_srv is NULL in deinit"); | ||
| 571 | else | ||
| 572 | deinit_logging_service_for_plugin(®_srv, &log_bi, &log_bs); | ||
| 573 | |||
| 574 | return 0; | 574 | return 0; |
| 575 | } | 575 | } |
| 576 | 576 | ||
| 577 | static struct st_mysql_information_schema info = | 577 | static struct st_mysql_information_schema info = |
| 578 | { MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION }; | 578 | { MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION }; |
| 579 | 579 | ||
| 580 | } // namespace table_sizes | ||
| 581 | |||
| 580 | mysql_declare_plugin(table_sizes) | 582 | mysql_declare_plugin(table_sizes) |
| 581 | { | 583 | { |
| 582 | MYSQL_INFORMATION_SCHEMA_PLUGIN, | 584 | MYSQL_INFORMATION_SCHEMA_PLUGIN, /* type */ |
| 583 | &info, /* type-specific descriptor */ | 585 | &table_sizes::info, /* descriptor */ |
| 584 | "TABLE_SIZES", /* table name */ | 586 | table_sizes::IS_TABLE_NAME, /* name */ |
| 585 | "Manuel Mausz", /* author */ | 587 | "Manuel Mausz", /* author */ |
| 586 | "Fast INFORMATION_SCHEMA table sizes", /* description */ | 588 | "Fast INFORMATION_SCHEMA table sizes", /* description */ |
| 587 | PLUGIN_LICENSE_GPL, /* license type */ | 589 | PLUGIN_LICENSE_GPL, /* plugin license */ |
| 588 | init, /* init function */ | 590 | table_sizes::view_init, /* init function (when loaded) */ |
| 589 | NULL, | 591 | nullptr, /* check uninstall function */ |
| 590 | NULL, | 592 | table_sizes::view_deinit, /* deinit function (when unloaded) */ |
| 591 | 0x0800, /* version = 8.0 */ | 593 | 0x0840, /* version = 8.4 */ |
| 592 | NULL, /* no status variables */ | 594 | nullptr, /* status variables */ |
| 593 | NULL, /* no system variables */ | 595 | nullptr, /* system variables */ |
| 594 | NULL, /* no reserved information */ | 596 | nullptr, /* reserved information */ |
| 595 | 0 /* no flags */ | 597 | 0 /* flags */ |
| 596 | } | 598 | } |
| 597 | mysql_declare_plugin_end; | 599 | mysql_declare_plugin_end; |
