More deficiencies in outfuncs/readfuncs processing
Tom Lane <tgl@sss.pgh.pa.us>
From: Tom Lane <tgl@sss.pgh.pa.us>
To: pgsql-hackers@lists.postgresql.org
Date: 2018-09-16T23:03:12Z
Lists: pgsql-hackers
Attachments
- 0001-write-read-parse-plan-trees.patch (text/x-diff) patch 0001
- 0002-required-fixups.patch (text/x-diff) patch 0002
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
Commits
-
Add a debugging option to stress-test outfuncs.c and readfuncs.c.
- d0cfc3d6a44a 12.0 landed
-
Fix some minor issues exposed by outfuncs/readfuncs testing.
- db1071d4ee9f 12.0 landed
-
Fix some probably-minor oversights in readfuncs.c.
- cdbdf85ec78f 10.6 landed
- 5c07d6497d8e 11.0 landed
- 09991e5a475b 12.0 landed