diff --git a/mysql-test/r/parser.result b/mysql-test/r/parser.result
index 002fbd02c2a868a6cf1d9981a25ba942cd6f9f7b..097f6dc69fff328c791b7524e206499eee669ff6 100644
--- a/mysql-test/r/parser.result
+++ b/mysql-test/r/parser.result
@@ -615,3 +615,55 @@ UPDATE t3 SET a4={d '1789-07-14'} WHERE a1=0;
 SELECT a1, a4 FROM t2 WHERE a4 LIKE {fn UCASE('1789-07-14')};
 a1	a4
 DROP TABLE t1, t2, t3;
+#
+# Bug#39559: dump of stored procedures / functions with C-style 
+#     comment can't be read back
+#
++----------+--------+
+| expected | result |
++----------+--------+
+|        2 |      2 | 
++----------+--------+
++----------+--------+
+| expected | result |
++----------+--------+
+|        1 |      1 | 
++----------+--------+
++----------+--------+
+| expected | result |
++----------+--------+
+|        3 |      3 | 
++----------+--------+
++----------+--------+
+| expected | result |
++----------+--------+
+|        2 |      2 | 
++----------+--------+
++----------+--------+
+| expected | result |
++----------+--------+
+|        7 |      7 | 
++----------+--------+
++----------+--------+
+| expected | result |
++----------+--------+
+|        8 |      8 | 
++----------+--------+
++----------+--------+
+| expected | result |
++----------+--------+
+|        7 |      7 | 
++----------+--------+
++----------+--------+
+| expected | result |
++----------+--------+
+|        4 |      4 | 
++----------+--------+
++----------+--------+
+| expected | result |
++----------+--------+
+|        4 |      4 | 
++----------+--------+
+#
+# End of 5.1 tests
+#
diff --git a/mysql-test/t/parser.test b/mysql-test/t/parser.test
index 7efc519e44185d0bf60af1281f7879799ef64677..e44fc85bc5e296b204030d33bd244ea38e9c24f0 100644
--- a/mysql-test/t/parser.test
+++ b/mysql-test/t/parser.test
@@ -724,3 +724,31 @@ SELECT {fn CONCAT(a1,a2)} FROM t1;
 UPDATE t3 SET a4={d '1789-07-14'} WHERE a1=0;
 SELECT a1, a4 FROM t2 WHERE a4 LIKE {fn UCASE('1789-07-14')};
 DROP TABLE t1, t2, t3;
+
+###########################################################################
+--echo #
+--echo # Bug#39559: dump of stored procedures / functions with C-style 
+--echo #     comment can't be read back
+--echo #
+
+--write_file $MYSQLTEST_VARDIR/tmp/bug39559.sql
+select 2 as expected, /*!01000/**/*/ 2 as result;
+select 1 as expected, /*!99998/**/*/ 1 as result;
+select 3 as expected, /*!01000 1 + */ 2 as result;
+select 2 as expected, /*!99990 1 + */ 2 as result;
+select 7 as expected, /*!01000 1 + /* 8 + */ 2 + */ 4 as result;
+select 8 as expected, /*!99998 1 + /* 2 + */ 4 + */ 8 as result;
+select 7 as expected, /*!01000 1 + /*!01000 8 + */ 2 + */ 4 as result;
+select 7 as expected, /*!01000 1 + /*!99998 8 + */ 2 + */ 4 as result;
+select 4 as expected, /*!99998 1 + /*!99998 8 + */ 2 + */ 4 as result;
+select 4 as expected, /*!99998 1 + /*!01000 8 + */ 2 + */ 4 as result;
+select 7 as expected, /*!01000 1 + /*!01000 8 + /*!01000 error */ 16 + */ 2 + */ 4 as result;
+select 4 as expected, /* 1 + /*!01000 8 + */ 2 + */ 4;
+EOF
+
+--exec $MYSQL --comment --force --table test <$MYSQLTEST_VARDIR/tmp/bug39559.sql
+--remove_file $MYSQLTEST_VARDIR/tmp/bug39559.sql
+
+--echo #
+--echo # End of 5.1 tests
+--echo #
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 19a19f2b6fbf035c41708c941674bd3046663f9c..5e24a18bea36b2d95890c1c9f61fa84b106cacf0 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -712,6 +712,53 @@ static inline uint int_token(const char *str,uint length)
   return ((uchar) str[-1] <= (uchar) cmp[-1]) ? smaller : bigger;
 }
 
