Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1idHr9-0002iC-Ue for pgsql-hackers@arkaria.postgresql.org; Fri, 06 Dec 2019 17:57:32 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1idHr8-0007kB-GD for pgsql-hackers@arkaria.postgresql.org; Fri, 06 Dec 2019 17:57:30 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1idHr7-0007k4-VZ for pgsql-hackers@lists.postgresql.org; Fri, 06 Dec 2019 17:57:30 +0000 Received: from mail-vs1-xe43.google.com ([2607:f8b0:4864:20::e43]) by makus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.92) (envelope-from ) id 1idHr3-0000Rm-3x for pgsql-hackers@postgresql.org; Fri, 06 Dec 2019 17:57:28 +0000 Received: by mail-vs1-xe43.google.com with SMTP id l24so5625364vsr.12 for ; Fri, 06 Dec 2019 09:57:24 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=2ndquadrant-com.20150623.gappssmtp.com; s=20150623; h=date:from:to:cc:subject:message-id:mime-version:content-disposition :content-transfer-encoding:in-reply-to:user-agent; bh=+LJXTpmHv6vG4Xbc4x8E9DLsZstrdsBnKqIxro9QR/U=; b=cZWpXK6xN5O9Bjamiyswzb8l63jecLNAeAVq7WdySAfTA2t4fe0BgkDvPLfFiEbxm3 Nfj73N/cATNh+NVXx8FUZP+Cly/A3spMVrtMbepR0L1SZKAB/SH6wcDfbvcw9mMMKA65 my4hgUJJpalkaE91izPWituRZNF+1J1IeQcxXxDInk9JwdiODzsW/j70wbvNgKIGAqoH Fhlhr6Shd5JiC8trtBK70mBtiYGUHhS7lbGxeZLW70svH/hT6P+i66kAaGNWkv5CnVfh nvg+yeTHbV7uyUNSdvj3H1cYo2AaDgJUu3MvYO7QkhTnmiBRl5Cnd1i/y2u4H1T2F3mF w7Yg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:mime-version :content-disposition:content-transfer-encoding:in-reply-to :user-agent; bh=+LJXTpmHv6vG4Xbc4x8E9DLsZstrdsBnKqIxro9QR/U=; b=gGn9hGqOrzBJpArpZrE+XHp+eMsUlAPHal8AvjEPMsDgJ3qRwIAgse4+Yoe26Wz6ug VWrz4j0hwyo9SEo3BMXwHopsxQ7dyF5+aUOluySNReBqGjBJ9h9oKGqL5+hm9uqcTbN6 KqgbwMZjQJEYygwX1c28yNWCaZrhItpQxMf9OsPNaVhzoWfD337kkyWFR6xwQnR/5S+E aNfP3cUZ5pWz7pEMuHASUdTFvOT5vy34i6aPODO3nxTnrxsARu1WBtSivrA772HJ+pn0 BFmW/rSS8nXm9PWCgPt9XRA6kiUwX2QCY6Y4Ex98Txwm5GWpaPubc2/SG8EQZ6aOSiXx PPsg== X-Gm-Message-State: APjAAAV0BvagDFlM5XRaNAZu4YBdWRoz9GuUe3Hjq5iI1h7TbuppB3K5 NkQ3fw0wm0PYd++c1fFjuWXH1g== X-Google-Smtp-Source: APXvYqzBaR8bGzQaw8PHugjM7P3eOJWjfdzN4JItPAHP7/6hEXNDelBP8pj/BN9NSyyFedz7HBK2gg== X-Received: by 2002:a67:fad3:: with SMTP id g19mr10454665vsq.216.1575655044029; Fri, 06 Dec 2019 09:57:24 -0800 (PST) Received: from nimloth.alvh.no-ip.org ([190.121.29.3]) by smtp.gmail.com with ESMTPSA id d8sm6665104uan.13.2019.12.06.09.57.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 06 Dec 2019 09:57:22 -0800 (PST) Received: by nimloth.alvh.no-ip.org (Postfix, from userid 1000) id D2FDC30081B; Fri, 6 Dec 2019 14:57:19 -0300 (-03) Date: Fri, 6 Dec 2019 14:57:19 -0300 From: Alvaro Herrera To: Tom Lane Cc: Andres Freund , Alexey Bashtanov , Peter Eisentraut , PostgreSQL Hackers Subject: Re: log bind parameter values on error Message-ID: <20191206175719.GA15456@alvherre.pgsql> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="VbJkn9YxBvnuCH5J" Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: <27177.1575591206@sss.pgh.pa.us> User-Agent: Mutt/1.10.1 (2018-07-13) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk --VbJkn9YxBvnuCH5J Content-Type: text/plain; charset=iso-8859-1 Content-Disposition: inline Content-Transfer-Encoding: 8bit On 2019-Dec-05, Tom Lane wrote: > Possibly a workable compromise is to emit the info as an error > context line, appending it to whatever context exists today. > The result might look like, say, > > ERROR: whatever > CONTEXT: SQL function "foo" > extended query with parameters x, y, ... This is easy to accomodate -- just change the errdetail() to errcontext. That makes the params be reported different than in the non-error case (for duration). > For extra credit maybe we could include the query's statement or > portal name? > > errcontext("extended query \"%s\" with parameters %s", ...); Sure. Done in the attached. > An independent point: it seems like just wishful thinking to imagine that > src/test/examples/ can serve as a regression test for this. Nor is the > proposed program very useful as an example. I'd drop that and find a > way to have an actual, routinely-exercised-by-check-world regression > test. If memory serves, pgbench can be cajoled into executing stuff > in extended query mode --- maybe we could create a test case using > that? I tried pgbench -c1 -t1 -n -M prepared -f errparameters.bnch with this file select '{ invalid ' as value \gset select column1::jsonb from (values (:value)) as q; and got these lines: 2019-12-06 13:49:36.388 -03 [31028] ERROR: invalid input syntax for type json 2019-12-06 13:49:36.388 -03 [31028] DETAIL: Token "invalid" is invalid. 2019-12-06 13:49:36.388 -03 [31028] CONTEXT: JSON data, line 1: { invalid... extended query with parameters: $1 = '{ invalid ' 2019-12-06 13:49:36.388 -03 [31028] STATEMENT: select column1::jsonb from (values ($1)) as q; With this file, select '1' as one \gset SELECT 1 / (random() / 2)::int, :one::int, :two::int; using the same pgbench invocation as above, I get this in the log: 2019-12-06 14:50:59.181 -03 [6187] ERROR: division by zero 2019-12-06 14:50:59.181 -03 [6187] CONTEXT: extended query with parameters: $1 = '1', $2 = NULL 2019-12-06 14:50:59.181 -03 [6187] STATEMENT: SELECT 1 / (random() / 2)::int, $1::int, $2::int; (While testing this I noticed that failing to strdup the text repr of the datum when it's given as a text-format parameter results in bogus output. So I added a pstrdup there.) (It seems a bit weird that if I assign NULL to :two pgbench stores the empty string, instead of the NULL that I get as in the above which is what happens when the variable is not defined at all. That's probably a bug in \gset ...) -- Álvaro Herrera https://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services --VbJkn9YxBvnuCH5J Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="errcontext.patch" diff --git a/src/backend/nodes/params.c b/src/backend/nodes/params.c index 13d90f6551..a881df578e 100644 --- a/src/backend/nodes/params.c +++ b/src/backend/nodes/params.c @@ -23,6 +23,7 @@ #include "utils/datum.h" #include "utils/lsyscache.h" #include "utils/memutils.h" +#include "utils/portal.h" /* @@ -361,14 +362,17 @@ BuildParamLogString(ParamListInfo params, char **knownTextValues) void ParamsErrorCallback(void *arg) { - ParamListInfo params = (ParamListInfo) arg; + ParamsErrorCbData *data = (ParamsErrorCbData *) arg; - if (params == NULL || params->paramValuesStr == NULL) + if (data == NULL || + data->params == NULL || + data->params->paramValuesStr == NULL) return; - /* - * XXX this clobbers any other DETAIL line that the error callsite could - * have had. Do we care? - */ - errdetail("parameters: %s", params->paramValuesStr); + if (data->portalName && data->portalName[0] != '\0') + errcontext("extended query \"%s\" with parameters: %s", + data->portalName, data->params->paramValuesStr); + else + errcontext("extended query with parameters: %s", + data->params->paramValuesStr); } diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 9a009a5a9b..05a03ae924 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -1753,7 +1753,7 @@ exec_bind_message(StringInfo input_message) */ if (numParams > 0) { - char **knownTextValues = NULL; + char **knownTextValues = NULL; /* allocate on first use */ params = makeParamList(numParams); @@ -1822,22 +1822,19 @@ exec_bind_message(StringInfo input_message) pval = OidInputFunctionCall(typinput, pstring, typioparam, -1); - /* - * Save the parameter string if we need it; otherwise free it. - */ + /* When logging params, save a copy for later. */ if (pstring) { if (log_parameters_on_error) { - /* - * Allocate this on first use, making sure to put it - * in a short-lived context. - */ if (knownTextValues == NULL) knownTextValues = MemoryContextAllocZero(MessageContext, numParams * sizeof(char *)); - knownTextValues[paramno] = pstring; + knownTextValues[paramno] = + pstring == pbuf.data ? + MemoryContextStrdup(MessageContext, pstring) : + pstring; } else if (pstring != pbuf.data) pfree(pstring); @@ -1905,7 +1902,8 @@ exec_bind_message(StringInfo input_message) /* Set the error callback so that parameters are logged, as needed */ params_errcxt.previous = error_context_stack; params_errcxt.callback = ParamsErrorCallback; - params_errcxt.arg = (void *) params; + params_errcxt.arg = (void *) &((ParamsErrorCbData) + { portal->name, params }); error_context_stack = ¶ms_errcxt; /* Get the result format codes */ @@ -2145,7 +2143,8 @@ exec_execute_message(const char *portal_name, long max_rows) */ params_errcxt.previous = error_context_stack; params_errcxt.callback = ParamsErrorCallback; - params_errcxt.arg = (void *) portalParams; + params_errcxt.arg = (void *) &((ParamsErrorCbData) + { portal->name, portalParams }); error_context_stack = ¶ms_errcxt; if (max_rows <= 0) diff --git a/src/include/nodes/params.h b/src/include/nodes/params.h index ba51dfe5e0..1e557ca7fd 100644 --- a/src/include/nodes/params.h +++ b/src/include/nodes/params.h @@ -150,6 +150,12 @@ typedef struct ParamExecData bool isnull; } ParamExecData; +/* type of argument for ParamsErrorCallback */ +typedef struct ParamsErrorCbData +{ + const char *portalName; + ParamListInfo params; +} ParamsErrorCbData; /* Functions found in src/backend/nodes/params.c */ extern ParamListInfo makeParamList(int numParams); --VbJkn9YxBvnuCH5J--