github-advanced-security[bot] commented on code in PR #19643:
URL: https://github.com/apache/druid/pull/19643#discussion_r3501362674
##########
extensions-contrib/openlineage-emitter/src/main/java/org/apache/druid/extensions/openlineage/OpenLineageRequestLogger.java:
##########
@@ -309,11 +347,275 @@
}
}
+ /**
+ * Column usage roles for the custom {@code druid_columnUsage} dataset
facet. Names align with
+ * OpenLineage transformation subtypes where they exist (GROUP_BY,
AGGREGATION, FILTER, JOIN);
+ * PROJECTION corresponds to OpenLineage IDENTITY/TRANSFORMATION (a
selected/projected column).
+ */
+ enum ColumnRole
+ {
+ PROJECTION, GROUP_BY, AGGREGATION, FILTER, JOIN
+ }
+
+ /**
+ * Resolves the per-base-table column-usage map for a native query, used to
attach the {@code schema}
+ * and {@code druid_columnUsage} dataset facets to input datasets. Handles
all datasource shapes:
+ * tables, joins (attributing columns per side via the planner's join
prefixes), unions, sub-queries
+ * (recursing into the sub-query's own columns), and datasource wrappers
(restricted/filtered/unnest).
+ * Columns that have no base table (lookups, inline data) are dropped rather
than fabricated.
+ *
+ * <p>Returns {@code null} (yielding table-level lineage only) when no
base-table columns can be
+ * determined, or on any error -- it never fabricates or mis-attributes
columns.
+ */
+ @Nullable
+ private Map<String, Map<String, EnumSet<ColumnRole>>>
extractColumnsByTable(Query<?> query)
+ {
+ try {
+ Map<String, Map<String, EnumSet<ColumnRole>>> result = new TreeMap<>();
+ collectInto(result, query);
+ return result.isEmpty() ? null : result;
+ }
+ // StackOverflowError (an Error, not an Exception) is caught too so that a
pathologically deep
+ // query plan degrades to table-level lineage rather than breaking the
request-logging path.
+ catch (Exception | StackOverflowError e) {
+ log.debug(e, "Failed to extract column lineage; falling back to
table-level lineage");
+ return null;
+ }
+ }
+
+ /**
+ * Walks {@code query}'s column-bearing parts and attributes the referenced
columns to the base
+ * tables of its datasource. {@link UnionQuery} (whose {@code
getDataSource()} is undefined) is
+ * handled by recursing into each of its branches.
+ */
+ private void collectInto(Map<String, Map<String, EnumSet<ColumnRole>>>
result, Query<?> query)
+ {
+ if (query instanceof UnionQuery) {
+ for (DataSource branch : ((UnionQuery) query).getDataSources()) {
+ attribute(result, branch, Collections.emptyMap());
+ }
+ return;
+ }
+ attribute(result, query.getDataSource(), collectColumnRoles(query));
+ }
+
+ /**
+ * Attributes {@code roles} (column to roles, expressed in {@code
dataSource}'s output namespace) to
+ * the underlying base tables, recursing through the datasource tree.
Sub-queries are recursed into
+ * via {@link #collectInto} (their columns come from their own parts, not
the outer references).
+ */
+ private void attribute(
+ Map<String, Map<String, EnumSet<ColumnRole>>> result,
+ DataSource dataSource,
+ Map<String, EnumSet<ColumnRole>> roles
+ )
+ {
+ if (dataSource instanceof TableDataSource) {
Review Comment:
## CodeQL / Chain of 'instanceof' tests
This if block performs a chain of 7 type tests - consider alternatives, e.g.
polymorphism or the visitor pattern.
[Show more
details](https://github.com/apache/druid/security/code-scanning/11326)
--
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]