List:Commits« Previous MessageNext Message »
From:Sasha Pachev Date:January 31 2006 3:58am
Subject:bk commit into 5.1 tree (sasha:1.2099)
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 repository of sasha. When sasha does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet
  1.2099 06/01/30 20:58:17 sasha@stripped +4 -0
  Merge spachev@stripped:/home/bk/mysql-5.1-new
  into  asksasha.com:/reiser-data/mysql-dev/mysql-5.1-new

  mysql-test/t/mysqltest.test
    1.32 06/01/30 20:58:13 sasha@stripped +1 -0
    merged

  mysql-test/r/mysqltest.result
    1.27 06/01/30 20:58:13 sasha@stripped +0 -1
    merged

  client/mysqltest.c
    1.175 06/01/30 20:58:13 sasha@stripped +0 -20
    merged

  BitKeeper/etc/ignore
    1.224 06/01/30 20:58:13 sasha@stripped +1 -0
    Added BitKeeper/etc/RESYNC_TREE to the ignore list

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	sasha
# Host:	mysql.sashanet.com
# Root:	/reiser-data/mysql-dev/mysql-5.1-new/RESYNC

--- 1.26/mysql-test/r/mysqltest.result	2006-01-23 00:58:08 -07:00
+++ 1.27/mysql-test/r/mysqltest.result	2006-01-30 20:58:13 -07:00
@@ -418,4 +418,22 @@
 select-me
 ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'insertz error query' at line 1
 drop table t1;
-drop table t1;
+select "b" as col1, "c" as col2;
+col1	col2
+b	c
+select "b" as col1, "b" as col2, "c" as col3;
+col1	col2	col3
+b	b	c
+seled "b" bs col1, "d" bs col2;
+col1	col2
+b	d
+select "raspberry and strawberry","blackberry","tomato";
+raspberry and strawberry	blackberry	tomato
+raspberry and strawberry	blackberry	tomato
+mysqltest: At line 1: Error parsing replace_regex "a"
+mysqltest: At line 1: Error parsing replace_regex "a;"
+mysqltest: At line 1: Error parsing replace_regex "a"
+mysqltest: At line 1: Error parsing replace_regex "a "
+mysqltest: At line 1: Error parsing replace_regex "a b"
+mysqltest: At line 1: Error parsing replace_regex "/a b c"
+mysqltest: At line 1: Error parsing replace_regex "/a /b c "

--- 1.31/mysql-test/t/mysqltest.test	2006-01-19 02:28:59 -07:00
+++ 1.32/mysql-test/t/mysqltest.test	2006-01-30 20:58:13 -07:00
@@ -1061,3 +1061,30 @@
 drop table t1;
 
 
+# test for replace_regex
+--replace_regex /at/b/
+select "at" as col1, "c" as col2;
+
+--replace_regex /at/b/i
+select "at" as col1, "AT" as col2, "c" as col3;
+
+--replace_regex /a/b/ /ct/d/
+select "a" as col1, "ct" as col2; 
+
+--replace_regex /(strawberry)/raspberry and \1/ /blueberry/blackberry/ /potato/tomato/;
+select "strawberry","blueberry","potato";
+
+--error 1
+--exec echo "--replace_regex a" | $MYSQL_TEST 2>&1
+--error 1
+--exec echo "--replace_regex a;" | $MYSQL_TEST 2>&1
+--error 1
+--exec echo "replace_regex a;" | $MYSQL_TEST 2>&1
+--error 1
+--exec echo "replace_regex a ;" | $MYSQL_TEST 2>&1
+--error 1
+--exec echo "replace_regex a b; echo OK;" | $MYSQL_TEST 2>&1
+--error 1
+--exec echo "--replace_regex /a b c" | $MYSQL_TEST 2>&1
+--error 1
+--exec echo "replace_regex /a /b c ;" | $MYSQL_TEST 2>&1 

--- 1.174/client/mysqltest.c	2006-01-13 09:44:28 -07:00
+++ 1.175/client/mysqltest.c	2006-01-30 20:58:13 -07:00
@@ -187,6 +187,35 @@
 static test_file* file_stack_end;
 uint start_lineno; /* Start line of query */
 
