Conversation
There was a problem hiding this comment.
Pull request overview
Adds support for COPY ... TO ... in the table model to export query results into TsFile format, integrating the feature across SQL grammar, AST/planner nodes, execution operators, and integration tests.
Changes:
- Extend relational SQL grammar + parser/AST to support
COPY TOwith options (format/table/time/tags/memory threshold). - Add planner/execution support (
CopyToNode+TableCopyToOperator) that writes query TsBlocks into a TsFile and returns a summary result row. - Add end-to-end integration tests covering multiple
COPY TOscenarios (table copy, query copy, tags/time overrides, auto-generated time column, joins).
Reviewed changes
Copilot reviewed 29 out of 29 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| pom.xml | Bumps tsfile.version snapshot used by the build. |
| iotdb-core/relational-grammar/src/main/antlr4/org/apache/iotdb/db/relational/grammar/sql/RelationalSql.g4 | Adds COPY TO statement + options to the relational SQL grammar and tokens. |
| iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/TsTable.java | Adds helper to find a table’s time column name. |
| iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/column/ColumnHeaderConstant.java | Adds COPY result headers/constants. |
| iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/IoTDBConstant.java | Introduces copy_to folder name constant. |
| iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/rescon/disk/TierManager.java | Adds folder selection support for copy_to export targets. |
| iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/util/SqlFormatter.java | Adds formatting support for CopyTo AST. |
| iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/AstBuilder.java | Builds CopyTo AST and parses COPY options. |
| iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/DefaultTraversalVisitor.java | Traversal support for CopyTo. |
| iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/CopyTo.java | New AST node representing COPY TO. |
| iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/AstVisitor.java | Visitor hook for CopyTo. |
| iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/UnaliasSymbolReferences.java | Adds unalias rewrite logic for CopyToNode. |
| iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/LogicalOptimizeFactory.java | Registers column-pruning rule for CopyToNode. |
| iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/Patterns.java | Adds pattern for matching CopyToNode. |
| iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/CopyToNode.java | New plan node for COPY TO execution. |
| iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/iterative/rule/PruneCopyToColumns.java | New rule to restrict child outputs for COPY. |
| iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/distribute/TableModelTypeProviderExtractor.java | Adds visitor handling for CopyToNode. |
| iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/distribute/TableDistributedPlanGenerator.java | Ensures COPY node participates in distributed plan generation. |
| iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/TableLogicalPlanner.java | Plans COPY TO into CopyToNode and changes output header logic. |
| iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/StatementAnalyzer.java | Adds analysis/scoping for CopyTo. |
| iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanVisitor.java | Adds PlanVisitor method for CopyToNode. |
| iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/TableOperatorGenerator.java | Generates TableCopyToOperator for CopyToNode. |
| iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/process/copyto/tsfile/TsFileFormatCopyToWriter.java | New writer that converts table TsBlocks into TsFile output + result row. |
| iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/process/copyto/tsfile/CopyToTsFileOptions.java | New TSFILE option inference + validation for COPY. |
| iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/process/copyto/TableCopyToOperator.java | New operator that writes query results to a target file and returns summary. |
| iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/process/copyto/IFormatCopyToWriter.java | New writer interface abstraction. |
| iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/process/copyto/CopyToOptions.java | New options interface + builder for COPY formats. |
| iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/header/DatasetHeader.java | Adds overload to map output columns to TsBlock indexes for COPY. |
| integration-test/src/test/java/org/apache/iotdb/relational/it/query/recent/copyto/IoTDBCopyToTsFileIT.java | New IT coverage for COPY TO TsFile in table model. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| private File createTargetFile(String path) throws Exception { | ||
| File file = new File(path); | ||
| if (file.getParent() == null) { | ||
| String dir = TierManager.getInstance().getNextFolderForCopyToTargetFile(); | ||
| file = new File(dir, path); | ||
| } | ||
| File parent = file.getParentFile(); | ||
| if (parent != null && !parent.exists() && !parent.mkdirs()) { | ||
| throw new IOException("Failed to create directories: " + parent); | ||
| } | ||
| if (!file.createNewFile()) { | ||
| throw new IOException("Target file already exists: " + file.getAbsolutePath()); | ||
| } |
There was a problem hiding this comment.
createTargetFile() will create a new file at an arbitrary user-supplied path (including absolute paths and paths with ..) and will also create parent directories. Since the path comes from a SQL statement, this effectively allows remote clients to write files anywhere the server user has permissions. Please restrict COPY TO targets to the dedicated copy_to directory (or another explicit allowlist/configured base dir), and reject absolute paths / path traversal.
...e/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/CopyTo.java
Show resolved
Hide resolved
| public PlanAndMappings visitCopyTo(CopyToNode node, UnaliasContext context) { | ||
| PlanAndMappings rewrittenSource = node.getChild().accept(this, context); | ||
| Map<Symbol, Symbol> mapping = new HashMap<>(rewrittenSource.getMappings()); | ||
| SymbolMapper mapper = symbolMapper(mapping); | ||
| List<Symbol> newChildPermittedOutputs = mapper.map(node.getChildPermittedOutputs()); | ||
| return new PlanAndMappings( | ||
| new CopyToNode( | ||
| node.getPlanNodeId(), | ||
| rewrittenSource.getRoot(), | ||
| node.getTargetFilePath(), | ||
| node.getCopyToOptions(), | ||
| newChildPermittedOutputs, | ||
| node.getInnerQueryDatasetHeader(), | ||
| node.getInnerQueryOutputNode()), |
There was a problem hiding this comment.
In visitCopyTo, the child plan is rewritten and symbols may be remapped, but innerQueryOutputNode is passed through unchanged. TableCopyToOperator later calls datasetHeader.setTableColumnToTsBlockIndexMap(innerQueryOutputNode, childNode) and relies on innerQueryOutputNode.getOutputSymbols() matching the (possibly rewritten) child’s output symbols; if they don’t, outputSymbolsIndexMap.get(...) can return null and fail at runtime. Please remap innerQueryOutputNode’s output symbols using the same SymbolMapper (similar to childPermittedOutputs), or store a symbol-independent mapping instead of the original OutputNode.
...b-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/rescon/disk/TierManager.java
Show resolved
Hide resolved
...ode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/util/SqlFormatter.java
Show resolved
Hide resolved
...pache/iotdb/db/queryengine/execution/operator/process/copyto/tsfile/CopyToTsFileOptions.java
Outdated
Show resolved
Hide resolved
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #17372 +/- ##
============================================
- Coverage 39.74% 39.72% -0.02%
Complexity 312 312
============================================
Files 5126 5134 +8
Lines 346228 346840 +612
Branches 44083 44181 +98
============================================
+ Hits 137608 137797 +189
- Misses 208620 209043 +423 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|



Description
This PR adds support for exporting query results (TsBlock) into Table Model TsFile through the SQL interface.