Merge pull request #462 from halfspawn/bb-10.2-ext
MDEV-14012 - sql_mode=Oracle: substr(): treat position 0 as position 1
This commit is contained in:
commit
081f5aa826
50
mysql-test/suite/compat/oracle/r/func_substr.result
Normal file
50
mysql-test/suite/compat/oracle/r/func_substr.result
Normal file
@ -0,0 +1,50 @@
|
||||
SET sql_mode=ORACLE;
|
||||
SELECT SUBSTR('abc',2,1),SUBSTR('abc',1,1), SUBSTR('abc',0,1) FROM dual;
|
||||
SUBSTR('abc',2,1) SUBSTR('abc',1,1) SUBSTR('abc',0,1)
|
||||
b a a
|
||||
SELECT SUBSTR('abc',2),SUBSTR('abc',1), SUBSTR('abc',0) FROM dual;
|
||||
SUBSTR('abc',2) SUBSTR('abc',1) SUBSTR('abc',0)
|
||||
bc abc abc
|
||||
SELECT SUBSTR(null,2,1),SUBSTR(null,1), SUBSTR(null,0) FROM dual;
|
||||
SUBSTR(null,2,1) SUBSTR(null,1) SUBSTR(null,0)
|
||||
NULL NULL NULL
|
||||
SELECT SUBSTR('abc',-2),SUBSTR('abc',-1), SUBSTR('abc',-0) FROM dual;
|
||||
SUBSTR('abc',-2) SUBSTR('abc',-1) SUBSTR('abc',-0)
|
||||
bc c abc
|
||||
SELECT SUBSTR('abc',-2,1),SUBSTR('abc',-1,1), SUBSTR('abc',-0,1) FROM dual;
|
||||
SUBSTR('abc',-2,1) SUBSTR('abc',-1,1) SUBSTR('abc',-0,1)
|
||||
b c a
|
||||
SELECT SUBSTR('abc',null) FROM dual;
|
||||
SUBSTR('abc',null)
|
||||
NULL
|
||||
SELECT SUBSTR('abc',2,null),SUBSTR('abc',1,null), SUBSTR('abc',0,null) FROM dual;
|
||||
SUBSTR('abc',2,null) SUBSTR('abc',1,null) SUBSTR('abc',0,null)
|
||||
NULL NULL NULL
|
||||
SELECT SUBSTR('abc',2,0),SUBSTR('abc',1,0), SUBSTR('abc',0,0) FROM dual;
|
||||
SUBSTR('abc',2,0) SUBSTR('abc',1,0) SUBSTR('abc',0,0)
|
||||
|
||||
create table t1 (c1 varchar(10),start integer, length integer);
|
||||
INSERT INTO t1 VALUES ('abc', 1, 1);
|
||||
INSERT INTO t1 VALUES ('abc', 0, 1);
|
||||
INSERT INTO t1 VALUES (null, 1, 1);
|
||||
INSERT INTO t1 VALUES (null, 0, 1);
|
||||
select substr(c1,start,length) from t1;
|
||||
substr(c1,start,length)
|
||||
a
|
||||
a
|
||||
NULL
|
||||
NULL
|
||||
drop table t1;
|
||||
EXPLAIN EXTENDED SELECT SUBSTR('abc',2,1) ;
|
||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
|
||||
Warnings:
|
||||
Note 1003 select substr_oracle('abc',2,1) AS "SUBSTR('abc',2,1)"
|
||||
CREATE VIEW v1 AS SELECT SUBSTR('abc',2,1) ;
|
||||
SHOW CREATE VIEW v1;
|
||||
View Create View character_set_client collation_connection
|
||||
v1 CREATE VIEW "v1" AS select substr_oracle('abc',2,1) AS "SUBSTR('abc',2,1)" latin1 latin1_swedish_ci
|
||||
SELECT * FROM v1;
|
||||
SUBSTR('abc',2,1)
|
||||
b
|
||||
DROP VIEW v1;
|
28
mysql-test/suite/compat/oracle/t/func_substr.test
Normal file
28
mysql-test/suite/compat/oracle/t/func_substr.test
Normal file
@ -0,0 +1,28 @@
|
||||
#
|
||||
# MDEV-14012 - sql_mode=Oracle: substr(): treat position 0 as position 1
|
||||
#
|
||||
|
||||
SET sql_mode=ORACLE;
|
||||
SELECT SUBSTR('abc',2,1),SUBSTR('abc',1,1), SUBSTR('abc',0,1) FROM dual;
|
||||
SELECT SUBSTR('abc',2),SUBSTR('abc',1), SUBSTR('abc',0) FROM dual;
|
||||
SELECT SUBSTR(null,2,1),SUBSTR(null,1), SUBSTR(null,0) FROM dual;
|
||||
SELECT SUBSTR('abc',-2),SUBSTR('abc',-1), SUBSTR('abc',-0) FROM dual;
|
||||
SELECT SUBSTR('abc',-2,1),SUBSTR('abc',-1,1), SUBSTR('abc',-0,1) FROM dual;
|
||||
SELECT SUBSTR('abc',null) FROM dual;
|
||||
SELECT SUBSTR('abc',2,null),SUBSTR('abc',1,null), SUBSTR('abc',0,null) FROM dual;
|
||||
SELECT SUBSTR('abc',2,0),SUBSTR('abc',1,0), SUBSTR('abc',0,0) FROM dual;
|
||||
|
||||
create table t1 (c1 varchar(10),start integer, length integer);
|
||||
INSERT INTO t1 VALUES ('abc', 1, 1);
|
||||
INSERT INTO t1 VALUES ('abc', 0, 1);
|
||||
INSERT INTO t1 VALUES (null, 1, 1);
|
||||
INSERT INTO t1 VALUES (null, 0, 1);
|
||||
select substr(c1,start,length) from t1;
|
||||
drop table t1;
|
||||
|
||||
EXPLAIN EXTENDED SELECT SUBSTR('abc',2,1) ;
|
||||
|
||||
CREATE VIEW v1 AS SELECT SUBSTR('abc',2,1) ;
|
||||
SHOW CREATE VIEW v1;
|
||||
SELECT * FROM v1;
|
||||
DROP VIEW v1;
|
@ -2876,6 +2876,20 @@ protected:
|
||||
};
|
||||
|
||||
|
||||
class Create_func_substr_oracle : public Create_native_func
|
||||
{
|
||||
public:
|
||||
virtual Item *create_native(THD *thd, LEX_CSTRING *name,
|
||||
List<Item> *item_list);
|
||||
|
||||
static Create_func_substr_oracle s_singleton;
|
||||
|
||||
protected:
|
||||
Create_func_substr_oracle() {}
|
||||
virtual ~Create_func_substr_oracle() {}
|
||||
};
|
||||
|
||||
|
||||
class Create_func_subtime : public Create_func_arg2
|
||||
{
|
||||
public:
|
||||
@ -6466,6 +6480,40 @@ Create_func_substr_index::create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *a
|
||||
}
|
||||
|
||||
|
||||
Create_func_substr_oracle Create_func_substr_oracle::s_singleton;
|
||||
|
||||
Item*
|
||||
Create_func_substr_oracle::create_native(THD *thd, LEX_CSTRING *name,
|
||||
List<Item> *item_list)
|
||||
{
|
||||
Item *func= NULL;
|
||||
int arg_count= item_list ? item_list->elements : 0;
|
||||
|
||||
switch (arg_count) {
|
||||
case 2:
|
||||
{
|
||||
Item *param_1= item_list->pop();
|
||||
Item *param_2= item_list->pop();
|
||||
func= new (thd->mem_root) Item_func_substr_oracle(thd, param_1, param_2);
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
Item *param_1= item_list->pop();
|
||||
Item *param_2= item_list->pop();
|
||||
Item *param_3= item_list->pop();
|
||||
func= new (thd->mem_root) Item_func_substr_oracle(thd, param_1, param_2, param_3);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name->str);
|
||||
break;
|
||||
}
|
||||
|
||||
return func;
|
||||
}
|
||||
|
||||
|
||||
Create_func_subtime Create_func_subtime::s_singleton;
|
||||
|
||||
Item*
|
||||
@ -7119,6 +7167,8 @@ static Native_func_registry func_array[] =
|
||||
{ { C_STRING_WITH_LEN("ST_WITHIN") }, GEOM_BUILDER(Create_func_within)},
|
||||
{ { C_STRING_WITH_LEN("ST_X") }, GEOM_BUILDER(Create_func_x)},
|
||||
{ { C_STRING_WITH_LEN("ST_Y") }, GEOM_BUILDER(Create_func_y)},
|
||||
{ { C_STRING_WITH_LEN("SUBSTR_ORACLE") },
|
||||
BUILDER(Create_func_substr_oracle)},
|
||||
{ { C_STRING_WITH_LEN("SUBSTRING_INDEX") }, BUILDER(Create_func_substr_index)},
|
||||
{ { C_STRING_WITH_LEN("SUBTIME") }, BUILDER(Create_func_subtime)},
|
||||
{ { C_STRING_WITH_LEN("TAN") }, BUILDER(Create_func_tan)},
|
||||
|
@ -1777,7 +1777,7 @@ String *Item_func_substr::val_str(String *str)
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
String *res = args[0]->val_str(str);
|
||||
/* must be longlong to avoid truncation */
|
||||
longlong start= args[1]->val_int();
|
||||
longlong start= get_position();
|
||||
/* Assumes that the maximum length of a String is < INT_MAX32. */
|
||||
/* Limit so that code sees out-of-bound value properly. */
|
||||
longlong length= arg_count == 3 ? args[2]->val_int() : INT_MAX32;
|
||||
@ -1827,7 +1827,7 @@ void Item_func_substr::fix_length_and_dec()
|
||||
DBUG_ASSERT(collation.collation != NULL);
|
||||
if (args[1]->const_item())
|
||||
{
|
||||
int32 start= (int32) args[1]->val_int();
|
||||
int32 start= (int32) get_position();
|
||||
if (args[1]->null_value)
|
||||
max_length= 0;
|
||||
else if (start < 0)
|
||||
|
@ -505,9 +505,12 @@ public:
|
||||
class Item_func_substr :public Item_str_func
|
||||
{
|
||||
String tmp_value;
|
||||
protected:
|
||||
virtual longlong get_position() { return args[1]->val_int(); }
|
||||
public:
|
||||
Item_func_substr(THD *thd, Item *a, Item *b): Item_str_func(thd, a, b) {}
|
||||
Item_func_substr(THD *thd, Item *a, Item *b, Item *c): Item_str_func(thd, a, b, c) {}
|
||||
Item_func_substr(THD *thd, Item *a, Item *b, Item *c):
|
||||
Item_str_func(thd, a, b, c) {}
|
||||
String *val_str(String *);
|
||||
void fix_length_and_dec();
|
||||
const char *func_name() const { return "substr"; }
|
||||
@ -515,6 +518,20 @@ public:
|
||||
{ return get_item_copy<Item_func_substr>(thd, mem_root, this); }
|
||||
};
|
||||
|
||||
class Item_func_substr_oracle :public Item_func_substr
|
||||
{
|
||||
protected:
|
||||
longlong get_position()
|
||||
{ longlong pos= args[1]->val_int(); return pos == 0 ? 1 : pos; }
|
||||
public:
|
||||
Item_func_substr_oracle(THD *thd, Item *a, Item *b):
|
||||
Item_func_substr(thd, a, b) {}
|
||||
Item_func_substr_oracle(THD *thd, Item *a, Item *b, Item *c):
|
||||
Item_func_substr(thd, a, b, c) {}
|
||||
const char *func_name() const { return "substr_oracle"; }
|
||||
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
|
||||
{ return get_item_copy<Item_func_substr_oracle>(thd, mem_root, this); }
|
||||
};
|
||||
|
||||
class Item_func_substr_index :public Item_str_func
|
||||
{
|
||||
|
@ -7182,6 +7182,22 @@ bool LEX::add_grant_command(THD *thd, enum_sql_command sql_command_arg,
|
||||
}
|
||||
|
||||
|
||||
Item *LEX::make_item_func_substr(THD *thd, Item *a, Item *b, Item *c)
|
||||
{
|
||||
return (thd->variables.sql_mode & MODE_ORACLE) ?
|
||||
new (thd->mem_root) Item_func_substr_oracle(thd, a, b, c) :
|
||||
new (thd->mem_root) Item_func_substr(thd, a, b, c);
|
||||
}
|
||||
|
||||
|
||||
Item *LEX::make_item_func_substr(THD *thd, Item *a, Item *b)
|
||||
{
|
||||
return (thd->variables.sql_mode & MODE_ORACLE) ?
|
||||
new (thd->mem_root) Item_func_substr_oracle(thd, a, b) :
|
||||
new (thd->mem_root) Item_func_substr(thd, a, b);
|
||||
}
|
||||
|
||||
|
||||
Item *LEX::make_item_func_replace(THD *thd,
|
||||
Item *org,
|
||||
Item *find,
|
||||
|
@ -3355,7 +3355,8 @@ public:
|
||||
const char *end);
|
||||
|
||||
Item *make_item_func_replace(THD *thd, Item *org, Item *find, Item *replace);
|
||||
|
||||
Item *make_item_func_substr(THD *thd, Item *a, Item *b, Item *c);
|
||||
Item *make_item_func_substr(THD *thd, Item *a, Item *b);
|
||||
/*
|
||||
Create a my_var instance for a ROW field variable that was used
|
||||
as an OUT SP parameter: CALL p1(var.field);
|
||||
|
@ -9865,26 +9865,22 @@ function_call_nonkeyword:
|
||||
}
|
||||
| SUBSTRING '(' expr ',' expr ',' expr ')'
|
||||
{
|
||||
$$= new (thd->mem_root) Item_func_substr(thd, $3, $5, $7);
|
||||
if ($$ == NULL)
|
||||
if (!($$= Lex->make_item_func_substr(thd, $3, $5, $7)))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
| SUBSTRING '(' expr ',' expr ')'
|
||||
{
|
||||
$$= new (thd->mem_root) Item_func_substr(thd, $3, $5);
|
||||
if ($$ == NULL)
|
||||
if (!($$= Lex->make_item_func_substr(thd, $3, $5)))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
| SUBSTRING '(' expr FROM expr FOR_SYM expr ')'
|
||||
{
|
||||
$$= new (thd->mem_root) Item_func_substr(thd, $3, $5, $7);
|
||||
if ($$ == NULL)
|
||||
if (!($$= Lex->make_item_func_substr(thd, $3, $5, $7)))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
| SUBSTRING '(' expr FROM expr ')'
|
||||
{
|
||||
$$= new (thd->mem_root) Item_func_substr(thd, $3, $5);
|
||||
if ($$ == NULL)
|
||||
if (!($$= Lex->make_item_func_substr(thd, $3, $5)))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
| SYSDATE opt_time_precision
|
||||
|
@ -9895,26 +9895,22 @@ function_call_nonkeyword:
|
||||
}
|
||||
| SUBSTRING '(' expr ',' expr ',' expr ')'
|
||||
{
|
||||
$$= new (thd->mem_root) Item_func_substr(thd, $3, $5, $7);
|
||||
if ($$ == NULL)
|
||||
if (!($$= Lex->make_item_func_substr(thd, $3, $5, $7)))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
| SUBSTRING '(' expr ',' expr ')'
|
||||
{
|
||||
$$= new (thd->mem_root) Item_func_substr(thd, $3, $5);
|
||||
if ($$ == NULL)
|
||||
if (!($$= Lex->make_item_func_substr(thd, $3, $5)))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
| SUBSTRING '(' expr FROM expr FOR_SYM expr ')'
|
||||
{
|
||||
$$= new (thd->mem_root) Item_func_substr(thd, $3, $5, $7);
|
||||
if ($$ == NULL)
|
||||
if (!($$= Lex->make_item_func_substr(thd, $3, $5, $7)))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
| SUBSTRING '(' expr FROM expr ')'
|
||||
{
|
||||
$$= new (thd->mem_root) Item_func_substr(thd, $3, $5);
|
||||
if ($$ == NULL)
|
||||
if (!($$= Lex->make_item_func_substr(thd, $3, $5)))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
| SYSDATE opt_time_precision
|
||||
|
Loading…
x
Reference in New Issue
Block a user