diff -au sql/set_var.cc.orig sql/set_var.cc
--- sql/set_var.cc.orig	2007-09-03 19:17:28.000000000 -0400
+++ sql/set_var.cc	2007-09-04 17:48:12.000000000 -0400
@@ -69,6 +69,10 @@
 extern ulong ndb_report_thresh_binlog_mem_usage;
 #endif
 
+/* dynamically-loaded parsers */
+#include "dyn_parser.h"
+#include <dlfcn.h>
+
 extern CHARSET_INFO *character_set_filesystem;
 
 
@@ -88,6 +92,8 @@
   delay_key_write_type_names, NULL
 };
 
+struct dynamic_parser_info dynamic_parsers[3];
+
 static int  sys_check_ftb_syntax(THD *thd,  set_var *var);
 static bool sys_update_ftb_syntax(THD *thd, set_var * var);
 static void sys_default_ftb_syntax(THD *thd, enum_var_type type);
@@ -117,6 +123,11 @@
 static void fix_max_relay_log_size(THD *thd, enum_var_type type);
 static void fix_max_connections(THD *thd, enum_var_type type);
 static int check_max_delayed_threads(THD *thd, set_var *var);
+static int  sys_check_parser(THD *thd,  set_var *var);
+static bool sys_update_parserN(THD *thd, set_var * var, uchar parser);
+static bool sys_update_parser0(THD *thd, set_var * var);
+static bool sys_update_parser1(THD *thd, set_var * var);
+static bool sys_update_parser2(THD *thd, set_var * var);
 static void fix_thd_mem_root(THD *thd, enum_var_type type);
 static void fix_trans_mem_root(THD *thd, enum_var_type type);
 static void fix_server_id(THD *thd, enum_var_type type);
@@ -348,6 +359,21 @@
                                                   &SV::optimizer_prune_level);
 static sys_var_thd_ulong        sys_optimizer_search_depth(&vars, "optimizer_search_depth",
                                                    &SV::optimizer_search_depth);
+static sys_var_str              sys_dynamic_parser0(&vars, "dynamic_parser1",
+                                          sys_check_parser,
+                                          sys_update_parser0,
+                                          0,
+                                          dynamic_parsers[0].name);
+static sys_var_str              sys_dynamic_parser1(&vars, "dynamic_parser2",
+                                          sys_check_parser,
+                                          sys_update_parser1,
+                                          0,
+                                          dynamic_parsers[1].name);
+static sys_var_str              sys_dynamic_parser2(&vars, "dynamic_parser3",
+                                          sys_check_parser,
+                                          sys_update_parser2,
+                                          0,
+                                          dynamic_parsers[2].name);
 
 const char *optimizer_use_mrr_names[] = {"auto", "force", "disable", NullS};
 TYPELIB optimizer_use_mrr_typelib= {
@@ -828,6 +854,44 @@
 	  sizeof(ft_boolean_syntax)-1);
 }
 
