diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index f869e159d6..bbe0dee8c6 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -41,6 +41,8 @@
 /* GUC parameters */
 bool		Transform_null_equals = false;
 
+/* Hook for plugins to get control in transformExprRecurse() */
+parse_expr_hook_type parse_expr_hook = NULL;
 
 static Node *transformExprRecurse(ParseState *pstate, Node *expr);
 static Node *transformParamRef(ParseState *pstate, ParamRef *pref);
@@ -307,9 +309,14 @@ transformExprRecurse(ParseState *pstate, Node *expr)
 			}
 
 		default:
-			/* should not reach here */
-			elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
-			result = NULL;		/* keep compiler quiet */
+			if (parse_expr_hook)
+				result = (*parse_expr_hook) (pstate, expr);
+			else
+			{
+				/* should not reach here */
+				elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
+				result = NULL;		/* keep compiler quiet */
+			}
 			break;
 	}
 
diff --git a/src/backend/parser/parser.c b/src/backend/parser/parser.c
index 875de7ba28..0dabbcecc5 100644
--- a/src/backend/parser/parser.c
+++ b/src/backend/parser/parser.c
@@ -26,6 +26,9 @@
 #include "parser/parser.h"
 #include "parser/scansup.h"
 
+/* Hook for plugins to get control in raw_parser() */
+parser_hook_type parser_hook = NULL;
+
 static bool check_uescapechar(unsigned char escape);
 static char *str_udeescape(const char *str, char escape,
 						   int position, core_yyscan_t yyscanner);
@@ -40,6 +43,18 @@ static char *str_udeescape(const char *str, char escape,
  */
 List *
 raw_parser(const char *str, RawParseMode mode)
+{
+	List *result;
+
+	if (parser_hook)
+		result = (*parser_hook) (str, mode);
+	else
+		result = standard_raw_parser(str, mode);
+	return result;
+}
+
+List *
+standard_raw_parser(const char *str, RawParseMode mode)
 {
 	core_yyscan_t yyscanner;
 	base_yy_extra_type yyextra;
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 05bb698cf4..6a69599db6 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -3101,7 +3101,9 @@ CreateCommandTag(Node *parsetree)
 				}
 			}
 			break;
-
+		case T_ExtensibleNode:
+			tag = CMDTAG_EXTENDED_COMMAND;
+			break;
 		default:
 			elog(WARNING, "unrecognized node type: %d",
 				 (int) nodeTag(parsetree));
diff --git a/src/include/parser/parse_expr.h b/src/include/parser/parse_expr.h
index 8ac4a0a369..6465a8d03e 100644
--- a/src/include/parser/parse_expr.h
+++ b/src/include/parser/parse_expr.h
@@ -15,6 +15,10 @@
 
 #include "parser/parse_node.h"
 
+/* Hook for plugins to get control in transformExprRecurse() */
+typedef Node *(*parse_expr_hook_type) (ParseState *pstate, Node *expr);
+extern PGDLLIMPORT parse_expr_hook_type parse_expr_hook;
+
 /* GUC parameters */
 extern bool Transform_null_equals;
 
diff --git a/src/include/parser/parser.h b/src/include/parser/parser.h
index 853b0f1606..8b1b915410 100644
--- a/src/include/parser/parser.h
+++ b/src/include/parser/parser.h
@@ -57,9 +57,13 @@ extern int	backslash_quote;
 extern bool escape_string_warning;
 extern PGDLLIMPORT bool standard_conforming_strings;
 
+/* Hook for plugins to get control in raw_parser() */
+typedef List *(*parser_hook_type) (const char *str, RawParseMode mode);;
+extern PGDLLIMPORT parser_hook_type parser_hook;
 
 /* Primary entry point for the raw parsing functions */
 extern List *raw_parser(const char *str, RawParseMode mode);
+extern List *standard_raw_parser(const char *str, RawParseMode mode);
 
 /* Utility functions exported by gram.y (perhaps these should be elsewhere) */
 extern List *SystemFuncName(char *name);
diff --git a/src/include/tcop/cmdtaglist.h b/src/include/tcop/cmdtaglist.h
index 9ba24d4ca9..c0d3427db5 100644
--- a/src/include/tcop/cmdtaglist.h
+++ b/src/include/tcop/cmdtaglist.h
@@ -178,6 +178,7 @@ PG_CMDTAG(CMDTAG_DROP_USER_MAPPING, "DROP USER MAPPING", true, false, false)
 PG_CMDTAG(CMDTAG_DROP_VIEW, "DROP VIEW", true, false, false)
 PG_CMDTAG(CMDTAG_EXECUTE, "EXECUTE", false, false, false)
 PG_CMDTAG(CMDTAG_EXPLAIN, "EXPLAIN", false, false, false)
+PG_CMDTAG(CMDTAG_EXTENDED_COMMAND, "EXTENDED COMMAND", false, false, false)
 PG_CMDTAG(CMDTAG_FETCH, "FETCH", false, false, true)
 PG_CMDTAG(CMDTAG_GRANT, "GRANT", true, false, false)
 PG_CMDTAG(CMDTAG_GRANT_ROLE, "GRANT ROLE", false, false, false)
