summaryrefslogtreecommitdiffstats
path: root/src/table_sizes.cc
diff options
context:
space:
mode:
authormanuel <manuel@mausz.at>2013-02-11 14:23:16 +0100
committermanuel <manuel@mausz.at>2013-02-11 14:23:16 +0100
commitbcff4f2e3520eaf170c282ba03d38ba6a4fa95cf (patch)
treeae902d4d88bae4611f2391fd800cbdbc5a6a0b50 /src/table_sizes.cc
downloadmysql-table_sizes-bcff4f2e3520eaf170c282ba03d38ba6a4fa95cf.tar.gz
mysql-table_sizes-bcff4f2e3520eaf170c282ba03d38ba6a4fa95cf.tar.bz2
mysql-table_sizes-bcff4f2e3520eaf170c282ba03d38ba6a4fa95cf.zip
initial import
Diffstat (limited to 'src/table_sizes.cc')
-rw-r--r--src/table_sizes.cc368
1 files changed, 368 insertions, 0 deletions
diff --git a/src/table_sizes.cc b/src/table_sizes.cc
new file mode 100644
index 0000000..b1fd8b0
--- /dev/null
+++ b/src/table_sizes.cc
@@ -0,0 +1,368 @@
1/*
2 This program is free software; you can redistribute it and/or modify
3 it under the terms of the GNU General Public License as published by
4 the Free Software Foundation; version 2 of the License.
5
6 This program is distributed in the hope that it will be useful,
7 but WITHOUT ANY WARRANTY; without even the implied warranty of
8 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 GNU General Public License for more details.
10
11 You should have received a copy of the GNU General Public License
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
14*/
15#include "mysql_inc.h"
16#include <sql/sql_show.h>
17#include <sql/sql_table.h>
18#include <sql/sql_parse.h>
19#include <sql/sql_db.h>
20
21#define STR_OR_NIL(S) ((S) ? (S) : "<nil>")
22
23typedef struct st_lookup_field_values
24{
25 LEX_STRING db_value, table_value;
26 bool wild_db_value, wild_table_value;
27} LOOKUP_FIELD_VALUES;
28
29bool calc_lookup_values_from_cond(THD *thd, COND *cond, TABLE_LIST *table,
30 LOOKUP_FIELD_VALUES *lookup_field_vals);
31
32/*----------------------------------------------------------------------------*/
33
34static int
35make_db_list(THD *thd, List<LEX_STRING> *db_names,
36 LOOKUP_FIELD_VALUES *lookup_field_vals)
37{
38 /*
39 If we have db lookup vaule we just add it to list and
40 exit from the function.
41 We don't do this for database names longer than the maximum
42 path length.
43 */
44 if (lookup_field_vals->db_value.str
45 && lookup_field_vals->db_value.length < FN_REFLEN)
46 {
47 if (db_names->push_back(&lookup_field_vals->db_value))
48 return 1;
49 return 0;
50 }
51
52 return (find_files(thd, db_names, NullS,
53 mysql_data_home, NullS, TRUE) != FIND_FILES_OK);
54}
55
56/*----------------------------------------------------------------------------*/
57
58struct TABLE_DATA
59{
60 LEX_STRING name;
61 longlong size;
62};
63
64static char *fn_remove_ext(char *name)
65{
66 char *res = strrchr(name, '.');
67 if (res)
68 return res;
69 return name + strlen(name);
70}
71
72/*
73 SYNOPSIS
74 thd thread handler
75 tables put found tables and their size in this list
76 db database name to set in TABLE_LIST structure
77 path path to database
78 wild filter for found files
79
80 RETURN
81 FIND_FILES_OK success
82 FIND_FILES_OOM out of memory error
83 FIND_FILES_DIR no such directory, or directory can't be read
84*/
85static find_files_result
86find_tables(THD *thd, List<TABLE_DATA> *tables,
87 const char *db, const char *path, const char *wild)
88{
89 char *ext;
90 MY_DIR *dirp;
91 FILEINFO *file;
92 uint file_name_len;
93 char uname[NAME_LEN + 1]; /* Unencoded name */
94#ifndef NO_EMBEDDED_ACCESS_CHECKS
95 uint col_access = thd->col_access;
96#endif
97 uint wild_length = 0;
98 TABLE_LIST table_list;
99 TABLE_DATA *table_data = NULL;
100 DBUG_ENTER("find_files");
101
102 bzero((char *)&table_list, sizeof(table_list));
103
104 if (!(dirp = my_dir(path, MYF(MY_WANT_STAT))))
105 {
106 if (my_errno == ENOENT)
107 my_error(ER_BAD_DB_ERROR, MYF(ME_BELL + ME_WAITTANG), db);
108 else
109 my_error(ER_CANT_READ_DIR, MYF(ME_BELL + ME_WAITTANG), path, my_errno);
110 DBUG_RETURN(FIND_FILES_DIR);
111 }
112
113 for (uint i = 0; i < (uint)dirp->number_off_files; i++)
114 {
115 file = dirp->dir_entry + i;
116 /* skip '.', '..', db.opt and temp files. */
117 if ((file->name[0] == '.' &&
118 (!file->name[1] || (file->name[1] == '.' && !file->name[2])))
119 || !my_strcasecmp(files_charset_info, file->name, MY_DB_OPT_FILE)
120 || is_prefix(file->name, tmp_file_prefix))
121 continue;
122
123 ext = fn_remove_ext(file->name);
124 *ext = 0;
125 file_name_len = filename_to_tablename(file->name, uname, sizeof(uname));
126
127 if (table_data != NULL
128 && !my_strcasecmp(files_charset_info, uname, table_data->name.str))
129 {
130 table_data->size += file->mystat->st_size;
131 continue;
132 }
133
134 if (wild)
135 {
136 if (lower_case_table_names)
137 {
138 if (my_wildcmp(files_charset_info,
139 uname, uname + file_name_len,
140 wild, wild + wild_length,
141 wild_prefix, wild_one, wild_many))
142 continue;
143 }
144 else if (wild_compare(uname, wild, 0))
145 continue;
146 }
147
148#ifndef NO_EMBEDDED_ACCESS_CHECKS
149 /* Don't show tables where we don't have any privileges */
150 if (db && !(col_access & TABLE_ACLS))
151 {
152 table_list.db = (char*)db;
153 table_list.db_length = strlen(db);
154 table_list.table_name = uname;
155 table_list.table_name_length = file_name_len;
156 table_list.grant.privilege = col_access;
157 if (check_grant(thd, TABLE_ACLS, &table_list, TRUE, 1, TRUE))
158 continue;
159 }
160#endif
161
162 table_data = new TABLE_DATA();
163 table_data->size = file->mystat->st_size;
164 if (!thd->make_lex_string(&table_data->name, uname, file_name_len, FALSE)
165 || tables->push_back(table_data))
166 {
167 my_dirend(dirp);
168 DBUG_RETURN(FIND_FILES_OOM);
169 }
170 }
171
172 DBUG_PRINT("info", ("found: %d files", tables->elements));
173 my_dirend(dirp);
174
175 //(void)ha_find_files(thd, db, path, wild, dir, files);
176
177 DBUG_RETURN(FIND_FILES_OK);
178}
179
180static int
181make_table_list(THD *thd, List<TABLE_DATA> *table_names, LEX *lex,
182 LEX_STRING *db_name)
183{
184 char path[FN_REFLEN + 1];
185 build_table_filename(path, sizeof(path) - 1, db_name->str, "", "", 0);
186
187 find_files_result res = find_tables(thd, table_names, db_name->str, path,
188 NullS);
189 if (res != FIND_FILES_OK)
190 {
191 /*
192 Downgrade errors about problems with database directory to warnings.
193 Another thread may have dropped database, and we may still have a name
194 for that directory.
195 */
196 if (res == FIND_FILES_DIR)
197 {
198 if (sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND)
199 return 1;
200 thd->clear_error();
201 return 2;
202 }
203 return 1;
204 }
205 return 0;
206}
207
208/*----------------------------------------------------------------------------*/
209
210static struct st_mysql_information_schema info =
211{ MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION };
212
213static ST_FIELD_INFO fields_info[] =
214{
215 {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
216 {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Name",
217 SKIP_OPEN_TABLE},
218 {"TABLE_SIZE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
219 (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Table_size", SKIP_OPEN_TABLE},
220 {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
221};
222
223static int fill_table(THD *thd, TABLE_LIST *tables, COND *cond)
224{
225 LEX *lex = thd->lex;
226 TABLE *table = tables->table;
227 LOOKUP_FIELD_VALUES lookup_field_vals;
228#ifndef NO_EMBEDDED_ACCESS_CHECKS
229 Security_context *sctx = thd->security_ctx;
230#endif
231 List<LEX_STRING> db_names;
232 List_iterator_fast<LEX_STRING> it(db_names);
233 int error = 1;
234
235 DBUG_ENTER("fill_table");
236
237 bzero((char *)&lookup_field_vals, sizeof(LOOKUP_FIELD_VALUES));
238 if (calc_lookup_values_from_cond(thd, cond, tables, &lookup_field_vals))
239 {
240 error = 0;
241 goto err;
242 }
243
244 if (lower_case_table_names)
245 {
246 /*
247 We can safely do in-place upgrades here since we are
248 allocating a new memory buffer for these strings.
249 */
250 if (lookup_field_vals.db_value.str && lookup_field_vals.db_value.str[0])
251 my_casedn_str(system_charset_info, lookup_field_vals.db_value.str);
252 if (lookup_field_vals.table_value.str && lookup_field_vals.table_value.str[0])
253 my_casedn_str(system_charset_info, lookup_field_vals.table_value.str);
254 }
255
256 DBUG_PRINT("INDEX VALUES", ("db_name='%s', table_name='%s'",
257 STR_OR_NIL(lookup_field_vals.db_value.str),
258 STR_OR_NIL(lookup_field_vals.table_value.str)));
259
260 if (!lookup_field_vals.wild_db_value && !lookup_field_vals.wild_table_value)
261 {
262 /*
263 if lookup value is empty string then
264 it's impossible table name or db name
265 */
266 if ((lookup_field_vals.db_value.str
267 && !lookup_field_vals.db_value.str[0])
268 || (lookup_field_vals.table_value.str
269 && !lookup_field_vals.table_value.str[0]))
270 {
271 error= 0;
272 goto err;
273 }
274 }
275
276 /* NOTE: doesn't change the output of EXPLAIN - maybe sometimes later */
277 if (lookup_field_vals.db_value.length
278 && !lookup_field_vals.wild_db_value)
279 tables->has_db_lookup_value = TRUE;
280 if (lookup_field_vals.table_value.length
281 && !lookup_field_vals.wild_table_value)
282 tables->has_table_lookup_value = TRUE;
283
284 if (lex->describe)
285 {
286 /* EXPLAIN SELECT */
287 error = 0;
288 goto err;
289 }
290
291 if (make_db_list(thd, &db_names, &lookup_field_vals))
292 goto err;
293
294 LEX_STRING *db_name;
295 while (db_name = it++)
296 {
297 if ((check_access(thd, SELECT_ACL, db_name->str, &thd->col_access, NULL, 0, 1)
298 || (!thd->col_access && check_grant_db(thd, db_name->str)))
299 && !sctx->master_access & (DB_ACLS | SHOW_DB_ACL)
300 && !acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name->str, 0))
301 continue;
302
303 List<TABLE_DATA> tables;
304 int res = make_table_list(thd, &tables, lex, db_name);
305 if (res)
306 {
307 tables.delete_elements();
308 if (res == 2) /* Not fatal error, continue */
309 continue;
310 goto err;
311 }
312
313 TABLE_DATA *table_data;
314 List_iterator_fast<TABLE_DATA> it_tables(tables);
315 while (table_data = it_tables++)
316 {
317 table->field[0]->store(db_name->str, db_name->length,
318 system_charset_info);
319 table->field[1]->store(table_data->name.str, table_data->name.length,
320 system_charset_info);
321 table->field[2]->set_notnull();
322 table->field[2]->store((longlong) table_data->size, TRUE);
323 if (schema_table_store_record(thd, table))
324 {
325 tables.delete_elements();
326 goto err;
327 }
328 }
329 tables.delete_elements();
330 }
331
332 error = 0;
333
334err:
335 DBUG_RETURN(error);
336
337 return 0;
338}
339
340static int init(void *ptr)
341{
342 ST_SCHEMA_TABLE *schema_table = (ST_SCHEMA_TABLE*)ptr;
343
344 schema_table->fields_info = fields_info;
345 schema_table->fill_table = fill_table;
346 schema_table->idx_field1 = 0;
347 schema_table->idx_field2 = 1;
348 schema_table->i_s_requested_object = OPTIMIZE_I_S_TABLE;
349 return 0;
350}
351
352mysql_declare_plugin(table_sizes)
353{
354 MYSQL_INFORMATION_SCHEMA_PLUGIN,
355 &info, /* type-specific descriptor */
356 "TABLE_SIZES", /* table name */
357 "Manuel Mausz", /* author */
358 "Fast INFORMATION_SCHEMA table sizes", /* description */
359 PLUGIN_LICENSE_GPL, /* license type */
360 init, /* init function */
361 NULL,
362 0x0010, /* version = 0.1 */
363 NULL, /* no status variables */
364 NULL, /* no system variables */
365 NULL, /* no reserved information */
366 0 /* no flags */
367}
368mysql_declare_plugin_end;