{"Entry":{"collection":"plan","key":"recursive-union","name":"Recursive Union","aliases":["Recursive Union","RecursiveUnion","T_RecursiveUnion"],"metadata":{"aliases":["Recursive Union","RecursiveUnion","T_RecursiveUnion"],"category":"Combination","content_hash":"644b31619c32148a2975b5d3f69bf1cb22484977db35fe1c5f2f7ee32bd431fb","imported_at":"2026-09-30T00:40:44.054849+08:00","name":"Recursive Union","name_zh":"RecursiveUnion","slug":"recursive-union","summary":"Executes the non-recursive and recursive terms of a recursive union using working and intermediate tables."}},"Definition":{"Collection":"plan","Key":"recursive-union","SourceDatabase":"center","Version":"18","SourceTable":"plan_node","SourceKey":"recursive-union","SourceRevision":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","Facts":{"comparison_data":{"initializer":"ExecInitRecursiveUnion","memory_mechanism":"tuplestore","node_tag":"T_RecursiveUnion","parallel_callbacks":[],"partial_modes":[],"strategies":[],"text_names":["Recursive Union"]},"comparison_hash":"483291c3112fd1d9f34701a541efd658b64074aa0300e044d5e96c65ca8e9023","description":["Executes the non-recursive and recursive terms of a recursive union using working and intermediate tables."],"evidence_kind":"source and documentation","explain_names":["Recursive Union"],"explain_prefixes":["Parallel","Async"],"facts":[{"label":"Core node tag","value":"T_RecursiveUnion"},{"label":"Structured EXPLAIN Node Type","value":"Recursive Union"},{"label":"Inputs","value":"Non-recursive and recursive child plans"},{"label":"Output","value":"Recursive query tuples"},{"label":"Executor initializer","value":"ExecInitRecursiveUnion"},{"label":"Memory mechanism","value":"tuplestore"}],"memory":{"description":"This node creates a tuplestore with work_mem. The tuplestore can move stored tuples to temporary files; this does not make work_mem a cap on every allocation made by the node.","evidence":[{"archive_sha256":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","label":"src/backend/executor/nodeRecursiveunion.c","path":"src/backend/executor/nodeRecursiveunion.c","sha256":"315c2d4d0a7a1ddf362ad19357cb62c7615592d2f51aaee87d313b4fe0d9536a","url":"https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2"},{"archive_sha256":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","label":"src/backend/utils/sort/tuplestore.c","path":"src/backend/utils/sort/tuplestore.c","sha256":"27a85416bafed557006c705ab5d0c5dce3d3c1702812bb54d136f2ac4c41055a","url":"https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2"}],"mechanism":"tuplestore","source_notes":[]},"node_tag":"T_RecursiveUnion","parallel_callbacks":[],"partial_modes":[],"related":[{"label":"EXPLAIN","url":"/wiki/sql/explain/?v=18"},{"label":"Using EXPLAIN","url":"/docs/18/using-explain.html"},{"label":"Parallel plans","url":"/docs/18/parallel-plans.html"},{"label":"work_mem","url":"/wiki/guc/work_mem/?v=18"}],"release":{"channel":"stable","label":"18.6","major":"18","ref":"PostgreSQL 18.6 source archive","revision":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","source_snapshot_utc":"","source_url":"https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2"},"runtime_verified":false,"sections":[{"paragraphs":["Structured formats use the Node Type above. Text-format spellings can also include operation, strategy, join type, scan direction or aggregation-stage attributes.","Text names recorded by this source: Recursive Union.","Parallel-aware and parallel-safe are different plan properties. A node running inside a parallel worker is not necessarily a parallel-aware node."],"title":"EXPLAIN names and attributes"},{"paragraphs":["This node creates a tuplestore with work_mem. The tuplestore can move stored tuples to temporary files; this does not make work_mem a cap on every allocation made by the node."],"title":"Memory and temporary storage"},{"paragraphs":["The source callbacks below can coordinate execution or collect worker instrumentation. Their presence is not a blanket claim that this node supports a shared parallel scan or shared state.","Callbacks in this build: none extracted from this node implementation."],"title":"Parallel execution and instrumentation"},{"paragraphs":["nodeRecursiveunion.c routines to handle RecursiveUnion nodes.","To implement UNION (without ALL), we need a hashtable that stores tuples already seen. The hash key is computed from the grouping columns.","If both child plans deliver the same fixed tuple slot type, we can tell BuildTupleHashTable to expect that slot type as input. Otherwise, we'll pass NULL denoting that any slot type is possible.","Scans the recursive query sequentially and returns the next qualifying tuple.","2.1 WT := RT 2.2 while WT is not empty repeat 2.3 to 2.6. if WT is empty returns RT 2.3 replace the name of recursive term with WT 2.4 evaluate the recursive term and store into WT 2.5 append WT to RT 2.6 go back to 2.2"],"title":"Executor implementation notes"},{"code":"case T_RecursiveUnion:\n\t\t\tpname = sname = \"Recursive Union\";\n\t\t\tbreak;","title":"EXPLAIN identity in core source"}],"source_inventory":{"executor":"src/backend/executor/execProcnode.c","explain":"src/backend/commands/explain.c","implementation":"src/backend/executor/nodeRecursiveunion.c"},"sources":[{"archive_sha256":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","label":"src/backend/commands/explain.c:1412","line":1412,"path":"src/backend/commands/explain.c","sha256":"34c86d6070224a0e981efef51f79101d6d505e5874f1684ace183034bab14bb4","url":"https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2"},{"archive_sha256":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","label":"src/backend/executor/execProcnode.c:191","line":191,"path":"src/backend/executor/execProcnode.c","sha256":"f8a06a3f539077249b20664b2812433db6d7bd12b2c0ca633525db43d06f112a","url":"https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2"},{"archive_sha256":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","label":"src/backend/executor/nodeRecursiveunion.c","path":"src/backend/executor/nodeRecursiveunion.c","sha256":"315c2d4d0a7a1ddf362ad19357cb62c7615592d2f51aaee87d313b4fe0d9536a","url":"https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2"},{"archive_sha256":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","label":"src/include/nodes/plannodes.h","path":"src/include/nodes/plannodes.h","sha256":"52422b327a8049fbbb20d8b96008a0fc0a6fafa60f7eff3c695d5b2e83830120","url":"https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2"},{"archive_sha256":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","label":"src/backend/utils/sort/tuplestore.c","path":"src/backend/utils/sort/tuplestore.c","sha256":"27a85416bafed557006c705ab5d0c5dce3d3c1702812bb54d136f2ac4c41055a","url":"https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2"}],"strategies":[],"tables":[{"columns":[{"key":"label","label":"Text-format label"},{"key":"identity","label":"Structured node identity"}],"key":"explain-labels","rows":[{"identity":"Recursive Union","label":"Recursive Union"}],"title":"EXPLAIN labels in this source build"}]},"ManualEvidence":{"release":{"channel":"stable","label":"18.6","major":"18","ref":"PostgreSQL 18.6 source archive","revision":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","source_snapshot_utc":"","source_url":"https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2"},"sources":[{"archive_sha256":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","label":"src/backend/commands/explain.c:1412","line":1412,"path":"src/backend/commands/explain.c","sha256":"34c86d6070224a0e981efef51f79101d6d505e5874f1684ace183034bab14bb4","url":"https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2"},{"archive_sha256":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","label":"src/backend/executor/execProcnode.c:191","line":191,"path":"src/backend/executor/execProcnode.c","sha256":"f8a06a3f539077249b20664b2812433db6d7bd12b2c0ca633525db43d06f112a","url":"https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2"},{"archive_sha256":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","label":"src/backend/executor/nodeRecursiveunion.c","path":"src/backend/executor/nodeRecursiveunion.c","sha256":"315c2d4d0a7a1ddf362ad19357cb62c7615592d2f51aaee87d313b4fe0d9536a","url":"https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2"},{"archive_sha256":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","label":"src/include/nodes/plannodes.h","path":"src/include/nodes/plannodes.h","sha256":"52422b327a8049fbbb20d8b96008a0fc0a6fafa60f7eff3c695d5b2e83830120","url":"https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2"},{"archive_sha256":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","label":"src/backend/utils/sort/tuplestore.c","path":"src/backend/utils/sort/tuplestore.c","sha256":"27a85416bafed557006c705ab5d0c5dce3d3c1702812bb54d136f2ac4c41055a","url":"https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2"}]},"MeasuredEvidence":{"runtime_verified":false}},"Text":{"Collection":"plan","Key":"recursive-union","SourceDatabase":"center","Version":"18","Locale":"en","Title":"Recursive Union","Summary":"Executes the non-recursive and recursive terms of a recursive union using working and intermediate tables.","BodyHTML":"\u003cp\u003eExecutes the non-recursive and recursive terms of a recursive union using working and intermediate tables.\u003c/p\u003e","SourceRevision":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","ContentHash":"620fa7579c35cf3eb5de58f9e2bbf5b2b1f6d5a36658701b38efdbe19aeea50a","Payload":{"description":["Executes the non-recursive and recursive terms of a recursive union using working and intermediate tables."],"related":[{"label":"EXPLAIN","url":"/wiki/sql/explain/?v=18"},{"label":"Using EXPLAIN","url":"/docs/18/using-explain.html"},{"label":"Parallel plans","url":"/docs/18/parallel-plans.html"},{"label":"work_mem","url":"/wiki/guc/work_mem/?v=18"}],"sections":[{"paragraphs":["Structured formats use the Node Type above. Text-format spellings can also include operation, strategy, join type, scan direction or aggregation-stage attributes.","Text names recorded by this source: Recursive Union.","Parallel-aware and parallel-safe are different plan properties. A node running inside a parallel worker is not necessarily a parallel-aware node."],"title":"EXPLAIN names and attributes"},{"paragraphs":["This node creates a tuplestore with work_mem. The tuplestore can move stored tuples to temporary files; this does not make work_mem a cap on every allocation made by the node."],"title":"Memory and temporary storage"},{"paragraphs":["The source callbacks below can coordinate execution or collect worker instrumentation. Their presence is not a blanket claim that this node supports a shared parallel scan or shared state.","Callbacks in this build: none extracted from this node implementation."],"title":"Parallel execution and instrumentation"},{"paragraphs":["nodeRecursiveunion.c routines to handle RecursiveUnion nodes.","To implement UNION (without ALL), we need a hashtable that stores tuples already seen. The hash key is computed from the grouping columns.","If both child plans deliver the same fixed tuple slot type, we can tell BuildTupleHashTable to expect that slot type as input. Otherwise, we'll pass NULL denoting that any slot type is possible.","Scans the recursive query sequentially and returns the next qualifying tuple.","2.1 WT := RT 2.2 while WT is not empty repeat 2.3 to 2.6. if WT is empty returns RT 2.3 replace the name of recursive term with WT 2.4 evaluate the recursive term and store into WT 2.5 append WT to RT 2.6 go back to 2.2"],"title":"Executor implementation notes"},{"code":"case T_RecursiveUnion:\n\t\t\tpname = sname = \"Recursive Union\";\n\t\t\tbreak;","title":"EXPLAIN identity in core source"}],"tables":[{"columns":[{"key":"label","label":"Text-format label"},{"key":"identity","label":"Structured node identity"}],"key":"explain-labels","rows":[{"identity":"Recursive Union","label":"Recursive Union"}],"title":"EXPLAIN labels in this source build"}]}},"RequestedLocale":"zh-Hans","Fallback":true,"Versions":["10","11","12","13","14","15","16","17","18","19","20"],"Locales":["en"],"Signatures":null,"Spellings":null,"SQLState":null,"Evidence":null}
