Skip to content

Commit 06fe44e

Browse files
committed
feat(analyzer): Add session property to gate CTAS IF NOT EXISTS query analysis (#27504)
1 parent 28bb900 commit 06fe44e

File tree

3 files changed

+47
-1
lines changed

3 files changed

+47
-1
lines changed

presto-main-base/src/main/java/com/facebook/presto/SystemSessionProperties.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,7 @@ public final class SystemSessionProperties
393393
public static final String NATIVE_ENFORCE_JOIN_BUILD_INPUT_PARTITION = "native_enforce_join_build_input_partition";
394394
public static final String NATIVE_EXECUTION_SCALE_WRITER_THREADS_ENABLED = "native_execution_scale_writer_threads_enabled";
395395
public static final String TRY_FUNCTION_CATCHABLE_ERRORS = "try_function_catchable_errors";
396+
public static final String ALWAYS_ANALYZE_CREATE_TABLE_QUERY_ENABLED = "always_analyze_create_table_query_enabled";
396397

397398
private final List<PropertyMetadata<?>> sessionProperties;
398399

@@ -2213,6 +2214,11 @@ public SystemSessionProperties(
22132214
TRY_FUNCTION_CATCHABLE_ERRORS,
22142215
"Comma-separated list of error code names that TRY function should catch (such as 'GENERIC_INTERNAL_ERROR,INVALID_ARGUMENTS')",
22152216
featuresConfig.getTryFunctionCatchableErrors(),
2217+
false),
2218+
booleanProperty(
2219+
ALWAYS_ANALYZE_CREATE_TABLE_QUERY_ENABLED,
2220+
"When enabled, analyze inner query on CTAS IF NOT EXISTS to populate view definitions for access control checks",
2221+
false,
22162222
false));
22172223
}
22182224

@@ -3772,4 +3778,9 @@ public static String getTryFunctionCatchableErrors(Session session)
37723778
{
37733779
return session.getSystemProperty(TRY_FUNCTION_CATCHABLE_ERRORS, String.class);
37743780
}
3781+
3782+
public static boolean isAlwaysAnalyzeCreateTableQueryEnabled(Session session)
3783+
{
3784+
return session.getSystemProperty(ALWAYS_ANALYZE_CREATE_TABLE_QUERY_ENABLED, Boolean.class);
3785+
}
37753786
}

presto-main-base/src/main/java/com/facebook/presto/sql/analyzer/StatementAnalyzer.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@
243243

244244
import static com.facebook.presto.SystemSessionProperties.getMaxGroupingSets;
245245
import static com.facebook.presto.SystemSessionProperties.isAllowWindowOrderByLiterals;
246+
import static com.facebook.presto.SystemSessionProperties.isAlwaysAnalyzeCreateTableQueryEnabled;
246247
import static com.facebook.presto.SystemSessionProperties.isLegacyMaterializedViews;
247248
import static com.facebook.presto.SystemSessionProperties.isMaterializedViewDataConsistencyEnabled;
248249
import static com.facebook.presto.SystemSessionProperties.isMaterializedViewPartitionFilteringEnabled;
@@ -774,6 +775,10 @@ protected Scope visitCreateTableAsSelect(CreateTableAsSelect node, Optional<Scop
774775
warningCollector.add(new PrestoWarning(
775776
StandardWarningCode.SEMANTIC_WARNING,
776777
format("Table '%s' already exists, skipping table creation", targetTable)));
778+
// Analyze the inner query to populate view definitions for access control checks
779+
if (isAlwaysAnalyzeCreateTableQueryEnabled(session)) {
780+
process(node.getQuery(), scope);
781+
}
777782
return createAndAssignScope(node, scope, Field.newUnqualified(node.getLocation(), "rows", BIGINT));
778783
}
779784
throw new SemanticException(TABLE_ALREADY_EXISTS, node, "Destination table '%s' already exists", targetTable);

presto-main-base/src/test/java/com/facebook/presto/sql/analyzer/TestViewDefinitionCollector.java

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
*/
1414
package com.facebook.presto.sql.analyzer;
1515

