diff --git a/src/interfaces/ecpg/ecpglib/execute.c b/src/interfaces/ecpg/ecpglib/execute.c
index 8e61339..ab9e7f9 100644
--- a/src/interfaces/ecpg/ecpglib/execute.c
+++ b/src/interfaces/ecpg/ecpglib/execute.c
@@ -1190,6 +1190,23 @@ store_input_from_desc(struct statement *stmt, struct descriptor_item *desc_item,
 	return true;
 }
 
+static void
+replace_param_marks_in_as_clause(char *text, bool std_strings)
+{
+	int	p;
+	bool	string = false;
+
+	for (p = 0; text[p]; ++p)
+	{
+		if (string && !std_strings && text[p] == '\\')	/* escape character */
+			p++;
+		else if (text[p] == '\'')
+			string = string ? false : true;
+		else if (!string && text[p] == '@')
+			text[p] = '$';
+	}
+}
+
 /*
  * ecpg_build_params
  *		Build statement parameters
@@ -1502,6 +1519,8 @@ ecpg_build_params(struct statement *stmt)
 		return false;
 	}
 
+	replace_param_marks_in_as_clause(stmt->command, std_strings);
+
 	return true;
 }
 
diff --git a/src/interfaces/ecpg/preproc/ecpg.addons b/src/interfaces/ecpg/preproc/ecpg.addons
index e805281..5340136 100644
--- a/src/interfaces/ecpg/preproc/ecpg.addons
+++ b/src/interfaces/ecpg/preproc/ecpg.addons
@@ -20,11 +20,18 @@ ECPG: stmtSelectStmt block
 ECPG: stmtUpdateStmt block
 	{ output_statement($1, 1, ECPGst_prepnormal); }
 ECPG: stmtExecuteStmt block
-	{ output_statement($1, 1, ECPGst_execute); }
-ECPG: stmtPrepareStmt block
 	{
 		if ($1.type == NULL || strlen($1.type) == 0)
+			output_statement($1.name, 1, ECPGst_execute);
+		else
+			output_statement($1.stmt, 0, ECPGst_normal);
+	}
+ECPG: stmtPrepareStmt block
+	{
+		if ($1.type == NULL)
 			output_prepare_statement($1.name, $1.stmt);
+		else if (strlen($1.type) == 0)
+			output_prepare_statement($1.name, cat_str(3, mm_strdup("\""), $1.stmt, mm_strdup("\"")));
 		else
 			output_statement(cat_str(5, mm_strdup("prepare"), $1.name, $1.type, mm_strdup("as"), $1.stmt), 0, ECPGst_normal);
 	}
@@ -276,20 +283,28 @@ ECPG: cursor_namename rule
 			$1 = curname;
 			$$ = $1;
 		}
-ECPG: PrepareStmtPREPAREprepared_nameprep_type_clauseASPreparableStmt block
+ECPG: ExecuteStmtEXECUTEprepared_nameexecute_param_clauseexecute_rest block
 	{
-		$$.name = $2;
+		$$.name = mm_strdup($2);
+		$$.stmt = cat_str(4, mm_strdup("execute"), $2, mm_strdup($3), $4);
 		$$.type = $3;
-		$$.stmt = cat_str(3, mm_strdup("\""), $5, mm_strdup("\""));
 	}
-	| PREPARE prepared_name FROM execstring
+ECPG: ExecuteStmtCREATEOptTempTABLEcreate_as_targetASEXECUTEnameexecute_param_clauseopt_with_data block
 	{
-		$$.name = $2;
+		$$.name = cat_str(8,mm_strdup("create"),$2,mm_strdup("table"),$4,mm_strdup("as execute"),$7,$8,$9);
+		$$.stmt = NULL;
 		$$.type = NULL;
-		$$.stmt = $4;
 	}
-ECPG: ExecuteStmtEXECUTEprepared_nameexecute_param_clauseexecute_rest block
-	{ $$ = $2; }
+ECPG: ExecuteStmtCREATEOptTempTABLEIF_PNOTEXISTScreate_as_targetASEXECUTEnameexecute_param_clauseopt_with_data block
+	{
+		$$.name = cat_str(8,mm_strdup("create"),$2,mm_strdup("table if not exists"),$7,mm_strdup("as execute"),$10,$11,$12);
+		$$.stmt = NULL;
+		$$.type = NULL;
+	}
+ECPG: ExplainableStmtExecuteStmt block
+	{
+		$$ = $1.stmt;
+	}
 ECPG: DeclareCursorStmtDECLAREcursor_namecursor_optionsCURSORopt_holdFORSelectStmt block
 	{
 		struct cursor *ptr, *this;
diff --git a/src/interfaces/ecpg/preproc/ecpg.header b/src/interfaces/ecpg/preproc/ecpg.header
index 366dc23..6462121 100644
--- a/src/interfaces/ecpg/preproc/ecpg.header
+++ b/src/interfaces/ecpg/preproc/ecpg.header
@@ -48,6 +48,9 @@ static struct this_type actual_type[STRUCT_DEPTH];
 static char *actual_startline[STRUCT_DEPTH];
 static int	varchar_counter = 1;
 static int	bytea_counter = 1;
+static bool	is_in_preparable_stmt = false;
+static char *prepared_name = NULL;
+static char *prepare_type_clause = NULL;
 
 /* temporarily store struct members while creating the data structure */
 struct ECPGstruct_member *struct_member_list[STRUCT_DEPTH] = { NULL };
