diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2018-09-18 17:11:54 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2018-09-18 17:11:54 -0400 |
commit | d0cfc3d6a44af1756ca5be8cb2414da7b8bf20d5 (patch) | |
tree | 5fdb37364f283c7965c53512d2bd58e6d6699cca /src/backend/nodes/readfuncs.c | |
parent | db1071d4ee9f0e348ab646e7c13184d480d40516 (diff) |
Add a debugging option to stress-test outfuncs.c and readfuncs.c.
In the normal course of operation, query trees will be serialized only if
they are stored as views or rules; and plan trees will be serialized only
if they get passed to parallel-query workers. This leaves an awful lot of
opportunity for bugs/oversights to not get detected, as indeed we've just
been reminded of the hard way.
To improve matters, this patch adds a new compile option
WRITE_READ_PARSE_PLAN_TREES, which is modeled on the longstanding option
COPY_PARSE_PLAN_TREES; but instead of passing all parse and plan trees
through copyObject, it passes them through nodeToString + stringToNode.
Enabling this option in a buildfarm animal or two will catch problems
at least for cases that are exercised by the regression tests.
A small problem with this idea is that readfuncs.c historically has
discarded location fields, on the reasonable grounds that parse
locations in a retrieved view are not relevant to the current query.
But doing that in WRITE_READ_PARSE_PLAN_TREES breaks pg_stat_statements,
and it could cause problems for future improvements that might try to
report error locations at runtime. To fix that, provide a variant
behavior in readfuncs.c that makes it restore location fields when
told to.
In passing, const-ify the string arguments of stringToNode and its
subsidiary functions, just because it annoyed me that they weren't
const already.
Discussion: https://postgr.es/m/17114.1537138992@sss.pgh.pa.us
Diffstat (limited to 'src/backend/nodes/readfuncs.c')
-rw-r--r-- | src/backend/nodes/readfuncs.c | 31 |
1 files changed, 21 insertions, 10 deletions
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index 81f568b3ee1..519deab63ab 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -17,10 +17,14 @@ * never read executor state trees, either. * * Parse location fields are written out by outfuncs.c, but only for - * possible debugging use. When reading a location field, we discard + * debugging use. When reading a location field, we normally discard * the stored value and set the location field to -1 (ie, "unknown"). * This is because nodes coming from a stored rule should not be thought * to have a known location in the current query's text. + * However, if restore_location_fields is true, we do restore location + * fields from the string. This is currently intended only for use by the + * WRITE_READ_PARSE_PLAN_TREES test code, which doesn't want to cause + * any change in the node contents. * *------------------------------------------------------------------------- */ @@ -51,7 +55,7 @@ /* And a few guys need only the pg_strtok support fields */ #define READ_TEMP_LOCALS() \ - char *token; \ + const char *token; \ int length /* ... but most need both */ @@ -120,12 +124,19 @@ token = pg_strtok(&length); /* get field value */ \ local_node->fldname = nullable_string(token, length) -/* Read a parse location field (and throw away the value, per notes above) */ +/* Read a parse location field (and possibly throw away the value) */ +#ifdef WRITE_READ_PARSE_PLAN_TREES +#define READ_LOCATION_FIELD(fldname) \ + token = pg_strtok(&length); /* skip :fldname */ \ + token = pg_strtok(&length); /* get field value */ \ + local_node->fldname = restore_location_fields ? atoi(token) : -1 +#else #define READ_LOCATION_FIELD(fldname) \ token = pg_strtok(&length); /* skip :fldname */ \ token = pg_strtok(&length); /* get field value */ \ (void) token; /* in case not used elsewhere */ \ local_node->fldname = -1 /* set field to "unknown" */ +#endif /* Read a Node field */ #define READ_NODE_FIELD(fldname) \ @@ -2804,7 +2815,7 @@ readDatum(bool typbyval) Size length, i; int tokenLength; - char *token; + const char *token; Datum res; char *s; @@ -2817,7 +2828,7 @@ readDatum(bool typbyval) token = pg_strtok(&tokenLength); /* read the '[' */ if (token == NULL || token[0] != '[') elog(ERROR, "expected \"[\" to start datum, but got \"%s\"; length = %zu", - token ? (const char *) token : "[NULL]", length); + token ? token : "[NULL]", length); if (typbyval) { @@ -2847,7 +2858,7 @@ readDatum(bool typbyval) token = pg_strtok(&tokenLength); /* read the ']' */ if (token == NULL || token[0] != ']') elog(ERROR, "expected \"]\" to end datum, but got \"%s\"; length = %zu", - token ? (const char *) token : "[NULL]", length); + token ? token : "[NULL]", length); return res; } @@ -2860,7 +2871,7 @@ readAttrNumberCols(int numCols) { int tokenLength, i; - char *token; + const char *token; AttrNumber *attr_vals; if (numCols <= 0) @@ -2884,7 +2895,7 @@ readOidCols(int numCols) { int tokenLength, i; - char *token; + const char *token; Oid *oid_vals; if (numCols <= 0) @@ -2908,7 +2919,7 @@ readIntCols(int numCols) { int tokenLength, i; - char *token; + const char *token; int *int_vals; if (numCols <= 0) @@ -2932,7 +2943,7 @@ readBoolCols(int numCols) { int tokenLength, i; - char *token; + const char *token; bool *bool_vals; if (numCols <= 0) |