+
+/**
+  Given a stream that is advanced to the first contained character in 
+  an open comment, consume the comment.  Optionally, if we are allowed, 
+  recurse so that we understand comments within this current comment.
+
+  At this level, we do not support version-condition comments.  We might 
+  have been called with having just passed one in the stream, though.  In 
+  that case, we probably want to tolerate mundane comments inside.  Thus,
+  the case for recursion.
+
+  @retval  Whether EOF reached before comment is closed.
+*/
+bool consume_comment(Lex_input_stream *lip, int remaining_recursions_permitted)
+{
+  reg1 uchar c;
+  while (! lip->eof())
+  {
+    c= lip->yyGet();
+
+    if (remaining_recursions_permitted > 0)
+    {
+      if ((c == '/') && (lip->yyPeek() == '*'))
+      {
+        lip->yySkip(); /* Eat asterisk */
+        consume_comment(lip, remaining_recursions_permitted-1);
+        continue;
+      }
+    }
+
+    if (c == '*')
+    {
+      if (lip->yyPeek() == '/')
+      {
+        lip->yySkip(); /* Eat slash */
+        return FALSE;
+      }
+    }
+
+    if (c == '\n')
+      lip->yylineno++;
+  }
+
+  return TRUE;
+}
+
+
 /*
   MYSQLlex remember the following states from the following MYSQLlex()
 
@@ -1204,6 +1251,8 @@ int MYSQLlex(void *arg, void *yythd)
       /* Reject '/' '*', since we might need to turn off the echo */
       lip->yyUnget();
 
+      lip->save_in_comment_state();
+
       if (lip->yyPeekn(2) == '!')
       {
         lip->in_comment= DISCARD_COMMENT;
@@ -1246,11 +1295,17 @@ int MYSQLlex(void *arg, void *yythd)
             /* Expand the content of the special comment as real code */
             lip->set_echo(TRUE);
             state=MY_LEX_START;
-            break;
+            break;  /* Do not treat contents as a comment.  */
+          }
+          else
+          {
+            comment_closed= ! consume_comment(lip, 1);
+            /* version allowed to have one level of comment inside. */
           }
         }
         else
         {
+          /* Not a version comment. */
           state=MY_LEX_START;
           lip->set_echo(TRUE);
           break;
@@ -1261,38 +1316,30 @@ int MYSQLlex(void *arg, void *yythd)
         lip->in_comment= PRESERVE_COMMENT;
         lip->yySkip();                  // Accept /
         lip->yySkip();                  // Accept *
+        comment_closed= ! consume_comment(lip, 0);
+        /* regular comments can have zero comments inside. */
       }
       /*
         Discard:
         - regular '/' '*' comments,
         - special comments '/' '*' '!' for a future version,
         by scanning until we find a closing '*' '/' marker.
-        Note: There is no such thing as nesting comments,
-        the first '*' '/' sequence seen will mark the end.
+
+        Nesting regular comments isn't allowed.  The first 
+        '*' '/' returns the parser to the previous state.
+
+        /#!VERSI oned containing /# regular #/ is allowed #/
+
+		Inside one versioned comment, another versioned comment
+		is treated as a regular discardable comment.  It gets
+		no special parsing.
       */
-      comment_closed= FALSE;
-      while (! lip->eof())
-      {
-        c= lip->yyGet();
-        if (c == '*')
-        {
-          if (lip->yyPeek() == '/')
-          {
-            lip->yySkip();
-            comment_closed= TRUE;
-            state = MY_LEX_START;
-            break;
-          }
-        }
-        else if (c == '\n')
-          lip->yylineno++;
-      }
+
       /* Unbalanced comments with a missing '*' '/' are a syntax error */
       if (! comment_closed)
         return (ABORT_SYM);
       state = MY_LEX_START;             // Try again
-      lip->in_comment= NO_COMMENT;
-      lip->set_echo(TRUE);
+      lip->restore_in_comment_state();
       break;
     case MY_LEX_END_LONG_COMMENT:
       if ((lip->in_comment != NO_COMMENT) && lip->yyPeek() == '/')
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index a48b99d07c791cbf24d4efb4b41f215e851860d0..cf825a57fd5df5c8700311cc8cfb310103e50f3d 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -1160,6 +1160,18 @@ class Lex_input_stream
     m_echo= echo;
   }
 
+  void save_in_comment_state()
+  {
+    m_echo_saved= m_echo;
+    in_comment_saved= in_comment;
+  }
+
+  void restore_in_comment_state()
+  {
+    m_echo= m_echo_saved;
+    in_comment= in_comment_saved;
+  }
+
   /**
     Skip binary from the input stream.
     @param n number of bytes to accept.
@@ -1417,6 +1429,7 @@ class Lex_input_stream
 
   /** Echo the parsed stream to the pre-processed buffer. */
   bool m_echo;
+  bool m_echo_saved;
 
   /** Pre-processed buffer. */
   char *m_cpp_buf;
@@ -1479,6 +1492,7 @@ class Lex_input_stream
 
   /** State of the lexical analyser for comments. */
   enum_comment_state in_comment;
+  enum_comment_state in_comment_saved;
 
   /**
     Starting position of the TEXT_STRING or IDENT in the pre-processed