+/* Stores regex substitutions */
+
+struct st_regex
+{
+  char* pattern; /* Pattern to be replaced */
+  char* replace; /* String or expression to replace the pattern with */
+  int icase; /* true if the match is case insensitive */
+};
+
+struct st_replace_regex
+{
+  DYNAMIC_ARRAY regex_arr; /* stores a list of st_regex subsitutions */
+  
+  /* 
+    Temporary storage areas for substitutions. To reduce unnessary copying
+    and memory freeing/allocation, we pre-allocate two buffers, and alternate
+    their use, one for input/one for output, the roles changing on the next
+    st_regex substition. At the end of substitutions  buf points to the 
+    one containing the final result.
+   */
+  char* buf;
+  char* even_buf;
+  uint even_buf_len;
+  char* odd_buf;
+  uint odd_buf_len;
+};
+
+struct st_replace_regex *glob_replace_regex= 0;
+
 static char TMPDIR[FN_REFLEN];
 static char delimiter[MAX_DELIMITER]= DEFAULT_DELIMITER;
 static uint delimiter_length= 1;
@@ -217,14 +246,9 @@
 static void timer_output(void);
 static ulonglong timer_now(void);
 
-/* Precompiled re's */
-static my_regex_t ps_re;     /* the query can be run using PS protocol */
-static my_regex_t sp_re;     /* the query can be run as a SP */
-static my_regex_t view_re;   /* the query can be run as a view*/
-
-static void init_re(void);
-static int match_re(my_regex_t *, char *);
-static void free_re(void);
+
+static int reg_replace(char** buf_p, int* buf_len_p, char *pattern, char *replace, 
+ char *string, int icase);
 
 static const char *embedded_server_groups[]=
 {
@@ -336,6 +360,7 @@
 Q_DISABLE_RECONNECT, Q_ENABLE_RECONNECT,
 Q_IF,
 Q_DISABLE_PARSING, Q_ENABLE_PARSING,
+Q_REPLACE_REGEX,
 
 Q_UNKNOWN,			       /* Unknown command.   */
 Q_COMMENT,			       /* Comments, ignored. */
@@ -429,6 +454,7 @@
   "if",
   "disable_parsing",
   "enable_parsing",
+  "replace_regex",
   0
 };
 
@@ -469,6 +495,7 @@
 uint replace_strings(struct st_replace *rep, my_string *start,
 		     uint *max_length, const char *from);
 void free_replace();
+static void free_replace_regex();
 static int insert_pointer_name(reg1 POINTER_ARRAY *pa,my_string name);
 void free_pointer_array(POINTER_ARRAY *pa);
 static int initialize_replace_buffer(void);
@@ -1927,6 +1954,204 @@
   DBUG_RETURN(start);
 }
 
