diff --git a/mysql-test/suite/compat/oracle/r/func_to_char.result b/mysql-test/suite/compat/oracle/r/func_to_char.result
new file mode 100644
index 00000000000..18384d928a0
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/func_to_char.result
@@ -0,0 +1,205 @@
+CREATE TABLE t_to_char(c1 date, c2 time, c3 timestamp);
+INSERT INTO t_to_char VALUES ('2021-11-03', '11:30:32', '2021-11-03 15:30:32');
+select to_char(c3, 'RRRRMMDDMIHH24SS') from t_to_char;
+to_char(c3, 'RRRRMMDDMIHH24SS')
+20211103301532
+select to_char(c3, 'MMDDMIRRRRHH24SS') from t_to_char;
+to_char(c3, 'MMDDMIRRRRHH24SS')
+11033020211532
+select to_char(c3, 'RRRR-MM-DD MI:HH24:SS') from t_to_char;
+to_char(c3, 'RRRR-MM-DD MI:HH24:SS')
+2021-11-03 30:15:32
+select to_char(c3, 'yyyy-mm-dd hh:mi:ss') from t_to_char;
+to_char(c3, 'yyyy-mm-dd hh:mi:ss')
+2021-11-03 03:30:32
+select to_char(c3, 'YYYY-MM-DD HH:MI:SS') from t_to_char;
+to_char(c3, 'YYYY-MM-DD HH:MI:SS')
+2021-11-03 03:30:32
+select to_char(c3, 'HH:MI:SS MM-DD-YYYY') from t_to_char;
+to_char(c3, 'HH:MI:SS MM-DD-YYYY')
+03:30:32 11-03-2021
+select to_char(c3, 'YYYY-DD-MON HH12:MI:SS') from t_to_char;
+to_char(c3, 'YYYY-DD-MON HH12:MI:SS')
+2021-03-Nov 03:30:32
+select to_char(c3, 'MONTH-YYYY-DD HH24:MI:SS') from t_to_char;
+to_char(c3, 'MONTH-YYYY-DD HH24:MI:SS')
+November-2021-03 15:30:32
+select to_char(c3, 'yyyy-mm-dd hh:mi:ss') from t_to_char;
+to_char(c3, 'yyyy-mm-dd hh:mi:ss')
+2021-11-03 03:30:32
+select to_char(c3, 'YYYY-MM-DD HH:MI:SS') from t_to_char;
+to_char(c3, 'YYYY-MM-DD HH:MI:SS')
+2021-11-03 03:30:32
+select to_char(c3, 'HH:MI:SS MM-DD-YYYY') from t_to_char;
+to_char(c3, 'HH:MI:SS MM-DD-YYYY')
+03:30:32 11-03-2021
+select to_char(c3, 'HH12:MI:SS MM-DD-YYYY') from t_to_char;
+to_char(c3, 'HH12:MI:SS MM-DD-YYYY')
+03:30:32 11-03-2021
+select to_char(c3, 'HH24:SS:MI MM-DD-YYYY') from t_to_char;
+to_char(c3, 'HH24:SS:MI MM-DD-YYYY')
+15:32:30 11-03-2021
+select to_char(c3, 'YYYY-DD-MON HH12:MI:SS') from t_to_char;
+to_char(c3, 'YYYY-DD-MON HH12:MI:SS')
+2021-03-Nov 03:30:32
+select to_char(c3, 'MONTH-YYYY-DD HH24:MI:SS') from t_to_char;
+to_char(c3, 'MONTH-YYYY-DD HH24:MI:SS')
+November-2021-03 15:30:32
+select to_char(c3, '--MONTH-YYYY-DD-- HH24:MI:SS') from t_to_char;
+to_char(c3, '--MONTH-YYYY-DD-- HH24:MI:SS')
+--November-2021-03-- 15:30:32
+select to_char(c1, 'RRRRMMDDMIHH24SS') from t_to_char;
+to_char(c1, 'RRRRMMDDMIHH24SS')
+20211103000000
+select to_char(c1, 'MMDDMIRRRRHH24SS') from t_to_char;
+to_char(c1, 'MMDDMIRRRRHH24SS')
+11030020210000
+select to_char(c1, 'RRRR-MM-DD MI:HH24:SS') from t_to_char;
+to_char(c1, 'RRRR-MM-DD MI:HH24:SS')
+2021-11-03 00:00:00
+select to_char(c1, 'yyyy-mm-dd hh:mi:ss') from t_to_char;
+to_char(c1, 'yyyy-mm-dd hh:mi:ss')
+2021-11-03 12:00:00
+select to_char(c1, 'YYYY-MM-DD HH:MI:SS') from t_to_char;
+to_char(c1, 'YYYY-MM-DD HH:MI:SS')
+2021-11-03 12:00:00
+select to_char(c1, 'HH:MI:SS MM-DD-YYYY') from t_to_char;
+to_char(c1, 'HH:MI:SS MM-DD-YYYY')
+12:00:00 11-03-2021
+select to_char(c1, 'YYYY-DD-MON HH12:MI:SS') from t_to_char;
+to_char(c1, 'YYYY-DD-MON HH12:MI:SS')
+2021-03-Nov 12:00:00
+select to_char(c1, 'MONTH-YYYY-DD HH24:MI:SS') from t_to_char;
+to_char(c1, 'MONTH-YYYY-DD HH24:MI:SS')
+November-2021-03 00:00:00
+select to_char(c1, 'yyyy-mm-dd hh:mi:ss') from t_to_char;
+to_char(c1, 'yyyy-mm-dd hh:mi:ss')
+2021-11-03 12:00:00
+select to_char(c1, 'YYYY-MM-DD HH:MI:SS') from t_to_char;
+to_char(c1, 'YYYY-MM-DD HH:MI:SS')
+2021-11-03 12:00:00
+select to_char(c1, 'HH:MI:SS MM-DD-YYYY') from t_to_char;
+to_char(c1, 'HH:MI:SS MM-DD-YYYY')
+12:00:00 11-03-2021
+select to_char(c1, 'HH12:MI:SS MM-DD-YYYY') from t_to_char;
+to_char(c1, 'HH12:MI:SS MM-DD-YYYY')
+12:00:00 11-03-2021
+select to_char(c1, 'HH24:SS:MI MM-DD-YYYY') from t_to_char;
+to_char(c1, 'HH24:SS:MI MM-DD-YYYY')
+00:00:00 11-03-2021
+select to_char(c1, 'YYYY-DD-MON HH12:MI:SS') from t_to_char;
+to_char(c1, 'YYYY-DD-MON HH12:MI:SS')
+2021-03-Nov 12:00:00
+select to_char(c1, 'MONTH-YYYY-DD HH24:MI:SS') from t_to_char;
+to_char(c1, 'MONTH-YYYY-DD HH24:MI:SS')
+November-2021-03 00:00:00
+select to_char(c1, ';-MONTH-YYYY-DD-- HH24:MI:SS') from t_to_char;
+to_char(c1, ';-MONTH-YYYY-DD-- HH24:MI:SS')
+;-November-2021-03-- 00:00:00
+select to_char(c2, 'RRRRMMDDMIHH24SS') from t_to_char;
+to_char(c2, 'RRRRMMDDMIHH24SS')
+00000000301132
+select to_char(c2, 'MMDDMIRRRRHH24SS') from t_to_char;
+to_char(c2, 'MMDDMIRRRRHH24SS')
+00003000001132
+select to_char(c2, 'RRRR-MM-DD MI:HH24:SS') from t_to_char;
+to_char(c2, 'RRRR-MM-DD MI:HH24:SS')
+0000-00-00 30:11:32
+select to_char(c2, 'yyyy-mm-dd hh:mi:ss') from t_to_char;
+to_char(c2, 'yyyy-mm-dd hh:mi:ss')
+0000-00-00 11:30:32
+select to_char(c2, 'YYYY-MM-DD HH:MI:SS') from t_to_char;
+to_char(c2, 'YYYY-MM-DD HH:MI:SS')
+0000-00-00 11:30:32
+select to_char(c2, 'HH:MI:SS MM-DD-YYYY') from t_to_char;
+to_char(c2, 'HH:MI:SS MM-DD-YYYY')
+11:30:32 00-00-0000
+select to_char(c2, 'YYYY-DD-MON HH12:MI:SS') from t_to_char;
+to_char(c2, 'YYYY-DD-MON HH12:MI:SS')
+0000-00-00 11:30:32
+select to_char(c2, 'MONTH-YYYY-DD HH24:MI:SS') from t_to_char;
+to_char(c2, 'MONTH-YYYY-DD HH24:MI:SS')
+00-0000-00 11:30:32
+select to_char(c2, 'yyyy-mm-dd hh:mi:ss') from t_to_char;
+to_char(c2, 'yyyy-mm-dd hh:mi:ss')
+0000-00-00 11:30:32
+select to_char(c2, 'YYYY-MM-DD HH:MI:SS') from t_to_char;
+to_char(c2, 'YYYY-MM-DD HH:MI:SS')
+0000-00-00 11:30:32
+select to_char(c2, 'HH:MI:SS MM-DD-YYYY') from t_to_char;
+to_char(c2, 'HH:MI:SS MM-DD-YYYY')
+11:30:32 00-00-0000
+select to_char(c2, 'HH12:MI:SS MM-DD-YYYY') from t_to_char;
+to_char(c2, 'HH12:MI:SS MM-DD-YYYY')
+11:30:32 00-00-0000
+select to_char(c2, 'HH24:SS:MI MM-DD-YYYY') from t_to_char;
+to_char(c2, 'HH24:SS:MI MM-DD-YYYY')
+11:32:30 00-00-0000
+select to_char(c2, 'YYYY-DD-MON HH12:MI:SS') from t_to_char;
+to_char(c2, 'YYYY-DD-MON HH12:MI:SS')
+0000-00-00 11:30:32
+select to_char(c2, 'MONTH-YYYY-DD HH24:MI:SS') from t_to_char;
+to_char(c2, 'MONTH-YYYY-DD HH24:MI:SS')
+00-0000-00 11:30:32
+select to_char(c2, ':;MONTH-YYYY-DD-- HH24:MI:SS') from t_to_char;
+to_char(c2, ':;MONTH-YYYY-DD-- HH24:MI:SS')
+:;00-0000-00-- 11:30:32
+select to_char(c3, 'YYYYYYYYYYYYYYY') from t_to_char;
+to_char(c3, 'YYYYYYYYYYYYYYY')
+202120212021021
+select to_char(c3, 'YYYYYYYYYYYYYYYDDDDDD') from t_to_char;
+to_char(c3, 'YYYYYYYYYYYYYYYDDDDDD')
+202120212021021030303
+select to_char(c3, 'YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY') from t_to_char;
+to_char(c3, 'YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY')
+NULL
+select to_char(c3, 'YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY-DD-MM') from t_to_char;
+to_char(c3, 'YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY-DD-MM')
+202120212021202120212021202120212021202120212021202120212021202120212021202120212021202120212021202120212021202120212021-03-11
+select to_char(c3, 'YYYYxDDD') from t_to_char;
+to_char(c3, 'YYYYxDDD')
+NULL
+select to_char(c3, 'xxYYYY-DD') from t_to_char;
+to_char(c3, 'xxYYYY-DD')
+NULL
+select to_char(c3, "YYYY/MM/DD HH MI SS") from t_to_char;
+to_char(c3, "YYYY/MM/DD HH MI SS")
+2021/11/03 03 30 32
+select to_char(c3, "YYYY,MM.DD HH;MI;SS") from t_to_char;
+to_char(c3, "YYYY,MM.DD HH;MI;SS")
+2021,11.03 03;30;32
+select to_char(c3, "YYYY-MM/DD HH.MI SS") from t_to_char;
+to_char(c3, "YYYY-MM/DD HH.MI SS")
+2021-11/03 03.30 32
+select to_char(c3, ";;YYYY-MM/DD HH.MI SS--") from t_to_char;
+to_char(c3, ";;YYYY-MM/DD HH.MI SS--")
+;;2021-11/03 03.30 32--
+select to_char(c3) from t_to_char;
+to_char(c3)
+2021-11-03 15:30:32
+select to_char(c3, "YYYY-MM-DD HH:MI:SS") from t_to_char;
+to_char(c3, "YYYY-MM-DD HH:MI:SS")
+2021-11-03 03:30:32
+select to_char(c3, "YYYY-MM-DD HH:MI:SS", "zh_CN") from t_to_char;
+ERROR 42000: Incorrect parameter count in the call to native function 'to_char'
+select to_char(c3, "YYYY-MM-DD HH:MI:SS", "NLS_DATE_LANGUAGE = zh_CN") from t_to_char;
+ERROR 42000: Incorrect parameter count in the call to native function 'to_char'
+select to_char(c3, 'DDD') from t_to_char;
+to_char(c3, 'DDD')
+NULL
+select to_char(c3, 'D') from t_to_char;
+to_char(c3, 'D')
+NULL
+select to_char(c3, 'DAY') from t_to_char;
+to_char(c3, 'DAY')
+NULL
+select to_char(c3, 'DS') from t_to_char;
+to_char(c3, 'DS')
+NULL
+select to_char(c3, 'IY') from t_to_char;
+to_char(c3, 'IY')
+NULL
+select to_char(c3, 'IYYY') from t_to_char;
+to_char(c3, 'IYYY')
+NULL
+DROP TABLE t_to_char;
diff --git a/mysql-test/suite/compat/oracle/t/func_to_char.test b/mysql-test/suite/compat/oracle/t/func_to_char.test
new file mode 100644
index 00000000000..650da63b851
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/func_to_char.test
@@ -0,0 +1,94 @@
+##############################################################
+# testcase for TO_CHAR() function for oracle
+##############################################################
+CREATE TABLE t_to_char(c1 date, c2 time, c3 timestamp);
+INSERT INTO t_to_char VALUES ('2021-11-03', '11:30:32', '2021-11-03 15:30:32');
+
+# test full output format
+select to_char(c3, 'RRRRMMDDMIHH24SS') from t_to_char;
+select to_char(c3, 'MMDDMIRRRRHH24SS') from t_to_char;
+select to_char(c3, 'RRRR-MM-DD MI:HH24:SS') from t_to_char;
+select to_char(c3, 'yyyy-mm-dd hh:mi:ss') from t_to_char;
+select to_char(c3, 'YYYY-MM-DD HH:MI:SS') from t_to_char;
+select to_char(c3, 'HH:MI:SS MM-DD-YYYY') from t_to_char;
+select to_char(c3, 'YYYY-DD-MON HH12:MI:SS') from t_to_char;
+# there are some spaces after AUGUST and oracle support bothupper/lowwer case
+select to_char(c3, 'MONTH-YYYY-DD HH24:MI:SS') from t_to_char;
+select to_char(c3, 'yyyy-mm-dd hh:mi:ss') from t_to_char;
+select to_char(c3, 'YYYY-MM-DD HH:MI:SS') from t_to_char;
+select to_char(c3, 'HH:MI:SS MM-DD-YYYY') from t_to_char;
+select to_char(c3, 'HH12:MI:SS MM-DD-YYYY') from t_to_char;
+select to_char(c3, 'HH24:SS:MI MM-DD-YYYY') from t_to_char;
+select to_char(c3, 'YYYY-DD-MON HH12:MI:SS') from t_to_char;
+select to_char(c3, 'MONTH-YYYY-DD HH24:MI:SS') from t_to_char;
+select to_char(c3, '--MONTH-YYYY-DD-- HH24:MI:SS') from t_to_char;
+
+select to_char(c1, 'RRRRMMDDMIHH24SS') from t_to_char;
+select to_char(c1, 'MMDDMIRRRRHH24SS') from t_to_char;
+select to_char(c1, 'RRRR-MM-DD MI:HH24:SS') from t_to_char;
+select to_char(c1, 'yyyy-mm-dd hh:mi:ss') from t_to_char;
+select to_char(c1, 'YYYY-MM-DD HH:MI:SS') from t_to_char;
+select to_char(c1, 'HH:MI:SS MM-DD-YYYY') from t_to_char;
+select to_char(c1, 'YYYY-DD-MON HH12:MI:SS') from t_to_char;
+select to_char(c1, 'MONTH-YYYY-DD HH24:MI:SS') from t_to_char;
+select to_char(c1, 'yyyy-mm-dd hh:mi:ss') from t_to_char;
+select to_char(c1, 'YYYY-MM-DD HH:MI:SS') from t_to_char;
+select to_char(c1, 'HH:MI:SS MM-DD-YYYY') from t_to_char;
+select to_char(c1, 'HH12:MI:SS MM-DD-YYYY') from t_to_char;
+select to_char(c1, 'HH24:SS:MI MM-DD-YYYY') from t_to_char;
+select to_char(c1, 'YYYY-DD-MON HH12:MI:SS') from t_to_char;
+select to_char(c1, 'MONTH-YYYY-DD HH24:MI:SS') from t_to_char;
+select to_char(c1, ';-MONTH-YYYY-DD-- HH24:MI:SS') from t_to_char;
+
+select to_char(c2, 'RRRRMMDDMIHH24SS') from t_to_char;
+select to_char(c2, 'MMDDMIRRRRHH24SS') from t_to_char;
+select to_char(c2, 'RRRR-MM-DD MI:HH24:SS') from t_to_char;
+select to_char(c2, 'yyyy-mm-dd hh:mi:ss') from t_to_char;
+select to_char(c2, 'YYYY-MM-DD HH:MI:SS') from t_to_char;
+select to_char(c2, 'HH:MI:SS MM-DD-YYYY') from t_to_char;
+select to_char(c2, 'YYYY-DD-MON HH12:MI:SS') from t_to_char;
+select to_char(c2, 'MONTH-YYYY-DD HH24:MI:SS') from t_to_char;
+select to_char(c2, 'yyyy-mm-dd hh:mi:ss') from t_to_char;
+select to_char(c2, 'YYYY-MM-DD HH:MI:SS') from t_to_char;
+select to_char(c2, 'HH:MI:SS MM-DD-YYYY') from t_to_char;
+select to_char(c2, 'HH12:MI:SS MM-DD-YYYY') from t_to_char;
+select to_char(c2, 'HH24:SS:MI MM-DD-YYYY') from t_to_char;
+select to_char(c2, 'YYYY-DD-MON HH12:MI:SS') from t_to_char;
+select to_char(c2, 'MONTH-YYYY-DD HH24:MI:SS') from t_to_char;
+select to_char(c2, ':;MONTH-YYYY-DD-- HH24:MI:SS') from t_to_char;
+
+# test for unusual format
+select to_char(c3, 'YYYYYYYYYYYYYYY') from t_to_char;
+select to_char(c3, 'YYYYYYYYYYYYYYYDDDDDD') from t_to_char;
+
+# oracle max length is 144
+select to_char(c3, 'YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY') from t_to_char;
+select to_char(c3, 'YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY-DD-MM') from t_to_char;
+
+# test for unsupported format
+select to_char(c3, 'YYYYxDDD') from t_to_char;
+select to_char(c3, 'xxYYYY-DD') from t_to_char;
+
+# test for separator
+select to_char(c3, "YYYY/MM/DD HH MI SS") from t_to_char;
+select to_char(c3, "YYYY,MM.DD HH;MI;SS") from t_to_char;
+select to_char(c3, "YYYY-MM/DD HH.MI SS") from t_to_char;
+select to_char(c3, ";;YYYY-MM/DD HH.MI SS--") from t_to_char;
+
+# now only support two parameter.
+select to_char(c3) from t_to_char;
+select to_char(c3, "YYYY-MM-DD HH:MI:SS") from t_to_char;
+--error 1582
+select to_char(c3, "YYYY-MM-DD HH:MI:SS", "zh_CN") from t_to_char;
+--error 1582
+select to_char(c3, "YYYY-MM-DD HH:MI:SS", "NLS_DATE_LANGUAGE = zh_CN") from t_to_char;
+
+# oracle support format but mariadb dont support
+select to_char(c3, 'DDD') from t_to_char;
+select to_char(c3, 'D') from t_to_char;
+select to_char(c3, 'DAY') from t_to_char;
+select to_char(c3, 'DS') from t_to_char;
+select to_char(c3, 'IY') from t_to_char;
+select to_char(c3, 'IYYY') from t_to_char;
+
+DROP TABLE t_to_char;
\ No newline at end of file
diff --git a/sql/item_create.cc b/sql/item_create.cc
index 62f4d9f9fee..1a089cdbe67 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -2131,6 +2131,19 @@ class Create_func_to_base64 : public Create_func_arg1
 };
 
 
