summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <vva@eagle.mysql.r18.ru>2003-05-29 17:47:31 -0400
committerunknown <vva@eagle.mysql.r18.ru>2003-05-29 17:47:31 -0400
commit69e084af1eedff2dda70fcf073dd4fa349718b69 (patch)
treea9f85257a75430a22735e52666cbf25e605ea2bb /sql
parentf440077bd03869f48ff278bc2b73fab7a30e282b (diff)
downloadmariadb-git-69e084af1eedff2dda70fcf073dd4fa349718b69.tar.gz
new version of help
Diffstat (limited to 'sql')
-rw-r--r--sql/mysql_priv.h1
-rw-r--r--sql/protocol.h2
-rw-r--r--sql/sql_help.cc782
-rw-r--r--sql/table.cc27
4 files changed, 556 insertions, 256 deletions
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 712c8853a20..a59f1d4b81a 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -877,6 +877,7 @@ bool check_db_name(char *db);
bool check_column_name(const char *name);
bool check_table_name(const char *name, uint length);
char *get_field(MEM_ROOT *mem, Field *field);
+bool get_field(MEM_ROOT *mem, Field *field, class String *res);
int wild_case_compare(CHARSET_INFO *cs, const char *str,const char *wildstr);
/* from hostname.cc */
diff --git a/sql/protocol.h b/sql/protocol.h
index 2110f1877c2..ffd61b3e848 100644
--- a/sql/protocol.h
+++ b/sql/protocol.h
@@ -60,6 +60,8 @@ public:
{ return store_longlong((longlong) from, 0); }
inline bool store(ulonglong from)
{ return store_longlong((longlong) from, 1); }
+ inline bool store(String *str)
+ { return store(str->c_ptr(),str->length(),str->charset()); }
virtual bool prepare_for_send(List<Item> *item_list)
{
diff --git a/sql/sql_help.cc b/sql/sql_help.cc
index 36c7ef87b17..a9b89a728d2 100644
--- a/sql/sql_help.cc
+++ b/sql/sql_help.cc
@@ -26,74 +26,155 @@ struct st_find_field
static struct st_find_field init_used_fields[]=
{
- { "help_topic", "name", 0},
- { "help_topic","description", 0},
- { "help_topic","example", 0},
- { "help_topic", "help_topic_id", 0},
- { "help_category","name", 0},
- { "help_category","help_category_id", 0},
- { "help_relation","help_topic_id", 0},
- { "help_relation","help_category_id", 0}
+ { "help_topic", "help_topic_id", 0},
+ { "help_topic", "name", 0},
+ { "help_topic", "help_category_id", 0},
+ { "help_topic", "description", 0},
+ { "help_topic", "example", 0},
+
+ { "help_category", "help_category_id", 0},
+ { "help_category", "parent_category_id", 0},
+ { "help_category", "name", 0},
+
+ { "help_keyword", "help_keyword_id", 0},
+ { "help_keyword", "name", 0},
+
+ { "help_relation", "help_topic_id", 0},
+ { "help_relation", "help_keyword_id", 0}
};
enum enum_used_fields
{
- help_topic_name=0, help_topic_description, help_topic_example,
- help_topic_help_topic_id,
- help_category_name, help_category_help_category_id,
- help_relation_help_topic_id, help_relation_help_category_id
+ help_topic_help_topic_id= 0,
+ help_topic_name,
+ help_topic_help_category_id,
+ help_topic_description,
+ help_topic_example,
+
+ help_category_help_category_id,
+ help_category_parent_category_id,
+ help_category_name,
+
+ help_keyword_help_keyword_id,
+ help_keyword_name,
+
+ help_relation_help_topic_id,
+ help_relation_help_keyword_id
};
/*
- Fill local used field structure with pointer to fields */
+ Fill st_find_field structure with pointers to fields
+
+ SYNOPSIS
+ init_fields()
+ thd Thread handler
+ tables list of all tables for fields
+ find_fields array of structures
+ count size of previous array
+
+ RETURN VALUES
+ 0 all ok
+ 1 one of the fileds didn't finded
+*/
static bool init_fields(THD *thd, TABLE_LIST *tables,
- struct st_find_field *find_field,
- uint count)
+ struct st_find_field *find_fields, uint count)
{
- for (; count-- ; find_field++)
+ DBUG_ENTER("init_fields");
+ for (; count-- ; find_fields++)
{
TABLE_LIST *not_used;
/* We have to use 'new' here as field will be re_linked on free */
- Item_field *field= new Item_field("mysql", find_field->table_name,
- find_field->field_name);
- if (!(find_field->field= find_field_in_tables(thd, field, tables,
- &not_used,
- TRUE)))
- return 1;
+ Item_field *field= new Item_field("mysql", find_fields->table_name,
+ find_fields->field_name);
+ if (!(find_fields->field= find_field_in_tables(thd, field, tables,
+ &not_used, TRUE)))
+ DBUG_RETURN(1);
}
- return 0;
+ DBUG_RETURN(0);
}
+/*
+
+ Returns variants of found topic for help (if it is just single topic,
+ returns description and example, or else returns only names..)
+
+ SYNOPSIS
+ memorize_variant_topic()
+
+ thd Thread handler
+ topics Table of topics
+ count number of alredy found topics
+ find_fields Filled array of information for work with fields
+
+ RETURN VALUES
+ names array of names of found topics (out)
-#define help_charset &my_charset_latin1
+ name name of found topic (out)
+ description description of found topic (out)
+ example example for found topic (out)
+
+ NOTE
+ Field 'names' is set only if more than one topic is found.
+ Fields 'name', 'description', 'example' are set only if
+ found exactly one topic.
+*/
+
+void memorize_variant_topic(THD *thd, TABLE *topics, int count,
+ struct st_find_field *find_fields,
+ List<String> *names,
+ String *name, String *description, String *example)
+{
+ DBUG_ENTER("memorize_variant_topic");
+ MEM_ROOT *mem_root= &thd->mem_root;
+ if (count==0)
+ {
+ get_field(mem_root,find_fields[help_topic_name].field, name);
+ get_field(mem_root,find_fields[help_topic_description].field, description);
+ get_field(mem_root,find_fields[help_topic_example].field, example);
+ }
+ else
+ {
+ if (count==1)
+ names->push_back(name);
+ String *new_name= new String;
+ get_field(mem_root,find_fields[help_topic_name].field,new_name);
+ names->push_back(new_name);
+ }
+ DBUG_VOID_RETURN;
+}
/*
Look for topics by mask
SYNOPSIS
search_topics()
- thd Thread handler
- topics Table of topic
- select Function to test for if matching help topic.
- Normally 'help_topic.name like 'bit%'
- pfname Pointer to Field structure for field "name"
- names List of founded topic's names (out)
- name Name of founded topic (out),
- Only set if founded exactly one topic)
- description Description of founded topic (out)
- Only set if founded exactly one topic.
- example Example for founded topic (out)
- Only if founded exactly one topic.
+ thd Thread handler
+ topics Table of topics
+ find_fields Filled array of info for fields
+ select Function to test for matching help topic.
+ Normally 'help_topic.name like 'bit%'
+
RETURN VALUES
- # number of topics founded
+ # number of topics found
+
+ names array of names of found topics (out)
+ name name of found topic (out)
+ description description of found topic (out)
+ example example for found topic (out)
+
+ NOTE
+ Field 'names' is set only if more than one topic was found.
+ Fields 'name', 'description', 'example' are set only if
+ exactly one topic was found.
+
*/
-int search_topics(THD *thd, TABLE *topics, struct st_find_field *find_field,
- SQL_SELECT *select, List<char> *names,
- char **name, char **description, char **example)
+int search_topics(THD *thd, TABLE *topics, struct st_find_field *find_fields,
+ SQL_SELECT *select, List<String> *names,
+ String *name, String *description, String *example)
{
- DBUG_ENTER("search_functions");
+ DBUG_ENTER("search_topics");
int count= 0;
READ_RECORD read_record_info;
@@ -102,139 +183,93 @@ int search_topics(THD *thd, TABLE *topics, struct st_find_field *find_field,
{
if (!select->cond->val_int()) // Dosn't match like
continue;
-
- char *lname= get_field(&thd->mem_root, find_field[help_topic_name].field);
+ memorize_variant_topic(thd,topics,count,find_fields,
+ names,name,description,example);
count++;
- if (count > 2)
- {
- names->push_back(lname);
- }
- else if (count == 1)
- {
- *description= get_field(&thd->mem_root,
- find_field[help_topic_description].field);
- *example= get_field(&thd->mem_root,
- find_field[help_topic_example].field);
- *name= lname;
- }
- else
- {
- names->push_back(*name);
- names->push_back(lname);
- *name= 0;
- *description= 0;
- *example= 0;
- }
}
end_read_record(&read_record_info);
+
DBUG_RETURN(count);
}
/*
- Look for categories by mask
+ Look for keyword by mask
SYNOPSIS
- search_categories()
- thd THD for init_read_record
- categories Table of categories
- select Function to test for if matching help topic.
- Normally 'help_topic.name like 'bit%'
- names List of founded topic's names (out)
- res_id Primary index of founded category (only if
- founded exactly one category)
+ search_keyword()
+ thd Thread handler
+ keywords Table of keywords
+ find_fields Filled array of info for fields
+ select Function to test for matching keyword.
+ Normally 'help_keyword.name like 'bit%'
+
+ key_id help_keyword_if of found topics (out)
RETURN VALUES
- # Number of categories founded
+ 0 didn't find any topics matching the mask
+ 1 found exactly one topic matching the mask
+ 2 found more then one topic matching the mask
*/
-int search_categories(THD *thd, TABLE *categories,
- struct st_find_field *find_fields,
- SQL_SELECT *select, List<char> *names, int16 *res_id)
+int search_keyword(THD *thd, TABLE *keywords, struct st_find_field *find_fields,
+ SQL_SELECT *select, int *key_id)
{
- Field *pfname= find_fields[help_category_name].field;
- DBUG_ENTER("search_categories");
+ DBUG_ENTER("search_keyword");
int count= 0;
- READ_RECORD read_record_info;
- init_read_record(&read_record_info, thd, categories, select,1,0);
- while (!read_record_info.read_record(&read_record_info))
+ READ_RECORD read_record_info;
+ init_read_record(&read_record_info, thd, keywords, select,1,0);
+ while (!read_record_info.read_record(&read_record_info) && count<2)
{
- if (select && !select->cond->val_int())
+ if (!select->cond->val_int()) // Dosn't match like
continue;
- char *lname= get_field(&thd->mem_root,pfname);
- if (++count == 1 && res_id)
- {
- Field *pcat_id= find_fields[help_category_help_category_id].field;
- *res_id= (int16) pcat_id->val_int();
- }
- names->push_back(lname);
+
+ *key_id= find_fields[help_keyword_help_keyword_id].field->val_int();
+
+ count++;
}
end_read_record(&read_record_info);
-
+
DBUG_RETURN(count);
}
-
/*
- Send to client rows in format:
- column1 : <name>
- column2 : <is_it_category>
+ Look for all topics with keyword
SYNOPSIS
- send_variant_2_list()
- protocol Protocol for sending
- names List of names
- cat Value of the column <is_it_category>
+ get_topics_for_keyword()
+ thd Thread handler
+ topics Table of topics
+ relations Table of m:m relation "topic/keyword"
+ find_fields Filled array of info for fields
+ key_id Primary index to use to find for keyword
RETURN VALUES
- -1 Writing fail
- 0 Data was successefully send
-*/
-
-int send_variant_2_list(Protocol *protocol, List<char> *names,
- const char *cat)
-{
- DBUG_ENTER("send_names");
-
- List_iterator<char> it(*names);
- const char *cur_name;
- while ((cur_name= it++))
- {
- protocol->prepare_for_resend();
- protocol->store(cur_name, system_charset_info);
- protocol->store(cat, system_charset_info);
- if (protocol->write())
- DBUG_RETURN(-1);
- }
- DBUG_RETURN(0);
-}
+ # number of topics found
+ names array of name of found topics (out)
-/*
- Look for all topics of category
+ name name of found topic (out)
+ description description of found topic (out)
+ example example for found topic (out)
- SYNOPSIS
- get_all_topics_for_category()
- thd Thread handler
- topics Table of topics
- relations Table of m:m relation "topic/category"
- cat_id Primary index looked for category
- res List of founded topic's names (out)
-
- RETURN VALUES
- -1 corrupt database
- 0 succesefull
+ NOTE
+ Field 'names' is set only if more than one topic was found.
+ Fields 'name', 'description', 'example' are set only if
+ exactly one topic was found.
*/
-int get_all_topics_for_category(THD *thd, TABLE *topics, TABLE *relations,
- struct st_find_field *find_fields,
- int16 cat_id, List<char> *res)
+int 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)
{
- char buff[8]; // Max int length
- DBUG_ENTER("get_all_topics_for_category");
-
+ char buff[8]; // Max int length
+ int count= 0;
int iindex_topic, iindex_relations;
- Field *rtopic_id, *rcat_id;
+ Field *rtopic_id, *rkey_id;
+
+ DBUG_ENTER("get_topics_for_keyword");
if ((iindex_topic= find_type((char*) "PRIMARY",
&topics->keynames, 1+2)-1)<0 ||
@@ -245,37 +280,156 @@ int get_all_topics_for_category(THD *thd, TABLE *topics, TABLE *relations,
DBUG_RETURN(-1);
}
rtopic_id= find_fields[help_relation_help_topic_id].field;
- rcat_id= find_fields[help_relation_help_category_id].field;
+ rkey_id= find_fields[help_relation_help_keyword_id].field;
topics->file->index_init(iindex_topic);
relations->file->index_init(iindex_relations);
- rcat_id->store((longlong) cat_id);
- rcat_id->get_key_image(buff, rcat_id->pack_length(), help_charset,
+ rkey_id->store((longlong) key_id);
+ rkey_id->get_key_image(buff, rkey_id->pack_length(), rkey_id->charset(),
Field::itRAW);
int key_res= relations->file->index_read(relations->record[0],
- (byte *)buff, rcat_id->pack_length(),
+ (byte *)buff, rkey_id->pack_length(),
HA_READ_KEY_EXACT);
- for ( ; !key_res && cat_id == (int16) rcat_id->val_int() ;
+ for ( ;
+ !key_res && key_id == (int16) rkey_id->val_int() ;
key_res= relations->file->index_next(relations->record[0]))
{
char topic_id_buff[8];
longlong topic_id= rtopic_id->val_int();
Field *field= find_fields[help_topic_help_topic_id].field;
field->store((longlong) topic_id);
- field->get_key_image(topic_id_buff, field->pack_length(), help_charset,
+ field->get_key_image(topic_id_buff, field->pack_length(), field->charset(),
Field::itRAW);
-
+
if (!topics->file->index_read(topics->record[0], (byte *)topic_id_buff,
- field->pack_length(),
- HA_READ_KEY_EXACT))
- res->push_back(get_field(&thd->mem_root,
- find_fields[help_topic_name].field));
+ field->pack_length(), HA_READ_KEY_EXACT))
+ {
+ memorize_variant_topic(thd,topics,count,find_fields,
+ names,name,description,example);
+ count++;
+ }
}
- DBUG_RETURN(0);
+ DBUG_RETURN(count);
+}
+
+/*
+ Look for topics with keyword by mask
+
+ SYNOPSIS
+ search_topics_by_keyword()
+ thd Thread handler
+ keywords Table of keywords
+ topics Table of topics
+ relations Table of m:m relation "topic/keyword"
+ find_fields Filled array of info for fields
+ select Function to test for if matching help keyword.
+ Normally 'help_keyword.name like 'bit%'
+
+ RETURN VALUES
+ # number of topics found
+
+ names array of name of found topics (out)
+
+ name name of found topic (out)
+ description description of found topic (out)
+ example example for found topic (out)
+
+ NOTE
+ Field 'names' is set only if more than one topic was found.
+ Fields 'name', 'description', 'example' are set only if
+ exactly one topic was found.
+*/
+
+int search_topics_by_keyword(THD *thd,
+ TABLE *keywords, TABLE *topics, TABLE *relations,
+ struct st_find_field *find_fields,
+ SQL_SELECT *select, List<String> *names,
+ String *name, String *description, String *example)
+{
+ int key_id;
+ return search_keyword(thd,keywords,find_fields,select,&key_id)!=1
+ ? 0 : get_topics_for_keyword(thd,topics,relations,find_fields,key_id,
+ names,name,description,example);
+}
+
+/*
+ Look for categories by mask
+
+ SYNOPSIS
+ search_categories()
+ thd THD for init_read_record
+ categories Table of categories
+ find_fields Filled array of info for fields
+ select Function to test for if matching help topic.
+ Normally 'help_vategory.name like 'bit%'
+ names List of found categories names (out)
+ res_id Primary index of found category (only if
+ found exactly one category)
+
+ RETURN VALUES
+ # Number of categories found
+*/
+
+int search_categories(THD *thd, TABLE *categories,
+ struct st_find_field *find_fields,
+ SQL_SELECT *select, List<String> *names, int16 *res_id)
+{
+ Field *pfname= find_fields[help_category_name].field;
+ Field *pcat_id= find_fields[help_category_help_category_id].field;
+ int count= 0;
+ READ_RECORD read_record_info;
+
+ DBUG_ENTER("search_categories");
+
+ init_read_record(&read_record_info, thd, categories, select,1,0);
+ while (!read_record_info.read_record(&read_record_info))
+ {
+ if (select && !select->cond->val_int())
+ continue;
+ String *lname= new String;
+ get_field(&thd->mem_root,pfname,lname);
+ if (++count == 1 && res_id)
+ *res_id= (int16) pcat_id->val_int();
+ names->push_back(lname);
+ }
+ end_read_record(&read_record_info);
+
+ DBUG_RETURN(count);
}
+/*
+ Look for all topics or subcategories of category
+
+ SYNOPSIS
+ get_all_items_for_category()
+ thd Thread handler
+ items Table of items
+ pfname Field "name" in items
+ select "where" part of query..
+ res list of finded names
+*/
+
+void get_all_items_for_category(THD *thd, TABLE *items, Field *pfname,
+ SQL_SELECT *select, List<String> *res)
+{
+ DBUG_ENTER("get_all_items_for_category");
+
+ READ_RECORD read_record_info;
+ init_read_record(&read_record_info, thd, items, select,1,0);
+ while (!read_record_info.read_record(&read_record_info))
+ {
+ if (!select->cond->val_int())
+ continue;
+ String *name= new String();
+ get_field(&thd->mem_root,pfname,name);
+ res->push_back(name);
+ }
+ end_read_record(&read_record_info);
+
+ DBUG_VOID_RETURN;
+}
/*
Send to client answer for help request
@@ -284,17 +438,16 @@ int get_all_topics_for_category(THD *thd, TABLE *topics, TABLE *relations,
send_answer_1()
protocol - protocol for sending
s1 - value of column "Name"
- s2 - value of column "Category"
- s3 - value of column "Description"
- s4 - value of column "Example"
+ s2 - value of column "Description"
+ s3 - value of column "Example"
IMPLEMENTATION
Format used:
- +----------+---------+------------+------------+
- |Name: |Category |Description |Example |
- +----------+---------+------------+------------+
- |String(64)|String(1)|String(1000)|String(1000)|
- +----------+---------+------------+------------+
+ +----------+------------+------------+
+ |name |description |example |
+ +----------+------------+------------+
+ |String(64)|String(1000)|String(1000)|
+ +----------+------------+------------+
with exactly one row!
RETURN VALUES
@@ -303,24 +456,21 @@ int get_all_topics_for_category(THD *thd, TABLE *topics, TABLE *relations,
0 Successeful send
*/
-int send_answer_1(Protocol *protocol, const char *s1, const char *s2,
- const char *s3, const char *s4)
+int send_answer_1(Protocol *protocol, String *s1, String *s2, String *s3)
{
DBUG_ENTER("send_answer_1");
List<Item> field_list;
- field_list.push_back(new Item_empty_string("Name",64));
- field_list.push_back(new Item_empty_string("Category",1));
- field_list.push_back(new Item_empty_string("Description",1000));
- field_list.push_back(new Item_empty_string("Example",1000));
+ field_list.push_back(new Item_empty_string("name",64));
+ field_list.push_back(new Item_empty_string("description",1000));
+ field_list.push_back(new Item_empty_string("example",1000));
if (protocol->send_fields(&field_list,1))
DBUG_RETURN(1);
protocol->prepare_for_resend();
- protocol->store(s1, system_charset_info);
- protocol->store(s2, system_charset_info);
- protocol->store(s3, system_charset_info);
- protocol->store(s4, system_charset_info);
+ protocol->store(s1);
+ protocol->store(s2);
+ protocol->store(s3);
if (protocol->write())
DBUG_RETURN(-1);
DBUG_RETURN(0);
@@ -332,28 +482,151 @@ int send_answer_1(Protocol *protocol, const char *s1, const char *s2,
SYNOPSIS
send_header_2()
- protocol - protocol for sending
+ protocol - protocol for sending
+ is_it_category - need column 'source_category_name'
IMPLEMENTATION
- +----------+---------+
- |Name: |Category |
- +----------+---------+
- |String(64)|String(1)|
- +----------+---------+
+ +- -+
+ |+-------------------- | +----------+--------------+
+ ||source_category_name | |name |is_it_category|
+ |+-------------------- | +----------+--------------+
+ ||String(64) | |String(64)|String(1) |
+ |+-------------------- | +----------+--------------+
+ +- -+
RETURN VALUES
result of protocol->send_fields
*/
-int send_header_2(Protocol *protocol)
+int send_header_2(Protocol *protocol, bool for_category)
{
- DBUG_ENTER("send_header2");
+ DBUG_ENTER("send_header_2");
List<Item> field_list;
- field_list.push_back(new Item_empty_string("Name",64));
- field_list.push_back(new Item_empty_string("Category",1));
+ if (for_category)
+ field_list.push_back(new Item_empty_string("source_category_name",64));
+ field_list.push_back(new Item_empty_string("name",64));
+ field_list.push_back(new Item_empty_string("is_it_category",1));
DBUG_RETURN(protocol->send_fields(&field_list,1));
}
+/*
+ strcmp for using in qsort
+
+ SYNOPSIS
+ strptrcmp()
+ ptr1 (const void*)&str1
+ ptr2 (const void*)&str2
+
+ RETURN VALUES
+ same as strcmp
+*/
+
+int string_ptr_cmp(const void* ptr1, const void* ptr2)
+{
+ String *str1= *(String**)ptr1;
+ String *str2= *(String**)ptr2;
+ return strcmp(str1->c_ptr(),str2->c_ptr());
+}
+
+/*
+ Send to client rows in format:
+ column1 : <name>
+ column2 : <is_it_category>
+
+ SYNOPSIS
+ send_variant_2_list()
+ protocol Protocol for sending
+ names List of names
+ cat Value of the column <is_it_category>
+ source_name name of category for all items..
+
+ RETURN VALUES
+ -1 Writing fail
+ 0 Data was successefully send
+*/
+
+int send_variant_2_list(MEM_ROOT *mem_root, Protocol *protocol,
+ List<String> *names,
+ const char *cat, String *source_name)
+{
+ DBUG_ENTER("send_variant_2_list");
+
+ String **pointers= (String**)alloc_root(mem_root,
+ sizeof(String*)*names->elements);
+ String **pos= pointers;
+
+ List_iterator<String> it(*names);
+ String *cur_name;
+ while (*pos++= it++);
+
+ qsort(pointers,names->elements,sizeof(String*),string_ptr_cmp);
+
+ String **end= pointers + names->elements;
+ for (String **pos= pointers; pos!=end; pos++)
+ {
+ protocol->prepare_for_resend();
+ if (source_name)
+ protocol->store(source_name);
+ protocol->store(*pos);
+ protocol->store(cat,1,&my_charset_latin1);
+ if (protocol->write())
+ DBUG_RETURN(-1);
+ }
+
+ DBUG_RETURN(0);
+}
+
+/*
+ Prepare simple SQL_SELECT table.* WHERE <Item>
+
+ SYNOPSIS
+ prepare_simple_select()
+ thd Thread handler
+ cond WHERE part of select
+ tables list of tables, used in WHERE
+ table goal table
+
+ error code of error (out)
+
+ RETURN VALUES
+ # created SQL_SELECT
+*/
+
+SQL_SELECT *prepare_simple_select(THD *thd, Item *cond, TABLE_LIST *tables,
+ TABLE *table, int *error)
+{
+ cond->fix_fields(thd, tables, &cond); // can never fail
+ SQL_SELECT *res= make_select(table,0,0,cond,error);
+ return (*error || (res && res->check_quick(0, HA_POS_ERROR))) ? 0 : res;
+}
+
+/*
+ Prepare simple SQL_SELECT table.* WHERE table.name LIKE mask
+
+ SYNOPSIS
+ prepare_select_for_name()
+ thd Thread handler
+ mask mask for compare with name
+ mlen length of mask
+ tables list of tables, used in WHERE
+ table goal table
+ pfname field "name" in table
+
+ error code of error (out)
+
+ RETURN VALUES
+ # created SQL_SELECT
+*/
+
+SQL_SELECT *prepare_select_for_name(THD *thd, const char *mask, uint mlen,
+ TABLE_LIST *tables, TABLE *table,
+ Field *pfname, int *error)
+{
+ Item *cond= new Item_func_like(new Item_field(pfname),
+ new Item_string(mask,mlen,pfname->charset()),
+ (char*) "\\");
+ return prepare_simple_select(thd,cond,tables,table,error);
+}
/*
Server-side function 'help'
@@ -371,12 +644,13 @@ int send_header_2(Protocol *protocol)
int mysqld_help(THD *thd, const char *mask)
{
Protocol *protocol= thd->protocol;
- SQL_SELECT *select= 0, *select_cat= 0;
- Item *cond_topic, *cond_cat;
+ SQL_SELECT *select_topics_by_name= 0, *select_keyword_by_name= 0,
+ *select_cat_by_name= 0, *select_topics_by_cat= 0, *select_cat_by_cat= 0,
+ *select_root_cats= 0;
st_find_field used_fields[array_elements(init_used_fields)];
DBUG_ENTER("mysqld_help");
- TABLE_LIST tables[3];
+ TABLE_LIST tables[4];
bzero((gptr)tables,sizeof(tables));
tables[0].alias= tables[0].real_name= (char*) "help_topic";
tables[0].lock_type= TL_READ;
@@ -389,11 +663,17 @@ int mysqld_help(THD *thd, const char *mask)
tables[2].alias= tables[2].real_name= (char*) "help_relation";
tables[2].lock_type= TL_READ;
tables[2].db= (char*) "mysql";
- tables[2].next= 0;
+ tables[2].next= &tables[3];
+ tables[3].alias= tables[3].real_name= (char*) "help_keyword";
+ tables[3].lock_type= TL_READ;
+ tables[3].db= (char*) "mysql";
+ tables[3].next= 0;
- List<char> function_list, categories_list;
- char *name, *description, *example;
+ List<String> topics_list, categories_list, subcategories_list;
+ String name, description, example;
int res, count_topics, count_categories, error;
+ uint mlen= strlen(mask);
+ MEM_ROOT *mem_root= &thd->mem_root;
if (open_and_lock_tables(thd, tables))
{
@@ -409,111 +689,101 @@ int mysqld_help(THD *thd, const char *mask)
goto end;
}
- /* TODO: Find out why these are needed (should not be) */
- tables[0].table->file->init_table_handle_for_HANDLER();
- tables[1].table->file->init_table_handle_for_HANDLER();
- tables[2].table->file->init_table_handle_for_HANDLER();
+ for (int i=0; i<sizeof(tables)/sizeof(TABLE_LIST); i++)
+ tables[i].table->file->init_table_handle_for_HANDLER();
- cond_topic= new Item_func_like(new Item_field(used_fields[help_topic_name].
- field),
- new Item_string(mask, strlen(mask),
- help_charset),
- (char*) "\\");
- cond_topic->fix_fields(thd, tables, &cond_topic); // can never fail
- select= make_select(tables[0].table,0,0,cond_topic,&error);
- if (error || (select && select->check_quick(0, HA_POS_ERROR)))
- {
- res= -1;
- goto end;
- }
-
- cond_cat= new Item_func_like(new Item_field(used_fields[help_category_name].
- field),
- new Item_string(mask, strlen(mask),
- help_charset),
- (char*) "\\");
- cond_cat->fix_fields(thd, tables, &cond_topic); // can never fail
- select_cat= make_select(tables[1].table,0,0,cond_cat,&error);
- if (error || (select_cat && select_cat->check_quick(0, HA_POS_ERROR)))
+ if (!(select_topics_by_name=
+ prepare_select_for_name(thd,mask,mlen,tables,tables[0].table,
+ used_fields[help_topic_name].field,&error)) ||
+ !(select_cat_by_name=
+ prepare_select_for_name(thd,mask,mlen,tables,tables[1].table,
+ used_fields[help_category_name].field,&error))||
+ !(select_keyword_by_name=
+ prepare_select_for_name(thd,mask,mlen,tables,tables[3].table,
+ used_fields[help_keyword_name].field,&error)))
{
res= -1;
goto end;
}
res= 1;
- count_topics= search_topics(thd,tables[0].table, used_fields, select,
- &function_list, &name, &description, &example);
+ count_topics= search_topics(thd,tables[0].table,used_fields,
+ select_topics_by_name,&topics_list,
+ &name, &description, &example);
+
+ if (count_topics == 0)
+ count_topics= search_topics_by_keyword(thd,tables[3].table,tables[0].table,
+ tables[2].table,used_fields,
+ select_keyword_by_name,&topics_list,
+ &name,&description,&example);
+
if (count_topics == 0)
{
int16 category_id;
- Item *cond=
- new Item_func_like(new
- Item_field(used_fields[help_category_name].field),
- new Item_string(mask, strlen(mask),
- help_charset),
- (char*) "\\");
- (void) cond->fix_fields(thd, tables, &cond); // can never fail
-
+ Field *cat_cat_id= used_fields[help_category_parent_category_id].field;
count_categories= search_categories(thd, tables[1].table, used_fields,
- select_cat, &categories_list,
- &category_id);
- if (count_categories == 1)
+ select_cat_by_name,
+ &categories_list,&category_id);
+ if (!count_categories)
{
- if (get_all_topics_for_category(thd,tables[0].table,
- tables[2].table, used_fields,
- category_id, &function_list))
- {
- res= -1;
+ if (send_header_2(protocol,false))
goto end;
- }
- List_iterator<char> it(function_list);
- char *cur_topic;
- char buff[1024];
- String example(buff, sizeof(buff), help_charset);
- example.length(0);
-
- while ((cur_topic= it++))
- {
- example.append(cur_topic);
- example.append("\n",1);
- }
- if ((send_answer_1(protocol, categories_list.head(),
- "Y","",example.ptr())))
+ }
+ else if (count_categories > 1)
+ {
+ if (send_header_2(protocol,false) ||
+ send_variant_2_list(mem_root,protocol,&categories_list,"Y",0))
goto end;
}
- else
+ else
{
- if (send_header_2(protocol))
+ Field *topic_cat_id= used_fields[help_topic_help_category_id].field;
+ Item *cond_topic_by_cat= new Item_func_equal(new Item_field(topic_cat_id),
+ new Item_int(category_id));
+ Item *cond_cat_by_cat= new Item_func_equal(new Item_field(cat_cat_id),
+ new Item_int(category_id));
+ if (!(select_topics_by_cat= prepare_simple_select(thd,cond_topic_by_cat,
+ tables,tables[0].table,
+ &error)) ||
+ !(select_cat_by_cat= prepare_simple_select(thd,cond_cat_by_cat,tables,
+ tables[1].table,&error)))
+ {
+ res= -1;
goto end;
- if (count_categories == 0)
- search_categories(thd,tables[1].table, used_fields, (SQL_SELECT *) 0,
- &categories_list, 0);
- if (send_variant_2_list(protocol,&categories_list,"Y"))
+ }
+ get_all_items_for_category(thd,tables[0].table,
+ used_fields[help_topic_name].field,
+ select_topics_by_cat,&topics_list);
+ get_all_items_for_category(thd,tables[1].table,
+ used_fields[help_category_name].field,
+ select_cat_by_cat,&subcategories_list);
+ String *cat= categories_list.head();
+ if (send_header_2(protocol, true) ||
+ send_variant_2_list(mem_root,protocol,&topics_list, "N",cat) ||
+ send_variant_2_list(mem_root,protocol,&subcategories_list,"Y",cat))
goto end;
}
}
else if (count_topics == 1)
{
- if (send_answer_1(protocol,name,"N",description, example))
+ if (send_answer_1(protocol,&name,&description,&example))
goto end;
}
else
{
/* First send header and functions */
- if (send_header_2(protocol) ||
- send_variant_2_list(protocol, &function_list, "N"))
+ if (send_header_2(protocol, false) ||
+ send_variant_2_list(mem_root,protocol, &topics_list, "N", 0))
goto end;
- search_categories(thd, tables[1].table, used_fields, select_cat,
- &categories_list, 0);
+ search_categories(thd, tables[1].table, used_fields,
+ select_cat_by_name,&categories_list, 0);
/* Then send categories */
- if (send_variant_2_list(protocol, &categories_list, "Y"))
+ if (send_variant_2_list(mem_root,protocol, &categories_list, "Y", 0))
goto end;
}
res= 0;
send_eof(thd);
end:
- delete select;
- delete select_cat;
DBUG_RETURN(res);
}
diff --git a/sql/table.cc b/sql/table.cc
index 3aed75c7ac6..908d6807450 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -1161,6 +1161,33 @@ rename_file_ext(const char * from,const char * to,const char * ext)
/*
+ Allocate string field in MEM_ROOT and return it as String
+
+ SYNOPSIS
+ get_field()
+ mem MEM_ROOT for allocating
+ field Field for retrieving of string
+ res result String
+
+ RETURN VALUES
+ true string is empty
+ false all ok
+*/
+
+bool get_field(MEM_ROOT *mem, Field *field, String *res)
+{
+ char buff[MAX_FIELD_WIDTH];
+ String str(buff,sizeof(buff),&my_charset_bin);
+ field->val_str(&str,&str);
+ uint length=str.length();
+ if (!length)
+ return true;
+ char *to= strmake_root(mem, str.ptr(), length);
+ res->set(to,length,((Field_str*)field)->charset());
+ return false;
+}
+
+/*
Allocate string field in MEM_ROOT and return it as NULL-terminated string
SYNOPSIS