+static int sys_check_parser(THD *thd, set_var *var)
+{
+  if (thd->security_ctx->master_access & SUPER_ACL) {
+    void* lib = dlopen(var->value->str_value.ptr(), RTLD_NOW);
+    if (lib) {
+      dlclose(lib);
+      return 0;
+    }
+    else
+    {
+      char* errstr = dlerror();
+      my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), errstr); // !!! need new error
+      return 1;
+    }
+  }
+  else
+  {
+    my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER");
+    return 1;
+  }
+}
+
+static bool sys_update_parserN(THD *thd, set_var * var, uchar parser)
+{
+  strmake(dynamic_parsers[parser].name, var->value->str_value.c_ptr(),
+	  sizeof(dynamic_parsers[parser].name)-1);
+  if (dynamic_parsers[parser].handle)
+    dlclose(dynamic_parsers[parser].handle);
+  dynamic_parsers[parser].handle = dlopen(dynamic_parsers[parser].name, RTLD_NOW);
+  dynamic_parsers[parser].initialize = (t_initialize*)dlsym(dynamic_parsers[parser].handle, "_Z10initializeP3THDPPc");
+  return 0;
+}
+static bool sys_update_parser0(THD *thd, set_var * var)
+{ return sys_update_parserN(thd, var, 0); }
+static bool sys_update_parser1(THD *thd, set_var * var)
+{ return sys_update_parserN(thd, var, 1); }
+static bool sys_update_parser2(THD *thd, set_var * var)
+{ return sys_update_parserN(thd, var, 2); }
 
 /*
   If one sets the LOW_PRIORIY UPDATES flag, we also must change the
diff -au client/mysqltest.c.orig client/mysqltest.c
--- client/mysqltest.c.orig	2007-09-03 19:07:45.000000000 -0400
+++ client/mysqltest.c	2007-09-03 14:51:56.000000000 -0400
@@ -500,7 +500,7 @@
   struct st_connection *cn= (struct st_connection*)arg;
 
   mysql_thread_init();
-  VOID(mysql_send_query(&cn->mysql, cn->cur_query, cn->cur_query_len));
+  VOID(mysql_send_query(&cn->mysql, cn->cur_query, cn->cur_query_len, 0));
 
   mysql_thread_end();
   pthread_mutex_lock(&cn->mutex);
@@ -517,7 +517,7 @@
   pthread_t tid;
 
   if (flags & QUERY_REAP_FLAG)
-    return mysql_send_query(&cn->mysql, q, q_len);
+	  return mysql_send_query(&cn->mysql, q, q_len, 0);
 
   if (pthread_mutex_init(&cn->mutex, NULL) ||
       pthread_cond_init(&cn->cond, NULL))
@@ -534,7 +534,7 @@
 
 #else /*EMBEDDED_LIBRARY*/
 
-#define do_send_query(cn,q,q_len,flags) mysql_send_query(&cn->mysql, q, q_len)
+#define do_send_query(cn,q,q_len,flags) mysql_send_query(&cn->mysql, q, q_len, 0)
 
 #endif /*EMBEDDED_LIBRARY*/
 
