home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 January / Chip_2001-01_cd1.bin / tema / mysql / mysql-3.23.28g-win-source.exe / sql / sql_show.cpp < prev    next >
C/C++ Source or Header  |  2000-11-22  |  34KB  |  1,054 lines

  1. /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
  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; either version 2 of the License, or
  6.    (at your option) any later version.
  7.  
  8.    This program is distributed in the hope that it will be useful,
  9.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.    GNU General Public License for more details.
  12.  
  13.    You should have received a copy of the GNU General Public License
  14.    along with this program; if not, write to the Free Software
  15.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  16.  
  17.  
  18. /* Function with list databases, tables or fields */
  19.  
  20. #undef USE_RAID
  21. #define USE_RAID
  22. #include "mysql_priv.h"
  23. #include "sql_select.h"                         // For select_describe
  24. #include "sql_acl.h"
  25. #include <my_dir.h>
  26. extern "C" pthread_mutex_t THR_LOCK_keycache;
  27.  
  28. static const char *grant_names[]={
  29.   "select","insert","update","delete","create","drop","reload","shutdown",
  30.   "process","file","grant","references","index","alter"};
  31.  
  32. static TYPELIB grant_types = { sizeof(grant_names)/sizeof(char **),
  33.                                "grant_types",
  34.                                grant_names};
  35.  
  36. static int mysql_find_files(THD *thd,List<char> *files, const char *db,
  37.                             const char *path, const char *wild, bool dir);
  38.  
  39. static int
  40. store_create_info(THD *thd, TABLE *table, String *packet);
  41.  
  42. static void
  43. append_identifier(THD *thd, String *packet, const char *name);
  44.  
  45. /****************************************************************************
  46. ** Send list of databases
  47. ** A database is a directory in the mysql_data_home directory
  48. ****************************************************************************/
  49.  
  50.  
  51. int
  52. mysqld_show_dbs(THD *thd,const char *wild)
  53. {
  54.   Item_string *field=new Item_string("",0);
  55.   List<Item> field_list;
  56.   char *end;
  57.   List<char> files;
  58.   char *file_name;
  59.   DBUG_ENTER("mysqld_show_dbs");
  60.  
  61.   field->name=(char*) thd->alloc(20+ (wild ? (uint) strlen(wild)+4: 0));
  62.   field->max_length=NAME_LEN;
  63.   end=strmov(field->name,"Database");
  64.   if (wild && wild[0])
  65.     strxmov(end," (",wild,")",NullS);
  66.   field_list.push_back(field);
  67.  
  68.   if (send_fields(thd,field_list,1))
  69.     DBUG_RETURN(1);
  70.   if (mysql_find_files(thd,&files,NullS,mysql_data_home,wild,1))
  71.     DBUG_RETURN(1);
  72.   List_iterator<char> it(files);
  73.   while ((file_name=it++))
  74.   {
  75.     thd->packet.length(0);
  76.     net_store_data(&thd->packet,file_name);
  77.     if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length()))
  78.       DBUG_RETURN(-1);
  79.   }
  80.   send_eof(&thd->net);
  81.   DBUG_RETURN(0);
  82. }
  83.  
  84. /***************************************************************************
  85. ** List all tables in a database (fast version)
  86. ** A table is a .frm file in the current databasedir
  87. ***************************************************************************/
  88.  
  89. int mysqld_show_tables(THD *thd,const char *db,const char *wild)
  90. {
  91.   Item_string *field=new Item_string("",0);
  92.   List<Item> field_list;
  93.   char path[FN_LEN],*end;
  94.   List<char> files;
  95.   char *file_name;
  96.   DBUG_ENTER("mysqld_show_tables");
  97.  
  98.   field->name=(char*) thd->alloc(20+(uint) strlen(db)+(wild ? (uint) strlen(wild)+4:0));
  99.   end=strxmov(field->name,"Tables_in_",db,NullS);
  100.   if (wild && wild[0])
  101.     strxmov(end," (",wild,")",NullS);
  102.   field->max_length=NAME_LEN;
  103.   (void) sprintf(path,"%s/%s",mysql_data_home,db);
  104.   (void) unpack_dirname(path,path);
  105.   field_list.push_back(field);
  106.   if (send_fields(thd,field_list,1))
  107.     DBUG_RETURN(1);
  108.   if (mysql_find_files(thd,&files,db,path,wild,0))
  109.     DBUG_RETURN(-1);
  110.   List_iterator<char> it(files);
  111.   while ((file_name=it++))
  112.   {
  113.     thd->packet.length(0);
  114.     net_store_data(&thd->packet,file_name);
  115.     if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length()))
  116.       DBUG_RETURN(-1);
  117.   }
  118.   send_eof(&thd->net);
  119.   DBUG_RETURN(0);
  120. }
  121.  
  122.  
  123. static int
  124. mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path,
  125.                  const char *wild, bool dir)
  126. {
  127.   uint i;
  128.   char *ext;
  129.   MY_DIR *dirp;
  130.   FILEINFO *file;
  131.   uint col_access=thd->col_access;
  132.   TABLE_LIST table_list;
  133.   DBUG_ENTER("mysql_find_files");
  134.  
  135.   bzero((char*) &table_list,sizeof(table_list));
  136.  
  137.   if (!(dirp = my_dir(path,MYF(MY_WME | (dir ? MY_WANT_STAT : 0)))))
  138.     DBUG_RETURN(-1);
  139.  
  140.   for (i=0 ; i < (uint) dirp->number_off_files  ; i++)
  141.   {
  142.     file=dirp->dir_entry+i;
  143.     if (dir)
  144.     {                                           /* Return databases */
  145. #ifdef USE_SYMDIR
  146.       char *ext;
  147.       if (my_use_symdir && !strcmp(ext=fn_ext(file->name), ".sym"))
  148.         *ext=0;                                 /* Remove extension */
  149.       else
  150. #endif
  151.       {
  152.         if (file->name[0] == '.' || !MY_S_ISDIR(file->mystat.st_mode) ||
  153.             (wild && wild[0] && wild_compare(file->name,wild)))
  154.           continue;
  155.       }
  156.     }
  157.     else
  158.     {
  159.         // Return only .frm files which isn't temp files.
  160.       if (my_strcasecmp(ext=fn_ext(file->name),reg_ext) ||
  161.           is_prefix(file->name,tmp_file_prefix))        // Mysql temp table
  162.         continue;
  163.       *ext=0;
  164.       if (wild && wild[0] && wild_compare(file->name,wild))
  165.         continue;
  166.     }
  167.     /* Don't show tables where we don't have any privileges */
  168.     if (db && !(col_access & TABLE_ACLS))
  169.     {
  170.       table_list.db= (char*) db;
  171.       table_list.real_name=file->name;
  172.       table_list.grant.privilege=col_access;
  173.       if (check_grant(thd,TABLE_ACLS,&table_list,1))
  174.         continue;
  175.     }
  176.     if (files->push_back(thd->strdup(file->name)))
  177.     {
  178.       my_dirend(dirp);
  179.       DBUG_RETURN(-1);
  180.     }
  181.   }
  182.   DBUG_PRINT("info",("found: %d files", files->elements));
  183.   my_dirend(dirp);
  184.   DBUG_RETURN(0);
  185. }
  186.  
  187. /***************************************************************************
  188. ** Extended version of mysqld_show_tables
  189. ***************************************************************************/
  190.  
  191. int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild)
  192. {
  193.   Item *item;
  194.   List<char> files;
  195.   List<Item> field_list;
  196.   char path[FN_LEN];
  197.   char *file_name;
  198.   TABLE *table;
  199.   String *packet= &thd->packet;
  200.   DBUG_ENTER("mysqld_extend_show_tables");
  201.  
  202.   (void) sprintf(path,"%s/%s",mysql_data_home,db);
  203.   (void) unpack_dirname(path,path);
  204.  
  205.   field_list.push_back(item=new Item_empty_string("Name",NAME_LEN));
  206.   item->maybe_null=1;
  207.   field_list.push_back(item=new Item_empty_string("Type",10));
  208.   item->maybe_null=1;
  209.   field_list.push_back(item=new Item_empty_string("Row_format",10));
  210.   item->maybe_null=1;
  211.   field_list.push_back(item=new Item_int("Rows",(longlong) 1,21));
  212.   item->maybe_null=1;
  213.   field_list.push_back(item=new Item_int("Avg_row_length",(int32) 0,21));
  214.   item->maybe_null=1;
  215.   field_list.push_back(item=new Item_int("Data_length",(longlong) 1,21));
  216.   item->maybe_null=1;
  217.   field_list.push_back(item=new Item_int("Max_data_length",(longlong) 1,21));
  218.   item->maybe_null=1;
  219.   field_list.push_back(item=new Item_int("Index_length",(longlong) 1,21));
  220.   item->maybe_null=1;
  221.   field_list.push_back(item=new Item_int("Data_free",(longlong) 1,21));
  222.   item->maybe_null=1;
  223.   field_list.push_back(item=new Item_int("Auto_increment",(longlong) 1,21));
  224.   item->maybe_null=1;
  225.   field_list.push_back(item=new Item_datetime("Create_time"));
  226.   item->maybe_null=1;
  227.   field_list.push_back(item=new Item_datetime("Update_time"));
  228.   item->maybe_null=1;
  229.   field_list.push_back(item=new Item_datetime("Check_time"));
  230.   item->maybe_null=1;
  231.   field_list.push_back(item=new Item_empty_string("Create_options",255));
  232.   item->maybe_null=1;
  233.   field_list.push_back(item=new Item_empty_string("Comment",80));
  234.   if (send_fields(thd,field_list,1))
  235.     DBUG_RETURN(1);
  236.  
  237.   if (mysql_find_files(thd,&files,db,path,wild,0))
  238.     DBUG_RETURN(-1);
  239.   List_iterator<char> it(files);
  240.   while ((file_name=it++))
  241.   {
  242.     TABLE_LIST table_list;
  243.     bzero((char*) &table_list,sizeof(table_list));
  244.     packet->length(0);
  245.     net_store_data(packet,file_name);
  246.     table_list.db=(char*) db;
  247.     table_list.real_name=table_list.name=file_name;
  248.     if (!(table = open_ltable(thd, &table_list, TL_READ)))
  249.     {
  250.       for (uint i=0 ; i < field_list.elements ; i++)
  251.         net_store_null(packet);
  252.       net_store_data(packet,thd->net.last_error);
  253.       thd->net.last_error[0]=0;
  254.     }
  255.     else
  256.     {
  257.       struct tm tm_tmp;
  258.       handler *file=table->file;
  259.       file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_NO_LOCK);
  260.       net_store_data(packet, file->table_type());
  261.       net_store_data(packet,
  262.                      (table->db_options_in_use & HA_OPTION_PACK_RECORD) ?
  263.                      "Dynamic" :
  264.                      (table->db_options_in_use & HA_OPTION_COMPRESS_RECORD)
  265.                      ? "Compressed" : "Fixed");
  266.       net_store_data(packet, (longlong) file->records);
  267.       net_store_data(packet, (uint32) file->mean_rec_length);
  268.       net_store_data(packet, (longlong) file->data_file_length);
  269.       if (file->max_data_file_length)
  270.         net_store_data(packet, (longlong) file->max_data_file_length);
  271.       else
  272.         net_store_null(packet);
  273.       net_store_data(packet, (longlong) file->index_file_length);
  274.       net_store_data(packet, (longlong) file->delete_length);
  275.       if (table->found_next_number_field)
  276.       {
  277.         table->next_number_field=table->found_next_number_field;
  278.         table->next_number_field->reset();
  279.         file->update_auto_increment();
  280.         net_store_data(packet, table->next_number_field->val_int());
  281.         table->next_number_field=0;
  282.       }
  283.       else
  284.         net_store_null(packet);
  285.       if (!file->create_time)
  286.         net_store_null(packet);
  287.       else
  288.       {
  289.         localtime_r(&file->create_time,&tm_tmp);
  290.         net_store_data(packet, &tm_tmp);
  291.       }
  292.       if (!file->update_time)
  293.         net_store_null(packet);
  294.       else
  295.       {
  296.         localtime_r(&file->update_time,&tm_tmp);
  297.         net_store_data(packet, &tm_tmp);
  298.       }
  299.       if (!file->check_time)
  300.         net_store_null(packet);
  301.       else
  302.       {
  303.         localtime_r(&file->check_time,&tm_tmp);
  304.         net_store_data(packet, &tm_tmp);
  305.       }
  306.       {
  307.         char option_buff[350],*ptr;
  308.         ptr=option_buff;
  309.         if (table->min_rows)
  310.         {
  311.           ptr=strmov(ptr," min_rows=");
  312.           ptr=longlong10_to_str(table->min_rows,ptr,10);
  313.         }
  314.         if (table->max_rows)
  315.         {
  316.           ptr=strmov(ptr," max_rows=");
  317.           ptr=longlong10_to_str(table->max_rows,ptr,10);
  318.         }
  319.         if (table->avg_row_length)
  320.         {
  321.           ptr=strmov(ptr," avg_row_length=");
  322.           ptr=longlong10_to_str(table->avg_row_length,ptr,10);
  323.         }
  324.         if (table->db_create_options & HA_OPTION_PACK_KEYS)
  325.           ptr=strmov(ptr," pack_keys=1");
  326.         if (table->db_create_options & HA_OPTION_NO_PACK_KEYS)
  327.           ptr=strmov(ptr," pack_keys=0");
  328.         if (table->db_create_options & HA_OPTION_CHECKSUM)
  329.           ptr=strmov(ptr," checksum=1");
  330.         if (table->db_create_options & HA_OPTION_DELAY_KEY_WRITE)
  331.           ptr=strmov(ptr," delay_key_write=1");
  332.         if (table->row_type != ROW_TYPE_DEFAULT)
  333.           ptr=strxmov(ptr, " format=", ha_row_type[(uint) table->row_type],
  334.                       NullS);
  335.         if (file->raid_type)
  336.         {
  337.           char buff[100];
  338.           sprintf(buff," raid_type=%s raid_chunks=%d raid_chunksize=%ld",
  339.                   my_raid_type(file->raid_type), file->raid_chunks, file->raid_chunksize/RAID_BLOCK_SIZE);
  340.           ptr=strmov(ptr,buff);
  341.         }
  342.         net_store_data(packet, option_buff+1,
  343.                        (ptr == option_buff ? 0 : (uint) (ptr-option_buff)-1));
  344.       }
  345.       net_store_data(packet, table->comment);
  346.  
  347.       close_thread_tables(thd,0);
  348.     }
  349.     if (my_net_write(&thd->net,(char*) packet->ptr(),
  350.                      packet->length()))
  351.       DBUG_RETURN(-1);
  352.   }
  353.   send_eof(&thd->net);
  354.   DBUG_RETURN(0);
  355. }
  356.  
  357.  
  358.  
  359. /***************************************************************************
  360. ** List all columns in a table
  361. ***************************************************************************/
  362.  
  363. int
  364. mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild)
  365. {
  366.   TABLE *table;
  367.   handler *file;
  368.   char tmp[MAX_FIELD_WIDTH];
  369.   DBUG_ENTER("mysqld_show_fields");
  370.   DBUG_PRINT("enter",("db: %s  table: %s",table_list->db,
  371.                       table_list->real_name));
  372.  
  373.   if (!(table = open_ltable(thd, table_list, TL_UNLOCK)))
  374.   {
  375.     send_error(&thd->net);
  376.     DBUG_RETURN(1);
  377.   }
  378.   file=table->file;
  379.   file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
  380.   (void) get_table_grant(thd, table_list);
  381.  
  382.   List<Item> field_list;
  383.   field_list.push_back(new Item_empty_string("Field",NAME_LEN));
  384.   field_list.push_back(new Item_empty_string("Type",40));
  385.   field_list.push_back(new Item_empty_string("Null",1));
  386.   field_list.push_back(new Item_empty_string("Key",3));
  387.   field_list.push_back(new Item_empty_string("Default",NAME_LEN));
  388.   field_list.push_back(new Item_empty_string("Extra",20));
  389.   field_list.push_back(new Item_empty_string("Privileges",80));
  390.  
  391.         // Send first number of fields and records
  392.   {
  393.     char *pos;
  394.     pos=net_store_length(tmp, (uint) field_list.elements);
  395.     pos=net_store_length(pos,(ulonglong) file->records);
  396.     (void) my_net_write(&thd->net,tmp,(uint) (pos-tmp));
  397.   }
  398.  
  399.   if (send_fields(thd,field_list,0))
  400.     DBUG_RETURN(1);
  401.   restore_record(table,2);      // Get empty record
  402.  
  403.   Field **ptr,*field;
  404.   for (ptr=table->field; (field= *ptr) ; ptr++)
  405.   {
  406.     if (!wild || !wild[0] || !wild_case_compare(field->field_name,wild))
  407.     {
  408. #ifdef NOT_USED
  409.       if (thd->col_access & TABLE_ACLS ||
  410.           ! check_grant_column(thd,table,field->field_name,
  411.                                (uint) strlen(field->field_name),1))
  412. #endif
  413.       {
  414.         byte *pos;
  415.         uint flags=field->flags;
  416.         String *packet= &thd->packet,type(tmp,sizeof(tmp));
  417.         uint col_access;
  418.         bool null_default_value=0;
  419.  
  420.         packet->length(0);
  421.         net_store_data(packet,field->field_name);
  422.         field->sql_type(type);
  423.         net_store_data(packet,type.ptr(),type.length());
  424.  
  425.         pos=(byte*) ((flags & NOT_NULL_FLAG) &&
  426.                      field->type() != FIELD_TYPE_TIMESTAMP ?
  427.                      "" : "YES");
  428.         net_store_data(packet,(const char*) pos);
  429.         pos=(byte*) ((field->flags & PRI_KEY_FLAG) ? "PRI" :
  430.                      (field->flags & UNIQUE_KEY_FLAG) ? "UNI" :
  431.                      (field->flags & MULTIPLE_KEY_FLAG) ? "MUL":"");
  432.         net_store_data(packet,(char*) pos);
  433.  
  434.         if (field->type() == FIELD_TYPE_TIMESTAMP ||
  435.             field->unireg_check == Field::NEXT_NUMBER)
  436.           null_default_value=1;
  437.         if (!null_default_value && !field->is_null())
  438.         {                                               // Not null by default
  439.           type.set(tmp,sizeof(tmp));
  440.           field->val_str(&type,&type);
  441.           net_store_data(packet,type.ptr(),type.length());
  442.         }
  443.         else if (field->maybe_null() || null_default_value)
  444.           net_store_null(packet);                       // Null as default
  445.         else
  446.           net_store_data(packet,tmp,0);
  447.  
  448.         char *end=tmp;
  449.         if (field->unireg_check == Field::NEXT_NUMBER)
  450.           end=strmov(tmp,"auto_increment");
  451.         net_store_data(packet,tmp,(uint) (end-tmp));
  452.  
  453.         /* Add grant options */
  454.         col_access= get_column_grant(thd,table_list,field) & COL_ACLS;
  455.         end=tmp;
  456.         for (uint bitnr=0; col_access ; col_access>>=1,bitnr++)
  457.         {
  458.           if (col_access & 1)
  459.           {
  460.             *end++=',';
  461.             end=strmov(end,grant_types.type_names[bitnr]);
  462.           }
  463.         }
  464.         net_store_data(packet,tmp+1,end == tmp ? 0 : (uint) (end-tmp-1));
  465.         if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
  466.           DBUG_RETURN(1);
  467.       }
  468.     }
  469.   }
  470.   send_eof(&thd->net);
  471.   DBUG_RETURN(0);
  472. }
  473.  
  474. int
  475. mysqld_show_create(THD *thd, TABLE_LIST *table_list)
  476. {
  477.   TABLE *table;
  478.   DBUG_ENTER("mysqld_show_create");
  479.   DBUG_PRINT("enter",("db: %s  table: %s",table_list->db,
  480.                       table_list->real_name));
  481.  
  482.   /* Only one table for now */
  483.   if (!(table = open_ltable(thd, table_list, TL_UNLOCK)))
  484.   {
  485.     send_error(&thd->net);
  486.     DBUG_RETURN(1);
  487.   }
  488.  
  489.   List<Item> field_list;
  490.   field_list.push_back(new Item_empty_string("Table",NAME_LEN));
  491.   field_list.push_back(new Item_empty_string("Create Table",1024));
  492.  
  493.   if (send_fields(thd,field_list,1))
  494.     DBUG_RETURN(1);
  495.  
  496.   String *packet = &thd->packet;
  497.   {
  498.     packet->length(0);
  499.     net_store_data(packet, table->table_name);
  500.     // a hack - we need to reserve some space for the length before
  501.     // we know what it is - let's assume that the length of create table
  502.     // statement will fit into 3 bytes ( 16 MB max :-) )
  503.     ulong store_len_offset = packet->length();
  504.     packet->length(store_len_offset + 4);
  505.     if (store_create_info(thd, table, packet))
  506.       DBUG_RETURN(-1);
  507.     ulong create_len = packet->length() - store_len_offset - 4;
  508.     if (create_len > 0x00ffffff) // better readable in HEX ...
  509.       DBUG_RETURN(1);  // just in case somebody manages to create a table
  510.     // with *that* much stuff in the definition
  511.  
  512.     // now we have to store the length in three bytes, even if it would fit
  513.     // into fewer, so we cannot use net_store_data() anymore,
  514.     // and do it ourselves
  515.     char* p = (char*)packet->ptr() + store_len_offset;
  516.     *p++ = (char) 253; // The client the length is stored using 3-bytes
  517.     int3store(p, create_len);
  518.  
  519.     // now we are in business :-)
  520.     if (my_net_write(&thd->net, (char*)packet->ptr(), packet->length()))
  521.       DBUG_RETURN(1);
  522.   }
  523.   send_eof(&thd->net);
  524.   DBUG_RETURN(0);
  525. }
  526.  
  527.  
  528. int
  529. mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
  530. {
  531.   TABLE *table;
  532.   char buff[256];
  533.   DBUG_ENTER("mysqld_show_keys");
  534.   DBUG_PRINT("enter",("db: %s  table: %s",table_list->db,
  535.                       table_list->real_name));
  536.  
  537.   if (!(table = open_ltable(thd, table_list, TL_UNLOCK)))
  538.   {
  539.     send_error(&thd->net);
  540.     DBUG_RETURN(1);
  541.   }
  542.  
  543.   List<Item> field_list;
  544.   Item *item;
  545.   field_list.push_back(new Item_empty_string("Table",NAME_LEN));
  546.   field_list.push_back(new Item_int("Non_unique",0,1));
  547.   field_list.push_back(new Item_empty_string("Key_name",NAME_LEN));
  548.   field_list.push_back(new Item_int("Seq_in_index",0,2));
  549.   field_list.push_back(new Item_empty_string("Column_name",NAME_LEN));
  550.   field_list.push_back(item=new Item_empty_string("Collation",1));
  551.   item->maybe_null=1;
  552.   field_list.push_back(item=new Item_int("Cardinality",0,11));
  553.   item->maybe_null=1;
  554.   field_list.push_back(item=new Item_int("Sub_part",0,3));
  555.   item->maybe_null=1;
  556.   field_list.push_back(item=new Item_empty_string("Packed",10));
  557.   item->maybe_null=1;
  558.   field_list.push_back(new Item_empty_string("Comment",255));
  559.   item->maybe_null=1;
  560.  
  561.   if (send_fields(thd,field_list,1))
  562.     DBUG_RETURN(1);
  563.  
  564.   KEY *key_info=table->key_info;
  565.   table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_TIME);
  566.   for (uint i=0 ; i < table->keys ; i++,key_info++)
  567.   {
  568.     KEY_PART_INFO *key_part= key_info->key_part;
  569.     char *end;
  570.     String *packet= &thd->packet;
  571.     for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
  572.     {
  573.       packet->length(0);
  574.       net_store_data(packet,table->table_name);
  575.       net_store_data(packet,((key_info->flags & HA_NOSAME) ? "0" :"1"), 1);
  576.       net_store_data(packet,key_info->name);
  577.       end=int10_to_str((long) (j+1),(char*) buff,10);
  578.       net_store_data(packet,buff,(uint) (end-buff));
  579.       net_store_data(packet,key_part->field ? key_part->field->field_name :
  580.                      "?unknown field?");
  581.       if (table->file->option_flag() & HA_READ_ORDER)
  582.         net_store_data(packet,((key_part->key_part_flag & HA_REVERSE_SORT)
  583.                                ? "D" : "A"), 1);
  584.       else
  585.         net_store_null(packet); /* purecov: inspected */
  586.       KEY *key=table->key_info+i;
  587.       if (key->rec_per_key[j])
  588.       {
  589.         ulong records=(table->file->records / key->rec_per_key[j]);
  590.         end=int10_to_str((long) records, buff, 10);
  591.         net_store_data(packet,buff,(uint) (end-buff));
  592.       }
  593.       else
  594.         net_store_null(packet);
  595.       if (!key_part->field ||
  596.           key_part->length !=
  597.           table->field[key_part->fieldnr-1]->key_length())
  598.       {
  599.         end=int10_to_str((long) key_part->length, buff,10); /* purecov: inspected */
  600.         net_store_data(packet,buff,(uint) (end-buff)); /* purecov: inspected */
  601.       }
  602.       else
  603.         net_store_null(packet);
  604.       net_store_null(packet);                   // No pack_information yet
  605.       net_store_null(packet);                   // No comments yet
  606.       if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
  607.         DBUG_RETURN(1); /* purecov: inspected */
  608.     }
  609.   }
  610.   send_eof(&thd->net);
  611.   DBUG_RETURN(0);
  612. }
  613.  
  614.  
  615. /****************************************************************************
  616. ** Return only fields for API mysql_list_fields
  617. ** Use "show table wildcard" in mysql instead of this
  618. ****************************************************************************/
  619.  
  620. void
  621. mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild)
  622. {
  623.   TABLE *table;
  624.   DBUG_ENTER("mysqld_list_fields");
  625.   DBUG_PRINT("enter",("table: %s",table_list->real_name));
  626.  
  627.   if (!(table = open_ltable(thd, table_list, TL_UNLOCK)))
  628.   {
  629.     send_error(&thd->net);
  630.     DBUG_VOID_RETURN;
  631.   }
  632.   List<Item> field_list;
  633.  
  634.   Field **ptr,*field;
  635.   for (ptr=table->field ; (field= *ptr); ptr++)
  636.   {
  637.     if (!wild || !wild[0] || !wild_case_compare(field->field_name,wild))
  638.       field_list.push_back(new Item_field(field));
  639.   }
  640.   restore_record(table,2);              // Get empty record
  641.   if (send_fields(thd,field_list,2))
  642.     DBUG_VOID_RETURN;
  643.   VOID(net_flush(&thd->net));
  644.   DBUG_VOID_RETURN;
  645. }
  646.  
  647. int
  648. mysqld_dump_create_info(THD *thd, TABLE *table, int fd)
  649. {
  650.   DBUG_ENTER("mysqld_dump_create_info");
  651.   DBUG_PRINT("enter",("table: %s",table->real_name));
  652.   String* packet = &thd->packet;
  653.   packet->length(0);
  654.  
  655.   if(store_create_info(thd,table,packet))
  656.     DBUG_RETURN(-1);
  657.  
  658.   if(fd < 0)
  659.   {
  660.     if(my_net_write(&thd->net, (char*)packet->ptr(), packet->length()))
  661.       DBUG_RETURN(-1);
  662.     VOID(net_flush(&thd->net));
  663.   }
  664.   else
  665.   {
  666.     if(my_write(fd, (const byte*) packet->ptr(), packet->length(),
  667.                 MYF(MY_WME)))
  668.       DBUG_RETURN(-1);
  669.   }
  670.  
  671.   DBUG_RETURN(0);
  672. }
  673.  
  674. static void
  675. append_identifier(THD *thd, String *packet, const char *name)
  676. {
  677.   if (thd->options & OPTION_QUOTE_SHOW_CREATE)
  678.   {
  679.     packet->append("`", 1);
  680.     packet->append(name);
  681.     packet->append("`", 1);
  682.   }
  683.   else
  684.   {
  685.     packet->append(name);
  686.   }
  687. }
  688.  
  689. static int
  690. store_create_info(THD *thd, TABLE *table, String *packet)
  691. {
  692.   DBUG_ENTER("store_create_info");
  693.   DBUG_PRINT("enter",("table: %s",table->real_name));
  694.  
  695.   restore_record(table,2); // Get empty record
  696.  
  697.   List<Item> field_list;
  698.   char tmp[MAX_FIELD_WIDTH];
  699.   String type(tmp, sizeof(tmp));
  700.   packet->append("CREATE TABLE ", 13);
  701.   append_identifier(thd,packet,table->real_name);
  702.   packet->append(" (\n", 3);
  703.  
  704.   Field **ptr,*field;
  705.   for (ptr=table->field ; (field= *ptr); ptr++)
  706.   {
  707.     if(ptr != table->field)
  708.       packet->append(",\n", 2);
  709.  
  710.     uint flags = field->flags;
  711.     packet->append("  ", 2);
  712.     append_identifier(thd,packet,field->field_name);
  713.     packet->append(' ');
  714.     // check for surprises from the previous call to Field::sql_type()
  715.     if(type.ptr() != tmp)
  716.       type.set(tmp, sizeof(tmp));
  717.  
  718.     field->sql_type(type);
  719.     packet->append(type.ptr(),type.length());
  720.  
  721.     bool has_default = (field->type() != FIELD_TYPE_BLOB && 
  722.             field->type() != FIELD_TYPE_TIMESTAMP &&
  723.             field->unireg_check != Field::NEXT_NUMBER);
  724.     if (flags & NOT_NULL_FLAG)
  725.       packet->append(" NOT NULL", 9);
  726.  
  727.     if (has_default)
  728.     {
  729.       packet->append(" default ", 9);
  730.       if (!field->is_null())
  731.       {                                             // Not null by default
  732.         type.set(tmp,sizeof(tmp));
  733.         field->val_str(&type,&type);
  734.         packet->append('\'');
  735.     if(type.length())
  736.           append_unescaped(packet, type.c_ptr());
  737.         packet->append('\'');
  738.       }
  739.       else if (field->maybe_null())
  740.         packet->append("NULL", 4);                    // Null as default
  741.       else
  742.         packet->append(tmp,0);
  743.     }
  744.  
  745.     if (field->unireg_check == Field::NEXT_NUMBER)
  746.           packet->append(" auto_increment", 15 );
  747.   }
  748.  
  749.   KEY *key_info=table->key_info;
  750.   table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_TIME);
  751.   uint primary_key = table->primary_key;
  752.  
  753.   for (uint i=0 ; i < table->keys ; i++,key_info++)
  754.   {
  755.     packet->append(",\n  ", 4);
  756.  
  757.     KEY_PART_INFO *key_part= key_info->key_part;
  758.     if(i == primary_key)
  759.       packet->append("PRIMARY ", 8);
  760.     else if(key_info->flags & HA_NOSAME)
  761.       packet->append("UNIQUE ", 7);
  762.     else if(key_info->flags & HA_FULLTEXT)
  763.       packet->append("FULLTEXT ", 9);
  764.     packet->append("KEY ", 4);
  765.  
  766.     if(i != primary_key)
  767.      append_identifier(thd,packet,key_info->name);
  768.  
  769.     packet->append('(');
  770.  
  771.     for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
  772.     {
  773.       if (j)
  774.         packet->append(',');
  775.  
  776.       if (key_part->field)
  777.         append_identifier(thd,packet,key_part->field->field_name);
  778.       if (!key_part->field ||
  779.           (key_part->length !=
  780.            table->field[key_part->fieldnr-1]->key_length() &&
  781.            !(key_info->flags & HA_FULLTEXT)))
  782.       {
  783.         char buff[64];
  784.         buff[0] = '(';
  785.         char* end=int10_to_str((long) key_part->length, buff + 1,10);
  786.         *end++ = ')';
  787.         packet->append(buff,(uint) (end-buff));
  788.       }
  789.     }
  790.     packet->append(')');
  791.   }
  792.   packet->append("\n)", 2);
  793.  
  794.   handler *file = table->file;
  795.   packet->append(" TYPE=", 6);
  796.   packet->append(file->table_type());
  797.   char buff[128];
  798.   char* p;
  799.  
  800.   if(table->min_rows)
  801.   {
  802.     packet->append(" MIN_ROWS=");
  803.     p = longlong10_to_str(table->min_rows, buff, 10);
  804.     packet->append(buff, (uint) (p - buff));
  805.   }
  806.  
  807.   if(table->max_rows)
  808.   {
  809.     packet->append(" MAX_ROWS=");
  810.     p = longlong10_to_str(table->max_rows, buff, 10);
  811.     packet->append(buff, (uint) (p - buff));
  812.   }
  813.  
  814.   if (table->db_create_options & HA_OPTION_PACK_KEYS)
  815.     packet->append(" PACK_KEYS=1", 12);
  816.   if (table->db_create_options & HA_OPTION_NO_PACK_KEYS)
  817.     packet->append(" PACK_KEYS=0", 12);
  818.   if (table->db_create_options & HA_OPTION_CHECKSUM)
  819.     packet->append(" CHECKSUM=1", 11);
  820.   if (table->db_create_options & HA_OPTION_DELAY_KEY_WRITE)
  821.     packet->append(" DELAY_KEY_WRITE=1",18);
  822.   if(table->comment)
  823.     {
  824.       packet->append(" COMMENT='", 10); 
  825.       append_unescaped(packet, table->comment);
  826.       packet->append('\'');
  827.     }
  828.  
  829.  
  830.   DBUG_RETURN(0);
  831. }
  832.  
  833.  
  834. /****************************************************************************
  835. ** Return info about all processes
  836. ** returns for each thread: thread id, user, host, db, command, info
  837. ****************************************************************************/
  838.  
  839. class thread_info :public ilink {
  840. public:
  841.   static void *operator new(size_t size) {return (void*) sql_alloc((uint) size); }
  842.   static void operator delete(void *ptr __attribute__((unused)),
  843.                               size_t size __attribute__((unused))) {} /*lint -e715 */
  844.  
  845.   ulong thread_id;
  846.   time_t start_time;
  847.   uint   command;
  848.   const char *user,*host,*db,*proc_info,*state_info;
  849.   char *query;
  850. };
  851.  
  852. #ifdef __GNUC__
  853. template class I_List<thread_info>;
  854. #endif
  855.  
  856.  
  857. void mysqld_list_processes(THD *thd,const char *user, bool verbose)
  858. {
  859.   Item *field;
  860.   List<Item> field_list;
  861.   I_List<thread_info> thread_infos;
  862.   ulong max_query_length= verbose ? max_allowed_packet : PROCESS_LIST_WIDTH;
  863.   DBUG_ENTER("mysqld_list_processes");
  864.  
  865.   field_list.push_back(new Item_int("Id",0,7));
  866.   field_list.push_back(new Item_empty_string("User",16));
  867.   field_list.push_back(new Item_empty_string("Host",64));
  868.   field_list.push_back(field=new Item_empty_string("db",NAME_LEN));
  869.   field->maybe_null=1;
  870.   field_list.push_back(new Item_empty_string("Command",16));
  871.   field_list.push_back(new Item_empty_string("Time",7));
  872.   field_list.push_back(field=new Item_empty_string("State",30));
  873.   field->maybe_null=1;
  874.   field_list.push_back(field=new Item_empty_string("Info",max_query_length));
  875.   field->maybe_null=1;
  876.   if (send_fields(thd,field_list,1))
  877.     DBUG_VOID_RETURN;
  878.  
  879.   VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
  880.   if (!thd->killed)
  881.   {
  882.     I_List_iterator<THD> it(threads);
  883.     THD *tmp;
  884.     while ((tmp=it++))
  885.     {
  886.       if ((tmp->net.vio || tmp->system_thread) &&
  887.           (!user || (tmp->user && !strcmp(tmp->user,user))))
  888.       {
  889.         thread_info *thd_info=new thread_info;
  890.  
  891.         thd_info->thread_id=tmp->thread_id;
  892.         thd_info->user=thd->strdup(tmp->user ? tmp->user : (tmp->system_thread ?
  893.                                   "system user" : "unauthenticated user"));
  894.         thd_info->host=thd->strdup(tmp->host ? tmp->host : (tmp->ip ? tmp->ip :
  895.                                    (tmp->system_thread ? "none" : "connecting host")));
  896.         if ((thd_info->db=tmp->db))             // Safe test
  897.           thd_info->db=thd->strdup(thd_info->db);
  898.         thd_info->command=(int) tmp->command;
  899.         if (tmp->mysys_var)
  900.           pthread_mutex_lock(&tmp->mysys_var->mutex);
  901.         thd_info->proc_info= (char*) (tmp->killed ? "Killed" : 0);
  902.         thd_info->state_info= (char*) (tmp->locked ? "Locked" :
  903.                                        tmp->net.reading_or_writing ?
  904.                                        (tmp->net.reading_or_writing == 2 ?
  905.                                         "Writing to net" :
  906.                                         thd_info->command == COM_SLEEP ? "" :
  907.                                         "Reading from net") :
  908.                                        tmp->proc_info ? tmp->proc_info :
  909.                                        tmp->mysys_var &&
  910.                                        tmp->mysys_var->current_cond ?
  911.                                        "Waiting on cond" : NullS);
  912.         if (tmp->mysys_var)
  913.           pthread_mutex_unlock(&tmp->mysys_var->mutex);
  914.  
  915. #if !defined(DONT_USE_THR_ALARM) && ! defined(SCO)
  916.         if (pthread_kill(tmp->real_id,0))
  917.           tmp->proc_info="*** DEAD ***";        // This shouldn't happen
  918. #endif
  919.         thd_info->start_time= tmp->start_time;
  920.         thd_info->query=0;
  921.         if (tmp->query)
  922.         {
  923.           uint length=(uint) strlen(tmp->query);
  924.           if (length > max_query_length)
  925.             length=max_query_length;
  926.           thd_info->query=(char*) thd->memdup(tmp->query,length+1);
  927.           thd_info->query[length]=0;
  928.         }
  929.         thread_infos.append(thd_info);
  930.       }
  931.     }
  932.   }
  933.   VOID(pthread_mutex_unlock(&LOCK_thread_count));
  934.  
  935.   thread_info *thd_info;
  936.   String *packet= &thd->packet;
  937.   while ((thd_info=thread_infos.get()))
  938.   {
  939.     char buff[20],*end;
  940.     packet->length(0);
  941.     end=int10_to_str((long) thd_info->thread_id, buff,10);
  942.     net_store_data(packet,buff,(uint) (end-buff));
  943.     net_store_data(packet,thd_info->user);
  944.     net_store_data(packet,thd_info->host);
  945.     if (thd_info->db)
  946.       net_store_data(packet,thd_info->db);
  947.     else
  948.       net_store_null(packet);
  949.     if (thd_info->proc_info)
  950.       net_store_data(packet,thd_info->proc_info);
  951.     else
  952.       net_store_data(packet,command_name[thd_info->command]);
  953.     if (thd_info->start_time)
  954.       net_store_data(packet,(uint32)
  955.                      (time((time_t*) 0) - thd_info->start_time));
  956.     else
  957.       net_store_null(packet);
  958.     if (thd_info->state_info)
  959.       net_store_data(packet,thd_info->state_info);
  960.     else
  961.       net_store_null(packet);
  962.     if (thd_info->query)
  963.       net_store_data(packet,thd_info->query);
  964.     else
  965.       net_store_null(packet);
  966.     if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
  967.       break; /* purecov: inspected */
  968.   }
  969.   send_eof(&thd->net);
  970.   DBUG_VOID_RETURN;
  971. }
  972.  
  973.  
  974. /*****************************************************************************
  975. ** Status functions
  976. *****************************************************************************/
  977.  
  978.  
  979. int mysqld_show(THD *thd, const char *wild, show_var_st *variables)
  980. {
  981.   uint i;
  982.   char buff[8192];
  983.   String packet2(buff,sizeof(buff));
  984.   List<Item> field_list;
  985.   DBUG_ENTER("mysqld_show");
  986.   field_list.push_back(new Item_empty_string("Variable_name",30));
  987.   field_list.push_back(new Item_empty_string("Value",256));
  988.   if (send_fields(thd,field_list,1))
  989.     DBUG_RETURN(1); /* purecov: inspected */
  990.  
  991.   pthread_mutex_lock(&THR_LOCK_keycache);
  992.   pthread_mutex_lock(&LOCK_status);
  993.   for (i=0; variables[i].name; i++)
  994.   {
  995.     if (!(wild && wild[0] && wild_compare(variables[i].name,wild)))
  996.     {
  997.       packet2.length(0);
  998.       net_store_data(&packet2,variables[i].name);
  999.       switch (variables[i].type){
  1000.       case SHOW_LONG:
  1001.       case SHOW_LONG_CONST:
  1002.         net_store_data(&packet2,(uint32) *(ulong*) variables[i].value);
  1003.         break;
  1004.       case SHOW_BOOL:
  1005.         net_store_data(&packet2,(ulong) *(bool*) variables[i].value ?
  1006.                        "ON" : "OFF");
  1007.         break;
  1008.       case SHOW_MY_BOOL:
  1009.         net_store_data(&packet2,(ulong) *(my_bool*) variables[i].value ?
  1010.                        "ON" : "OFF");
  1011.         break;
  1012.       case SHOW_INT_CONST:
  1013.       case SHOW_INT:
  1014.         net_store_data(&packet2,(uint32) *(int*) variables[i].value);
  1015.         break;
  1016.       case SHOW_CHAR:
  1017.         net_store_data(&packet2,variables[i].value);
  1018.         break;
  1019.       case SHOW_STARTTIME:
  1020.         net_store_data(&packet2,(uint32) (thd->query_start() - start_time));
  1021.         break;
  1022.       case SHOW_QUESTION:
  1023.         net_store_data(&packet2,(uint32) thd->query_id);
  1024.         break;
  1025.       case SHOW_OPENTABLES:
  1026.         net_store_data(&packet2,(uint32) cached_tables());
  1027.         break;
  1028.       case SHOW_CHAR_PTR:
  1029.         {
  1030.           char *value= *(char**) variables[i].value;
  1031.           net_store_data(&packet2,value ? value : "");
  1032.           break;
  1033.         }
  1034.       }
  1035.       if (my_net_write(&thd->net, (char*) packet2.ptr(),packet2.length()))
  1036.         goto err;                               /* purecov: inspected */
  1037.     }
  1038.   }
  1039.   pthread_mutex_unlock(&LOCK_status);
  1040.   pthread_mutex_unlock(&THR_LOCK_keycache);
  1041.   send_eof(&thd->net);
  1042.   DBUG_RETURN(0);
  1043.  
  1044.  err:
  1045.   pthread_mutex_unlock(&LOCK_status);
  1046.   pthread_mutex_unlock(&THR_LOCK_keycache);
  1047.   DBUG_RETURN(1);
  1048. }
  1049.  
  1050. #ifdef __GNUC__
  1051. template class List_iterator<char>;
  1052. template class List<char>;
  1053. #endif
  1054.