+class Create_func_to_char : public Create_native_func
+{
+public:
+  virtual Item *create_native(THD *thd, LEX_CSTRING *name, List<Item> *item_list);
+
+  static Create_func_to_char s_singleton;
+
+protected:
+  Create_func_to_char() {}
+  virtual ~Create_func_to_char() {}
+};
+
+
 class Create_func_to_days : public Create_func_arg1
 {
 public:
@@ -5130,6 +5143,44 @@ Create_func_to_base64::create_1_arg(THD *thd, Item *arg1)
 }
 
 
+Create_func_to_char Create_func_to_char::s_singleton;
+
+Item*
+Create_func_to_char::create_native(THD *thd, LEX_CSTRING *name,
+				   List<Item> *item_list)
+{
+  Item *func= NULL;
+  int arg_count= 0;
+
+  if (item_list != NULL)
+    arg_count= item_list->elements;
+
+  switch (arg_count) {
+  case 1:
+  {
+    Item *param_1= item_list->pop();
+    Item *i0= new (thd->mem_root) Item_string_sys(thd, "YYYY-MM-DD HH24:MI:SS",  21);
+    func= new (thd->mem_root) Item_func_tochar(thd, param_1, i0);
+    break;
+  }
+  case 2:
+  {
+    Item *param_1= item_list->pop();
+    Item *param_2= item_list->pop();
+    func= new (thd->mem_root) Item_func_tochar(thd, param_1, param_2);
+    break;
+  }
+  default:
+  {
+    my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name->str);
+    break;
+  }
+  }
+
+  return func;
+}
+
+
 Create_func_to_days Create_func_to_days::s_singleton;
 
 Item*