diff -au client/mysql.cc.orig client/mysql.cc
--- client/mysql.cc.orig	2007-09-03 19:07:45.000000000 -0400
+++ client/mysql.cc	2007-09-03 14:52:29.000000000 -0400
@@ -1828,7 +1828,17 @@
   for (uint retry=0;; retry++)
   {
     int error;
-    if (!mysql_real_query(&mysql,buf,length))
+    uchar parser = 0;
+    if (!strncmp(buf, "parser", 6) && buf[6] != 0 && buf[7] == ':') {
+      parser = buf[6]-'0';
+      if (parser > 0 || parser < PARSERS) {
+	buf += 8;
+	length -= 8;
+      } else {
+	// !!! error: invalid parser
+      }
+    }
+    if (!mysql_parser_query(&mysql,buf,length,parser))
       return 0;
     error= put_error(&mysql);
     if (mysql_errno(&mysql) != CR_SERVER_GONE_ERROR || retry > 1 ||
diff -au sql/sql_parse.cc.orig sql/sql_parse.cc
--- sql/sql_parse.cc.orig	2007-08-26 04:36:04.000000000 -0400
+++ sql/sql_parse.cc	2007-09-05 09:54:19.000000000 -0400
@@ -28,6 +28,10 @@
 #include "events.h"
 #include "sql_trigger.h"
 
+/* dynamically-loaded parsers */
+#include "dyn_parser.h"
+#include <dlfcn.h>
+
 /**
   @defgroup Runtime_Environment Runtime Environment
   @{
@@ -80,6 +84,10 @@
   { C_STRING_WITH_LEN("Set option") },
   { C_STRING_WITH_LEN("Fetch") },
   { C_STRING_WITH_LEN("Daemon") },
+  { C_STRING_WITH_LEN("Parser 0") },
+  { C_STRING_WITH_LEN("Parser 1") },
+  { C_STRING_WITH_LEN("Parser 2") },
+  { C_STRING_WITH_LEN("Parser 3") },
   { C_STRING_WITH_LEN("Error") }  // Last command number
 };
 
@@ -431,7 +439,7 @@
     */
     thd->query_id=next_query_id();
     thd->set_time();
-    mysql_parse(thd, thd->query, length, & found_semicolon);
+    mysql_parse(thd, thd->query, length, & found_semicolon, 0);
     close_thread_tables(thd);			// Free tables
 
     if (thd->is_fatal_error)
@@ -842,6 +850,9 @@
     break;
   }
   case COM_QUERY:
+  case COM_PARSER1:
+  case COM_PARSER2:
+  case COM_PARSER3:
   {
     if (alloc_query(thd, packet, packet_length))
       break;					// fatal error is set
@@ -856,7 +867,8 @@
     if (!(specialflag & SPECIAL_NO_PRIOR))
       my_pthread_setprio(pthread_self(),QUERY_PRIOR);
 
-    mysql_parse(thd, thd->query, thd->query_length, & found_semicolon);
+    int parser = command == COM_QUERY ? 0 : command - COM_PARSER0;
+    mysql_parse(thd, thd->query, thd->query_length, & found_semicolon, parser);
 
     while (!thd->killed && found_semicolon && !thd->net.report_error)
     {
@@ -885,7 +897,7 @@
       thd->set_time(); /* Reset the query start time. */
       /* TODO: set thd->lex->sql_command to SQLCOM_END here */
       VOID(pthread_mutex_unlock(&LOCK_thread_count));
-      mysql_parse(thd, next_packet, length, & found_semicolon);
+      mysql_parse(thd, next_packet, length, & found_semicolon, parser);
     }
 
     if (!(specialflag & SPECIAL_NO_PRIOR))
@@ -5302,7 +5314,7 @@
 */
 
 void mysql_parse(THD *thd, const char *inBuf, uint length,
-                 const char ** found_semicolon)
+                 const char ** found_semicolon, uchar parser)
 {
   DBUG_ENTER("mysql_parse");
 
@@ -5336,7 +5348,24 @@
 
     Lex_input_stream lip(thd, inBuf, length);
 
-    bool err= parse_sql(thd, &lip, NULL);
+    bool err;
+    if (parser == 0) {
+      err= parse_sql(thd, &lip, NULL);
+    } else {
+      struct dynamic_parser_info* p = &dynamic_parsers[parser-1];
+      if (p->initialize) {
+	char* space = (char*)malloc(strlen(lip.get_ptr())+1);
+	strcpy(space, lip.get_ptr());
+
+	Dynamic_parser* parser = p->initialize(thd, &space);
+	err= parser->parse();
+	delete parser;
+      } else {
+	my_error(ER_WRONG_DB_NAME ,MYF(0), "parser not loaded");//!!!need error
+	err= 1;
+      }
+    }
+
     *found_semicolon= lip.found_semicolon;
 
     if (!err)
@@ -7160,6 +7189,14 @@
   return err_status;
 }
 
+
+/* fill Dynamic_parser's vtable with dummy functions */
+int Dynamic_parser::parse() {
+}
+
+Dynamic_parser::~Dynamic_parser() {
+}
+
 /**
   @} (end of group Runtime_Environment)
 */
diff -au sql-common/client.c.orig sql-common/client.c
--- sql-common/client.c.orig	2007-09-03 19:07:45.000000000 -0400
+++ sql-common/client.c	2007-09-05 07:54:48.000000000 -0400
@@ -2757,7 +2757,8 @@
 */
 
 int STDCALL
-mysql_send_query(MYSQL* mysql, const char* query, ulong length)
+mysql_send_query(MYSQL* mysql, const char* query, 
+		 ulong length, unsigned char parser)
 {
   DBUG_ENTER("mysql_send_query");
   DBUG_PRINT("enter",("rpl_parse: %d  rpl_pivot: %d",
@@ -2777,7 +2778,8 @@
   mysql->last_used_con = mysql;
 #endif
 
-  DBUG_RETURN(simple_command(mysql, COM_QUERY, (uchar*) query, length, 1));
+  enum enum_server_command command = parser ? COM_PARSER0 + parser : COM_QUERY;
+  DBUG_RETURN(simple_command(mysql, command, (uchar*) query, length, 1));
 }
 
 
@@ -2788,7 +2790,20 @@
   DBUG_PRINT("enter",("handle: 0x%lx", (long) mysql));
   DBUG_PRINT("query",("Query = '%-.4096s'",query));
 
-  if (mysql_send_query(mysql,query,length))
+  if (mysql_send_query(mysql,query,length,0))
+    DBUG_RETURN(1);
+  DBUG_RETURN((int) (*mysql->methods->read_query_result)(mysql));
+}
+
+
+int STDCALL
+mysql_parser_query(MYSQL *mysql, const char *query, ulong length, uchar parser)
+{
+  DBUG_ENTER("mysql_real_query");
+  DBUG_PRINT("enter",("handle: 0x%lx", (long) mysql));
+  DBUG_PRINT("query",("Query = '%-.4096s'",query));
+
+  if (mysql_send_query(mysql,query,length,parser))
     DBUG_RETURN(1);
   DBUG_RETURN((int) (*mysql->methods->read_query_result)(mysql));
 }
diff -au sql/slave.cc.orig sql/slave.cc
diff -au sql/log_event.cc.orig sql/log_event.cc
--- sql/log_event.cc.orig	2007-09-03 19:07:45.000000000 -0400
+++ sql/log_event.cc	2007-09-03 14:53:12.000000000 -0400
@@ -2083,7 +2083,7 @@
       
       /* Execute the query (note that we bypass dispatch_command()) */
       const char* found_semicolon= NULL;
-      mysql_parse(thd, thd->query, thd->query_length, &found_semicolon);
+      mysql_parse(thd, thd->query, thd->query_length, &found_semicolon, 0);
       log_slow_statement(thd);
     }
     else
diff -au sql/mysql_priv.h.orig sql/mysql_priv.h
--- sql/mysql_priv.h.orig	2007-08-26 18:38:30.000000000 -0400
+++ sql/mysql_priv.h	2007-09-03 14:53:51.000000000 -0400
@@ -970,7 +970,7 @@
                      bool force_switch);
 
 void mysql_parse(THD *thd, const char *inBuf, uint length,
-                 const char ** semicolon);
+                 const char ** semicolon, uchar parser);
 
 bool mysql_test_parse_for_slave(THD *thd,char *inBuf,uint length);
 bool is_update_query(enum enum_sql_command command);
