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_class.cpp < prev    next >
C/C++ Source or Header  |  2000-11-21  |  16KB  |  612 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. /*****************************************************************************
  19. **
  20. ** This file implements classes defined in sql_class.h
  21. ** Especially the classes to handle a result from a select
  22. **
  23. *****************************************************************************/
  24.  
  25. #ifdef __GNUC__
  26. #pragma implementation                // gcc: Class implementation
  27. #endif
  28.  
  29. #include "mysql_priv.h"
  30. #include "sql_acl.h"
  31. #include <m_ctype.h>
  32. #include <sys/stat.h>
  33. #ifdef    __WIN__
  34. #include <io.h>
  35. #endif
  36.  
  37. /*****************************************************************************
  38. ** Instansiate templates
  39. *****************************************************************************/
  40.  
  41. #ifdef __GNUC__
  42. /* Used templates */
  43. template class List<Key>;
  44. template class List_iterator<Key>;
  45. template class List<key_part_spec>;
  46. template class List_iterator<key_part_spec>;
  47. template class List<Alter_drop>;
  48. template class List_iterator<Alter_drop>;
  49. template class List<Alter_column>;
  50. template class List_iterator<Alter_column>;
  51. #endif
  52.  
  53. /****************************************************************************
  54. ** User variables
  55. ****************************************************************************/
  56.  
  57. static byte* get_var_key(user_var_entry *entry, uint *length,
  58.              my_bool not_used __attribute__((unused)))
  59. {
  60.   *length=(uint) entry->name.length;
  61.   return (byte*) entry->name.str;
  62. }
  63.  
  64. static void free_var(user_var_entry *entry)
  65. {
  66.   char *pos= (char*) entry+ALIGN_SIZE(sizeof(*entry));
  67.   if (entry->value && entry->value != pos)
  68.     my_free(entry->value, MYF(0));
  69.   my_free((char*) entry,MYF(0));
  70. }
  71.  
  72.  
  73. /****************************************************************************
  74. ** Thread specific functions
  75. ****************************************************************************/
  76.  
  77. THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0),
  78.        insert_id_used(0),
  79.        bootstrap(0),in_lock_tables(0),
  80.        global_read_lock(0)
  81. {
  82.    host=user=db=query=ip=0;
  83.   proc_info="login";
  84.   locked=killed=count_cuted_fields=some_tables_deleted=no_errors=password=
  85.     query_start_used=0;
  86.   query_length=col_access=0;
  87.   query_error=0;
  88.   server_id = ::server_id;
  89.   server_status=SERVER_STATUS_AUTOCOMMIT;
  90.   next_insert_id=last_insert_id=0;
  91.   open_tables=temporary_tables=0;
  92.   tmp_table=0;
  93.   lock=locked_tables=0;
  94.   used_tables=0;
  95.   cuted_fields=0L;
  96.   options=thd_startup_options;
  97.   update_lock_default= low_priority_updates ? TL_WRITE_LOW_PRIORITY : TL_WRITE;
  98.   start_time=(time_t) 0;
  99.   current_linfo =  0;
  100.   slave_thread = 0;
  101.   last_nx_table = last_nx_db = 0;
  102.   inactive_timeout=net_wait_timeout;
  103.   open_options=ha_open_options;
  104.   cond_count=0;
  105.   command=COM_CONNECT;
  106.   set_query_id=1;
  107.   default_select_limit= HA_POS_ERROR;
  108.   max_join_size=  ((::max_join_size != ~ (ulong) 0L) ? ::max_join_size :
  109.            HA_POS_ERROR);
  110.   convert_set=0;
  111.   mysys_var=0;
  112.   db_access=NO_ACCESS;
  113.   hash_init(&user_vars, USER_VARS_HASH_SIZE, 0, 0,
  114.         (hash_get_key) get_var_key,
  115.         (void (*)(void*)) free_var,0);
  116.   net.vio=0;
  117.   ull=0;
  118.   system_thread=0;
  119.   bzero((char*) &mem_root,sizeof(mem_root));
  120. #if defined(HAVE_BERKELEY_DB) || defined(HAVE_INNOBASE_DB) || defined(HAVE_GEMENI_DB)
  121.   if (open_cached_file(&transaction.trans_log,
  122.                mysql_tmpdir,LOG_PREFIX,0,MYF(MY_WME)))
  123.     killed=1;
  124.   transaction.bdb_lock_count=0;
  125. #endif
  126.   transaction.bdb_tid=0;
  127.  
  128. #ifdef    __WIN__
  129.   real_id = 0 ;
  130. #endif
  131. }
  132.  
  133. THD::~THD()
  134. {
  135.   DBUG_ENTER("~THD()");
  136.   /* Close connection */
  137.   if (net.vio)
  138.   {
  139.     vio_delete(net.vio);
  140.     net_end(&net);
  141.   }
  142.   ha_rollback(this);
  143.   if (locked_tables)
  144.   {
  145.     lock=locked_tables; locked_tables=0;
  146.     close_thread_tables(this);
  147.   }
  148.   close_temporary_tables(this);
  149. #if defined(HAVE_BERKELEY_DB) || defined(HAVE_INNOBASE_DB) || defined(HAVE_GEMENI_DB)
  150.   close_cached_file(&transaction.trans_log);
  151. #endif
  152.   if (global_read_lock)
  153.   {
  154.     pthread_mutex_lock(&LOCK_open);
  155.     ::global_read_lock--;
  156.     pthread_cond_broadcast(&COND_refresh);
  157.     pthread_mutex_unlock(&LOCK_open);
  158.   }
  159.   if (ull)
  160.   {
  161.     pthread_mutex_lock(&LOCK_user_locks);
  162.     item_user_lock_release(ull);
  163.     pthread_mutex_unlock(&LOCK_user_locks);
  164.   }
  165.   hash_free(&user_vars);
  166.  
  167.   DBUG_PRINT("info", ("freeing host"));
  168.   
  169.   if (host != localhost)            // If not pointer to constant
  170.     safeFree(host);
  171.   safeFree(user);
  172.   safeFree(db);
  173.   safeFree(ip);
  174.   free_root(&mem_root,MYF(0));
  175.   mysys_var=0;                    // Safety (shouldn't be needed)
  176.   DBUG_VOID_RETURN;
  177. }
  178.  
  179. // remember the location of thread info, the structure needed for
  180. // sql_alloc() and the structure for the net buffer
  181.  
  182. bool THD::store_globals()
  183. {
  184.   return (my_pthread_setspecific_ptr(THR_THD,  this) ||
  185.       my_pthread_setspecific_ptr(THR_MALLOC, &mem_root) ||
  186.       my_pthread_setspecific_ptr(THR_NET,  &net));
  187. }
  188.  
  189. /*****************************************************************************
  190. ** Functions to provide a interface to select results
  191. *****************************************************************************/
  192.  
  193. select_result::select_result()
  194. {
  195.   thd=current_thd;
  196. }
  197.  
  198. static String default_line_term("\n"),default_escaped("\\"),
  199.           default_field_term("\t");
  200.  
  201. sql_exchange::sql_exchange(char *name,bool flag)
  202.   :file_name(name), opt_enclosed(0), dumpfile(flag), skip_lines(0)
  203. {
  204.   field_term= &default_field_term;
  205.   enclosed=   line_start= &empty_string;
  206.   line_term=  &default_line_term;
  207.   escaped=    &default_escaped;
  208. }
  209.  
  210. bool select_send::send_fields(List<Item> &list,uint flag)
  211. {
  212.   return ::send_fields(thd,list,flag);
  213. }
  214.  
  215.  
  216. /* Send data to client. Returns 0 if ok */
  217.  
  218. bool select_send::send_data(List<Item> &items)
  219. {
  220.   List_iterator<Item> li(items);
  221.   String *packet= &thd->packet;
  222.   DBUG_ENTER("send_data");
  223.  
  224.   if (thd->offset_limit)
  225.   {                        // using limit offset,count
  226.     thd->offset_limit--;
  227.     DBUG_RETURN(0);
  228.   }
  229.   packet->length(0);                // Reset packet
  230.   Item *item;
  231.   while ((item=li++))
  232.   {
  233.     if (item->send(packet))
  234.     {
  235.       packet->free();                // Free used
  236.       my_error(ER_OUT_OF_RESOURCES,MYF(0));
  237.       DBUG_RETURN(1);
  238.     }
  239.   }
  240.   thd->sent_row_count++;
  241.   bool error=my_net_write(&thd->net,(char*) packet->ptr(),packet->length());
  242.   DBUG_RETURN(error);
  243. }
  244.  
  245.  
  246. void select_send::send_error(uint errcode,const char *err)
  247. {
  248.   ::send_error(&thd->net,errcode,err);
  249. }
  250.  
  251. bool select_send::send_eof()
  252. {
  253.   /* Unlock tables before sending packet to gain some speed */
  254.   if (thd->lock)
  255.   {
  256.     mysql_unlock_tables(thd, thd->lock); thd->lock=0;
  257.   }
  258.   ::send_eof(&thd->net);
  259.   return 0;
  260. }
  261.  
  262.  
  263. /***************************************************************************
  264. ** Export of select to textfile
  265. ***************************************************************************/
  266.  
  267.  
  268. select_export::~select_export()
  269. {
  270.   if (file >= 0)
  271.   {                    // This only happens in case of error
  272.     (void) end_io_cache(&cache);
  273.     (void) my_close(file,MYF(0));
  274.     file= -1;
  275.   }
  276.   thd->sent_row_count=row_count;
  277. }
  278.  
  279. int
  280. select_export::prepare(List<Item> &list)
  281. {
  282.   char path[FN_REFLEN];
  283.   uint option=4;
  284.   bool blob_flag=0;
  285. #ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
  286.   option|=1;                    // Force use of db directory
  287. #endif
  288.   if ((uint) strlen(exchange->file_name) + NAME_LEN >= FN_REFLEN)
  289.     strmake(path,exchange->file_name,FN_REFLEN-1);
  290.   (void) fn_format(path,exchange->file_name, thd->db ? thd->db : "", "",
  291.            option);
  292.   if (!access(path,F_OK))
  293.   {
  294.     my_error(ER_FILE_EXISTS_ERROR,MYF(0),exchange->file_name);
  295.     return 1;
  296.   }
  297.   /* Create the file world readable */
  298.   if ((file=my_create(path, 0666, O_WRONLY, MYF(MY_WME))) < 0)
  299.     return 1;
  300. #ifdef HAVE_FCHMOD
  301.   (void) fchmod(file,0666);            // Because of umask()
  302. #else
  303.   (void) chmod(path,0666);
  304. #endif
  305.   if (init_io_cache(&cache,file,0L,WRITE_CACHE,0L,1,MYF(MY_WME)))
  306.   {
  307.     my_close(file,MYF(0));
  308.     file= -1;
  309.     return 1;
  310.   }
  311.   /* Check if there is any blobs in data */
  312.   {
  313.     List_iterator<Item> li(list);
  314.     Item *item;
  315.     while ((item=li++))
  316.     {
  317.       if (item->max_length >= MAX_BLOB_WIDTH)
  318.       {
  319.     blob_flag=1;
  320.     break;
  321.       }
  322.     }
  323.   }
  324.   field_term_length=exchange->field_term->length();
  325.   if (!exchange->line_term->length())
  326.     exchange->line_term=exchange->field_term;    // Use this if it exists
  327.   field_sep_char= (exchange->enclosed->length() ? (*exchange->enclosed)[0] :
  328.            field_term_length ? (*exchange->field_term)[0] : INT_MAX);
  329.   escape_char=    (exchange->escaped->length() ? (*exchange->escaped)[0] : -1);
  330.   line_sep_char= (exchange->line_term->length() ?
  331.           (*exchange->line_term)[0] : INT_MAX);
  332.   if (!field_term_length)
  333.     exchange->opt_enclosed=0;
  334.   if (!exchange->enclosed->length())
  335.     exchange->opt_enclosed=1;            // A little quicker loop
  336.   fixed_row_size= (!field_term_length && !exchange->enclosed->length() &&
  337.            !blob_flag);
  338.   return 0;
  339. }
  340.  
  341.  
  342. bool select_export::send_data(List<Item> &items)
  343. {
  344.  
  345.   DBUG_ENTER("send_data");
  346.   char buff[MAX_FIELD_WIDTH],null_buff[2],space[MAX_FIELD_WIDTH];
  347.   bool space_inited=0;
  348.   String tmp(buff,sizeof(buff)),*res;
  349.   tmp.length(0);
  350.  
  351.   if (thd->offset_limit)
  352.   {                        // using limit offset,count
  353.     thd->offset_limit--;
  354.     DBUG_RETURN(0);
  355.   }
  356.   row_count++;
  357.   Item *item;
  358.   char *buff_ptr=buff;
  359.   uint used_length=0,items_left=items.elements;
  360.   List_iterator<Item> li(items);
  361.  
  362.   if (my_b_write(&cache,(byte*) exchange->line_start->ptr(),
  363.          exchange->line_start->length()))
  364.     goto err;
  365.   while ((item=li++))
  366.   {
  367.     Item_result result_type=item->result_type();
  368.     res=item->str_result(&tmp);
  369.     if (res && (!exchange->opt_enclosed || result_type == STRING_RESULT))
  370.     {
  371.       if (my_b_write(&cache,(byte*) exchange->enclosed->ptr(),
  372.              exchange->enclosed->length()))
  373.     goto err;
  374.     }
  375.     if (!res)
  376.     {                        // NULL
  377.       if (!fixed_row_size)
  378.       {
  379.     if (escape_char != -1)            // Use \N syntax
  380.     {
  381.       null_buff[0]=escape_char;
  382.       null_buff[1]='N';
  383.       if (my_b_write(&cache,(byte*) null_buff,2))
  384.         goto err;
  385.     }
  386.     else if (my_b_write(&cache,(byte*) "NULL",4))
  387.       goto err;
  388.       }
  389.       else
  390.       {
  391.     used_length=0;                // Fill with space
  392.       }
  393.     }
  394.     else
  395.     {
  396.       if (fixed_row_size)
  397.     used_length=min(res->length(),item->max_length);
  398.       else
  399.     used_length=res->length();
  400.       if (result_type == STRING_RESULT && escape_char != -1)
  401.       {
  402.     char *pos,*start,*end;
  403.  
  404.     for (start=pos=(char*) res->ptr(),end=pos+used_length ;
  405.          pos != end ;
  406.          pos++)
  407.     {
  408. #ifdef USE_MB
  409.       if (use_mb(default_charset_info))
  410.       {
  411.         int l;
  412.         if ((l=my_ismbchar(default_charset_info, pos, end)))
  413.         {
  414.           pos += l-1;
  415.           continue;
  416.         }
  417.       }
  418. #endif
  419.       if ((int) *pos == escape_char || (int) *pos == field_sep_char ||
  420.           (int) *pos == line_sep_char || !*pos)
  421.       {
  422.         char tmp_buff[2];
  423.         tmp_buff[0]= escape_char;
  424.         tmp_buff[1]= *pos ? *pos : '0';
  425.         if (my_b_write(&cache,(byte*) start,(uint) (pos-start)) ||
  426.         my_b_write(&cache,(byte*) tmp_buff,2))
  427.           goto err;
  428.         start=pos+1;
  429.       }
  430.     }
  431.     if (my_b_write(&cache,(byte*) start,(uint) (pos-start)))
  432.       goto err;
  433.       }
  434.       else if (my_b_write(&cache,(byte*) res->ptr(),used_length))
  435.     goto err;
  436.     }
  437.     if (fixed_row_size)
  438.     {                        // Fill with space
  439.       if (item->max_length > used_length)
  440.       {
  441.     /* QQ:  Fix by adding a my_b_fill() function */
  442.     if (!space_inited)
  443.     {
  444.       space_inited=1;
  445.       bfill(space,sizeof(space),' ');
  446.     }
  447.     uint length=item->max_length-used_length;
  448.     for ( ; length > sizeof(space) ; length-=sizeof(space))
  449.     {
  450.       if (my_b_write(&cache,(byte*) space,sizeof(space)))
  451.         goto err;
  452.     }
  453.     if (my_b_write(&cache,(byte*) space,length))
  454.       goto err;
  455.       }
  456.     }
  457.     buff_ptr=buff;                // Place separators here
  458.     if (res && (!exchange->opt_enclosed || result_type == STRING_RESULT))
  459.     {
  460.       memcpy(buff_ptr,exchange->enclosed->ptr(),exchange->enclosed->length());
  461.       buff_ptr+=exchange->enclosed->length();
  462.     }
  463.     if (--items_left)
  464.     {
  465.       memcpy(buff_ptr,exchange->field_term->ptr(),field_term_length);
  466.       buff_ptr+=field_term_length;
  467.     }
  468.     if (my_b_write(&cache,(byte*) buff,(uint) (buff_ptr-buff)))
  469.       goto err;
  470.   }
  471.   if (my_b_write(&cache,(byte*) exchange->line_term->ptr(),
  472.          exchange->line_term->length()))
  473.     goto err;
  474.   DBUG_RETURN(0);
  475. err:
  476.   DBUG_RETURN(1);
  477. }
  478.  
  479.  
  480. void select_export::send_error(uint errcode,const char *err)
  481. {
  482.   ::send_error(&thd->net,errcode,err);
  483.   (void) end_io_cache(&cache);
  484.   (void) my_close(file,MYF(0));
  485.   file= -1;
  486. }
  487.  
  488.  
  489. bool select_export::send_eof()
  490. {
  491.   int error=test(end_io_cache(&cache));
  492.   if (my_close(file,MYF(MY_WME)))
  493.     error=1;
  494.   if (error)
  495.     ::send_error(&thd->net);
  496.   else
  497.     ::send_ok(&thd->net,row_count);
  498.   file= -1;
  499.   return error;
  500. }
  501.  
  502.  
  503. /***************************************************************************
  504. ** Dump  of select to a binary file
  505. ***************************************************************************/
  506.  
  507.  
  508. select_dump::~select_dump()
  509. {
  510.   if (file >= 0)
  511.   {                    // This only happens in case of error
  512.     (void) end_io_cache(&cache);
  513.     (void) my_close(file,MYF(0));
  514.     file= -1;
  515.   }
  516. }
  517.  
  518. int
  519. select_dump::prepare(List<Item> &list __attribute__((unused)))
  520. {
  521.   uint option=4;
  522. #ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
  523.   option|=1;                    // Force use of db directory
  524. #endif
  525.   (void) fn_format(path,exchange->file_name, thd->db ? thd->db : "", "",
  526.            option);
  527.   if (!access(path,F_OK))
  528.   {
  529.     my_error(ER_FILE_EXISTS_ERROR,MYF(0),exchange->file_name);
  530.     return 1;
  531.   }
  532.   /* Create the file world readable */
  533.   if ((file=my_create(path, 0666, O_WRONLY, MYF(MY_WME))) < 0)
  534.     return 1;
  535. #ifdef HAVE_FCHMOD
  536.   (void) fchmod(file,0666);            // Because of umask()
  537. #else
  538.   (void) chmod(path,0666);
  539. #endif
  540.   if (init_io_cache(&cache,file,0L,WRITE_CACHE,0L,1,MYF(MY_WME)))
  541.   {
  542.     my_close(file,MYF(0));
  543.     my_delete(path,MYF(0));
  544.     file= -1;
  545.     return 1;
  546.   }
  547.   return 0;
  548. }
  549.  
  550.  
  551. bool select_dump::send_data(List<Item> &items)
  552. {
  553.   List_iterator<Item> li(items);
  554.   char buff[MAX_FIELD_WIDTH];
  555.   String tmp(buff,sizeof(buff)),*res;
  556.   tmp.length(0);
  557.   Item *item;
  558.   DBUG_ENTER("send_data");
  559.  
  560.   if (thd->offset_limit)
  561.   {                        // using limit offset,count
  562.     thd->offset_limit--;
  563.     DBUG_RETURN(0);
  564.   }
  565.   if (row_count++ > 1) 
  566.   {
  567.     my_error(ER_TOO_MANY_ROWS,MYF(0));
  568.     goto err;
  569.   }
  570.   while ((item=li++))
  571.   {
  572.     res=item->str_result(&tmp);
  573.     if (!res)                    // If NULL
  574.     {
  575.       if (my_b_write(&cache,(byte*) "",1))
  576.     goto err;
  577.     }
  578.     else if (my_b_write(&cache,(byte*) res->ptr(),res->length()))
  579.     {
  580.       my_error(ER_ERROR_ON_WRITE,MYF(0), path, my_errno);
  581.       goto err;
  582.     }
  583.   }
  584.   DBUG_RETURN(0);
  585. err:
  586.   DBUG_RETURN(1);
  587. }
  588.  
  589.  
  590. void select_dump::send_error(uint errcode,const char *err)
  591. {
  592.   ::send_error(&thd->net,errcode,err);
  593.   (void) end_io_cache(&cache);
  594.   (void) my_close(file,MYF(0));
  595.   (void) my_delete(path,MYF(0));        // Delete file on error
  596.   file= -1;
  597. }
  598.  
  599.  
  600. bool select_dump::send_eof()
  601. {
  602.   int error=test(end_io_cache(&cache));
  603.   if (my_close(file,MYF(MY_WME)))
  604.     error=1;
  605.   if (error)
  606.     ::send_error(&thd->net);
  607.   else
  608.     ::send_ok(&thd->net,row_count);
  609.   file= -1;
  610.   return error;
  611. }
  612.