16+
import com.facebook.presto.Session;
1617
import com.facebook.presto.spi.WarningCollector;
1718
import com.facebook.presto.spi.analyzer.AccessControlReferences;
1819
import com.facebook.presto.sql.tree.Statement;
@@ -24,6 +25,10 @@
2425
import java.util.Optional;
2526
import java.util.stream.Collectors;
2627

28+
import static com.facebook.presto.SystemSessionProperties.ALWAYS_ANALYZE_CREATE_TABLE_QUERY_ENABLED;
29+
import static com.facebook.presto.SystemSessionProperties.CHECK_ACCESS_CONTROL_ON_UTILIZED_COLUMNS_ONLY;
30+
import static com.facebook.presto.SystemSessionProperties.CHECK_ACCESS_CONTROL_WITH_SUBFIELDS;
31+
import static com.facebook.presto.testing.TestingSession.testSessionBuilder;
2732
import static com.facebook.presto.transaction.TransactionBuilder.transaction;
2833
import static com.facebook.presto.util.AnalyzerUtil.checkAccessPermissions;
2934
import static org.testng.Assert.assertEquals;
@@ -62,6 +67,26 @@ public void testCreateTableAsSelectWithViews()
6267
), ImmutableMap.of());
6368
}
6469

70+
public void testCreateTableAsSelectIfNotExistsWithViews()
71+
{
72+
// t1 already exists, so this hits the IF NOT EXISTS no-op path.
73+
// With always_analyze_create_table_query_enabled, view definitions should still be populated.
74+
Session sessionWithProperty = testSessionBuilder()
75+
.setCatalog(TPCH_CATALOG)
76+
.setSchema("s1")
77+
.setSystemProperty(CHECK_ACCESS_CONTROL_ON_UTILIZED_COLUMNS_ONLY, "true")
78+
.setSystemProperty(CHECK_ACCESS_CONTROL_WITH_SUBFIELDS, "true")
79+
.setSystemProperty(ALWAYS_ANALYZE_CREATE_TABLE_QUERY_ENABLED, "true")
80+
.build();
81+
82+
@Language("SQL") String query = "CREATE TABLE IF NOT EXISTS t1 AS SELECT view_definer1.a, view_definer1.c, view_invoker2.y FROM view_definer1 left join view_invoker2 on view_invoker2.y = view_definer1.c";
83+
84+
assertViewDefinitions(sessionWithProperty, query, ImmutableMap.of(
85+
"tpch.s1.view_invoker2", "select x, y, z from t13",
86+
"tpch.s1.view_definer1", "select a,b,c from t1"
87+
), ImmutableMap.of());
88+
}
89+
6590
public void testExplainWithViews()
6691
{
6792
@Language("SQL") String query = "EXPLAIN SELECT view_definer1.a, view_definer1.c, view_invoker2.y FROM view_definer1 left join view_invoker2 on view_invoker2.y = view_definer1.c";
@@ -193,12 +218,17 @@ public void testExplainTypeValidateExplainAnalyzeWithViews()
193218
}
194219

195220
private void assertViewDefinitions(@Language("SQL") String query, Map<String, String> expectedViewDefinitions, Map<String, String> expectedMaterializedViewDefinitions)
221+
{
222+
assertViewDefinitions(CLIENT_SESSION, query, expectedViewDefinitions, expectedMaterializedViewDefinitions);
223+
}
224+
225+
private void assertViewDefinitions(Session clientSession, @Language("SQL") String query, Map<String, String> expectedViewDefinitions, Map<String, String> expectedMaterializedViewDefinitions)
196226
{
197227
transaction(transactionManager, accessControl)
198228
.singleStatement()
199229
.readUncommitted()
200230
.readOnly()
201-
.execute(CLIENT_SESSION, session -> {
231+
.execute(clientSession, session -> {
202232
Analyzer analyzer = createAnalyzer(session, metadata, WarningCollector.NOOP, Optional.of(createTestingQueryExplainer(session, accessControl, metadata)), query);
203233
Statement statement = SQL_PARSER.createStatement(query);
204234
Analysis analysis = analyzer.analyzeSemantic(statement, false);

0 commit comments

Comments
 (0)