More deficiencies in outfuncs/readfuncs processing

From: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
To: pgsql-hackers(at)lists(dot)postgresql(dot)org
Subject: More deficiencies in outfuncs/readfuncs processing
Date: 2018-09-16 23:03:12
Message-ID: 17114.1537138992@sss.pgh.pa.us
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

The report in

https://www.postgresql.org/message-id/flat/3690074f-abd2-56a9-144a-aa5545d7a291%40postgrespro.ru

set off substantial alarm bells for me about whether outfuncs/readfuncs
processing had any additional problems we'd failed to notice. I thought
that to investigate that, it'd be a good idea to invent a debugging option
comparable to COPY_PARSE_PLAN_TREES, except it passes all parse and plan
trees through nodeToString + stringToNode rather than copyObject. I did
so, and darn if a number of creepy-crawlies didn't get shaken out of the
woodwork immediately. The first attached patch adds that debugging option
(plus some hackery I'll explain in a moment). I propose that some form of
this should go into HEAD and we should configure at least one buildfarm
animal to enable it. The second attached patch fixes the bugs I found;
parts of it need to get back-patched.

This debugging option also exposes the XMLNAMESPACES issue shown in the
aforementioned thread. So the patch shown there needs to go in first,
or you get a core dump in xml-enabled builds. But the sum total of all
three patches does pass make check-world.

The hackery in patch 0001 has to do with copying queryId, stmt_location,
and stmt_len fields forward across nodeToString + stringToNode. The
core regression tests pass fine without that, but pg_stat_statements
falls over, because it needs that data to survive parse analysis as
well as planning.

As far as queryId goes, I'm satisfied with the hack shown here of just
having pg_rewrite_query propagate the field forward across the test.
There's a case to be made for fixing it by storing queryId in stored rules
instead, but that would require a far higher commitment to stability and
universality of the queryId computation than we've made so far. Such a
change seems like something to consider separately if at all. (Note that
no hack is needed for plan trees, because _outPlannedStmt/_readPlannedStmt
already transmit the queryId for a plan.)

The location fields are a much more ticklish matter, because the behavior
for those ties into a bunch of historical and possible future behaviors.
Currently, although outfuncs.c prints node location fields just fine,
readfuncs.c ignores the stored values and inserts -1. The reason for
that is to be able to distinguish nodes that actually came from the
current query (for which the locations actually mean something with
respect to a query text we have at hand) from nodes that came from some
stored view or rule (for which we lack corresponding query text). So
readfuncs.c marks nodes of the latter type as "unknown location" and all
is well. As this patch stands, when the debug option is on, all nodes
coming out of the parser will have unknown locations, except for the
top-level Query or PlannedStmt node that we specially hacked. That's not
great; a debugging option shouldn't risk behavioral changes like that.
Right now, we pass regression tests anyway because pretty much nothing
after parse analysis looks at the location fields, but there have been
discussions about changing that so as to get better execution-time
error reporting.

I thought for a bit about replacing those hacks with something like
this in readfuncs.c:

#ifdef WRITE_READ_PARSE_PLAN_TREES
#define READ_LOCATION_FIELD(fldname) READ_INT_FIELD(fldname)
#else
// existing definition of READ_LOCATION_FIELD
#endif

but that breaks the property of clearing the location info coming
in from stored rules, so it's unlikely to be satisfactory. Another
idea is to have a runtime switch in readfuncs.c, allowing stringToNode
to treat location fields as it does now while there'd be an additional
entry point that would read location fields like plain ints. Then
we'd use the latter for the test code. This is a bit ugly but it might
be the best solution.

Patch 0002 addresses several more-or-less-independent issues that are
exposed by running the regression tests with patch 0001 activated:

* Query.withCheckOptions fails to propagate through write+read, because
it's intentionally ignored by outfuncs/readfuncs on the grounds that
it'd always be NIL anyway in stored rules. This seems like premature
optimization of the worst sort, since it's not even saving very much:
if the assumption holds, what's suppressed from a stored Query is only
" :withCheckOptions <>", hardly a big savings. And of course if the
assumption ever fails to hold, it's just broken, and broken in a non
obvious way too (you'd only notice if you expected a check option
failure and didn't get one). So this is pretty dumb and I think we
ought to fix it by treating that field normally in outfuncs/readfuncs.
That'd require a catversion bump, but we only need to do it in HEAD.
The only plausible alternative is to change _equalQuery to ignore
withCheckOptions, which does not sound like a good idea at all.

* The system expects TABLEFUNC RTEs to have coltypes, coltypmods, and
colcollations lists, but outfuncs doesn't dump them and readfuncs
doesn't restore them. This doesn't cause obvious failures, because
the only things that look at those fields are expandRTE() and
get_rte_attribute_type(), which are mostly used during parse analysis.
But expandRTE() is used in the rewriter and planner, so probably it's
possible to cause a crash or misbehavior with a stored view that returns
the result of an XMLTABLE FROM-item. I've not tried to build a test case,
but I'm pretty sure we need to back-patch a fix for this as far back as
we have XMLTABLE. Fortunately, because those fields are redundant with
the TableFunc node, we can just link to the lists we read in the TableFunc
node rather than force a catversion bump to store them separately. (This
is pretty grotty, but since it's replicating the physical duplication
established by addRangeTableEntryForTableFunc, I think it's OK.)

* readfuncs.c omits read support for NamedTuplestoreScan plan nodes.
This accidentally fails to break parallel query because a query using
a named tuplestore would never be considered parallel-safe anyway,
so we don't have to ship it to workers. Still, I'm pretty certain
this is somebody's sloppy oversight not an intentional omission,
and propose that we should back-patch that addition as far back as
NamedTuplestoreScan exists (ie v10). There seem to be no other cases
where we've omitted plan node read support, so this one has little
excuse to live.

* Several places that convert a view RTE into a subquery RTE, or similar
manipulations, failed to clear out fields that were specific to the
original RTE type and should be zero in a subquery RTE. This has no real
impact on the system, but since readfuncs.c will leave such fields as
zero, equalfuncs.c thinks the nodes are different leading to a reported
failure. I'm satisfied with patching this in HEAD. (You could
alternatively argue that we should change _equalRangeTblEntry to ignore
fields that are not supposed to be set based on the rtekind, but I don't
think that's a good idea.)

* BuildOnConflictExcludedTargetlist randomly set the resname of some
TargetEntries to "" not NULL. outfuncs/readfuncs don't distinguish those
cases, and so the string will read back in as NULL ... but equalfuncs.c
does distinguish. Perhaps we ought to try to make things more consistent
in this area --- but it's just useless extra code space for
BuildOnConflictExcludedTargetlist to not use NULL here, so I fixed it for
now by making it do so. Again, changing this in HEAD seems sufficient.

Comments?

regards, tom lane

Attachment Content-Type Size
0001-write-read-parse-plan-trees.patch text/x-diff 3.8 KB
0002-required-fixups.patch text/x-diff 6.0 KB

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Thomas Munro 2018-09-17 00:04:34 Re: [HACKERS] proposal - Default namespaces for XPath expressions (PostgreSQL 11)
Previous Message Thomas Munro 2018-09-16 22:42:34 Re: infinite loop in parallel hash joins / DSA / get_best_segment