+/*
+ * errdetail_execute
+ *
+ * Add an errdetail() line showing the query referenced by an EXECUTE, if any.
+ * The argument is the raw parsetree list.
+ */
+static int
+errdetail_execute(List *raw_parsetree_list)
+{
+ ListCell *parsetree_item;
+
+ foreach(parsetree_item, raw_parsetree_list)
+ {
+ Node *parsetree = (Node *) lfirst(parsetree_item);
+
+ if (IsA(parsetree, ExecuteStmt))
+ {
+ ExecuteStmt *stmt = (ExecuteStmt *) parsetree;
+ PreparedStatement *pstmt;
+
+ pstmt = FetchPreparedStatement(stmt->name, false);
+ if (pstmt && pstmt->plansource->query_string)
+ {
+ errdetail("prepare: %s", pstmt->plansource->query_string);
+ return 0;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * errdetail_params
+ *
+ * Add an errdetail() line showing bind-parameter data, if available.
+ */
+static int
+errdetail_params(ParamListInfo params)
+{
+ /* We mustn't call user-defined I/O functions when in an aborted xact */
+ if (params && params->numParams > 0 && !IsAbortedTransactionBlockState())
+ {
+ StringInfoData param_str;
+ MemoryContext oldcontext;
+ int paramno;
+
+ /* Make sure any trash is generated in MessageContext */
+ oldcontext = MemoryContextSwitchTo(MessageContext);
+
+ initStringInfo(¶m_str);
+
+ for (paramno = 0; paramno < params->numParams; paramno++)
+ {
+ ParamExternData *prm = ¶ms->params[paramno];
+ Oid typoutput;
+ bool typisvarlena;
+ char *pstring;
+ char *p;
+
+ appendStringInfo(¶m_str, "%s$%d = ",
+ paramno > 0 ? ", " : "",
+ paramno + 1);
+
+ if (prm->isnull || !OidIsValid(prm->ptype))
+ {
+ appendStringInfoString(¶m_str, "NULL");
+ continue;
+ }
+
+ getTypeOutputInfo(prm->ptype, &typoutput, &typisvarlena);
+
+ pstring = OidOutputFunctionCall(typoutput, prm->value);
+
+ appendStringInfoCharMacro(¶m_str, '\'');
+ for (p = pstring; *p; p++)
+ {
+ if (*p == '\'') /* double single quotes */
+ appendStringInfoCharMacro(¶m_str, *p);
+ appendStringInfoCharMacro(¶m_str, *p);
+ }
+ appendStringInfoCharMacro(¶m_str, '\'');
+
+ pfree(pstring);
+ }
+
+ errdetail("parameters: %s", param_str.data);
+
+ pfree(param_str.data);
+
+ MemoryContextSwitchTo(oldcontext);
+ }
+
+ return 0;