{"record":{"id":"090f4c824ea7601b","repo":"apache/druid","slug":"restricted-data-source-s-with-policy-s-is-no","errorCode":null,"errorMessage":"Restricted data source [%s] with policy [%s] is not supported","messagePattern":"Restricted data source \\[(.+?)\\] with policy \\[(.+?)\\] is not supported","errorType":"exception","errorClass":"QueryUnsupportedException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/query/planning/PreJoinableClause.java","lineNumber":83,"sourceCode":"\n  public DataSource getDataSource()\n  {\n    return dataSource;\n  }\n\n  /**\n   * If the data source is a {@link RestrictedDataSource} with a {@link NoRestrictionPolicy}, unwraps it to a table and return.\n   * <p>\n   * This is a temporary workaround to allow the planner to work with {@link RestrictedDataSource} as the right-side join.\n   */\n  public DataSource maybeUnwrapRestrictedDataSource()\n  {\n    if (dataSource instanceof RestrictedDataSource) {\n      RestrictedDataSource restricted = (RestrictedDataSource) dataSource;\n      if (restricted.getPolicy() instanceof NoRestrictionPolicy) {\n        return restricted.getBase();\n      } else {\n        throw new QueryUnsupportedException(StringUtils.format(\n            \"Restricted data source [%s] with policy [%s] is not supported\",\n            restricted.getBase(),\n            restricted.getPolicy()\n        ));\n      }\n    } else {\n      return dataSource;\n    }\n  }\n\n  public JoinType getJoinType()\n  {\n    return joinType;\n  }\n\n  public JoinConditionAnalysis getCondition()\n  {\n    return condition;","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/query/planning/PreJoinableClause.java#L65-L101","documentation":"PreJoinableClause.maybeUnwrapRestrictedDataSource unwraps a RestrictedDataSource only when its policy is NoRestrictionPolicy; any actual restriction policy on a joinable clause is unsupported in this code path and raises QueryUnsupportedException. Druid does not yet support applying row-level restriction policies inside join subqueries.","triggerScenarios":"A SQL/native query with a join whose joinable clause's data source carries a RestrictedDataSource with a non-NoRestriction policy (e.g. user-based row filtering).","commonSituations":"Combining row-level security policies with JOIN queries; nesting a restricted table as a subquery inside a join in SQL.","solutions":["Restructure the query so the restricted table is the base (outer) data source, not the join clause","Remove the restriction policy from the joined data source","Filter the joinable subquery explicitly with WHERE clauses instead of a policy","Upgrade Druid if newer versions add support for restricted joinables"],"exampleFix":"// before: restricted table used as join subquery\nSELECT ... FROM main JOIN restricted_t ON ...\n// after: pre-filter explicitly\nSELECT ... FROM main JOIN (SELECT * FROM t WHERE tenant_id = 'x') AS rt ON ...","handlingStrategy":"try-catch","validationCode":"if (dataSource instanceof RestrictedDataSource\n    && !(((RestrictedDataSource) dataSource).getPolicy() instanceof NoRestrictionPolicy)) {\n  throw new UnsupportedOperationException(\"cannot use restricted datasource inside a joinable clause\");\n}","typeGuard":"boolean isUnrestricted(DataSource ds) {\n  return !(ds instanceof RestrictedDataSource)\n      || ((RestrictedDataSource) ds).getPolicy() instanceof NoRestrictionPolicy;\n}","tryCatchPattern":"try {\n  runQuery(query);\n} catch (QueryUnsupportedException e) {\n  if (e.getMessage().contains(\"Restricted data source\")) {\n    // rewrite: move filtering into an explicit WHERE subquery\n    runQuery(rewriteWithoutRestrictedJoin(query));\n  } else throw e;\n}","preventionTips":["Keep restricted (row-level-security) tables as the base data source of a query","Use explicit WHERE filters in join subqueries instead of policies"],"tags":["join","row-level-security","restricted-datasource","unsupported"],"backgroundTag":"unsupported-operation","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}