1 /* Copyright (c) 2002, 2012, Oracle and/or its affiliates.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 of the License.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software
14 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
15
16 #include "mariadb.h"
17 #include "sql_priv.h"
18 #include "unireg.h"
19 #include "sql_help.h"
20 #include "sql_table.h" // primary_key_name
21 #include "sql_base.h" // REPORT_ALL_ERRORS, setup_tables
22 #include "opt_range.h" // SQL_SELECT
23 #include "records.h" // init_read_record, end_read_record
24
25 struct st_find_field
26 {
27 const char *table_name, *field_name;
28 Field *field;
29 };
30
31 /* Used fields */
32
33 static struct st_find_field init_used_fields[]=
34 {
35 { "help_topic", "help_topic_id", 0},
36 { "help_topic", "name", 0},
37 { "help_topic", "help_category_id", 0},
38 { "help_topic", "description", 0},
39 { "help_topic", "example", 0},
40
41 { "help_category", "help_category_id", 0},
42 { "help_category", "parent_category_id", 0},
43 { "help_category", "name", 0},
44
45 { "help_keyword", "help_keyword_id", 0},
46 { "help_keyword", "name", 0},
47
48 { "help_relation", "help_topic_id", 0},
49 { "help_relation", "help_keyword_id", 0}
50 };
51
52 enum enum_used_fields
53 {
54 help_topic_help_topic_id= 0,
55 help_topic_name,
56 help_topic_help_category_id,
57 help_topic_description,
58 help_topic_example,
59
60 help_category_help_category_id,
61 help_category_parent_category_id,
62 help_category_name,
63
64 help_keyword_help_keyword_id,
65 help_keyword_name,
66
67 help_relation_help_topic_id,
68 help_relation_help_keyword_id
69 };
70
71
72 /*
73 Fill st_find_field structure with pointers to fields
74
75 SYNOPSIS
76 init_fields()
77 thd Thread handler
78 tables list of all tables for fields
79 find_fields array of structures
80 count size of previous array
81
82 RETURN VALUES
83 0 all ok
84 1 one of the fileds was not found
85 */
86
init_fields(THD * thd,TABLE_LIST * tables,struct st_find_field * find_fields,uint count)87 static bool init_fields(THD *thd, TABLE_LIST *tables,
88 struct st_find_field *find_fields, uint count)
89 {
90 Name_resolution_context *context= &thd->lex->select_lex.context;
91 DBUG_ENTER("init_fields");
92 context->resolve_in_table_list_only(tables);
93 for (; count-- ; find_fields++)
94 {
95 LEX_CSTRING field_name= {find_fields->field_name,
96 strlen(find_fields->field_name) };
97 /* We have to use 'new' here as field will be re_linked on free */
98 Item_field *field= (new (thd->mem_root)
99 Item_field(thd, context,
100 "mysql",
101 find_fields->table_name,
102 &field_name));
103 if (!(find_fields->field= find_field_in_tables(thd, field, tables, NULL,
104 0, REPORT_ALL_ERRORS, 1,
105 TRUE)))
106 DBUG_RETURN(1);
107 bitmap_set_bit(find_fields->field->table->read_set,
108 find_fields->field->field_index);
109 /* To make life easier when setting values in keys */
110 bitmap_set_bit(find_fields->field->table->write_set,
111 find_fields->field->field_index);
112 }
113 DBUG_RETURN(0);
114 }
115
116
117 /*
118 Returns variants of found topic for help (if it is just single topic,
119 returns description and example, or else returns only names..)
120
121 SYNOPSIS
122 memorize_variant_topic()
123
124 thd Thread handler
125 topics Table of topics
126 count number of alredy found topics
127 find_fields Filled array of information for work with fields
128
129 RETURN VALUES
130 names array of names of found topics (out)
131
132 name name of found topic (out)
133 description description of found topic (out)
134 example example for found topic (out)
135
136 NOTE
137 Field 'names' is set only if more than one topic is found.
138 Fields 'name', 'description', 'example' are set only if
139 found exactly one topic.
140 */
141
memorize_variant_topic(THD * thd,TABLE * topics,int count,struct st_find_field * find_fields,List<String> * names,String * name,String * description,String * example)142 void memorize_variant_topic(THD *thd, TABLE *topics, int count,
143 struct st_find_field *find_fields,
144 List<String> *names,
145 String *name, String *description, String *example)
146 {
147 DBUG_ENTER("memorize_variant_topic");
148 MEM_ROOT *mem_root= thd->mem_root;
149 if (count==0)
150 {
151 get_field(mem_root,find_fields[help_topic_name].field, name);
152 get_field(mem_root,find_fields[help_topic_description].field, description);
153 get_field(mem_root,find_fields[help_topic_example].field, example);
154 }
155 else
156 {
157 if (count == 1)
158 names->push_back(name, thd->mem_root);
159 String *new_name= new (thd->mem_root) String;
160 get_field(mem_root,find_fields[help_topic_name].field,new_name);
161 names->push_back(new_name, thd->mem_root);
162 }
163 DBUG_VOID_RETURN;
164 }
165
166 /*
167 Look for topics by mask
168
169 SYNOPSIS
170 search_topics()
171 thd Thread handler
172 topics Table of topics
173 find_fields Filled array of info for fields
174 select Function to test for matching help topic.
175 Normally 'help_topic.name like 'bit%'
176
177 RETURN VALUES
178 # number of topics found
179
180 names array of names of found topics (out)
181 name name of found topic (out)
182 description description of found topic (out)
183 example example for found topic (out)
184
185 NOTE
186 Field 'names' is set only if more than one topic was found.
187 Fields 'name', 'description', 'example' are set only if
188 exactly one topic was found.
189
190 */
191
search_topics(THD * thd,TABLE * topics,struct st_find_field * find_fields,SQL_SELECT * select,List<String> * names,String * name,String * description,String * example)192 int search_topics(THD *thd, TABLE *topics, struct st_find_field *find_fields,
193 SQL_SELECT *select, List<String> *names,
194 String *name, String *description, String *example)
195 {
196 int count= 0;
197 READ_RECORD read_record_info;
198 DBUG_ENTER("search_topics");
199
200 /* Should never happen. As this is part of help, we can ignore this */
201 if (init_read_record(&read_record_info, thd, topics, select, NULL, 1, 0,
202 FALSE))
203 DBUG_RETURN(0);
204
205 while (!read_record_info.read_record())
206 {
207 if (!select->cond->val_int()) // Doesn't match like
208 continue;
209 memorize_variant_topic(thd,topics,count,find_fields,
210 names,name,description,example);
211 count++;
212 }
213 end_read_record(&read_record_info);
214
215 DBUG_RETURN(count);
216 }
217
218 /*
219 Look for keyword by mask
220
221 SYNOPSIS
222 search_keyword()
223 thd Thread handler
224 keywords Table of keywords
225 find_fields Filled array of info for fields
226 select Function to test for matching keyword.
227 Normally 'help_keyword.name like 'bit%'
228
229 key_id help_keyword_if of found topics (out)
230
231 RETURN VALUES
232 0 didn't find any topics matching the mask
233 1 found exactly one topic matching the mask
234 2 found more then one topic matching the mask
235 */
236
search_keyword(THD * thd,TABLE * keywords,struct st_find_field * find_fields,SQL_SELECT * select,int * key_id)237 int search_keyword(THD *thd, TABLE *keywords,
238 struct st_find_field *find_fields,
239 SQL_SELECT *select, int *key_id)
240 {
241 int count= 0;
242 READ_RECORD read_record_info;
243 DBUG_ENTER("search_keyword");
244 /* Should never happen. As this is part of help, we can ignore this */
245 if (init_read_record(&read_record_info, thd, keywords, select, NULL, 1, 0,
246 FALSE))
247 DBUG_RETURN(0);
248
249 while (!read_record_info.read_record() && count<2)
250 {
251 if (!select->cond->val_int()) // Dosn't match like
252 continue;
253
254 *key_id= (int)find_fields[help_keyword_help_keyword_id].field->val_int();
255
256 count++;
257 }
258 end_read_record(&read_record_info);
259
260 DBUG_RETURN(count);
261 }
262
263 /*
264 Look for all topics with keyword
265
266 SYNOPSIS
267 get_topics_for_keyword()
268 thd Thread handler
269 topics Table of topics
270 relations Table of m:m relation "topic/keyword"
271 find_fields Filled array of info for fields
272 key_id Primary index to use to find for keyword
273
274 RETURN VALUES
275 # number of topics found
276
277 names array of name of found topics (out)
278
279 name name of found topic (out)
280 description description of found topic (out)
281 example example for found topic (out)
282
283 NOTE
284 Field 'names' is set only if more than one topic was found.
285 Fields 'name', 'description', 'example' are set only if
286 exactly one topic was found.
287 */
288
get_topics_for_keyword(THD * thd,TABLE * topics,TABLE * relations,struct st_find_field * find_fields,int16 key_id,List<String> * names,String * name,String * description,String * example)289 int get_topics_for_keyword(THD *thd, TABLE *topics, TABLE *relations,
290 struct st_find_field *find_fields, int16 key_id,
291 List<String> *names,
292 String *name, String *description, String *example)
293 {
294 uchar buff[8]; // Max int length
295 int count= 0;
296 int iindex_topic, iindex_relations;
297 Field *rtopic_id, *rkey_id;
298 DBUG_ENTER("get_topics_for_keyword");
299
300 if ((iindex_topic=
301 find_type(primary_key_name, &topics->s->keynames,
302 FIND_TYPE_NO_PREFIX) - 1) < 0 ||
303 (iindex_relations=
304 find_type(primary_key_name, &relations->s->keynames,
305 FIND_TYPE_NO_PREFIX) - 1) < 0)
306 {
307 my_message(ER_CORRUPT_HELP_DB, ER_THD(thd, ER_CORRUPT_HELP_DB), MYF(0));
308 DBUG_RETURN(-1);
309 }
310 rtopic_id= find_fields[help_relation_help_topic_id].field;
311 rkey_id= find_fields[help_relation_help_keyword_id].field;
312
313 if (topics->file->ha_index_init(iindex_topic,1) ||
314 relations->file->ha_index_init(iindex_relations,1))
315 {
316 if (topics->file->inited)
317 topics->file->ha_index_end();
318 my_message(ER_CORRUPT_HELP_DB, ER_THD(thd, ER_CORRUPT_HELP_DB), MYF(0));
319 DBUG_RETURN(-1);
320 }
321
322 rkey_id->store((longlong) key_id, TRUE);
323 rkey_id->get_key_image(buff, rkey_id->pack_length(), Field::itRAW);
324 int key_res= relations->file->ha_index_read_map(relations->record[0],
325 buff, (key_part_map) 1,
326 HA_READ_KEY_EXACT);
327
328 for ( ;
329 !key_res && key_id == (int16) rkey_id->val_int() ;
330 key_res= relations->file->ha_index_next(relations->record[0]))
331 {
332 uchar topic_id_buff[8];
333 longlong topic_id= rtopic_id->val_int();
334 Field *field= find_fields[help_topic_help_topic_id].field;
335 field->store((longlong) topic_id, TRUE);
336 field->get_key_image(topic_id_buff, field->pack_length(), Field::itRAW);
337
338 if (!topics->file->ha_index_read_map(topics->record[0], topic_id_buff,
339 (key_part_map)1, HA_READ_KEY_EXACT))
340 {
341 memorize_variant_topic(thd,topics,count,find_fields,
342 names,name,description,example);
343 count++;
344 }
345 }
346 topics->file->ha_index_end();
347 relations->file->ha_index_end();
348 DBUG_RETURN(count);
349 }
350
351 /*
352 Look for categories by mask
353
354 SYNOPSIS
355 search_categories()
356 thd THD for init_read_record
357 categories Table of categories
358 find_fields Filled array of info for fields
359 select Function to test for if matching help topic.
360 Normally 'help_vategory.name like 'bit%'
361 names List of found categories names (out)
362 res_id Primary index of found category (only if
363 found exactly one category)
364
365 RETURN VALUES
366 # Number of categories found
367 */
368
search_categories(THD * thd,TABLE * categories,struct st_find_field * find_fields,SQL_SELECT * select,List<String> * names,int16 * res_id)369 int search_categories(THD *thd, TABLE *categories,
370 struct st_find_field *find_fields,
371 SQL_SELECT *select, List<String> *names, int16 *res_id)
372 {
373 Field *pfname= find_fields[help_category_name].field;
374 Field *pcat_id= find_fields[help_category_help_category_id].field;
375 int count= 0;
376 READ_RECORD read_record_info;
377 DBUG_ENTER("search_categories");
378
379 /* Should never happen. As this is part of help, we can ignore this */
380 if (init_read_record(&read_record_info, thd, categories, select, NULL,
381 1, 0, FALSE))
382 DBUG_RETURN(0);
383 while (!read_record_info.read_record())
384 {
385 if (select && !select->cond->val_int())
386 continue;
387 String *lname= new (thd->mem_root) String;
388 get_field(thd->mem_root,pfname,lname);
389 if (++count == 1 && res_id)
390 *res_id= (int16) pcat_id->val_int();
391 names->push_back(lname, thd->mem_root);
392 }
393 end_read_record(&read_record_info);
394
395 DBUG_RETURN(count);
396 }
397
398 /*
399 Look for all topics or subcategories of category
400
401 SYNOPSIS
402 get_all_items_for_category()
403 thd Thread handler
404 items Table of items
405 pfname Field "name" in items
406 select "where" part of query..
407 res list of finded names
408 */
409
get_all_items_for_category(THD * thd,TABLE * items,Field * pfname,SQL_SELECT * select,List<String> * res)410 void get_all_items_for_category(THD *thd, TABLE *items, Field *pfname,
411 SQL_SELECT *select, List<String> *res)
412 {
413 READ_RECORD read_record_info;
414 DBUG_ENTER("get_all_items_for_category");
415
416 /* Should never happen. As this is part of help, we can ignore this */
417 if (init_read_record(&read_record_info, thd, items, select, NULL, 1, 0,
418 FALSE))
419 DBUG_VOID_RETURN;
420
421 while (!read_record_info.read_record())
422 {
423 if (!select->cond->val_int())
424 continue;
425 String *name= new (thd->mem_root) String();
426 get_field(thd->mem_root,pfname,name);
427 res->push_back(name, thd->mem_root);
428 }
429 end_read_record(&read_record_info);
430
431 DBUG_VOID_RETURN;
432 }
433
434 /*
435 Send to client answer for help request
436
437 SYNOPSIS
438 send_answer_1()
439 protocol - protocol for sending
440 s1 - value of column "Name"
441 s2 - value of column "Description"
442 s3 - value of column "Example"
443
444 IMPLEMENTATION
445 Format used:
446 +----------+------------+------------+
447 |name |description |example |
448 +----------+------------+------------+
449 |String(64)|String(1000)|String(1000)|
450 +----------+------------+------------+
451 with exactly one row!
452
453 RETURN VALUES
454 1 Writing of head failed
455 -1 Writing of row failed
456 0 Successeful send
457 */
458
send_answer_1(Protocol * protocol,String * s1,String * s2,String * s3)459 int send_answer_1(Protocol *protocol, String *s1, String *s2, String *s3)
460 {
461 THD *thd= protocol->thd;
462 MEM_ROOT *mem_root= thd->mem_root;
463 DBUG_ENTER("send_answer_1");
464
465 List<Item> field_list;
466 field_list.push_back(new (mem_root) Item_empty_string(thd, "name", 64),
467 mem_root);
468 field_list.push_back(new (mem_root) Item_empty_string(thd, "description", 1000),
469 mem_root);
470 field_list.push_back(new (mem_root) Item_empty_string(thd, "example", 1000),
471 mem_root);
472
473 if (protocol->send_result_set_metadata(&field_list,
474 Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
475 DBUG_RETURN(1);
476
477 protocol->prepare_for_resend();
478 protocol->store(s1);
479 protocol->store(s2);
480 protocol->store(s3);
481 if (protocol->write())
482 DBUG_RETURN(-1);
483 DBUG_RETURN(0);
484 }
485
486
487 /*
488 Send to client help header
489
490 SYNOPSIS
491 send_header_2()
492 protocol - protocol for sending
493 is_it_category - need column 'source_category_name'
494
495 IMPLEMENTATION
496 +- -+
497 |+-------------------- | +----------+--------------+
498 ||source_category_name | |name |is_it_category|
499 |+-------------------- | +----------+--------------+
500 ||String(64) | |String(64)|String(1) |
501 |+-------------------- | +----------+--------------+
502 +- -+
503
504 RETURN VALUES
505 result of protocol->send_result_set_metadata
506 */
507
send_header_2(Protocol * protocol,bool for_category)508 int send_header_2(Protocol *protocol, bool for_category)
509 {
510 THD *thd= protocol->thd;
511 MEM_ROOT *mem_root= thd->mem_root;
512 DBUG_ENTER("send_header_2");
513 List<Item> field_list;
514 if (for_category)
515 field_list.push_back(new (mem_root)
516 Item_empty_string(thd, "source_category_name", 64),
517 mem_root);
518 field_list.push_back(new (mem_root)
519 Item_empty_string(thd, "name", 64),
520 mem_root);
521 field_list.push_back(new (mem_root)
522 Item_empty_string(thd, "is_it_category", 1),
523 mem_root);
524 DBUG_RETURN(protocol->send_result_set_metadata(&field_list,
525 Protocol::SEND_NUM_ROWS |
526 Protocol::SEND_EOF));
527 }
528
529 /*
530 strcmp for using in qsort
531
532 SYNOPSIS
533 strptrcmp()
534 ptr1 (const void*)&str1
535 ptr2 (const void*)&str2
536
537 RETURN VALUES
538 same as strcmp
539 */
540
string_ptr_cmp(const void * ptr1,const void * ptr2)541 extern "C" int string_ptr_cmp(const void* ptr1, const void* ptr2)
542 {
543 String *str1= *(String**)ptr1;
544 String *str2= *(String**)ptr2;
545 return strcmp(str1->c_ptr(),str2->c_ptr());
546 }
547
548 /*
549 Send to client rows in format:
550 column1 : <name>
551 column2 : <is_it_category>
552
553 SYNOPSIS
554 send_variant_2_list()
555 protocol Protocol for sending
556 names List of names
557 cat Value of the column <is_it_category>
558 source_name name of category for all items..
559
560 RETURN VALUES
561 -1 Writing fail
562 0 Data was successefully send
563 */
564
send_variant_2_list(MEM_ROOT * mem_root,Protocol * protocol,List<String> * names,const char * cat,String * source_name)565 int send_variant_2_list(MEM_ROOT *mem_root, Protocol *protocol,
566 List<String> *names,
567 const char *cat, String *source_name)
568 {
569 DBUG_ENTER("send_variant_2_list");
570
571 String **pointers= (String**)alloc_root(mem_root,
572 sizeof(String*)*names->elements);
573 String **pos;
574 String **end= pointers + names->elements;
575
576 List_iterator<String> it(*names);
577 for (pos= pointers; pos!=end; (*pos++= it++))
578 ;
579
580 my_qsort(pointers,names->elements,sizeof(String*),string_ptr_cmp);
581
582 for (pos= pointers; pos!=end; pos++)
583 {
584 protocol->prepare_for_resend();
585 if (source_name)
586 protocol->store(source_name);
587 protocol->store(*pos);
588 protocol->store(cat,1,&my_charset_latin1);
589 if (protocol->write())
590 DBUG_RETURN(-1);
591 }
592
593 DBUG_RETURN(0);
594 }
595
596 /*
597 Prepare simple SQL_SELECT table.* WHERE <Item>
598
599 SYNOPSIS
600 prepare_simple_select()
601 thd Thread handler
602 cond WHERE part of select
603 table goal table
604
605 error code of error (out)
606
607 RETURN VALUES
608 # created SQL_SELECT
609 */
610
prepare_simple_select(THD * thd,Item * cond,TABLE * table,int * error)611 SQL_SELECT *prepare_simple_select(THD *thd, Item *cond,
612 TABLE *table, int *error)
613 {
614 cond->fix_fields_if_needed(thd, &cond); // can never fail
615
616 /* Assume that no indexes cover all required fields */
617 table->covering_keys.clear_all();
618
619 SQL_SELECT *res= make_select(table, 0, 0, cond, 0, 0, error);
620 if (unlikely(*error) ||
621 (likely(res) && unlikely(res->check_quick(thd, 0, HA_POS_ERROR))) ||
622 (likely(res) && res->quick && unlikely(res->quick->reset())))
623 {
624 delete res;
625 res=0;
626 }
627 return res;
628 }
629
630 /*
631 Prepare simple SQL_SELECT table.* WHERE table.name LIKE mask
632
633 SYNOPSIS
634 prepare_select_for_name()
635 thd Thread handler
636 mask mask for compare with name
637 mlen length of mask
638 tables list of tables, used in WHERE
639 table goal table
640 pfname field "name" in table
641
642 error code of error (out)
643
644 RETURN VALUES
645 # created SQL_SELECT
646 */
647
prepare_select_for_name(THD * thd,const char * mask,size_t mlen,TABLE_LIST * tables,TABLE * table,Field * pfname,int * error)648 SQL_SELECT *prepare_select_for_name(THD *thd, const char *mask, size_t mlen,
649 TABLE_LIST *tables, TABLE *table,
650 Field *pfname, int *error)
651 {
652 MEM_ROOT *mem_root= thd->mem_root;
653 Item *cond= new (mem_root)
654 Item_func_like(thd,
655 new (mem_root)
656 Item_field(thd, pfname),
657 new (mem_root) Item_string(thd, mask, (uint)mlen,
658 pfname->charset()),
659 new (mem_root) Item_string_ascii(thd, "\\"),
660 FALSE);
661 if (unlikely(thd->is_fatal_error))
662 return 0; // OOM
663 return prepare_simple_select(thd, cond, table, error);
664 }
665
666
667 /*
668 Server-side function 'help'
669
670 SYNOPSIS
671 mysqld_help()
672 thd Thread handler
673
674 RETURN VALUES
675 FALSE Success
676 TRUE Error and send_error already commited
677 */
678
mysqld_help_internal(THD * thd,const char * mask)679 static bool mysqld_help_internal(THD *thd, const char *mask)
680 {
681 Protocol *protocol= thd->protocol;
682 SQL_SELECT *select;
683 st_find_field used_fields[array_elements(init_used_fields)];
684 List<TABLE_LIST> leaves;
685 TABLE_LIST tables[4];
686 List<String> topics_list, categories_list, subcategories_list;
687 String name, description, example;
688 int count_topics, count_categories, error;
689 size_t mlen= strlen(mask);
690 size_t i;
691 MEM_ROOT *mem_root= thd->mem_root;
692 LEX_CSTRING MYSQL_HELP_TOPIC_NAME= {STRING_WITH_LEN("help_topic") };
693 LEX_CSTRING MYSQL_HELP_CATEGORY_NAME= {STRING_WITH_LEN("help_category") };
694 LEX_CSTRING MYSQL_HELP_RELATION_NAME= {STRING_WITH_LEN("help_relation") };
695 LEX_CSTRING MYSQL_HELP_KEYWORD_NAME= {STRING_WITH_LEN("help_keyword") };
696 DBUG_ENTER("mysqld_help");
697
698 tables[0].init_one_table(&MYSQL_SCHEMA_NAME, &MYSQL_HELP_TOPIC_NAME, 0, TL_READ);
699 tables[1].init_one_table(&MYSQL_SCHEMA_NAME, &MYSQL_HELP_CATEGORY_NAME, 0, TL_READ);
700 tables[2].init_one_table(&MYSQL_SCHEMA_NAME, &MYSQL_HELP_RELATION_NAME, 0, TL_READ);
701 tables[3].init_one_table(&MYSQL_SCHEMA_NAME, &MYSQL_HELP_KEYWORD_NAME, 0, TL_READ);
702 tables[0].next_global= tables[0].next_local=
703 tables[0].next_name_resolution_table= &tables[1];
704 tables[1].next_global= tables[1].next_local=
705 tables[1].next_name_resolution_table= &tables[2];
706 tables[2].next_global= tables[2].next_local=
707 tables[2].next_name_resolution_table= &tables[3];
708
709 /*
710 HELP must be available under LOCK TABLES.
711 Reset and backup the current open tables state to
712 make it possible.
713 */
714 Open_tables_backup open_tables_state_backup;
715 if (open_system_tables_for_read(thd, tables, &open_tables_state_backup))
716 goto error2;
717
718 /*
719 Init tables and fields to be usable from items
720 tables do not contain VIEWs => we can pass 0 as conds
721 */
722 thd->lex->select_lex.context.table_list=
723 thd->lex->select_lex.context.first_name_resolution_table= &tables[0];
724 if (setup_tables(thd, &thd->lex->select_lex.context,
725 &thd->lex->select_lex.top_join_list,
726 tables, leaves, FALSE, FALSE))
727 goto error;
728 memcpy((char*) used_fields, (char*) init_used_fields, sizeof(used_fields));
729 if (init_fields(thd, tables, used_fields, array_elements(used_fields)))
730 goto error;
731 for (i=0; i<sizeof(tables)/sizeof(TABLE_LIST); i++)
732 tables[i].table->file->init_table_handle_for_HANDLER();
733
734 if (!(select=
735 prepare_select_for_name(thd,mask,mlen,tables,tables[0].table,
736 used_fields[help_topic_name].field,&error)))
737 goto error;
738
739 count_topics= search_topics(thd,tables[0].table,used_fields,
740 select,&topics_list,
741 &name, &description, &example);
742 delete select;
743
744 if (thd->is_error())
745 goto error;
746
747 if (count_topics == 0)
748 {
749 int UNINIT_VAR(key_id);
750 if (!(select=
751 prepare_select_for_name(thd,mask,mlen,tables,tables[3].table,
752 used_fields[help_keyword_name].field,
753 &error)))
754 goto error;
755
756 count_topics= search_keyword(thd,tables[3].table, used_fields, select,
757 &key_id);
758 delete select;
759 count_topics= (count_topics != 1) ? 0 :
760 get_topics_for_keyword(thd,tables[0].table,tables[2].table,
761 used_fields,key_id,&topics_list,&name,
762 &description,&example);
763 }
764
765 if (count_topics == 0)
766 {
767 int16 category_id;
768 Field *cat_cat_id= used_fields[help_category_parent_category_id].field;
769 if (!(select=
770 prepare_select_for_name(thd,mask,mlen,tables,tables[1].table,
771 used_fields[help_category_name].field,
772 &error)))
773 goto error;
774
775 count_categories= search_categories(thd, tables[1].table, used_fields,
776 select,
777 &categories_list,&category_id);
778 delete select;
779 if (!count_categories)
780 {
781 if (send_header_2(protocol,FALSE))
782 goto error;
783 }
784 else if (count_categories > 1)
785 {
786 if (send_header_2(protocol,FALSE) ||
787 send_variant_2_list(mem_root,protocol,&categories_list,"Y",0))
788 goto error;
789 }
790 else
791 {
792 Field *topic_cat_id= used_fields[help_topic_help_category_id].field;
793 Item *cond_topic_by_cat=
794 new (mem_root)
795 Item_func_equal(thd,
796 new (mem_root)
797 Item_field(thd, topic_cat_id),
798 new (mem_root)
799 Item_int(thd, (int32) category_id));
800 Item *cond_cat_by_cat=
801 new (mem_root)
802 Item_func_equal(thd,
803 new (mem_root) Item_field(thd, cat_cat_id),
804 new (mem_root) Item_int(thd, (int32) category_id));
805 if (!(select= prepare_simple_select(thd, cond_topic_by_cat,
806 tables[0].table, &error)))
807 goto error;
808 get_all_items_for_category(thd,tables[0].table,
809 used_fields[help_topic_name].field,
810 select,&topics_list);
811 delete select;
812 if (!(select= prepare_simple_select(thd, cond_cat_by_cat,
813 tables[1].table, &error)))
814 goto error;
815 get_all_items_for_category(thd,tables[1].table,
816 used_fields[help_category_name].field,
817 select,&subcategories_list);
818 delete select;
819 String *cat= categories_list.head();
820 if (send_header_2(protocol, TRUE) ||
821 send_variant_2_list(mem_root,protocol,&topics_list, "N",cat) ||
822 send_variant_2_list(mem_root,protocol,&subcategories_list,"Y",cat))
823 goto error;
824 }
825 }
826 else if (count_topics == 1)
827 {
828 if (send_answer_1(protocol,&name,&description,&example))
829 goto error;
830 }
831 else
832 {
833 /* First send header and functions */
834 if (send_header_2(protocol, FALSE) ||
835 send_variant_2_list(mem_root,protocol, &topics_list, "N", 0))
836 goto error;
837 if (!(select=
838 prepare_select_for_name(thd,mask,mlen,tables,tables[1].table,
839 used_fields[help_category_name].field,&error)))
840 goto error;
841 search_categories(thd, tables[1].table, used_fields,
842 select,&categories_list, 0);
843 delete select;
844 /* Then send categories */
845 if (send_variant_2_list(mem_root,protocol, &categories_list, "Y", 0))
846 goto error;
847 }
848 my_eof(thd);
849
850 close_system_tables(thd, &open_tables_state_backup);
851 DBUG_RETURN(FALSE);
852
853 error:
854 close_system_tables(thd, &open_tables_state_backup);
855
856 error2:
857 DBUG_RETURN(TRUE);
858 }
859
860
mysqld_help(THD * thd,const char * mask)861 bool mysqld_help(THD *thd, const char *mask)
862 {
863 sql_mode_t sql_mode_backup= thd->variables.sql_mode;
864 thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH;
865 bool rc= mysqld_help_internal(thd, mask);
866 thd->variables.sql_mode= sql_mode_backup;
867 return rc;
868 }
869