+/*
+  Finds the next (non-escaped) '/' in the expression.
+  (If the character '/' is needed, it can be escaped using '\'.)
+*/
+
+#define PARSE_REGEX_ARG \
+  while (p < expr_end) \
+  {\
+    char c= *p;\
+    if (c == '/')\
+    {\
+      if (last_c == '\\')\
+      {\
+        buf_p[-1]= '/';\
+      }\
+      else\
+      {\
+        *buf_p++ = 0;\
+        break;\
+      }  \
+    }  \
+    else\
+      *buf_p++ = c;\
+       \
+    last_c= c;\
+    p++;\
+  }  \
+
+/*
+  Initializes the regular substitution expression to be used in the 
+  result output of test.
+
+  Returns: st_replace_regex struct with pairs of substitutions
+*/
+  
+static struct st_replace_regex* init_replace_regex(char* expr)
+{
+  struct st_replace_regex* res;
+  char* buf,*expr_end;
+  char* p;
+  char* buf_p;
+  uint expr_len= strlen(expr);
+  char last_c = 0;
+  struct st_regex reg;
+ 
+  /* my_malloc() will die on fail with MY_FAE */    
+  res=(struct st_replace_regex*)my_malloc(
+              sizeof(*res)+expr_len ,MYF(MY_FAE+MY_WME));
+  my_init_dynamic_array(&res->regex_arr,sizeof(struct st_regex),128,128);
+    
+  buf= (char*)res + sizeof(*res);
+  expr_end= expr + expr_len;
+  p= expr;
+  buf_p= buf;  
+   
+  /* for each regexp substitution statement */
+  while (p < expr_end)
+  {
+    bzero(&reg,sizeof(reg));
+    /* find the start of the statement */
+    while (p < expr_end)
+    {
+      if (*p == '/')
+        break;
+      p++;  
+    }  
+    
+    if (p == expr_end || ++p == expr_end)
+    {
+      if (res->regex_arr.elements)
+        break;
+      else  
+        goto err;
+    }
+    /* we found the start */  
+    reg.pattern= buf_p;
+    
+    /* Find first argument -- pattern string to be removed */
+    PARSE_REGEX_ARG
+    
+    if (p == expr_end || ++p == expr_end)
+      goto err;
+  
+    /* buf_p now points to the replacement pattern terminated with \0 */  
+    reg.replace= buf_p;  
+    
+    /* Find second argument -- replace string to replace pattern */
+    PARSE_REGEX_ARG
+    
+    if (p == expr_end)
+      goto err;
+    
+    /* skip the ending '/' in the statement */    
+    p++;
+    
+    /* Check if we should do matching case insensitive */
+    if (p < expr_end && *p == 'i')
+      reg.icase= 1;    
+    
+    /* done parsing the statement, now place it in regex_arr */
+    if (insert_dynamic(&res->regex_arr,(gptr) &reg))
+      die("Out of memory");
+  }  
+  res->odd_buf_len= res->even_buf_len= 8192;
+  res->even_buf= (char*)my_malloc(res->even_buf_len,MYF(MY_WME+MY_FAE));  
+  res->odd_buf= (char*)my_malloc(res->odd_buf_len,MYF(MY_WME+MY_FAE));  
+  res->buf= res->even_buf;
+        
+  return res;  
+  
+err:
+  my_free((gptr)res,0);
+  die("Error parsing replace_regex \"%s\"", expr);
+  return 0;    
+}
+
+/*  
+   Execute all substitutions on val.
+
+   Returns: true if substituition was made, false otherwise
+   Side-effect: Sets r->buf to be the buffer with all substitutions done.
+   
+   IN: 
+     struct st_replace_regex* r
+     char* val
+   Out: 
+     struct st_replace_regex* r
+     r->buf points at the resulting buffer
+     r->even_buf and r->odd_buf might have been reallocated  
+     r->even_buf_len and r->odd_buf_len might have been changed
+     
+  TODO:  at some point figure out if there is a way to do everything
+         in one pass 
+*/
+
+static int multi_reg_replace(struct st_replace_regex* r,char* val)
+{
+  uint i;
+  char* in_buf, *out_buf;
+  int* buf_len_p;
+  
+  in_buf= val;
+  out_buf= r->even_buf;
+  buf_len_p= &r->even_buf_len;
+  r->buf= 0;
+  
+  /* For each substitution, do the replace */
+  for (i= 0; i < r->regex_arr.elements; i++)
+  {
+    struct st_regex re;
+    char* save_out_buf= out_buf;
+    
+    get_dynamic(&r->regex_arr,(gptr)&re,i);
+    
+    if (!reg_replace(&out_buf, buf_len_p, re.pattern, re.replace,
+       in_buf, re.icase))
+    {
+      /* if the buffer has been reallocated, make adjustements */
+      if (save_out_buf != out_buf)
+      {
+        if (save_out_buf == r->even_buf)
+          r->even_buf= out_buf;
+        else
+          r->odd_buf= out_buf;  
+      }
+        
+      r->buf= out_buf;
+      if (in_buf == val)
+        in_buf= r->odd_buf;
+        
+      swap_variables(char*,in_buf,out_buf);
+      
+      buf_len_p= (out_buf == r->even_buf) ? &r->even_buf_len :
+          &r->odd_buf_len;
+    }   
+  }
+  
+  return (r->buf == 0);
+}
+
+/*
+  Parse the regular expression to be used in all result files
+  from now on.
+  
+  The syntax is --replace_regex /from/to/i /from/to/i ...
+  i means case-insensitive match. If omitted, the match is 
+  case-sensitive
+  
+*/
+static void get_replace_regex(struct st_query *q)
+{
+  char *expr= q->first_argument;
+  free_replace_regex();
+  if (!(glob_replace_regex=init_replace_regex(expr)))
+    die("Could not init replace_regex");
+  q->last_argument= q->end;  
+}
+
 
 /*
   Get arguments for replace. The syntax is:
@@ -1979,6 +2204,18 @@
   DBUG_VOID_RETURN;
 }
 
+static void free_replace_regex()
+{
+  if (glob_replace_regex)
+  {
+    my_free(glob_replace_regex->even_buf,MYF(MY_ALLOW_ZERO_PTR));
+    my_free(glob_replace_regex->odd_buf,MYF(MY_ALLOW_ZERO_PTR));
+    my_free((char*) glob_replace_regex,MYF(0));
+    glob_replace_regex=0;
+  }
+}
+
+
 void free_replace()
 {
   DBUG_ENTER("free_replace");
@@ -2277,6 +2514,7 @@
 
 err:
   free_replace();
+  free_replace_regex();
   return error;
 }
 
@@ -3126,6 +3364,214 @@
   str_to_file(fn_format(reject_file, record_file,"",".reject",2), buf, size);
 }
 
+static void check_regerr(my_regex_t* r, int err)
+{
+  char err_buf[1024];
+
+  if (err)
+  {
+    my_regerror(err,r,err_buf,sizeof(err_buf));
+    die("Regex error: %s\n", err_buf);
+  }  
+}
+
+/* 
+  auxiluary macro used by reg_replace
+  makes sure the result buffer has sufficient length
+*/  
+#define SECURE_REG_BUF   if (buf_len < need_buf_len)\
+  {\
+    int off= res_p - buf;\
+    buf= (char*)my_realloc(buf,need_buf_len,MYF(MY_WME+MY_FAE));\
+    res_p= buf + off;\
+    buf_len= need_buf_len;\
+  }\
+
+/*
+  Performs a regex substitution
+  
+  IN:
+  
+    buf_p - result buffer pointer. Will change if reallocated
+    buf_len_p - result buffer length. Will change if the buffer is reallocated
+    pattern - regexp pattern to match
+    replace - replacement expression
+    string - the string to perform substituions in
+    icase - flag, if set to 1 the match is case insensitive
+ */  
+static int reg_replace(char** buf_p, int* buf_len_p, char *pattern, 
+  char *replace, char *string, int icase)
+{
+  my_regex_t r;
+  my_regmatch_t* subs;
+  char* buf_end, *replace_end;
+  char* buf= *buf_p;
+  int len;
+  int buf_len,need_buf_len;
+  int cflags= REG_EXTENDED;
+  int err_code;
+  char* res_p,*str_p,*str_end;
+  
+  buf_len= *buf_len_p;  
+  len= strlen(string);
+  str_end= string + len;
+  
+  /* start with a buffer of a reasonable size that hopefully will not 
+     need to be reallocated
+   */
+  need_buf_len= len * 2 + 1;
+  res_p= buf;
+
+  SECURE_REG_BUF    
+  
+  buf_end = buf + buf_len;
+  
+  if (icase)
+    cflags |= REG_ICASE;
+    
+  if ((err_code=my_regcomp(&r,pattern,cflags,&my_charset_latin1)))
+  {
+    check_regerr(&r,err_code);
+    return 1;
+  }  
+  
+  subs= (my_regmatch_t*)my_malloc(sizeof(my_regmatch_t) * (r.re_nsub+1),
+     MYF(MY_WME+MY_FAE));
+  
+  *res_p= 0;
+  str_p= string;
+  replace_end= replace + strlen(replace);
+  
+  /* for each pattern match instance perform a replacement */
+  while (!err_code)
+  {
+    /* find the match */
+    err_code= my_regexec(&r,str_p, r.re_nsub+1, subs, 
+      (str_p == string) ? REG_NOTBOL : 0);
+    
+    /* if regular expression error (eg. bad syntax, or out of memory) */  
+    if (err_code && err_code != REG_NOMATCH)
+    {
+      check_regerr(&r,err_code);
+      my_regfree(&r);
+      return 1;
+    }
+    
+    /* if match found */
+    if (!err_code)
+    {
+      char* expr_p= replace;
+      int c;
+      
+      /* 
+        we need at least what we have so far in the buffer + the part
+        before this match
+      */
+      need_buf_len= (res_p - buf) + subs[0].rm_so;
+      
+      /* on this pass, calculate the memory for the result buffer */
+      while (expr_p < replace_end)
+      {
+        int back_ref_num= -1;
+        c= *expr_p;
+               
+        if (c == '\\' && expr_p + 1 < replace_end)
+        {
+          back_ref_num= expr_p[1] - '0';
+        }
+        
+        /* found a valid back_ref (eg. \1)*/
+        if (back_ref_num >= 0 && back_ref_num <= (int)r.re_nsub)
+        {
+          int start_off,end_off;
+          if ((start_off=subs[back_ref_num].rm_so) > -1 && 
+                   (end_off=subs[back_ref_num].rm_eo) > -1)
+          {
+             need_buf_len += (end_off - start_off);    
+          }  
+          expr_p += 2;
+        }
+        else
+        {
+          expr_p++;
+          need_buf_len++;
+        }
+      }
+      need_buf_len++;
+      /* 
+        now that we know the size of the buffer, 
+        make sure it is big enough
+      */  
+      SECURE_REG_BUF
+      
+      /* copy the pre-match part */
+      if (subs[0].rm_so)
+      {
+        memcpy(res_p,str_p,subs[0].rm_so);
+        res_p += subs[0].rm_so;
+      }
+        
+      expr_p= replace;
+      
+      /* copy the match and expand back_refs */
+      while (expr_p < replace_end)
+      {
+        int back_ref_num= -1;
+        c= *expr_p;
+        
+        if (c == '\\' && expr_p + 1 < replace_end)
+        {
+          back_ref_num= expr_p[1] - '0';
+        }
+        
+        if (back_ref_num >= 0 && back_ref_num <= (int)r.re_nsub)
+        {
+          int start_off,end_off;
+          if ((start_off=subs[back_ref_num].rm_so) > -1 && 
+                   (end_off=subs[back_ref_num].rm_eo) > -1)
+          {
+             int block_len= end_off - start_off;
+             memcpy(res_p,str_p + start_off, block_len);
+             res_p += block_len; 
+          }  
+          expr_p += 2;
+        }
+        else
+        {
+          *res_p++ = *expr_p++;
+        }
+      } 
+      
+      /* handle the post-match part */
+      if (subs[0].rm_so == subs[0].rm_eo)
+      {
+        if (str_p + subs[0].rm_so >= str_end)
+          break;
+        str_p += subs[0].rm_eo ;
+        *res_p++ = *str_p++; 
+      }    
+      else
+      {
+        str_p += subs[0].rm_eo;
+      }  
+    }
+    else /* no match this time, just copy the string as is */
+    {
+      int left_in_str= str_end-str_p;
+      need_buf_len= (res_p-buf) + left_in_str;
+      SECURE_REG_BUF
+      memcpy(res_p,str_p,left_in_str);
+      res_p += left_in_str;
+      str_p= str_end;
+    }
+  }      
+  my_regfree(&r);   
+  *res_p= 0;
+  *buf_p= buf;
+  *buf_len_p= buf_len; 
+  return 0;
+}
+
 
 /* Append the string to ds, with optional replace */
 
