Commit 4b44b849 authored by unknown's avatar unknown

Fixed problem with range optimization over overlapping ranges (#2448)


mysql-test/r/ctype_tis620.result:
  Cleanup test
mysql-test/r/range.result:
  Test problem with range optimization over overlapping ranges (#2448)
mysql-test/t/ctype_tis620.test:
  Cleanup test
mysql-test/t/range.test:
  Test problem with range optimization over overlapping ranges (#2448)
sql/mysqld.cc:
  Remove debug statement
strings/ctype-tis620.c:
  est problem with range optimization over overlapping ranges (#2448)
parent 7ba7ce6e
DROP TABLE IF EXISTS t620; drop table if exists t1;
CREATE TABLE t620 ( CREATE TABLE t1 (
recid int(11) NOT NULL auto_increment, recid int(11) NOT NULL auto_increment,
dyninfo text, dyninfo text,
PRIMARY KEY (recid) PRIMARY KEY (recid)
) TYPE=MyISAM; ) ENGINE=MyISAM;
INSERT INTO t620 VALUES (1,'color=\"STB,NPG\"\r\nengine=\"J30A13\"\r\nframe=\"MRHCG1640YP4\"\r\ngrade=\"V6\"\r\nmodel=\"ACCORD\"\r\nmodelcode=\"CG164YEN\"\r\ntype=\"VT6\"\r\n'); INSERT INTO t1 VALUES (1,'color=\"STB,NPG\"\r\nengine=\"J30A13\"\r\nframe=\"MRHCG1640YP4\"\r\ngrade=\"V6\"\r\nmodel=\"ACCORD\"\r\nmodelcode=\"CG164YEN\"\r\ntype=\"VT6\"\r\n');
INSERT INTO t620 VALUES (2,'color=\"HTM,NPG,DEG,RGS\"\r\nengine=\"F23A5YP1\"\r\nframe=\"MRHCF8640YP3\"\r\ngrade=\"EXi AT\"\r\nmodel=\"ACCORD\"\r\nmodelcode=\"CF864YE\"\r\ntype=\"EXA\"\r\n'); INSERT INTO t1 VALUES (2,'color=\"HTM,NPG,DEG,RGS\"\r\nengine=\"F23A5YP1\"\r\nframe=\"MRHCF8640YP3\"\r\ngrade=\"EXi AT\"\r\nmodel=\"ACCORD\"\r\nmodelcode=\"CF864YE\"\r\ntype=\"EXA\"\r\n');
SELECT DISTINCT SELECT DISTINCT
(IF( LOCATE( 'year=\"', dyninfo ) = 1, (IF( LOCATE( 'year=\"', dyninfo ) = 1,
SUBSTRING( dyninfo, 6+1, LOCATE('\"\r',dyninfo) - 6 -1), SUBSTRING( dyninfo, 6+1, LOCATE('\"\r',dyninfo) - 6 -1),
IF( LOCATE( '\nyear=\"', dyninfo ), IF( LOCATE( '\nyear=\"', dyninfo ),
SUBSTRING( dyninfo, LOCATE( '\nyear=\"', dyninfo ) + 7, SUBSTRING( dyninfo, LOCATE( '\nyear=\"', dyninfo ) + 7,
LOCATE( '\"\r', SUBSTRING( dyninfo, LOCATE( '\nyear=\"', dyninfo ) +7 )) - 1), '' ))) AS year LOCATE( '\"\r', SUBSTRING( dyninfo, LOCATE( '\nyear=\"', dyninfo ) +7 )) - 1), '' ))) AS year
FROM t620 FROM t1
HAVING year != '' ORDER BY year; HAVING year != '' ORDER BY year;
year year
DROP TABLE t1;
...@@ -300,3 +300,16 @@ SELECT COUNT(*) FROM t1 WHERE (c=0 and b=1) or (c=0 and a=1); ...@@ -300,3 +300,16 @@ SELECT COUNT(*) FROM t1 WHERE (c=0 and b=1) or (c=0 and a=1);
COUNT(*) COUNT(*)
6 6
DROP TABLE t1; DROP TABLE t1;
CREATE TABLE t1 ( a int not null, b int not null, INDEX ab(a,b) );
INSERT INTO t1 VALUES (47,1), (70,1), (15,1), (15, 4);
SELECT * FROM t1
WHERE
(
( b =1 AND a BETWEEN 14 AND 21 ) OR
( b =2 AND a BETWEEN 16 AND 18 ) OR
( b =3 AND a BETWEEN 15 AND 19 ) OR
(a BETWEEN 19 AND 47)
);
a b
15 1
47 1
DROP TABLE IF EXISTS t620; --disable_warnings
CREATE TABLE t620 ( drop table if exists t1;
--enable_warnings
CREATE TABLE t1 (
recid int(11) NOT NULL auto_increment, recid int(11) NOT NULL auto_increment,
dyninfo text, dyninfo text,
PRIMARY KEY (recid) PRIMARY KEY (recid)
) TYPE=MyISAM; ) ENGINE=MyISAM;
INSERT INTO t620 VALUES (1,'color=\"STB,NPG\"\r\nengine=\"J30A13\"\r\nframe=\"MRHCG1640YP4\"\r\ngrade=\"V6\"\r\nmodel=\"ACCORD\"\r\nmodelcode=\"CG164YEN\"\r\ntype=\"VT6\"\r\n'); INSERT INTO t1 VALUES (1,'color=\"STB,NPG\"\r\nengine=\"J30A13\"\r\nframe=\"MRHCG1640YP4\"\r\ngrade=\"V6\"\r\nmodel=\"ACCORD\"\r\nmodelcode=\"CG164YEN\"\r\ntype=\"VT6\"\r\n');
INSERT INTO t620 VALUES (2,'color=\"HTM,NPG,DEG,RGS\"\r\nengine=\"F23A5YP1\"\r\nframe=\"MRHCF8640YP3\"\r\ngrade=\"EXi AT\"\r\nmodel=\"ACCORD\"\r\nmodelcode=\"CF864YE\"\r\ntype=\"EXA\"\r\n'); INSERT INTO t1 VALUES (2,'color=\"HTM,NPG,DEG,RGS\"\r\nengine=\"F23A5YP1\"\r\nframe=\"MRHCF8640YP3\"\r\ngrade=\"EXi AT\"\r\nmodel=\"ACCORD\"\r\nmodelcode=\"CF864YE\"\r\ntype=\"EXA\"\r\n');
SELECT DISTINCT SELECT DISTINCT
(IF( LOCATE( 'year=\"', dyninfo ) = 1, (IF( LOCATE( 'year=\"', dyninfo ) = 1,
...@@ -14,5 +17,7 @@ SELECT DISTINCT ...@@ -14,5 +17,7 @@ SELECT DISTINCT
IF( LOCATE( '\nyear=\"', dyninfo ), IF( LOCATE( '\nyear=\"', dyninfo ),
SUBSTRING( dyninfo, LOCATE( '\nyear=\"', dyninfo ) + 7, SUBSTRING( dyninfo, LOCATE( '\nyear=\"', dyninfo ) + 7,
LOCATE( '\"\r', SUBSTRING( dyninfo, LOCATE( '\nyear=\"', dyninfo ) +7 )) - 1), '' ))) AS year LOCATE( '\"\r', SUBSTRING( dyninfo, LOCATE( '\nyear=\"', dyninfo ) +7 )) - 1), '' ))) AS year
FROM t620 FROM t1
HAVING year != '' ORDER BY year; HAVING year != '' ORDER BY year;
DROP TABLE t1;
...@@ -238,7 +238,7 @@ SELECT * FROM t1 WHERE a IN(1,2) AND b=5; ...@@ -238,7 +238,7 @@ SELECT * FROM t1 WHERE a IN(1,2) AND b=5;
DROP TABLE t1; DROP TABLE t1;
# #
# Test error with # Test problem with range optimzer and sub ranges
# #
CREATE TABLE t1 (a int, b int, c int, INDEX (c,a,b)); CREATE TABLE t1 (a int, b int, c int, INDEX (c,a,b));
...@@ -249,3 +249,17 @@ SELECT COUNT(*) FROM t1 WHERE (c=0 and a=1) or (c=0 and b=1); ...@@ -249,3 +249,17 @@ SELECT COUNT(*) FROM t1 WHERE (c=0 and a=1) or (c=0 and b=1);
SELECT COUNT(*) FROM t1 WHERE (c=0 and b=1) or (c=0 and a=1); SELECT COUNT(*) FROM t1 WHERE (c=0 and b=1) or (c=0 and a=1);
DROP TABLE t1; DROP TABLE t1;
#
# Test problem with range optimization over overlapping ranges (#2448)
#
CREATE TABLE t1 ( a int not null, b int not null, INDEX ab(a,b) );
INSERT INTO t1 VALUES (47,1), (70,1), (15,1), (15, 4);
SELECT * FROM t1
WHERE
(
( b =1 AND a BETWEEN 14 AND 21 ) OR
( b =2 AND a BETWEEN 16 AND 18 ) OR
( b =3 AND a BETWEEN 15 AND 19 ) OR
(a BETWEEN 19 AND 47)
);
...@@ -4747,7 +4747,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), ...@@ -4747,7 +4747,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
berkeley_env_flags|= DB_TXN_NOSYNC; berkeley_env_flags|= DB_TXN_NOSYNC;
else else
berkeley_env_flags&= ~DB_TXN_NOSYNC; berkeley_env_flags&= ~DB_TXN_NOSYNC;
printf("berkeley_env_flags: %d, arg '%s'\n", berkeley_env_flags, argument);
break; break;
case OPT_BDB_NO_RECOVER: case OPT_BDB_NO_RECOVER:
berkeley_init_flags&= ~(DB_RECOVER); berkeley_init_flags&= ~(DB_RECOVER);
......
...@@ -1710,6 +1710,8 @@ key_or(SEL_ARG *key1,SEL_ARG *key2) ...@@ -1710,6 +1710,8 @@ key_or(SEL_ARG *key1,SEL_ARG *key2)
return 0; // OOM return 0; // OOM
tmp->copy_max_to_min(&key); tmp->copy_max_to_min(&key);
tmp->increment_use_count(key1->use_count+1); tmp->increment_use_count(key1->use_count+1);
/* Increment key count as it may be used for next loop */
key.increment_use_count(1);
new_arg->next_key_part=key_or(tmp->next_key_part,key.next_key_part); new_arg->next_key_part=key_or(tmp->next_key_part,key.next_key_part);
key1=key1->insert(new_arg); key1=key1->insert(new_arg);
break; break;
...@@ -2708,15 +2710,18 @@ int QUICK_SELECT_DESC::get_next() ...@@ -2708,15 +2710,18 @@ int QUICK_SELECT_DESC::get_next()
} }
else else
{ {
/* Heikki changed Sept 11, 2002: since InnoDB does not store the cursor /*
Heikki changed Sept 11, 2002: since InnoDB does not store the cursor
position if READ_KEY_EXACT is used to a primary key with all position if READ_KEY_EXACT is used to a primary key with all
key columns specified, we must use below HA_READ_KEY_OR_NEXT, key columns specified, we must use below HA_READ_KEY_OR_NEXT,
so that InnoDB stores the cursor position and is able to move so that InnoDB stores the cursor position and is able to move
the cursor one step backward after the search. */ the cursor one step backward after the search. */
DBUG_ASSERT(range->flag & NEAR_MAX || range_reads_after_key(range)); DBUG_ASSERT(range->flag & NEAR_MAX || range_reads_after_key(range));
/* Note: even if max_key is only a prefix, HA_READ_AFTER_KEY will /*
* do the right thing - go past all keys which match the prefix */ Note: even if max_key is only a prefix, HA_READ_AFTER_KEY will
do the right thing - go past all keys which match the prefix
*/
result=file->index_read(record, (byte*) range->max_key, result=file->index_read(record, (byte*) range->max_key,
range->max_length, range->max_length,
((range->flag & NEAR_MAX) ? ((range->flag & NEAR_MAX) ?
......
...@@ -449,153 +449,71 @@ uchar NEAR sort_order_tis620[]= ...@@ -449,153 +449,71 @@ uchar NEAR sort_order_tis620[]=
(uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377', (uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377',
}; };
/* Convert thai string to "Standard C String Function" sortable string
/*
Convert thai string to "Standard C String Function" sortable string
Arg: const source string and length of converted string Arg: const source string and length of converted string
Ret: Sortable string Ret: Sortable string
*/ */
static void _thai2sortable(uchar *tstr) static void _thai2sortable(uchar *tstr)
{ {
uchar *p ; uchar *p;
int len,tlen ; int len, tlen;
uchar c,l2bias ; uchar l2bias;
tlen= len = strlen (tstr) ; tlen= len= strlen (tstr);
l2bias = 256 - 8 ; l2bias= 256 - 8;
for (p=tstr; tlen > 0; p++,tlen--) for (p= tstr; tlen > 0; p++, tlen--)
{ {
c = *p ; uchar c= *p;
if (isthai(c)) if (isthai(c))
{ {
int *t_ctype0 = t_ctype[c] ; int *t_ctype0= t_ctype[c];
if (isconsnt(c)) if (isconsnt(c))
l2bias -= 8 ; l2bias -= 8;
if (isldvowel(c) && isconsnt(p[1])) if (isldvowel(c) && isconsnt(p[1]))
{ {
/* /* simply swap between leading-vowel and consonant */
simply swap between leading-vowel and consonant *p= p[1];
*/ p[1]= c;
*p = p[1]; tlen--;
p[1]= c ;
tlen-- ;
p++; p++;
continue ; continue;
} }
// if found level 2 char (L2_GARAN,L2_TONE*,L2_TYKHU) move to last /* if found level 2 char (L2_GARAN,L2_TONE*,L2_TYKHU) move to last */
if (t_ctype0[1]>= L2_GARAN) if (t_ctype0[1] >= L2_GARAN)
{ {
// l2bias use to control position weight of l2char
// example (*=l2char) XX*X must come before X*XX
strcpy (p,p+1) ;
tstr[len-1] = l2bias + t_ctype0[1]- L2_GARAN +1 ;
p-- ;
continue ;
}
}
else
{
l2bias -= 8 ;
*p = to_lower_tis620[c];
}
/* /*
this routine skip non-printable char l2bias use to control position weight of l2char
but not necessary, leave it like raw ascii 8 bits example (*=l2char) XX*X must come before X*XX
*/
/*
t_ctype0 = t_ctype[p[0]];
if ((t_ctype0[0]|t_ctype0[1]|t_ctype0[2])==IGNORE)
{
strcpy(p,p+1);
p-- ;
}
*/ */
strmov(p,p+1);
tstr[len-1]= l2bias + t_ctype0[1]- L2_GARAN +1;
p--;
continue;
} }
}
/*
NOTE: isn't it faster to alloc buffer in calling function?
*/
/*
Sathit's NOTE: we don't use this function anymore
static uchar* thai2sortable(const uchar * tstr,int len)
{
*/
/* We use only 3 levels (neglect capitalization). */
/*
const uchar* p= tstr;
uchar *outBuf;
uchar *pRight1, *pRight2, *pRight3;
uchar *pLeft1, *pLeft2, *pLeft3;
uint bufSize;
uint RightSize;
len= (int) strnlen((char*) tstr,len);
bufSize= (uint) buffsize((char*) tstr);
RightSize= sizeof(uchar) * (len + 1);
if (!(outBuf= pLeft1= pRight1=
(uchar *)malloc(sizeof(uchar) * bufSize + RightSize*2)))
return (uchar*) tstr;
pLeft2= pRight2= pRight1 + sizeof(uchar) * bufSize;
pLeft3= pRight3= pRight2 + RightSize;
while (--len > 0)
{
int *t_ctype0= t_ctype[p[0]];
if (isldvowel(*p) && isconsnt(p[1]))
{
int *t_ctype1= t_ctype[p[1]];
*pRight1++= t_ctype1[0];
*pRight2++= t_ctype1[1];
*pRight3++= t_ctype1[2];
*pRight1++= t_ctype0[0];
*pRight2++= t_ctype0[1];
*pRight3++= t_ctype0[2];
p+= 2;
len--;
} }
else else
{ {
*pRight1= t_ctype0[0]; l2bias-= 8;
if(*pRight1 != IGNORE) *p= to_lower_tis620[c];
pRight1++;
*pRight2= t_ctype0[1];
if (*pRight2 != IGNORE)
pRight2++;
*pRight3= t_ctype0[2];
if(*pRight3 != IGNORE)
pRight3++;
p++;
} }
} }
if (!len)
{
int *t_ctype0= t_ctype[p[0]];
*pRight1= t_ctype0[0];
if (*pRight1 != IGNORE)
pRight1++;
*pRight2= t_ctype0[1];
if (*pRight2 != IGNORE)
pRight2++;
*pRight3= t_ctype0[2];
if (*pRight3 != IGNORE)
pRight3++;
}
*pRight1++= L2_BLANK;
*pRight2++= L3_BLANK;
*pRight3++= '\0';
memcpy(pRight1, pLeft2, pRight2 - pLeft2);
pRight1+= pRight2 - pLeft2;
memcpy(pRight1, pLeft3, pRight3 - pLeft3);
return outBuf;
} }
*/
/* strncoll() replacement, compare 2 string, both are conveted to sortable string
/*
strncoll() replacement, compare 2 string, both are converted to sortable
string
Arg: 2 Strings and it compare length Arg: 2 Strings and it compare length
Ret: strcmp result Ret: strcmp result
*/ */
int my_strnncoll_tis620(const uchar * s1, int len1, const uchar * s2, int len2) int my_strnncoll_tis620(const uchar * s1, int len1, const uchar * s2, int len2)
{ {
uchar buf[80] ; uchar buf[80] ;
...@@ -604,63 +522,80 @@ int my_strnncoll_tis620(const uchar * s1, int len1, const uchar * s2, int len2) ...@@ -604,63 +522,80 @@ int my_strnncoll_tis620(const uchar * s1, int len1, const uchar * s2, int len2)
len1= (int) strnlen((char*) s1,len1); len1= (int) strnlen((char*) s1,len1);
len2= (int) strnlen((char*) s2,len2); len2= (int) strnlen((char*) s2,len2);
tc1= buf;
if ((len1 + len2 +2) > (int) sizeof(buf)) if ((len1 + len2 +2) > (int) sizeof(buf))
tc1 = (uchar *)malloc(len1+len2) ; tc1= (uchar*) malloc(len1+len2);
else tc2= tc1 + len1+1;
tc1 = buf ; memcpy((char*) tc1, (char*) s1, len1);
tc2 = tc1 + len1+1 ; tc1[len1]= 0; /* if length(s1)> len1, need to put 'end of string' */
strncpy((char *)tc1,(char *)s1,len1) ; memcpy((char *)tc2, (char *)s2, len2);
tc1[len1] = 0; // if s1's length > len1, need to put 'end of string' tc2[len2]= 0; /* put end of string */
strncpy((char *)tc2,(char *)s2,len2) ;
tc2[len2] = 0; // put end of string
_thai2sortable(tc1); _thai2sortable(tc1);
_thai2sortable(tc2); _thai2sortable(tc2);
i= strcmp((char*)tc1, (char*)tc2); i= strcmp((char*)tc1, (char*)tc2);
if (tc1 != buf ) if (tc1 != buf)
free(tc1); free(tc1);
return i; return i;
} }
/* strnxfrm replacment, convert Thai string to sortable string
/*
strnxfrm replacment, convert Thai string to sortable string
Arg: Destination buffer, source string, dest length and source length Arg: Destination buffer, source string, dest length and source length
Ret: Conveted string size Ret: Conveted string size
*/ */
int my_strnxfrm_tis620(uchar * dest, const uchar * src, int len, int srclen) int my_strnxfrm_tis620(uchar * dest, const uchar * src, int len, int srclen)
{ {
if (len > srclen) if (len > srclen)
len = srclen ; len= srclen ;
strncpy (dest,src,len) ; strnmov(dest, src, len) ;
dest[len] = 0; // if src's length > len, need to put 'end of string' dest[len]= 0; /* if length(src) > len, need to put 'end of string' */
_thai2sortable(dest); _thai2sortable(dest);
return strlen(dest); return strlen(dest);
} }
/* strcoll replacment, compare 2 strings
/*
strcoll replacment, compare 2 strings
Arg: 2 strings Arg: 2 strings
Ret: strcmp result Ret: strcmp result
*/ */
int my_strcoll_tis620(const uchar * s1, const uchar * s2) int my_strcoll_tis620(const uchar * s1, const uchar * s2)
{ {
return my_strnncoll_tis620(s1, strlen((char *)s1),s2,strlen((char *)s2)); return my_strnncoll_tis620(s1, strlen((char *)s1),s2,strlen((char *)s2));
} }
/* strxfrm replacment, convert Thai string to sortable string
/*
strxfrm replacment, convert Thai string to sortable string
Arg: Destination buffer, String and dest buffer size Arg: Destination buffer, String and dest buffer size
Ret: Converting string size Ret: Converting string size
*/ */
int my_strxfrm_tis620(uchar * dest, const uchar * src, int len) int my_strxfrm_tis620(uchar * dest, const uchar * src, int len)
{ {
return my_strnxfrm_tis620(dest,src,len,strlen((char *)src)); return my_strnxfrm_tis620(dest,src,len,strlen((char *)src));
} }
/* Convert SQL like string to C string
Arg: String, its length, escape character, resource length, minimal string and maximum string /*
Ret: Alway 0 Convert SQL LIKE string to C string
Arg: String, its length, escape character, resource length,
minimal string and maximum string
Ret: Always 0
*/ */
/* We just copy this function from opt_range.cc. No need to convert to /*
We just copy this function from opt_range.cc. No need to convert to
thai2sortable string. min_str and max_str will be use for comparison and thai2sortable string. min_str and max_str will be use for comparison and
converted there. */ converted there.
*/
#define max_sort_chr ((char) 255) #define max_sort_chr ((char) 255)
#define wild_one '_' #define wild_one '_'
#define wild_many '%' #define wild_many '%'
...@@ -692,7 +627,7 @@ my_bool my_like_range_tis620(const char *ptr, uint ptr_length, pchar escape, ...@@ -692,7 +627,7 @@ my_bool my_like_range_tis620(const char *ptr, uint ptr_length, pchar escape,
*min_length= (uint) (min_str - min_org); *min_length= (uint) (min_str - min_org);
*max_length=res_length; *max_length=res_length;
do { do {
*min_str++ = ' '; /* Because if key compression */ *min_str++ = ' '; /* Because of key compression */
*max_str++ = max_sort_chr; *max_str++ = max_sort_chr;
} while (min_str != min_end); } while (min_str != min_end);
return 0; return 0;
...@@ -702,18 +637,21 @@ my_bool my_like_range_tis620(const char *ptr, uint ptr_length, pchar escape, ...@@ -702,18 +637,21 @@ my_bool my_like_range_tis620(const char *ptr, uint ptr_length, pchar escape,
*min_length= *max_length = (uint) (min_str - min_org); *min_length= *max_length = (uint) (min_str - min_org);
while (min_str != min_end) while (min_str != min_end)
*min_str++ = *max_str++ = ' '; /* Because if key compression */ *min_str++= *max_str++ = ' '; /* Because of key compression */
return 0; return 0;
} }
/* Thai normalization for input sub system
/*
Thai normalization for input sub system
Arg: Buffer, 's length, String, 'length Arg: Buffer, 's length, String, 'length
Ret: Void
*/ */
void ThNormalize(uchar* ptr, uint field_length, const uchar* from, uint length) void ThNormalize(uchar* ptr, uint field_length, const uchar* from, uint length)
{ {
const uchar* fr= from; const uchar *fr= from;
uchar* p= ptr; uchar *p= ptr;
uint i; uint i;
if (length > field_length) if (length > field_length)
...@@ -721,24 +659,21 @@ void ThNormalize(uchar* ptr, uint field_length, const uchar* from, uint length) ...@@ -721,24 +659,21 @@ void ThNormalize(uchar* ptr, uint field_length, const uchar* from, uint length)
for (i=0;i<length;i++,p++,fr++) for (i=0;i<length;i++,p++,fr++)
{ {
*p = *fr ; *p= *fr ;
/* Sathit's NOTE: it's better idea not to do any normalize /* Sathit's NOTE: it's better idea not to do any normalize */
*/
if (istone(*fr) || isdiacrt1(*fr)) if (istone(*fr) || isdiacrt1(*fr))
{ {
if (i > 0 && (islwrvowel(fr[-1]) || isuprvowel(fr[-1]))) if (i > 0 && (islwrvowel(fr[-1]) || isuprvowel(fr[-1])))
continue ; continue;
if(islwrvowel(fr[1]) || isuprvowel(fr[1])) if(islwrvowel(fr[1]) || isuprvowel(fr[1]))
{ {
*p= fr[1]; *p= fr[1];
p[1]= *fr; p[1]= *fr;
fr++; fr++;
p++; p++;
i++ ; i++;
} }
} }
} }
} }
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