diff --git a/mysql-test/suite/compat/oracle/r/func_substr.result b/mysql-test/suite/compat/oracle/r/func_substr.result
new file mode 100644
index 0000000..eca5f48
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/func_substr.result
@@ -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;
diff --git a/mysql-test/suite/compat/oracle/t/func_substr.test b/mysql-test/suite/compat/oracle/t/func_substr.test
new file mode 100644
index 0000000..79fbeae
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/func_substr.test
@@ -0,0 +1,28 @@
+#
+# Testing SUBSTR : if start index is equal to 0, act as if it's equals to 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;
\ No newline at end of file
diff --git a/sql/item_create.cc b/sql/item_create.cc
index e0bfe7a..5421266 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -2876,6 +2876,20 @@ class Create_func_substr_index : public Create_func_arg3
 };
 
 
+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:
@@ -6460,6 +6474,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*
@@ -7113,6 +7161,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)},
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 6138b67..c37d603 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -1760,10 +1760,15 @@ void Item_func_right::fix_length_and_dec()
 
 String *Item_func_substr::val_str(String *str)
 {
+  return substr_value(str, args[1]->val_int());
+}
+
+
+String *Item_func_substr::substr_value(String *str, longlong start)
+{
   DBUG_ASSERT(fixed == 1);
   String *res  = args[0]->val_str(str);
-  /* must be longlong to avoid truncation */
-  longlong start= args[1]->val_int();
+  /* parameter "start" must be longlong to avoid truncation */
   /* 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;
@@ -1807,13 +1812,21 @@ String *Item_func_substr::val_str(String *str)
 
 void Item_func_substr::fix_length_and_dec()
 {
-  max_length=args[0]->max_length;
+  bool constitem= args[1]->const_item();
+  substr_fix_length_and_dec(constitem, constitem ? (int32) args[1]->val_int() :
+                                                   0);
+}
+
+
+void Item_func_substr::substr_fix_length_and_dec(bool constitem,
+                                                 int32 start)
+{
+  max_length= args[0]->max_length;
 
   agg_arg_charsets_for_string_result(collation, args, 1);
   DBUG_ASSERT(collation.collation != NULL);
-  if (args[1]->const_item())
+  if (constitem)
   {
-    int32 start= (int32) args[1]->val_int();
     if (args[1]->null_value)
       max_length= 0;
     else if (start < 0)
@@ -1833,6 +1846,23 @@ void Item_func_substr::fix_length_and_dec()
 }
 
 
+String *Item_func_substr_oracle::val_str(String *str)
+{
+  longlong start= args[1]->val_int();
+  return substr_value(str, start == 0 ? 1 : start);
+}
+
+
+void Item_func_substr_oracle::fix_length_and_dec()
+{
+  int32 start= 0;
+  bool constitem= args[1]->const_item();
+  if (constitem && (start= (int32) args[1]->val_int()) == 0)
+    start= 1;
+  substr_fix_length_and_dec(constitem, start);
+}
+
+
 void Item_func_substr_index::fix_length_and_dec()
 { 
   if (agg_arg_charsets_for_string_result_with_comparison(collation, args, 2))
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index c022282..28cb4e8 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -507,14 +507,30 @@ class Item_func_substr :public Item_str_func
   String tmp_value;
 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();
+  String *substr_value(String *str, longlong start);
+  void substr_fix_length_and_dec(bool constitem, int32 start);
   const char *func_name() const { return "substr"; }
   Item *get_copy(THD *thd, MEM_ROOT *mem_root)
   { return get_item_copy<Item_func_substr>(thd, mem_root, this); }
 };
 
+class Item_func_substr_oracle :public Item_func_substr
+{
+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) {}
+  String *val_str(String *);
+  void fix_length_and_dec();
+  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
 {
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 8112b95..f00c52e 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -7192,6 +7192,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,
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 79f2b11..f7c48df 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -3358,7 +3358,8 @@ struct LEX: public Query_tables_list
                           const LEX_CSTRING *var_name,
                           const LEX_CSTRING *field_name,
                           uint pos_in_q, uint length_in_q);
-
+  Item *make_item_func_substr(THD *thd, Item *a, Item *b, Item *c);
+  Item *make_item_func_substr(THD *thd, Item *a, Item *b);
   Item *make_item_func_replace(THD *thd, Item *org, Item *find, Item *replace);
 
   /*
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 647ed1a..9e9448b 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -9853,26 +9853,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
diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy
index f0f365d..329ba29 100644
--- a/sql/sql_yacc_ora.yy
+++ b/sql/sql_yacc_ora.yy
@@ -9890,26 +9890,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