@@ -3139,6 +3585,16 @@
       die("Out of memory in replace");
     val=out_buff;
   }
+  
+  if (glob_replace_regex)
+  {
+    if (!multi_reg_replace(glob_replace_regex,(char*)val))        
+    {   
+      val= glob_replace_regex->buf;   
+      len= strlen(val);
+    }  
+  }
+  
   dynstr_append_mem(ds, val, len);
 }
 
@@ -3577,6 +4033,7 @@
 
 end:
   free_replace();
+  free_replace_regex();
 
   /*
     We save the return code (mysql_errno(mysql)) from the last call sent
@@ -3887,18 +4344,7 @@
 
 end:
   free_replace();
-
-  if (!disable_warnings)
-  {
-    dynstr_free(&ds_prepare_warnings);
-    dynstr_free(&ds_execute_warnings);
-  }
-
-  /*
-    We save the return code (mysql_stmt_errno(stmt)) from the last call sent
-    to the server into the mysqltest builtin variable $mysql_errno. This
-    variable then can be used from the test case itself.
-  */
+  free_replace_regex();
   var_set_errno(mysql_stmt_errno(stmt));
 #ifndef BUG15518_FIXED
   mysql_stmt_close(stmt);
@@ -4623,6 +5069,10 @@
       case Q_REPLACE:
 	get_replace(q);
 	break;
+      case Q_REPLACE_REGEX:
+        get_replace_regex(q);
+        break;
+
       case Q_REPLACE_COLUMN:
 	get_replace_column(q);
 	break;

--- 1.223/BitKeeper/etc/ignore	2006-01-13 09:04:07 -07:00
+++ 1.224/BitKeeper/etc/ignore	2006-01-30 20:58:13 -07:00
@@ -1611,3 +1611,4 @@
 vio/viotest.cpp
 zlib/*.ds?
 zlib/*.vcproj
+BitKeeper/etc/RESYNC_TREE
Thread
bk commit into 5.1 tree (sasha:1.2099)Sasha Pachev31 Jan