mirror of
https://github.com/MariaDB/server.git
synced 2025-07-27 18:02:13 +03:00
Fixed a lot of wrong memory references as reported by valgrind
Portability fixes Added new client function: mysql_get_server_version() New server help code (From Victor Vagin) Fixed wrong usage of binary() Disabled RTREE usage for now. BitKeeper/etc/ignore: added scripts/fill_help_tables.sql client/mysql.cc: Some fixes when using 'help' cmd-line-utils/libedit/compat.h: Portability fix cmd-line-utils/libedit/fgetln.c: Portability fix include/mysql.h: Added new client function: mysql_get_server_version() libmysql/libmysql.c: Added new client function: mysql_get_server_version() libmysqld/libmysqld.c: Fixed prototype mysql-test/install_test_db.sh: Added creation of help tables mysql-test/r/connect.result: Added help tables mysql-test/r/myisam.result: Test of RTREE index mysql-test/r/type_ranges.result: updated results mysql-test/t/myisam.test: Test of RTREE index mysql-test/t/type_ranges.test: Updated test mysys/charset.c: Indentation change mysys/my_symlink.c: Removed compiler warning scripts/fill_help_tables.sh: Update for new help tables sql/field.cc: Indentation changes sql/filesort.cc: Optimized character set usage sql/item_cmpfunc.cc: Fix wrong usage of binary() sql/item_cmpfunc.h: Fix wrong usage of binary() sql/item_func.cc: Fix wrong usage of binary() sql/item_func.h: Fix wrong usage of binary() sql/item_strfunc.cc: Fix wrong usage of binary() sql/item_sum.cc: Fix wrong usage of binary() sql/item_sum.h: Fix wrong usage of binary() sql/key.cc: Indentation change sql/lex.h: HELP -> HELP_SYM sql/mysql_priv.h: Make get_field() more general sql/password.c: Indentation change + variable initialisation moved sql/sql_acl.cc: Make get_field() more general sql/sql_base.cc: Added comments + assertion for double call to mysql_lock_tables sql/sql_cache.cc: Indentation changes sql/sql_class.h: Added need_strxnfrm to SORT_FIELD to be able to optimise character set handling in filesort sql/sql_derived.cc: Renamed variables sql/sql_help.cc: New help functions (from Victor Vagin) sql/sql_lex.cc: Removed variables that doesn't have to be initialized for each query sql/sql_lex.h: Removed not used variable (olap) sql/sql_parse.cc: Fixed (not fatal) access of unitialized memory Indentation / code cleanup sql/sql_prepare.cc: Indentaion cleanup sql/sql_table.cc: Disabled RTREE until 5.0 sql/sql_udf.cc: Make get_field() more general sql/sql_yacc.yy: Removed access to uninitialized memory Always set offset_limit and select_limit when using LIMIT (removed warnings) Allow usage of 'help week' sql/table.cc: Make get_field() more general More comments sql/table.h: Fixded type of TABLE_LIST->derived sql/time.cc: Stricter date / datetime handling (to be able to handle timestamps with days and microseconds) strings/ctype-bin.c: Added cha
This commit is contained in:
667
sql/sql_help.cc
667
sql/sql_help.cc
@ -15,288 +15,294 @@
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#include "mysql_priv.h"
|
||||
#include "sql_select.h" // For select_describe
|
||||
#include "sql_acl.h"
|
||||
|
||||
/***************************************************************************
|
||||
** Get help on string
|
||||
***************************************************************************/
|
||||
struct st_find_field
|
||||
{
|
||||
const char *table_name, *field_name;
|
||||
Field *field;
|
||||
};
|
||||
|
||||
/* Used fields */
|
||||
|
||||
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}
|
||||
};
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
/*
|
||||
Fill local used field structure with pointer to fields */
|
||||
|
||||
static bool init_fields(THD *thd, TABLE_LIST *tables,
|
||||
struct st_find_field *find_field,
|
||||
uint count)
|
||||
{
|
||||
for (; count-- ; find_field++)
|
||||
{
|
||||
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,
|
||||
¬_used,
|
||||
TRUE)))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#define help_charset &my_charset_latin1
|
||||
|
||||
MI_INFO *open_help_file(THD *thd, const char *name)
|
||||
{
|
||||
char path[FN_REFLEN];
|
||||
(void) sprintf(path,"%s/mysql_help/%s",mysql_data_home,name);
|
||||
MI_INFO *res= 0;
|
||||
if (!(res= mi_open(path,O_RDONLY,HA_OPEN_WAIT_IF_LOCKED)))
|
||||
{
|
||||
send_error(thd,ER_CORRUPT_HELP_DB);
|
||||
return 0;
|
||||
}
|
||||
mi_extra(res,HA_EXTRA_WAIT_LOCK,0);
|
||||
return res;
|
||||
}
|
||||
/*
|
||||
Look for topics by mask
|
||||
|
||||
#define size_hf_func_id 4 /* func_id int unsigned, */
|
||||
#define size_hf_name 64 /* name varchar(64), */
|
||||
#define size_hf_url 128 /* url varchar(128), */
|
||||
#define size_hf_description sizeof(char*) /* description text, */
|
||||
#define size_hf_example sizeof(char*) /* example text, */
|
||||
#define size_hf_min_args 16 /* min_args tinyint, */
|
||||
#define size_hf_max_args 16 /* max_args tinyint, */
|
||||
#define size_hf_date_created 8 /* date_created datetime, */
|
||||
#define size_hf_last_modified 8 /* last_modified timestamp, */
|
||||
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.
|
||||
RETURN VALUES
|
||||
# number of topics founded
|
||||
*/
|
||||
|
||||
#define offset_hf_func_id 1
|
||||
#define offset_hf_name (offset_hf_func_id+size_hf_func_id)
|
||||
#define offset_hf_url (offset_hf_name+size_hf_name)
|
||||
#define offset_hf_description (offset_hf_url+size_hf_url)
|
||||
#define offset_hf_example (offset_hf_description+size_hf_description)
|
||||
#define offset_hf_min_args (offset_hf_example+size_hf_example)
|
||||
#define offset_hf_max_args (offset_hf_min_args+size_hf_min_args)
|
||||
#define offset_hf_date_created (offset_hf_max_args+size_hf_max_args)
|
||||
#define offset_hf_last_modified (offset_hf_date_created+size_hf_date_created)
|
||||
|
||||
#define HELP_LEAF_SIZE (offset_hf_last_modified+size_hf_last_modified)
|
||||
|
||||
class help_leaf{
|
||||
public:
|
||||
char record[HELP_LEAF_SIZE];
|
||||
|
||||
inline const char *get_name()
|
||||
{
|
||||
return &record[offset_hf_name];
|
||||
}
|
||||
|
||||
inline const char *get_description()
|
||||
{
|
||||
return *((char**)&record[199/*offset_hf_description*/]);
|
||||
}
|
||||
|
||||
inline const char *get_example()
|
||||
{
|
||||
return *((char**)&record[209/*offset_hf_example*/]);
|
||||
}
|
||||
|
||||
void prepare_fields()
|
||||
{
|
||||
const char *name= get_name();
|
||||
const char *c= name + size_hf_name - 1;
|
||||
while (*c==' ') c--;
|
||||
int len= c-name+1;
|
||||
((char*)name)[len]= '\0';
|
||||
}
|
||||
};
|
||||
|
||||
int search_functions(MI_INFO *file_leafs, const char *mask,
|
||||
List<String> *names,
|
||||
String **name, String **description, String **example)
|
||||
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)
|
||||
{
|
||||
DBUG_ENTER("search_functions");
|
||||
int count= 0;
|
||||
|
||||
if (mi_scan_init(file_leafs))
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
help_leaf leaf;
|
||||
|
||||
while (!mi_scan(file_leafs,(byte*)&leaf))
|
||||
|
||||
READ_RECORD read_record_info;
|
||||
init_read_record(&read_record_info, thd, topics, select,1,0);
|
||||
while (!read_record_info.read_record(&read_record_info))
|
||||
{
|
||||
leaf.prepare_fields();
|
||||
|
||||
const char *lname= leaf.get_name();
|
||||
if (wild_case_compare(help_charset,lname,mask))
|
||||
if (!select->cond->val_int()) // Dosn't match like
|
||||
continue;
|
||||
count++;
|
||||
|
||||
if (count>2)
|
||||
char *lname= get_field(&thd->mem_root, find_field[help_topic_name].field);
|
||||
count++;
|
||||
if (count > 2)
|
||||
{
|
||||
String *s= new String(lname,help_charset);
|
||||
if (!s->copy())
|
||||
names->push_back(s);
|
||||
names->push_back(lname);
|
||||
}
|
||||
else if (count==1)
|
||||
else if (count == 1)
|
||||
{
|
||||
*description= new String(leaf.get_description(),help_charset);
|
||||
*example= new String(leaf.get_example(),help_charset);
|
||||
*name= new String(lname,help_charset);
|
||||
(*description)->copy();
|
||||
(*example)->copy();
|
||||
(*name)->copy();
|
||||
*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);
|
||||
delete *description;
|
||||
delete *example;
|
||||
names->push_back(lname);
|
||||
*name= 0;
|
||||
*description= 0;
|
||||
*example= 0;
|
||||
|
||||
String *s= new String(lname,help_charset);
|
||||
if (!s->copy())
|
||||
names->push_back(s);
|
||||
}
|
||||
}
|
||||
end_read_record(&read_record_info);
|
||||
DBUG_RETURN(count);
|
||||
}
|
||||
|
||||
/*
|
||||
Look for categories 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)
|
||||
|
||||
RETURN VALUES
|
||||
# Number of categories founded
|
||||
*/
|
||||
|
||||
int search_categories(THD *thd, TABLE *categories,
|
||||
struct st_find_field *find_fields,
|
||||
SQL_SELECT *select, List<char> *names, int16 *res_id)
|
||||
{
|
||||
Field *pfname= find_fields[help_category_name].field;
|
||||
DBUG_ENTER("search_categories");
|
||||
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))
|
||||
{
|
||||
if (select && !select->cond->val_int())
|
||||
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);
|
||||
}
|
||||
end_read_record(&read_record_info);
|
||||
|
||||
DBUG_RETURN(count);
|
||||
}
|
||||
|
||||
#define size_hc_cat_id 2 /* cat_id smallint, */
|
||||
#define size_hc_name 64 /* name varchar(64), */
|
||||
#define size_hc_url 128 /* url varchar(128), */
|
||||
#define size_hc_date_created 8 /* date_created datetime, */
|
||||
#define size_hc_last_modified 8 /* last_modified timestamp, */
|
||||
|
||||
#define offset_hc_cat_id 0
|
||||
#define offset_hc_name (offset_hc_cat_id+size_hc_cat_id)
|
||||
#define offset_hc_url (offset_hc_name+size_hc_name)
|
||||
#define offset_hc_date_created (offset_hc_url+size_hc_url)
|
||||
#define offset_hc_last_modified (offset_hc_date_created+size_hc_date_created)
|
||||
/*
|
||||
Send to client rows in format:
|
||||
column1 : <name>
|
||||
column2 : <is_it_category>
|
||||
|
||||
#define HELP_CATEGORY_SIZE (offset_hc_last_modified+size_hc_last_modified)
|
||||
SYNOPSIS
|
||||
send_variant_2_list()
|
||||
protocol Protocol for sending
|
||||
names List of names
|
||||
cat Value of the column <is_it_category>
|
||||
|
||||
class help_category{
|
||||
public:
|
||||
char record[HELP_CATEGORY_SIZE];
|
||||
RETURN VALUES
|
||||
-1 Writing fail
|
||||
0 Data was successefully send
|
||||
*/
|
||||
|
||||
inline int16 get_cat_id()
|
||||
{
|
||||
return sint2korr(&record[offset_hc_cat_id]);
|
||||
}
|
||||
|
||||
inline const char *get_name()
|
||||
{
|
||||
return &record[offset_hc_name];
|
||||
}
|
||||
|
||||
void prepare_fields()
|
||||
{
|
||||
const char *name= get_name();
|
||||
const char *c= name + size_hc_name - 1;
|
||||
while (*c==' ') c--;
|
||||
int len= c-name+1;
|
||||
((char*)name)[len]= '\0';
|
||||
}
|
||||
};
|
||||
|
||||
int search_categories(THD *thd,
|
||||
const char *mask, List<String> *names, int16 *res_id)
|
||||
{
|
||||
DBUG_ENTER("search_categories");
|
||||
int count= 0;
|
||||
|
||||
MI_INFO *file_categories= 0;
|
||||
if (!(file_categories= open_help_file(thd,"function_category_name")))
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
if (mi_scan_init(file_categories))
|
||||
{
|
||||
mi_close(file_categories);
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
help_category category;
|
||||
|
||||
|
||||
while (!mi_scan(file_categories,(byte*)&category))
|
||||
{
|
||||
category.prepare_fields();
|
||||
|
||||
const char *lname= category.get_name();
|
||||
if (mask && wild_case_compare(help_charset,lname,mask))
|
||||
continue;
|
||||
count++;
|
||||
|
||||
if (count==1 && res_id)
|
||||
*res_id= category.get_cat_id();
|
||||
|
||||
String *s= new String(lname,help_charset);
|
||||
if (!s->copy())
|
||||
names->push_back(s);
|
||||
}
|
||||
|
||||
mi_close(file_categories);
|
||||
DBUG_RETURN(count);
|
||||
}
|
||||
|
||||
int send_variant_2_list(Protocol *protocol, List<String> *names,
|
||||
my_bool is_category)
|
||||
int send_variant_2_list(Protocol *protocol, List<char> *names,
|
||||
const char *cat)
|
||||
{
|
||||
DBUG_ENTER("send_names");
|
||||
|
||||
List_iterator<String> it(*names);
|
||||
String *cur_name;
|
||||
while ((cur_name = it++))
|
||||
|
||||
List_iterator<char> it(*names);
|
||||
const char *cur_name;
|
||||
while ((cur_name= it++))
|
||||
{
|
||||
protocol->prepare_for_resend();
|
||||
protocol->store(cur_name->ptr());
|
||||
protocol->store(is_category ? "Y" : "N");
|
||||
protocol->store(cur_name);
|
||||
protocol->store(cat);
|
||||
if (protocol->write())
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
#define size_hcn_cat_id 2 /* cat_id smallint, */
|
||||
#define size_hcn_func_id 4 /* func_id int, */
|
||||
|
||||
#define offset_hcn_cat_id 1
|
||||
#define offset_hcn_func_id (offset_hcn_cat_id+size_hcn_cat_id)
|
||||
/*
|
||||
Look for all topics of category
|
||||
|
||||
#define HELP_CATEGORY_NAME_SIZE (offset_hcn_func_id + size_hcn_func_id)
|
||||
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)
|
||||
|
||||
class help_category_leaf{
|
||||
public:
|
||||
char record[HELP_CATEGORY_NAME_SIZE];
|
||||
RETURN VALUES
|
||||
-1 corrupt database
|
||||
0 succesefull
|
||||
*/
|
||||
|
||||
inline int16 get_cat_id()
|
||||
{
|
||||
return sint2korr(&record[offset_hcn_cat_id]);
|
||||
}
|
||||
|
||||
inline int get_func_id()
|
||||
{
|
||||
return sint3korr(&record[offset_hcn_func_id]);
|
||||
}
|
||||
};
|
||||
|
||||
int get_all_names_for_category(THD *thd,MI_INFO *file_leafs,
|
||||
int16 cat_id, List<String> *res)
|
||||
int get_all_topics_for_category(THD *thd, TABLE *topics, TABLE *relations,
|
||||
struct st_find_field *find_fields,
|
||||
int16 cat_id, List<char> *res)
|
||||
{
|
||||
DBUG_ENTER("get_all_names_for_category");
|
||||
|
||||
MI_INFO *file_names_categories= 0;
|
||||
if (!(file_names_categories= open_help_file(thd,"function_category")))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
help_category_leaf cat_leaf;
|
||||
help_leaf leaf;
|
||||
int key_res= mi_rkey(file_names_categories, (byte*)&cat_leaf, 0,
|
||||
(const byte*)&cat_id,2,HA_READ_KEY_EXACT);
|
||||
|
||||
while (!key_res && cat_leaf.get_cat_id()==cat_id)
|
||||
char buff[8]; // Max int length
|
||||
DBUG_ENTER("get_all_topics_for_category");
|
||||
|
||||
int iindex_topic, iindex_relations;
|
||||
Field *rtopic_id, *rcat_id;
|
||||
|
||||
if ((iindex_topic= find_type((char*) "PRIMARY",
|
||||
&topics->keynames, 1+2)-1)<0 ||
|
||||
(iindex_relations= find_type((char*) "PRIMARY",
|
||||
&relations->keynames, 1+2)-1)<0)
|
||||
{
|
||||
int leaf_id= cat_leaf.get_func_id();
|
||||
|
||||
if (!mi_rkey(file_leafs, (byte*)&leaf, 0,
|
||||
(const byte*)&leaf_id,4,HA_READ_KEY_EXACT))
|
||||
{
|
||||
leaf.prepare_fields();
|
||||
String *s= new String(leaf.get_name(),help_charset);
|
||||
if (!s->copy())
|
||||
res->push_back(s);
|
||||
}
|
||||
|
||||
key_res= mi_rnext(file_names_categories, (byte*)&cat_leaf, 0);
|
||||
send_error(thd,ER_CORRUPT_HELP_DB);
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
rtopic_id= find_fields[help_relation_help_topic_id].field;
|
||||
rcat_id= find_fields[help_relation_help_category_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,
|
||||
Field::itRAW);
|
||||
int key_res= relations->file->index_read(relations->record[0],
|
||||
buff, rcat_id->pack_length(),
|
||||
HA_READ_KEY_EXACT);
|
||||
|
||||
for ( ; !key_res && cat_id == (int16) rcat_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::itRAW);
|
||||
|
||||
mi_close(file_names_categories);
|
||||
|
||||
if (!topics->file->index_read(topics->record[0], topic_id_buff,
|
||||
field->pack_length(),
|
||||
HA_READ_KEY_EXACT))
|
||||
res->push_back(get_field(&thd->mem_root,
|
||||
find_fields[help_topic_name].field));
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Send to client answer for help request
|
||||
|
||||
SYNOPSIS
|
||||
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"
|
||||
|
||||
IMPLEMENTATION
|
||||
Format used:
|
||||
+----------+---------+------------+------------+
|
||||
|Name: |Category |Description |Example |
|
||||
+----------+---------+------------+------------+
|
||||
|String(64)|String(1)|String(1000)|String(1000)|
|
||||
+----------+---------+------------+------------+
|
||||
with exactly one row!
|
||||
|
||||
RETURN VALUES
|
||||
1 Writing of head failed
|
||||
-1 Writing of row failed
|
||||
0 Successeful send
|
||||
*/
|
||||
|
||||
int send_answer_1(Protocol *protocol, const char *s1, const char *s2,
|
||||
const char *s3, const char *s4)
|
||||
{
|
||||
@ -306,10 +312,10 @@ int send_answer_1(Protocol *protocol, const char *s1, const char *s2,
|
||||
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));
|
||||
|
||||
|
||||
if (protocol->send_fields(&field_list,1))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
|
||||
protocol->prepare_for_resend();
|
||||
protocol->store(s1);
|
||||
protocol->store(s2);
|
||||
@ -317,11 +323,28 @@ int send_answer_1(Protocol *protocol, const char *s1, const char *s2,
|
||||
protocol->store(s4);
|
||||
if (protocol->write())
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Send to client help header
|
||||
|
||||
SYNOPSIS
|
||||
send_header_2()
|
||||
protocol - protocol for sending
|
||||
|
||||
IMPLEMENTATION
|
||||
+----------+---------+
|
||||
|Name: |Category |
|
||||
+----------+---------+
|
||||
|String(64)|String(1)|
|
||||
+----------+---------+
|
||||
|
||||
RETURN VALUES
|
||||
result of protocol->send_fields
|
||||
*/
|
||||
|
||||
int send_header_2(Protocol *protocol)
|
||||
{
|
||||
DBUG_ENTER("send_header2");
|
||||
@ -332,79 +355,165 @@ int send_header_2(Protocol *protocol)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Server-side function 'help'
|
||||
|
||||
SYNOPSIS
|
||||
mysqld_help()
|
||||
thd Thread handler
|
||||
|
||||
RETURN VALUES
|
||||
0 Success
|
||||
1 Error and send_error already commited
|
||||
-1 error && send_error should be issued (normal case)
|
||||
*/
|
||||
|
||||
int mysqld_help(THD *thd, const char *mask)
|
||||
{
|
||||
Protocol *protocol= thd->protocol;
|
||||
SQL_SELECT *select= 0, *select_cat= 0;
|
||||
Item *cond_topic, *cond_cat;
|
||||
st_find_field used_fields[array_elements(init_used_fields)];
|
||||
DBUG_ENTER("mysqld_help");
|
||||
|
||||
MI_INFO *file_leafs= 0;
|
||||
if (!(file_leafs= open_help_file(thd,"function")))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
List<String> function_list, categories_list;
|
||||
String *name, *description, *example;
|
||||
int res;
|
||||
|
||||
int count= search_functions(file_leafs, mask,
|
||||
&function_list,&name,&description,&example);
|
||||
if (count < 0)
|
||||
|
||||
TABLE_LIST tables[3];
|
||||
bzero((gptr)tables,sizeof(tables));
|
||||
tables[0].alias= tables[0].real_name= (char*) "help_topic";
|
||||
tables[0].lock_type= TL_READ;
|
||||
tables[0].db= (char*) "mysql";
|
||||
tables[0].next= &tables[1];
|
||||
tables[1].alias= tables[1].real_name= (char*) "help_category";
|
||||
tables[1].lock_type= TL_READ;
|
||||
tables[1].db= (char*) "mysql";
|
||||
tables[1].next= &tables[2];
|
||||
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;
|
||||
|
||||
List<char> function_list, categories_list;
|
||||
char *name, *description, *example;
|
||||
int res, count_topics, count_categories, error;
|
||||
|
||||
if (open_and_lock_tables(thd, tables))
|
||||
{
|
||||
res= 1;
|
||||
res= -1;
|
||||
goto end;
|
||||
}
|
||||
else if (count==0)
|
||||
/* Init tables and fields to be usable from items */
|
||||
setup_tables(tables);
|
||||
memcpy((char*) used_fields, (char*) init_used_fields, sizeof(used_fields));
|
||||
if (init_fields(thd, tables, used_fields, array_elements(used_fields)))
|
||||
{
|
||||
res= -1;
|
||||
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();
|
||||
|
||||
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)))
|
||||
{
|
||||
res= -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
res= 1;
|
||||
count_topics= search_topics(thd,tables[0].table, used_fields, select,
|
||||
&function_list, &name, &description, &example);
|
||||
if (count_topics == 0)
|
||||
{
|
||||
int16 category_id;
|
||||
count= search_categories(thd, mask, &categories_list, &category_id);
|
||||
if (count<0)
|
||||
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
|
||||
|
||||
count_categories= search_categories(thd, tables[1].table, used_fields,
|
||||
select_cat, &categories_list,
|
||||
&category_id);
|
||||
if (count_categories == 1)
|
||||
{
|
||||
res= 1;
|
||||
goto end;
|
||||
}
|
||||
else if (count==1)
|
||||
{
|
||||
if ((res= get_all_names_for_category(thd, file_leafs,
|
||||
category_id,&function_list)))
|
||||
goto end;
|
||||
List_iterator<String> it(function_list);
|
||||
String *cur_leaf, example;
|
||||
while ((cur_leaf = it++))
|
||||
if (get_all_topics_for_category(thd,tables[0].table,
|
||||
tables[2].table, used_fields,
|
||||
category_id, &function_list))
|
||||
{
|
||||
example.append(*cur_leaf);
|
||||
res= -1;
|
||||
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 ((res= send_answer_1(protocol, categories_list.head()->ptr(),
|
||||
"Y","",example.ptr())))
|
||||
if ((send_answer_1(protocol, categories_list.head(),
|
||||
"Y","",example.ptr())))
|
||||
goto end;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((res= send_header_2(protocol)) ||
|
||||
(count==0 &&
|
||||
(search_categories(thd, 0, &categories_list, 0)<0 &&
|
||||
((res= 1)))) ||
|
||||
(res= send_variant_2_list(protocol,&categories_list,true)))
|
||||
if (send_header_2(protocol))
|
||||
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"))
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
else if (count==1)
|
||||
else if (count_topics == 1)
|
||||
{
|
||||
if ((res= send_answer_1(protocol,name->ptr(),"N",
|
||||
description->ptr(), example->ptr())))
|
||||
if (send_answer_1(protocol,name,"N",description, example))
|
||||
goto end;
|
||||
}
|
||||
else if ((res= send_header_2(protocol)) ||
|
||||
(res= send_variant_2_list(protocol,&function_list,false)) ||
|
||||
(search_categories(thd, mask, &categories_list, 0)<0 &&
|
||||
((res=1))) ||
|
||||
(res= send_variant_2_list(protocol,&categories_list,true)))
|
||||
else
|
||||
{
|
||||
goto end;
|
||||
/* First send header and functions */
|
||||
if (send_header_2(protocol) ||
|
||||
send_variant_2_list(protocol, &function_list, "N"))
|
||||
goto end;
|
||||
search_categories(thd, tables[1].table, used_fields, select_cat,
|
||||
&categories_list, 0);
|
||||
/* Then send categories */
|
||||
if (send_variant_2_list(protocol, &categories_list, "Y"))
|
||||
goto end;
|
||||
}
|
||||
|
||||
res= 0;
|
||||
|
||||
send_eof(thd);
|
||||
|
||||
end:
|
||||
mi_close(file_leafs);
|
||||
delete select;
|
||||
delete select_cat;
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
|
Reference in New Issue
Block a user