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]

Reply via email to