diff -au include/mysql_com.h.orig include/mysql_com.h
--- include/mysql_com.h.orig	2007-08-25 15:13:27.000000000 -0400
+++ include/mysql_com.h	2007-09-03 14:54:03.000000000 -0400
@@ -60,6 +60,7 @@
   servers won't be able to handle them as 'unsupported'.
 */
 
+#define PARSERS 3 // c.f. COM_PARSER1, COM_PARSER2, COM_PARSER3 below
 enum enum_server_command
 {
   COM_SLEEP, COM_QUIT, COM_INIT_DB, COM_QUERY, COM_FIELD_LIST,
@@ -69,6 +70,11 @@
   COM_TABLE_DUMP, COM_CONNECT_OUT, COM_REGISTER_SLAVE,
   COM_STMT_PREPARE, COM_STMT_EXECUTE, COM_STMT_SEND_LONG_DATA, COM_STMT_CLOSE,
   COM_STMT_RESET, COM_SET_OPTION, COM_STMT_FETCH, COM_DAEMON,
+
+  /* add-on parsers */
+  COM_PARSER0, /* !!! change to COM_QUERY on next protocol change */
+  COM_PARSER1, COM_PARSER2, COM_PARSER3, 
+
   /* don't forget to update const char *command_name[] in sql_parse.cc */
 
   /* Must be last */
diff -au include/mysql.h.orig include/mysql.h
--- include/mysql.h.orig	2007-09-03 19:07:45.000000000 -0400
+++ include/mysql.h	2007-09-03 14:54:03.000000000 -0400
@@ -446,9 +446,13 @@
 int		STDCALL mysql_select_db(MYSQL *mysql, const char *db);
 int		STDCALL mysql_query(MYSQL *mysql, const char *q);
 int		STDCALL mysql_send_query(MYSQL *mysql, const char *q,
-					 unsigned long length);
+					 unsigned long length, 
+					 unsigned char parser);
 int		STDCALL mysql_real_query(MYSQL *mysql, const char *q,
-					unsigned long length);
+					 unsigned long length);
+int		STDCALL mysql_parser_query(MYSQL *mysql, const char *q,
+					   unsigned long length,
+					   unsigned char parser);
 MYSQL_RES *     STDCALL mysql_store_result(MYSQL *mysql);
 MYSQL_RES *     STDCALL mysql_use_result(MYSQL *mysql);
 