@@ -5577,6 +5628,7 @@ static Native_func_registry func_array[] =
   { { STRING_WITH_LEN("TIME_FORMAT") }, BUILDER(Create_func_time_format)},
   { { STRING_WITH_LEN("TIME_TO_SEC") }, BUILDER(Create_func_time_to_sec)},
   { { STRING_WITH_LEN("TO_BASE64") }, BUILDER(Create_func_to_base64)},
+  { { STRING_WITH_LEN("TO_CHAR") }, BUILDER(Create_func_to_char)},
   { { STRING_WITH_LEN("TO_DAYS") }, BUILDER(Create_func_to_days)},
   { { STRING_WITH_LEN("TO_SECONDS") }, BUILDER(Create_func_to_seconds)},
   { { STRING_WITH_LEN("UCASE") }, BUILDER(Create_func_ucase)},
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index b4f706984a5..707f93f3366 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -5371,3 +5371,469 @@ longlong Item_func_wsrep_sync_wait_upto::val_int()
 }
 
 #endif /* WITH_WSREP */
+
+static inline bool is_special(const char *ptr)
+{
+  switch (*ptr) {
+
+  default:
+    return false;
+  }
+}
+
+static bool make_date_time_oracle(const String *format,
+                                  const MYSQL_TIME *l_time,
+                                  const MY_LOCALE *locale,
+                                  String *str)
+{
+  char intbuff[15];
+  uint hours_i;
+  uint weekday;
+  ulong length;
+  const char *ptr, *end;
+
+  str->length(0);
+
+  end= (ptr= format->ptr()) + format->length();
+
+  for (; ptr < end ; ptr++)
+  {
+    switch (*ptr) {
+    case 'Y':
+    case 'y':
+      /* format: YY/YYY/YYYY */
+      if (*(ptr+1) == 'Y' || *(ptr+1) == 'y')
+      {
+        if (*(ptr+2) != 'Y' && *(ptr+2) != 'y') /* YY */
+        {
+          length= (uint) (int10_to_str(l_time->year%100, intbuff, 10) - intbuff);
+          str->append_with_prefill(intbuff, length, 2, '0');
+          ptr+= 1;
+        }
+        else
+        {
+          if (*(ptr+3) == 'Y' || *(ptr+3) == 'y') /* YYYY */
+          {
+            length= (uint) (int10_to_str(l_time->year, intbuff, 10) - intbuff);
+            str->append_with_prefill(intbuff, length, 4, '0');
+            ptr+= 3;
+          }
+          else /* YYY */
+          {
+            length= (uint) (int10_to_str(l_time->year%1000, intbuff, 10) - intbuff);
+            str->append_with_prefill(intbuff, length, 3, '0');
+            ptr+=2;
+          }
+        }
+      }
+      else /* Y */
+      {
+        length= (uint) (int10_to_str(l_time->year%10, intbuff, 10) - intbuff);
+        str->append_with_prefill(intbuff, length, 1, '0');
+      }
+      break;
+
+    case 'R':
+    case 'r':
+      /* format: RR/RRRR */
+      if (*(ptr+1) == 'R' || *(ptr+1) == 'r')
+      {
+        if (*(ptr+2) != 'R' && *(ptr+2) != 'r') /* RR */
+        {
+          length= (uint) (int10_to_str(l_time->year%100, intbuff, 10) - intbuff);
+          str->append_with_prefill(intbuff, length, 2, '0');
+          ptr+= 1;
+        }
+        else
+        {
+          if (*(ptr+3) == 'R' || *(ptr+3) == 'r') /* RRRR */
+          {
+            length= (uint) (int10_to_str(l_time->year, intbuff, 10) - intbuff);
+            str->append_with_prefill(intbuff, length, 4, '0');
+            ptr+= 3;
+          }
+          else /* don not support RRR */
+          {
+            return 1;
+          }
+        }
+      }
+      else /* R */
+      {
+        return 1;
+      }
+      break;
+
+    case 'M':
+    case 'm':
+      /* format: MM */
+      if (*(ptr+1) == 'M' || *(ptr+1) == 'm')
+      {
+        length= (uint) (int10_to_str(l_time->month, intbuff, 10) - intbuff);
+        str->append_with_prefill(intbuff, length, 2, '0');
+        ptr+= 1;
+      }
+      else if (*(ptr+1) == 'I' || *(ptr+1) == 'i') /* format: MI */
+      {
+        length= (uint) (int10_to_str(l_time->minute, intbuff, 10) - intbuff);
+        str->append_with_prefill(intbuff, length, 2, '0');
+        ptr= ptr+1;
+      }
+      else if ((*(ptr+1) == 'O' || *(ptr+1) == 'o') &&
+               (*(ptr+2) == 'N' || *(ptr+2) == 'n')) /* format: MON/MONTH */
+      {
+        if ((*(ptr+3) == 'T' || *(ptr+3) == 't') &&
+            (*(ptr+4) == 'H' || *(ptr+4) == 'h')) /* NONTH */
+        {
+	  if (l_time->month  > 0 && l_time->month < 12)
+	  {
+	    str->append(locale->month_names->type_names[l_time->month-1],
+			(uint) strlen(locale->month_names->type_names[l_time->month-1]),
+			system_charset_info);
+	  }
+	  else
+	  {
+	    length= (uint) (int10_to_str(l_time->month, intbuff, 10) - intbuff);
+	    str->append_with_prefill(intbuff, length, 2, '0');
+	  }
+          ptr+= 4;
+        }
+        else /*MON*/
+        {
+	  if (l_time->month  > 0 && l_time->month < 12)
+	  {
+	    str->append(locale->ab_month_names->type_names[l_time->month-1],
+                      (uint) strlen(locale->ab_month_names->type_names[l_time->month-1]),
+                      system_charset_info);
+	  }
+	  else
+	  {
+	    length= (uint) (int10_to_str(l_time->month, intbuff, 10) - intbuff);
+	    str->append_with_prefill(intbuff, length, 2, '0');
+	  }
+
+          ptr+= 2;
+        }
+      }
+      else
+      {
+        return 1;
+      }
+      break;
+
+    case 'D':
+    case 'd':
+      if(*(ptr+1) == 'D' || *(ptr+1) == 'd')
+      {
+        length= (uint) (int10_to_str(l_time->day, intbuff, 10) - intbuff);
+        str->append_with_prefill(intbuff, length, 2, '0');
+        ptr+= 1;
+      }
+      else if (*(ptr+1) == 'Y' || *(ptr+1) == 'y')
+      {
+	if (l_time->day != 0)
+	{
+        weekday=calc_weekday(calc_daynr(l_time->year,l_time->month,
+                             l_time->day), 0);
+        str->append(locale->ab_day_names->type_names[weekday],
+                    (uint) strlen(locale->ab_day_names->type_names[weekday]),
+                    system_charset_info);
+	}
+	else
+	{
+	  length= (uint) (int10_to_str(l_time->day, intbuff, 10) - intbuff);
+	  str->append_with_prefill(intbuff, length, 2, '0');
+	}
+        ptr+= 1;
+      }
+      else
+      {
+        return 1;
+      }
+      break;
+
+    case 'H':
+    case 'h':
+      if (*(ptr+1) == 'H' || *(ptr+1) == 'h')
+      {
+        if (*(ptr+2) == '2' && *(ptr+3) == '4')
+        {
+          length= (uint) (int10_to_str(l_time->hour, intbuff, 10) - intbuff);
+          str->append_with_prefill(intbuff, length, 2, '0');
+          ptr+= 3;
+        }
+        else if (*(ptr+2) == '1' && *(ptr+3) == '2')
+        {
+          hours_i= (l_time->hour%24 + 11)%12+1;
+          length= (uint) (int10_to_str(hours_i, intbuff, 10) - intbuff);
+          str->append_with_prefill(intbuff, length, 2, '0');
+          ptr+= 3;
+        }
+        else
+        {
+          hours_i= (l_time->hour%24 + 11)%12+1;
+          length= (uint) (int10_to_str(hours_i, intbuff, 10) - intbuff);
+          str->append_with_prefill(intbuff, length, 2, '0');
+          ptr+= 1;
+        }
+      }
+      else
+      {
+        return 1;
+      }
+      break;
+
+    case 'S':
+    case 's':
+      if (*(ptr+1) == 'S' || *(ptr+1) == 's')
+      {
+        length= (uint) (int10_to_str(l_time->second, intbuff, 10) - intbuff);
+        str->append_with_prefill(intbuff, length, 2, '0');
+        ptr++;
+      }
+      else
+      {
+        return 1;
+      }
+      break;
+    case ':':
+    case '-':
+    case '/':
+    case '.':
+    case ',':
+    case ';':
+    case ' ':
+      str->append(*ptr);
+      break;
+    default:
+      return 1;
+    }
+  }
+  return 0;
+}
+
+uint Item_func_tochar::format_length(const String *format)
+{
+  uint size=0;
+  const char *ptr=format->ptr();
+  const char *end=ptr+format->length();
+
+  /* oralce max length of format string is 144 */
+  if (format->length() > 144)
+    return 0;
+
+  for (; ptr < end ; ptr++)
+  {
+    switch (*ptr) {
+    case 'y':
+    case 'Y':
+      if (*(ptr+1) == 'Y' || *(ptr+1) == 'y')
+      {
+        if (*(ptr+2) != 'Y' && *(ptr+2) != 'y') /* YY */
+        {
+          ptr+= 1;
+          size+= 2;
+        }
+        else
+        {
+          if (*(ptr+3) == 'Y' || *(ptr+3) == 'y') /* YYYY */
+          {
+            ptr+= 3;
+            size+= 4;
+          }
+          else /* YYY */
+          {
+            ptr+= 2;
+            size+= 3;
+          }
+        }
+      }
+      else
+      {
+        size += 1;
+      }
+      break;
+
+    case 'r':
+    case 'R':
+      if (*(ptr+1) == 'R' || *(ptr+1) == 'r')
+      {
+        if (*(ptr+2) != 'R' && *(ptr+2) != 'r') /* YY */
+        {
+          ptr+= 1;
+          size+= 2;
+        }
+        else
+        {
+          if (*(ptr+3) == 'R' || *(ptr+3) == 'r') /* RRRR */
+          {
+            ptr+= 3;
+            size+= 4;
+          }
+          else
+          {
+            return 0;
+          }
+        }
+      }
+      else
+      {
+        size+= 1;
+      }
+      break;
+
+    case 'm':
+    case 'M':
+      if (*(ptr+1) == 'M' || *(ptr+1) == 'I' ||
+          *(ptr+1) == 'm' || *(ptr+1) == 'i')
+      {
+        size+= 2;
+        ptr++;
+      }
+      else
+      {
+        if (*(ptr+1) == 'O' || *(ptr+1) == 'o')
+        {
+          if (*(ptr+2) == 'N' || *(ptr+1) == 'n')
+          {
+            if ((*(ptr+3) == 'T' || *(ptr+3) == 't') &&
+                (*(ptr+4) == 'H' || *(ptr+4) == 'h')) /* NONTH */
+            {
+              size+= 64;
+              ptr+= 4;
+            }
+            else /* MON */
+            {
+              size+= 32;
+              ptr+= 2;
+            }
+          }
+          else
+            return 0;
+        }
+        else
+          return 0;
+      }
+      break;
+
+    case 'h':
+    case 'H':
+      if (*(ptr+1) == 'H' || *(ptr+1) == 'h')
+      {
+        if ((*(ptr+2) == '2' && *(ptr+3) == '4') ||
+            (*(ptr+2) == '1' && *(ptr+3) == '2'))
+          ptr+= 3;
+        else
+          ptr+= 1;
+      }
+      else
+        return 0;
+      size += 2;
+      break;
+
+    case 'd':
+    case 'D':
+      if(*(ptr+1) == 'D' || *(ptr+1) == 'd')
+      {
+        size+= 2;
+      }
+      else if (*(ptr+1) == 'Y' || *(ptr+1) == 'y')
+      {
+        size+= 3;
+      }
+      else
+        return 1;
+      ptr+= 1;
+      break;
+
+    case 's':
+    case 'S':
+      if (*(ptr+1) == 'S' || *(ptr+1) == 's')
+        size+= 2;
+      ptr+= 1;
+      break;
+
+    default:
+      size++;
+      break;
+      }
+  }
+
+  return size;
+}
+
+bool Item_func_tochar::fix_length_and_dec()
+{
+  THD* thd= current_thd;
+
+  locale= thd->variables.lc_time_names;
+  Item *arg1= args[1]->this_item();
+
+  decimals=0;
+  CHARSET_INFO *cs= thd->variables.collation_connection;
+  my_repertoire_t repertoire= arg1->collation.repertoire;
+  if (!thd->variables.lc_time_names->is_ascii)
+    repertoire|= MY_REPERTOIRE_EXTENDED;
+  collation.set(cs, arg1->collation.derivation, repertoire);
+  StringBuffer<STRING_BUFFER_USUAL_SIZE> buffer;
+  String *str;
+  if (args[1]->basic_const_item() && (str= args[1]->val_str(&buffer)))
+  {                                             // Optimize the normal case
+    fixed_length=1;
+    max_length= format_length(str) * collation.collation->mbmaxlen;
+  }
+  else
+  {
+    fixed_length=0;
+    max_length=MY_MIN(arg1->max_length, MAX_BLOB_WIDTH) * 10 *
+                   collation.collation->mbmaxlen;
+    set_if_smaller(max_length,MAX_BLOB_WIDTH);
+  }
+  maybe_null=1;                                 // If wrong date
+  return FALSE;
+}
+
+String* Item_func_tochar::val_str(String* str)
+{
+
+  StringBuffer<64> format_buffer;
+  String *format;
+  MYSQL_TIME l_time;
+  uint size;
+  const MY_LOCALE *lc= 0;
+
+  date_conv_mode_t mode= TIME_CONV_NONE;
+  THD *thd= current_thd;
+
+  if ((null_value= args[0]->get_date(thd, &l_time,
+                                     Temporal::Options(mode, thd))))
+    return 0;
+
+  if (args[1])
+  {
+    if (!(format= args[1]->val_str(&format_buffer)) || !format->length())
+    goto null_date;
+  }
+
+  if (!max_length)
+    goto null_date;
+
+  lc= locale;
+  size= max_length;
+
+  if (size < MAX_DATE_STRING_REP_LENGTH)
+    size= MAX_DATE_STRING_REP_LENGTH;
+
+  DBUG_ASSERT(format != str);
+  if (str->alloc(size))
+    goto null_date;
+
+  /* Create the result string */
+  str->set_charset(collation.collation);
+  if (!make_date_time_oracle(format, &l_time, lc, str))
+    return str;
+
+null_date:
+  null_value= 1;
+  return 0;
+}
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 1ae62a4a6e8..47ab10abab1 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -1868,4 +1868,39 @@ class Item_func_wsrep_sync_wait_upto: public Item_int_func
 };
 #endif /* WITH_WSREP */
 
+class Item_func_tochar :public Item_str_func
+{
+  bool check_arguments() const
+  {
+    return args[0]->check_type_can_return_date(func_name()) ||
+           check_argument_types_can_return_text(1, arg_count);
+  }
+
+  const MY_LOCALE *locale;
+  int fixed_length;
+  String value;
+
+public:
+  Item_func_tochar(THD *thd, Item *a):
+    Item_str_func(thd, a), locale(0) {}
+
+  Item_func_tochar(THD *thd, Item *a, Item *b):
+    Item_str_func(thd, a, b), locale(0) {}
+
+  String *val_str(String *str);
+  const char *func_name() const { return "to_char"; }
+  bool fix_length_and_dec();
+  uint format_length(const String *format);
+
+  bool check_vcol_func_processor(void *arg)
+  {
+    if (arg_count > 2)
+      return false;
+    return mark_unsupported_function(func_name(), "()", arg, VCOL_SESSION_FUNC);
+  }
+
+  Item *get_copy(THD *thd)
+  { return get_item_copy<Item_func_tochar>(thd, this); }
+};
+
 #endif /* ITEM_STRFUNC_INCLUDED */
