morningman commented on code in PR #69488:
URL: https://github.com/apache/doris/pull/69488#discussion_r4389341960
##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/insert/InsertUtils.java:
##########
@@ -477,15 +491,67 @@ private static Plan normalizePlanWithoutLock(LogicalPlan
plan, TableIf table,
}
static List<Column> connectorWriteSchema(TableIf table, boolean full) {
+ return pinnedConnectorWriteSchema(table).orElseGet(() ->
table.getBaseSchema(full));
+ }
+
+ private static Optional<List<Column>> pinnedConnectorWriteSchema(TableIf
table) {
ConnectContext context = ConnectContext.get();
- if (context != null && context.getStatementContext() != null) {
- Optional<List<Column>> pinned =
-
context.getStatementContext().getConnectorWriteSchema(table.getId());
- if (pinned.isPresent()) {
- return pinned.get();
- }
+ if (context == null || context.getStatementContext() == null) {
+ return Optional.empty();
}
- return table.getBaseSchema(full);
+ return
context.getStatementContext().getConnectorWriteSchema(table.getId());
+ }
+
+ /**
+ * The pinned writer schema of a target whose column defaults apply to
writes only. The read schema of such a
+ * table carries no defaults, so DEFAULT(column) in an INSERT into it must
resolve against this schema.
+ */
+ private static Optional<List<Column>> writeOnlyDefaultColumns(TableIf
table) {
+ if (!(table instanceof PluginDrivenExternalTable)
+ || !((PluginDrivenExternalTable)
table).hasWriteOnlyDefaults()) {
+ return Optional.empty();
+ }
+ return pinnedConnectorWriteSchema(table);
+ }
+
+ /** Resolve DEFAULT(column) in one inserted value by name against the
target's pinned writer schema. */
+ private static NamedExpression resolveDefaultReferences(NamedExpression
value,
+ Optional<List<Column>> writeOnlyDefaultColumns, TableIf table,
List<String> targetNameParts) {
+ if (!writeOnlyDefaultColumns.isPresent()) {
+ return value;
+ }
+ return (NamedExpression)
ConnectorWriteSchemaUtils.resolveDefaultReferences(value,
+ writeOnlyDefaultColumns.get(), (ExternalTable) table,
ConnectContext.get(), targetNameParts, null);
+ }
+
+ /**
+ * Resolve DEFAULT(column) in the select lists of an INSERT ... SELECT by
name against the target's pinned
+ * writer schema, before the source relations are bound, so it names a
target column whatever the source is.
+ * A derived table in FROM is a query of its own: DEFAULT(column) in it
names a column of its own FROM clause,
+ * as without this resolution, so it is left alone.
+ */
+ private static Plan resolveSelectDefaultReferences(Plan query,
Optional<List<Column>> writeOnlyDefaultColumns,
+ TableIf table, List<String> targetNameParts) {
+ if (query instanceof LogicalSubQueryAlias) {
+ return query;
+ }
+ Plan plan = query.withChildren(child -> resolveSelectDefaultReferences(
+ child, writeOnlyDefaultColumns, table, targetNameParts));
+ if (plan instanceof LogicalProject) {
+ LogicalProject<?> project = (LogicalProject<?>) plan;
+ return project.withProjects(project.getProjects().stream()
+ .map(projection -> resolveDefaultReferences(
Review Comment:
Fixed in 37a93201c64. `UnboundStar` keeps the `REPLACE` list of `SELECT *
REPLACE(expr AS c)` in a field instead of as expression children, so resolving
the expression tree of each projection never reached it.
`InsertUtils.resolveDefaultReferences` now also resolves the replacements of a
star against the pinned writer schema and rebuilds the star with the same
qualifier and `EXCEPT` list. `INSERT INTO t(c) SELECT * REPLACE(DEFAULT(c) AS
c) FROM src` now writes the target's write-default, as `SELECT DEFAULT(c) FROM
src` does: the replacement is resolved before binding, so the default of
`src.c` never reaches it. A replacement follows the same rules as the rest of
the select list, so a qualifier other than the target's (`DEFAULT(src.c)`)
fails there too. A star inside a derived table is still left to binding.
I found no other part of a select list that the walk skips: `EXCEPT` accepts
column names only, and window frame bounds accept literals only. Subqueries are
the known limitation from
https://github.com/apache/doris/pull/69488#discussion_r4355508080.
`InsertUtilsTest#writeOnlyDefaultInStarReplacementResolvesByTargetColumnName`
covers `src.* EXCEPT(score) REPLACE(DEFAULT(name) AS name)`: the replacement
becomes the pinned default, and the qualifier and the `EXCEPT` list are kept.
With the previous commit the replacement is still `DEFAULT(name)`. branch-4.2
and branch-4.1 resolve each projection the same way, so they have the same gap;
I'll pass that on.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]