diff -au include/dyn_parser.h.orig include/dyn_parser.h
--- include/dyn_parser.h.orig	2007-09-03 19:10:02.000000000 -0400
+++ include/dyn_parser.h	2007-09-03 19:09:52.000000000 -0400
@@ -0,0 +1,33 @@
+#ifndef _dyn_parser_h
+#define _dyn_parser_h
+/*-- use only from C++
+  #ifdef  __cplusplus
+  extern "C" {
+  #endif
+*/
+
+class Dynamic_parser {
+
+public:
+  Dynamic_parser(THD *thd, char** ptr) {
+    this->thd= thd;
+  }
+  virtual ~Dynamic_parser();
+  virtual int parse();
+
+  THD *thd;
+};
+extern "C" {
+  typedef Dynamic_parser* t_initialize(THD *, char **);
+}
+
+struct dynamic_parser_info {
+  char name[FN_REFLEN];
+  void* handle;
+  t_initialize* initialize;
+  //  Dynamic_parser* (*initialize)(THD *, char **);
+};
+extern struct dynamic_parser_info dynamic_parsers[];
+
+#endif /* _dyn_parser_h */
+
diff -au sql/backup/meta_backup.cc.orig sql/backup/meta_backup.cc
--- sql/backup/meta_backup.cc.orig	2007-09-03 21:55:06.000000000 -0400
+++ sql/backup/meta_backup.cc	2007-09-03 21:55:43.000000000 -0400
@@ -361,7 +361,7 @@
   pthread_mutex_unlock(&::LOCK_thread_count);
 
   const char *ptr;
-  ::mysql_parse(thd,thd->query,thd->query_length,&ptr);
+  ::mysql_parse(thd,thd->query,thd->query_length,&ptr,0);
 
   thd->net.vio= save_vio;
 
diff -au sql/ha_ndbcluster_binlog.cc.orig sql/ha_ndbcluster_binlog.cc
--- sql/ha_ndbcluster_binlog.cc.orig	2007-09-03 21:56:23.000000000 -0400
+++ sql/ha_ndbcluster_binlog.cc	2007-09-03 21:56:28.000000000 -0400
@@ -277,7 +277,7 @@
     thd->options&= ~OPTION_BIN_LOG;
     
   DBUG_PRINT("query", ("%s", thd->query));
-  mysql_parse(thd, thd->query, thd->query_length, &found_semicolon);
+  mysql_parse(thd, thd->query, thd->query_length, &found_semicolon, 0);
 
   if (no_print_error && thd->query_error)
   {