@@ -201,6 +204,14 @@ make_name(void)
 }
 
 static char *
+replace_params_to_special_notation()
+{
+	char *p = mm_strdup(base_yytext);
+	*p = '@';
+	return p;
+}
+
+static char *
 create_questionmarks(char *name, bool array)
 {
 	struct variable *p = find_variable(name);
@@ -574,6 +585,7 @@ add_typedef(char *name, char *dimension, char *length, enum ECPGttype type_enum,
 		types = this;
 	}
 }
+
 %}
 
 %expect 0
@@ -593,4 +605,5 @@ add_typedef(char *name, char *dimension, char *length, enum ECPGttype type_enum,
 	struct	fetch_desc	descriptor;
 	struct  su_symbol	struct_union;
 	struct	prep		prep;
+	struct	exec		exec;
 }
diff --git a/src/interfaces/ecpg/preproc/ecpg.trailer b/src/interfaces/ecpg/preproc/ecpg.trailer
index 1d58c77..1ba139e 100644
--- a/src/interfaces/ecpg/preproc/ecpg.trailer
+++ b/src/interfaces/ecpg/preproc/ecpg.trailer
@@ -45,6 +45,27 @@ CreateAsStmt: CREATE OptTemp TABLE create_as_target AS {FoundInto = 0;} SelectSt
 		}
 		;
 
+PrepareStmt: PREPARE prepared_name prep_type_clause AS
+	{
+		prepared_name = $2;
+		prepare_type_clause = $3;
+		is_in_preparable_stmt = true;
+	}
+	PreparableStmt
+	{
+		$$.name = prepared_name;
+		$$.type = mm_strdup(prepare_type_clause);
+		$$.stmt = $6;
+		is_in_preparable_stmt = false;
+	}
+	| PREPARE prepared_name FROM execstring
+	{
+		$$.name = $2;
+		$$.type = NULL;
+		$$.stmt = $4;
+	}
+	;
+
 at: AT connection_object
 		{
 			connection = $2;
@@ -1775,7 +1796,14 @@ cvariable:	CVARIABLE
 		}
 		;
 
-ecpg_param:	PARAM		{ $$ = make_name(); } ;
+ecpg_param:	PARAM
+	{
+		if (is_in_preparable_stmt)
+			$$ = replace_params_to_special_notation();
+		else
+			$$ = make_name();
+	}
+	;
 
 ecpg_bconst:	BCONST		{ $$ = make_name(); } ;
 
diff --git a/src/interfaces/ecpg/preproc/ecpg.type b/src/interfaces/ecpg/preproc/ecpg.type
index 519b737..da77a85 100644
--- a/src/interfaces/ecpg/preproc/ecpg.type
+++ b/src/interfaces/ecpg/preproc/ecpg.type
@@ -145,3 +145,6 @@
 %type  <type>   var_type
 
 %type  <action> action
+
+%type  <prep> PrepareStmt
+
diff --git a/src/interfaces/ecpg/preproc/parse.pl b/src/interfaces/ecpg/preproc/parse.pl
index 6f67a5e..9521a94 100644
--- a/src/interfaces/ecpg/preproc/parse.pl
+++ b/src/interfaces/ecpg/preproc/parse.pl
@@ -58,6 +58,7 @@ my %replace_string = (
 # ECPG-only replace_types are defined in ecpg-replace_types
 my %replace_types = (
 	'PrepareStmt'      => '<prep>',
+	'ExecuteStmt'      => '<exec>',
 	'opt_array_bounds' => '<index>',
 
 	# "ignore" means: do not create type and rules for this non-term-id
@@ -65,6 +66,7 @@ my %replace_types = (
 	'stmtmulti'          => 'ignore',
 	'CreateAsStmt'       => 'ignore',
 	'DeallocateStmt'     => 'ignore',
+	'PrepareStmt'	     => 'ignore',
 	'ColId'              => 'ignore',
 	'type_function_name' => 'ignore',
 	'ColLabel'           => 'ignore',
diff --git a/src/interfaces/ecpg/preproc/type.h b/src/interfaces/ecpg/preproc/type.h
index 94377ff..e913f05 100644
--- a/src/interfaces/ecpg/preproc/type.h
+++ b/src/interfaces/ecpg/preproc/type.h
@@ -106,6 +106,13 @@ struct prep
 	char	   *type;
 };
 
+struct exec
+{
+	char	   *name;
+	char	   *stmt;
+	char	   *type;
+};
+
 struct this_type
 {
 	enum ECPGttype type_enum;
