Commit 9adf688b authored by vva@genie.(none)'s avatar vva@genie.(none)

add help command on server side

parent 7777d2b8
......@@ -205,8 +205,8 @@ typedef struct {
} COMMANDS;
static COMMANDS commands[] = {
{ "help", 'h', com_help, 0, "Display this help." },
{ "?", '?', com_help, 0, "Synonym for `help'." },
{ "help", 'h', com_help, 1, "Display this help." },
{ "?", '?', com_help, 1, "Synonym for `help'." },
{ "clear", 'c', com_clear, 0, "Clear command."},
{ "connect",'r', com_connect,1,
"Reconnect to the server. Optional arguments are db and host." },
......@@ -382,8 +382,9 @@ int main(int argc,char *argv[])
}
}
#endif
sprintf(buff,
"Type 'help;' or '\\h' for help. Type '\\c' to clear the buffer.\n");
sprintf(buff, "%s%s",
"Type 'help;' or '\\h' for help. Type '\\c' to clear the buffer.\n",
"Type 'help [[%]function name[%]]' to get help on usage of function.\n");
put_info(buff,INFO_INFO);
status.exit_status=read_lines(1); // read lines and execute them
if (opt_outfile)
......@@ -1322,19 +1323,141 @@ static int reconnect(void)
The different commands
***************************************************************************/
int mysql_real_query_for_lazy(const char *buf, int length)
{
for (uint retry=0;; retry++)
{
if (!mysql_real_query(&mysql,buf,length))
return 0;
uint error=put_info(mysql_error(&mysql),INFO_ERROR, mysql_errno(&mysql));
if (mysql_errno(&mysql) != CR_SERVER_GONE_ERROR || retry > 1
|| status.batch)
return error;
if (reconnect())
return error;
}
}
int mysql_store_result_for_lazy(MYSQL_RES **result)
{
if ((*result=mysql_store_result(&mysql)))
return 0;
if (mysql_error(&mysql)[0])
return put_info(mysql_error(&mysql),INFO_ERROR,mysql_errno(&mysql));
return 0;
}
static int com_server_help(String *buffer __attribute__((unused)),
char *line __attribute__((unused)), char *help_arg)
{
MYSQL_ROW cur;
const char *server_cmd= buffer->ptr();
char cmd_buf[100];
if (help_arg[0]!='\'')
{
(void*)sprintf(cmd_buf,"help \'%s\';",help_arg);
server_cmd= cmd_buf;
}
char buff[16], time_buf[32];
MYSQL_RES *result;
ulong timer;
uint error= 0;
if (!status.batch)
{
old_buffer= *buffer;
old_buffer.copy();
}
if (!connected && reconnect())
return 1;
timer= start_timer();
error= mysql_real_query_for_lazy(server_cmd,strlen(server_cmd));
if (error)
return error;
error= mysql_store_result_for_lazy(&result);
if (error)
return error;
if (result)
{
int num_rows= mysql_num_rows(result);
if (num_rows==1)
{
if (!(cur= mysql_fetch_row(result)))
return -1;
init_pager();
if (cur[1][0]=='Y')
{
tee_fprintf(PAGER, "\nHelp topic \'%s\'\n", cur[0]);
tee_fprintf(PAGER, "%s\n", cur[2]);
tee_fprintf(PAGER, "For help on specific function please type 'help <function>' where function is one of next :\n%s\n", cur[3]);
}
else
{
tee_fprintf(PAGER, "\nName : \'%s\'\n\n", cur[0]);
tee_fprintf(PAGER, "Description : \n%s\n\n", cur[2]);
tee_fprintf(PAGER, "Examples : \n%s\n", cur[3]);
}
end_pager();
}
else if (num_rows>1)
{
put_info("\nMany help items for your request exist", INFO_INFO);
put_info("For more specific request please type 'help <item>' where item is one of next :", INFO_INFO);
init_pager();
char last_char= '_';
while ((cur= mysql_fetch_row(result))){
if (cur[1][0]!=last_char){
put_info("-------------------------------------------", INFO_INFO);
put_info(cur[1][0]=='Y' ?
"categories:" : "functions:", INFO_INFO);
put_info("-------------------------------------------", INFO_INFO);
}
last_char= cur[1][0];
tee_fprintf(PAGER, "%s\n", cur[0]);
}
tee_fprintf(PAGER, "\n");
end_pager();
}
else
{
put_info("\nNothing found\n", INFO_INFO);
}
}
mysql_free_result(result);
return error;
}
static int
com_help (String *buffer __attribute__((unused)),
char *line __attribute__((unused)))
{
reg1 int i;
char * help_arg= strchr(line,' ');
if (help_arg)
{
return com_server_help(buffer,line,help_arg+1);
}
else
{
put_info("\nFor the complete MySQL Manual online visit:\n http://www.mysql.com/documentation\n", INFO_INFO);
put_info("For info on technical support from MySQL developers visit:\n http://www.mysql.com/support\n", INFO_INFO);
put_info("For info on MySQL books, utilities, consultants, etc. visit:\n http://www.mysql.com/portal\n", INFO_INFO);
put_info("List of all MySQL commands:", INFO_INFO);
if (!named_cmds)
put_info(" (Commands must appear first on line and end with ';')\n",
INFO_INFO);
put_info("Note that all text commands must be first on line and end with ';'",INFO_INFO);
for (i = 0; commands[i].name; i++)
{
if (commands[i].func)
......@@ -1347,6 +1470,7 @@ com_help (String *buffer __attribute__((unused)),
mysql_thread_id(&mysql));
else
tee_fprintf(stdout, "Not connected! Reconnect with 'connect'!\n\n");
}
return 0;
}
......@@ -1411,23 +1535,14 @@ com_go(String *buffer,char *line __attribute__((unused)))
}
timer=start_timer();
for (uint retry=0;; retry++)
{
if (!mysql_real_query(&mysql,buffer->ptr(),buffer->length()))
break;
error=put_info(mysql_error(&mysql),INFO_ERROR, mysql_errno(&mysql));
if (mysql_errno(&mysql) != CR_SERVER_GONE_ERROR || retry > 1
|| status.batch)
{
buffer->length(0); // Remove query on error
return error;
}
if (reconnect())
error= mysql_real_query_for_lazy(buffer->ptr(),buffer->length());
if (error)
{
buffer->length(0); // Remove query on error
return error;
}
}
error=0;
buffer->length(0);
......@@ -1440,13 +1555,9 @@ com_go(String *buffer,char *line __attribute__((unused)))
}
else
{
if (!(result=mysql_store_result(&mysql)))
{
if (mysql_error(&mysql)[0])
{
return put_info(mysql_error(&mysql),INFO_ERROR,mysql_errno(&mysql));
}
}
error= mysql_store_result_for_lazy(&result);
if (error)
return error;
}
if (verbose >= 3 || !opt_silent)
......@@ -2772,3 +2883,5 @@ void sql_element_free(void *ptr)
my_free((gptr) ptr,MYF(0));
}
#endif /* EMBEDDED_LIBRARY */
......@@ -258,4 +258,5 @@
#define ER_SUBSELECT_NO_1_COL 1239
#define ER_SUBSELECT_NO_1_ROW 1240
#define ER_UNKNOWN_STMT_HANDLER 1241
#define ER_CORRUPT_HELP_DB 1242
#define ER_ERROR_MESSAGES 242
......@@ -52,11 +52,13 @@ EXTRA_SCRIPTS = make_binary_distribution.sh \
mysql_explain_log.sh \
mysqld_multi.sh \
mysql_tableinfo.sh \
mysqld_safe.sh
mysqld_safe.sh \
fill_func_tables.sh
EXTRA_DIST = $(EXTRA_SCRIPTS) \
mysqlaccess.conf \
mysqlbug
mysqlbug \
fill_func_tables.sql
pkgdata_DATA = make_binary_distribution
......@@ -76,7 +78,8 @@ CLEANFILES = @server_scripts@ \
mysql_find_rows \
mysqlhotcopy \
mysqldumpslow \
mysqld_multi
mysqld_multi \
fill_func_tables.sql
SUPERCLEANFILES = mysqlbug
......@@ -127,3 +130,8 @@ SUFFIXES = .sh
# Don't update the files from bitkeeper
%::SCCS/s.%
all: fill_func_tables.sql
fill_func_tables.sql: fill_func_tables ../Docs/manual.texi
./fill_func_tables < ../Docs/manual.texi > fill_func_tables.sql
\ No newline at end of file
#!@PERL@
# fill_func_tables - parse ../Docs/manual.texi
# Original version by vva
my $cat_name= "";
my $func_name= "";
my $text= "";
my $example= "";
local $mode= "";
sub prepare_name
{
my ($a)= @_;
$a =~ s/(\@itemize \@bullet)/ /g;
$a =~ s/(\@end itemize)/ /g;
$a =~ s/(\@end multitable)/ /g;
$a =~ s/(\@end table)/ /g;
$a =~ s/(\@cindex(.*?)\n)/ /g;
$a =~ s/(\@multitable \@columnfractions(.*?)\n)/ /g;
$a =~ s/(\@node(.*?)\n)/ /g;
$a =~ s/(\@tab)/\t/g;
$a =~ s/\@item/ /g;
$a =~ s/\@code\{((.|\n)+?)\}/$1/go;
$a =~ s/\@strong\{(.+?)\}/$1/go;
$a =~ s/\@samp\{(.+?)\}/$1/go;
$a =~ s/\@emph\{((.|\n)+?)\}/\/$1\//go;
$a =~ s/\@xref\{((.|\n)+?)\}/See also : [$1]/go;
$a =~ s/\@ref\{((.|\n)+?)\}/[$1]/go;
$a =~ s/\'/\'\'/g;
$a =~ s/\\/\\\\/g;
$a =~ s/\`/\`\`/g;
$a =~ s/\@table \@code/ /g;
$a =~ s/\(\)//g;
$a =~ s/((\w|\s)+)\(([\+-=><\/%*!<>\s]+)\)/$3/gxs; #$a =~ s/((\w|\s)+)\(([\+-=><\/%*!<>\s]+)\)/$3 $1/gxs;
$a =~ s/([\+-=><\/%*!<>\s]+)\(((\w|\s)+)\)/$1/gxs;#$a =~ s/([\+-=><\/%*!<>\s]+)\(((\w|\s)+)\)/$1 $2/gxs;
$a =~ s/((\w|\s)+)\((.+)\)/$1/gxs;
return $a;
}
sub prepare_text
{
my ($a)= @_;
$a =~ s/(\@itemize \@bullet)/ /g;
$a =~ s/(\@end itemize)/ /g;
$a =~ s/(\@end multitable)/ /g;
$a =~ s/(\@end table)/ /g;
$a =~ s/(\@cindex(.*?)\n)/ /g;
$a =~ s/(\@multitable \@columnfractions(.*?)\n)/ /g;
$a =~ s/(\@node(.*?)\n)/ /g;
$a =~ s/(\@tab)/\t/g;
$a =~ s/\@itemx/ /g;
$a =~ s/\@item/ /g;
$a =~ s/\@code\{((.|\n)+?)\}/$1/go;
$a =~ s/\@strong\{(.+?)\}/$1/go;
$a =~ s/\@samp\{(.+?)\}/$1/go;
$a =~ s/\@emph\{((.|\n)+?)\}/\/$1\//go;
$a =~ s/\@xref\{((.|\n)+?)\}/See also : [$1]/go;
$a =~ s/\@ref\{((.|\n)+?)\}/[$1]/go;
$a =~ s/\'/\'\'/g;
$a =~ s/\\/\\\\/g;
$a =~ s/\`/\`\`/g;
$a =~ s/(\n*?)$//g;
$a =~ s/\n/\\n/g;
$a =~ s/\@table \@code/ /g;
return $a;
}
sub prepare_example
{
my ($a)= @_;
$a =~ s/\'/\'\'/g;
$a =~ s/\\/\\\\/g;
$a =~ s/\`/\`\`/g;
$a =~ s/(\n*?)$//g;
$a =~ s/\n/\\n/g;
return $a;
}
sub flush_all
{
my ($mode) = @_;
if ($mode eq ""){return;}
$func_name= prepare_name($func_name);
$text= prepare_text($text);
$example= prepare_example($example);
if ($func_name ne "" && $text ne "" && !($func_name =~ /[abcdefghikjlmnopqrstuvwxyz]/)){
print "INSERT INTO function (name,description,example) VALUES (";
print "'$func_name',";
print "'$text',";
print "'$example'";
print ");\n";
print "INSERT INTO function_category (cat_id,func_id) VALUES (\@cur_category,LAST_INSERT_ID());\n";
}
$func_name= "";
$text= "";
$example= "";
$mode= "";
}
sub new_category
{
my ($category)= @_;
$category= prepare_text($category);
print "INSERT INTO function_category_name (name) VALUES (\'$category\');\n";
print "SELECT \@cur_category:=LAST_INSERT_ID();\n";
}
print "INSERT INTO db (Host,DB,User,Select_priv) VALUES ('%','mysql_help','','Y');\n";
print "CREATE DATABASE mysql_help;\n";
print "USE mysql_help;\n";
print "DROP TABLE IF EXISTS function;\n";
print "CREATE TABLE function (";
print " func_id int unsigned not null auto_increment,";
print " name varchar(64) not null,";
print " url varchar(128) not null,";
print " description text not null,";
print " example text not null,";
print " min_args tinyint not null,";
print " max_args tinyint,";
print " date_created datetime not null,";
print " last_modified timestamp not null,";
print " primary key (func_id)";
print ") type=myisam;\n\n";
print "DROP TABLE IF EXISTS function_category_name;\n";
print "CREATE TABLE function_category_name (";
print " cat_id smallint unsigned not null auto_increment,";
print " name varchar(64) not null,";
print " url varchar(128) not null,";
print " date_created datetime not null,";
print " last_modified timestamp not null,";
print " primary key (cat_id)";
print ") type=myisam;\n\n";
print "DROP TABLE IF EXISTS function_category;\n";
print "CREATE TABLE function_category (";
print " cat_id smallint unsigned not null references function_category_name,";
print " func_id int unsigned not null references function,";
print " primary key (cat_id, func_id)";
print ") type=myisam;\n\n";
print "DELETE FROM function_category_name;\n";
print "DELETE FROM function_category;\n";
print "DELETE FROM function;\n";
print "SELECT \@cur_category:=null;\n\n";
my $in_section_6_3= 0;
for(<>)
{
if ($_=~/\@section Functions for Use in \@code{SELECT} and \@code{WHERE} Clauses/ &&
!$in_section_6_3){
$in_section_6_3= 1;
next;
}
if ($_=~/\@section/ && $in_section_6_3){
$in_section_6_3= 0;
next;
}
if (!$in_section_6_3) { next; }
my $c_name= "";
($c_name)=m|\@c for_mysql_help,(.+?)$|;
if (!($c_name eq "") && ! ($c_name =~ m/$cat_name/i)){
($cat_name)= $c_name;
new_category($cat_name);
next;
}
($c_name)=m|\@subsubsection (.+?)$|;
if (!($c_name eq "") && ! ($c_name =~ m/$cat_name/i)){
($cat_name)= $c_name;
new_category($cat_name);
next;
}
($c_name)=m|\@subsection (.+?)$|;
if (!($c_name eq "") && ! ($c_name =~ m/$cat_name/i)){
($cat_name)= $c_name;
new_category($cat_name);
next;
}
($f_name)=m|\@findex (.+?)$|;
if (!($f_name eq "")){
flush_all($mode);
($func_name)= ($f_name);
$mode= "text";
next;
}
if ($_=~/\@example/ && ($mode eq "text")){
$mode= "example";
next;
}
if ($_=~/\@end example/ && ($mode eq "example")){
flush_all($mode);
next;
}
if ($mode eq "text") { $text .= $_; }
if ($mode eq "example") { $example .= $_; }
}
print "DELETE function_category_name ";
print "FROM function_category_name ";
print "LEFT JOIN function_category ON function_category.cat_id=function_category_name.cat_id ";
print "WHERE function_category.cat_id is null;"
......@@ -307,8 +307,8 @@ then
fi
echo "Installing all prepared tables"
if eval "$execdir/mysqld $defaults --bootstrap --skip-grant-tables \
--basedir=$basedir --datadir=$ldata --skip-innodb --skip-bdb $args" << END_OF_DATA
if (
cat << END_OF_DATA
use mysql;
$c_d
$i_d
......@@ -325,6 +325,9 @@ $i_f
$c_t
$c_c
END_OF_DATA
cat fill_func_tables.sql
) | eval "$execdir/mysqld $defaults --bootstrap --skip-grant-tables \
--basedir=$basedir --datadir=$ldata --skip-innodb --skip-bdb $args"
then
echo ""
if test "$IN_RPM" -eq 0
......
......@@ -84,7 +84,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \
slave.cc sql_repl.cc sql_union.cc sql_derived.cc \
mini_client.cc mini_client_errors.c \
stacktrace.c repl_failsafe.h repl_failsafe.cc sql_olap.cc\
gstream.cc spatial.cc
gstream.cc spatial.cc sql_help.cc
gen_lex_hash_SOURCES = gen_lex_hash.cc
gen_lex_hash_LDADD = $(LDADD) $(CXXLDFLAGS)
......
......@@ -172,6 +172,7 @@ static SYMBOL symbols[] = {
{ "HANDLER", SYM(HANDLER_SYM),0,0},
{ "HASH", SYM(HASH_SYM),0,0},
{ "HEAP", SYM(HEAP_SYM),0,0},
{ "HELP", SYM(HELP),0,0},
{ "HIGH_PRIORITY", SYM(HIGH_PRIORITY),0,0},
{ "HOUR", SYM(HOUR_SYM),0,0},
{ "HOUR_MINUTE", SYM(HOUR_MINUTE_SYM),0,0},
......
......@@ -505,6 +505,7 @@ int mysqld_show_charsets(THD *thd,const char *wild);
int mysqld_show_table_types(THD *thd);
int mysqld_show_privileges(THD *thd);
int mysqld_show_column_types(THD *thd);
int mysqld_help (THD *thd, const char *text);
/* sql_prepare.cc */
int compare_prep_stmt(PREP_STMT *a, PREP_STMT *b, void *not_used);
......
......@@ -252,3 +252,4 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Corrupt or doesn\'t exist help database",
......@@ -246,3 +246,4 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Corrupt or doesn\'t exist help database",
......@@ -254,3 +254,4 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Corrupt or doesn\'t exist help database",
......@@ -243,3 +243,4 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Corrupt or doesn\'t exist help database",
......@@ -248,3 +248,4 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Corrupt or doesn\'t exist help database",
......@@ -243,3 +243,4 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Corrupt or doesn\'t exist help database",
......@@ -246,3 +246,4 @@
"Subselect return more than 1 field",
"Subselect return more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Corrupt or doesn\'t exist help database",
......@@ -243,3 +243,4 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Corrupt or doesn\'t exist help database",
......@@ -245,3 +245,4 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Corrupt or doesn\'t exist help database",
......@@ -243,3 +243,4 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Corrupt or doesn\'t exist help database",
......@@ -245,3 +245,4 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Corrupt or doesn\'t exist help database",
......@@ -243,3 +243,4 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Corrupt or doesn\'t exist help database",
......@@ -245,3 +245,4 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Corrupt or doesn\'t exist help database",
......@@ -245,3 +245,4 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Corrupt or doesn\'t exist help database",
......@@ -247,3 +247,4 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Corrupt or doesn\'t exist help database",
......@@ -243,3 +243,4 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Corrupt or doesn\'t exist help database",
......@@ -247,3 +247,4 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Corrupt or doesn\'t exist help database",
......@@ -246,3 +246,4 @@
" ",
" ",
"Unknown prepared statement handler (%ld) given to %s",
"Corrupt or doesn\'t exist help database",
......@@ -239,3 +239,4 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Corrupt or doesn\'t exist help database",
......@@ -251,3 +251,4 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Corrupt or doesn\'t exist help database",
......@@ -244,3 +244,4 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Corrupt or doesn\'t exist help database",
......@@ -243,3 +243,4 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Corrupt or doesn\'t exist help database",
......@@ -248,3 +248,4 @@
"i i i 1 ",
"i i i 1 ",
"Unknown prepared statement handler (%ld) given to %s",
"Corrupt or doesn\'t exist help database",
/* Copyright (C) 2000 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
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
***************************************************************************/
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;
}
#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, */
#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)
{
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))
{
leaf.prepare_fields();
const char *lname= leaf.get_name();
if (wild_case_compare(system_charset_info,lname,mask))
continue;
count++;
if (count>2)
{
String *s= new String(lname,system_charset_info);
if (!s->copy())
names->push_back(s);
}
else if (count==1)
{
*description= new String(leaf.get_description(),system_charset_info);
*example= new String(leaf.get_example(),system_charset_info);
*name= new String(lname,system_charset_info);
(*description)->copy();
(*example)->copy();
(*name)->copy();
}
else
{
names->push_back(*name);
delete *description;
delete *example;
*name= 0;
*description= 0;
*example= 0;
String *s= new String(lname,system_charset_info);
if (!s->copy())
names->push_back(s);
}
}
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)
#define HELP_CATEGORY_SIZE (offset_hc_last_modified+size_hc_last_modified)
class help_category{
public:
char record[HELP_CATEGORY_SIZE];
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(system_charset_info,lname,mask))
continue;
count++;
if (count==1 && res_id)
*res_id= category.get_cat_id();
String *s= new String(lname,system_charset_info);
if (!s->copy())
names->push_back(s);
}
mi_close(file_categories);
DBUG_RETURN(count);
}
int send_variant_2_list(THD *thd, List<String> *names, my_bool is_category)
{
DBUG_ENTER("send_names");
List_iterator<String> it(*names);
String *cur_name;
String *packet= &thd->packet;
while ((cur_name = it++))
{
packet->length(0);
net_store_data(packet, cur_name->ptr());
net_store_data(packet, is_category ? "Y" : "N");
if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
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)
#define HELP_CATEGORY_NAME_SIZE (offset_hcn_func_id + size_hcn_func_id)
class help_category_leaf{
public:
char record[HELP_CATEGORY_NAME_SIZE];
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)
{
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)
{
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(),system_charset_info);
if (!s->copy())
res->push_back(s);
}
key_res= mi_rnext(file_names_categories, (byte*)&cat_leaf, 0);
}
mi_close(file_names_categories);
DBUG_RETURN(0);
}
int send_answer_1(THD *thd, const char *s1, const char *s2,
const char *s3, const char *s4)
{
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("is_category",1));
field_list.push_back(new Item_empty_string("description",1000));
field_list.push_back(new Item_empty_string("example",1000));
if (send_fields(thd,field_list,1))
DBUG_RETURN(1);
String *packet= &thd->packet;
packet->length(0);
net_store_data(packet, s1);
net_store_data(packet, s2);
net_store_data(packet, s3);
net_store_data(packet, s4);
if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
DBUG_RETURN(-1);
DBUG_RETURN(0);
}
int send_header_2(THD *thd)
{
DBUG_ENTER("send_header2");
List<Item> field_list;
field_list.push_back(new Item_empty_string("name",64));
field_list.push_back(new Item_empty_string("is_category",1));
DBUG_RETURN(send_fields(thd,field_list,1));
}
int mysqld_help (THD *thd, const char *mask)
{
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)
{
res= 1;
goto end;
}
else if (count==0)
{
int16 category_id;
count= search_categories(thd, mask, &categories_list, &category_id);
if (count<0)
{
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++))
{
example.append(*cur_leaf);
example.append("\n",1);
}
if (res= send_answer_1(thd, categories_list.head()->ptr(),
"Y","",example.ptr()))
goto end;
}
else
{
if ((res= send_header_2(thd)) ||
(count==0 &&
(search_categories(thd, 0, &categories_list, 0)<0 &&
(res= 1))) ||
(res= send_variant_2_list(thd,&categories_list,true)))
goto end;
}
}
else if (count==1)
{
if (res= send_answer_1(thd,name->ptr(),"N",
description->ptr(), example->ptr()))
goto end;
}
else if((res= send_header_2(thd)) ||
(res= send_variant_2_list(thd,&function_list,false)) ||
(search_categories(thd, mask, &categories_list, 0)<0 &&
(res=1)) ||
(res= send_variant_2_list(thd,&categories_list,true)))
{
goto end;
}
send_eof(thd);
end:
mi_close(file_leafs);
DBUG_RETURN(res);
}
......@@ -66,7 +66,7 @@ enum enum_sql_command {
SQLCOM_SHOW_BINLOG_EVENTS, SQLCOM_SHOW_NEW_MASTER, SQLCOM_DO,
SQLCOM_SHOW_WARNS, SQLCOM_EMPTY_QUERY, SQLCOM_SHOW_ERRORS,
SQLCOM_SHOW_COLUMN_TYPES, SQLCOM_SHOW_TABLE_TYPES, SQLCOM_SHOW_PRIVILEGES,
SQLCOM_END
SQLCOM_END, SQLCOM_HELP,
};
enum lex_states
......@@ -383,6 +383,7 @@ typedef struct st_lex
bool derived_tables, describe;
uint slave_thd_opt;
CHARSET_INFO *charset;
char *help_arg;
} LEX;
......
......@@ -1486,6 +1486,10 @@ mysql_execute_command(THD *thd)
send_ok(thd);
break;
case SQLCOM_HELP:
res= mysqld_help(thd,lex->help_arg);
break;
case SQLCOM_PURGE:
{
if (check_global_access(thd, SUPER_ACL))
......
......@@ -505,6 +505,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token SUBJECT_SYM
%token CIPHER_SYM
%token HELP
%left SET_VAR
%left OR_OR_CONCAT OR
%left AND
......@@ -637,7 +639,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
handler_rkey_function handler_read_or_scan
single_multi table_wild_list table_wild_one opt_wild union union_list
precision union_option opt_on_delete_item subselect_start opt_and
subselect_end select_var_list select_var_list_init
subselect_end select_var_list select_var_list_init help
END_OF_INPUT
%type <NONE>
......@@ -699,7 +701,18 @@ verb_clause:
| handler
| unlock
| update
| use;
| use
| help;
/* help */
help:
HELP TEXT_STRING
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_HELP;
lex->help_arg= $2.str;
}
/* change master */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment