В письме от четверг, 3 января 2019 г. 17:15:08 MSK пользователь Alvaro Herrera написал:
> I would have liked to get a StaticAssert in the definition, but I don't > think it's possible. A standard Assert() should be possible, though. Asserts are cool thing. I found some unexpected stuff. parallel_workers option is claimed to be heap-only option. But in src/backend/optimizer/util/plancat.c in get_relation_info RelationGetParallelWorkers is being called for both heap and toast tables (and not only for them). Because usually there are no reloptions for toast, it returns default -1 value. If some reloptions were set for toast table, RelationGetParallelWorkers will return a value from uninitialized memory. This will happen because StdRdOptions structure is filled with values in fillRelOptions function. And fillRelOptions first iterates on options list, and then on elems. So if option is not in "option list" than it's value will not be set. And options list comes from parseRelOptions where only options with proper relation kind is selected from [type]RelOpts[] arrays. So parallel_workers will not be added to options in the case of toast table because it is claimed to be applicable only to RELOPT_KIND_HEAP Thus if toast has some options set, and rd_options in relation is not NULL, get_relation_info will use value from uninitialized memory as number of parallel workers. To reproduce this Assert you can change RelationGetParallelWorkers macros in src/include/utils/rel.h #define IsHeapRelation(relation) \ (relation->rd_rel->relkind == RELKIND_RELATION || \ relation->rd_rel->relkind == RELKIND_MATVIEW ) #define RelationGetParallelWorkers(relation, defaultpw) \ (AssertMacro(IsHeapRelation(relation)), \ ((relation)->rd_options ? \ ((StdRdOptions *) (relation)->rd_options)->parallel_workers : \ (defaultpw))) and see how it asserts. It will happen just on the db_initiaisation phase of make check. If you add relation->rd_rel->relkind == RELKIND_TOASTEDVALUE to the Assertion, it will Assert in cases when get_relation_info is called for partitioned table. This case is not a problem for now, because partitioned table has no options and you will always have NULL in rd_options and get default value. But it will become a problem when somebody adds some options, especially it would be a problem if this options do not use StdRdOptions structure. Also it is called for foreign tables and sequences. So my suggestion of a hotfix is to replcace rel->rel_parallel_workers = RelationGetParallelWorkers(relation,-1); from get_relation_info with the following code switch (relation->rd_rel->relkind) { case RELKIND_RELATION: case RELKIND_MATVIEW: rel->rel_parallel_workers = RelationGetParallelWorkers(relation,-1); break; case RELKIND_TOASTVALUE: case RELKIND_PARTITIONED_TABLE: case RELKIND_SEQUENCE: case REPLICA_IDENTITY_FULL: /* Foreign table */ rel->rel_parallel_workers = -1; break; default: /* Other relkinds are not supported */ Assert(false); } But I am not familiar with get_relation_info and parallel_workers specific. So I suspect real fix may be quite different. Also I would suggest to fix it in all supported stable branches that have parallel_workers option, because this bug may give something unexpected when some toast options are set.