Skip to content

Commit

Permalink
Add SHOW CREATE FUNCTION
Browse files Browse the repository at this point in the history
  • Loading branch information
electrum committed May 6, 2024
1 parent 72b392e commit aaff6b5
Show file tree
Hide file tree
Showing 39 changed files with 285 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ statement
| SHOW CREATE SCHEMA qualifiedName #showCreateSchema
| SHOW CREATE VIEW qualifiedName #showCreateView
| SHOW CREATE MATERIALIZED VIEW qualifiedName #showCreateMaterializedView
| SHOW CREATE FUNCTION qualifiedName #showCreateFunction
| SHOW TABLES ((FROM | IN) qualifiedName)?
(LIKE pattern=string (ESCAPE escape=string)?)? #showTables
| SHOW SCHEMAS ((FROM | IN) identifier)?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,12 +135,12 @@ private void verifyFormattedFunction(String sql, FunctionSpecification function)
}
}

static Optional<CatalogSchemaName> defaultFunctionSchema(SqlEnvironmentConfig config)
public static Optional<CatalogSchemaName> defaultFunctionSchema(SqlEnvironmentConfig config)
{
return combine(config.getDefaultFunctionCatalog(), config.getDefaultFunctionSchema(), CatalogSchemaName::new);
}

static QualifiedObjectName qualifiedFunctionName(Optional<CatalogSchemaName> functionSchema, Node node, QualifiedName name)
public static QualifiedObjectName qualifiedFunctionName(Optional<CatalogSchemaName> functionSchema, Node node, QualifiedName name)
{
List<String> parts = name.getParts();
return switch (parts.size()) {
Expand Down
2 changes: 2 additions & 0 deletions core/trino-main/src/main/java/io/trino/metadata/Metadata.java
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,8 @@ default ResolvedFunction getCoercion(Type fromType, Type toType)

FunctionDependencyDeclaration getFunctionDependencies(Session session, CatalogHandle catalogHandle, FunctionId functionId, BoundSignature boundSignature);

Collection<LanguageFunction> getLanguageFunctions(Session session, QualifiedObjectName name);

boolean languageFunctionExists(Session session, QualifiedObjectName name, String signatureToken);

void createLanguageFunction(Session session, QualifiedObjectName name, LanguageFunction function, boolean replace);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2604,6 +2604,16 @@ public AggregationFunctionMetadata getAggregationFunctionMetadata(Session sessio
return builder.build();
}

@Override
public Collection<LanguageFunction> getLanguageFunctions(Session session, QualifiedObjectName name)
{
CatalogMetadata catalogMetadata = getRequiredCatalogMetadata(session, name.catalogName());
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);

return metadata.getLanguageFunctions(session.toConnectorSession(catalogHandle), name.asSchemaFunctionName());
}

@Override
public boolean languageFunctionExists(Session session, QualifiedObjectName name, String signatureToken)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,13 @@ void checkCanRevokeRoles(SecurityContext context,
*/
void checkCanDropFunction(SecurityContext context, QualifiedObjectName functionName);

/**
* Check if identity is allowed to execute SHOW CREATE FUNCTION.
*
* @throws AccessDeniedException if not allowed
*/
void checkCanShowCreateFunction(SecurityContext context, QualifiedObjectName functionName);

default List<ViewExpression> getRowFilters(SecurityContext context, QualifiedObjectName tableName)
{
return ImmutableList.of();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1375,6 +1375,19 @@ public void checkCanDropFunction(SecurityContext securityContext, QualifiedObjec
catalogAuthorizationCheck(functionName.catalogName(), securityContext, (control, context) -> control.checkCanDropFunction(context, functionName.asSchemaRoutineName()));
}

@Override
public void checkCanShowCreateFunction(SecurityContext context, QualifiedObjectName functionName)
{
requireNonNull(context, "context is null");
requireNonNull(functionName, "functionName is null");

checkCanAccessCatalog(context, functionName.catalogName());

systemAuthorizationCheck(control -> control.checkCanShowCreateFunction(context.toSystemSecurityContext(), functionName.asCatalogSchemaRoutineName()));

catalogAuthorizationCheck(functionName.catalogName(), context, (control, connectorContext) -> control.checkCanShowCreateFunction(connectorContext, functionName.asSchemaRoutineName()));
}

@Override
public List<ViewExpression> getRowFilters(SecurityContext context, QualifiedObjectName tableName)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -288,4 +288,7 @@ public void checkCanCreateFunction(SecurityContext context, QualifiedObjectName

@Override
public void checkCanDropFunction(SecurityContext context, QualifiedObjectName functionName) {}

@Override
public void checkCanShowCreateFunction(SecurityContext context, QualifiedObjectName functionName) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
import static io.trino.spi.security.AccessDeniedException.denySetUser;
import static io.trino.spi.security.AccessDeniedException.denySetViewAuthorization;
import static io.trino.spi.security.AccessDeniedException.denyShowColumns;
import static io.trino.spi.security.AccessDeniedException.denyShowCreateFunction;
import static io.trino.spi.security.AccessDeniedException.denyShowCreateSchema;
import static io.trino.spi.security.AccessDeniedException.denyShowCreateTable;
import static io.trino.spi.security.AccessDeniedException.denyShowCurrentRoles;
Expand Down Expand Up @@ -568,4 +569,10 @@ public void checkCanDropFunction(SecurityContext context, QualifiedObjectName fu
{
denyDropFunction(functionName.toString());
}

@Override
public void checkCanShowCreateFunction(SecurityContext context, QualifiedObjectName functionName)
{
denyShowCreateFunction(functionName.toString());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,12 @@ public void checkCanDropFunction(SecurityContext context, QualifiedObjectName fu
delegate().checkCanDropFunction(context, functionName);
}

@Override
public void checkCanShowCreateFunction(SecurityContext context, QualifiedObjectName functionName)
{
delegate().checkCanShowCreateFunction(context, functionName);
}

@Override
public List<ViewExpression> getRowFilters(SecurityContext context, QualifiedObjectName tableName)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,12 @@ public void checkCanDropFunction(ConnectorSecurityContext context, SchemaRoutine
accessControl.checkCanDropFunction(securityContext, new QualifiedObjectName(catalogName, function.getSchemaName(), function.getRoutineName()));
}

@Override
public void checkCanShowCreateFunction(ConnectorSecurityContext context, SchemaRoutineName function)
{
accessControl.checkCanShowCreateFunction(securityContext, new QualifiedObjectName(catalogName, function.getSchemaName(), function.getRoutineName()));
}

@Override
public List<ViewExpression> getRowFilters(ConnectorSecurityContext context, SchemaTableName tableName)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,14 @@
import io.trino.spi.connector.SchemaTableName;
import io.trino.spi.function.FunctionKind;
import io.trino.spi.function.FunctionMetadata;
import io.trino.spi.function.LanguageFunction;
import io.trino.spi.function.SchemaFunctionName;
import io.trino.spi.predicate.Domain;
import io.trino.spi.security.PrincipalType;
import io.trino.spi.security.TrinoPrincipal;
import io.trino.spi.session.PropertyMetadata;
import io.trino.spi.type.Type;
import io.trino.sql.SqlEnvironmentConfig;
import io.trino.sql.analyzer.AnalyzerFactory;
import io.trino.sql.parser.ParsingException;
import io.trino.sql.parser.SqlParser;
Expand Down Expand Up @@ -118,6 +120,8 @@
import static io.trino.connector.informationschema.InformationSchemaTable.SCHEMATA;
import static io.trino.connector.informationschema.InformationSchemaTable.TABLES;
import static io.trino.connector.informationschema.InformationSchemaTable.TABLE_PRIVILEGES;
import static io.trino.execution.CreateFunctionTask.defaultFunctionSchema;
import static io.trino.execution.CreateFunctionTask.qualifiedFunctionName;
import static io.trino.metadata.MetadataListing.listCatalogNames;
import static io.trino.metadata.MetadataListing.listCatalogs;
import static io.trino.metadata.MetadataListing.listSchemas;
Expand All @@ -133,6 +137,7 @@
import static io.trino.spi.StandardErrorCode.INVALID_VIEW;
import static io.trino.spi.StandardErrorCode.INVALID_VIEW_PROPERTY;
import static io.trino.spi.StandardErrorCode.MISSING_CATALOG_NAME;
import static io.trino.spi.StandardErrorCode.NOT_FOUND;
import static io.trino.spi.StandardErrorCode.NOT_SUPPORTED;
import static io.trino.spi.StandardErrorCode.SCHEMA_NOT_FOUND;
import static io.trino.spi.StandardErrorCode.TABLE_NOT_FOUND;
Expand Down Expand Up @@ -180,9 +185,11 @@ public final class ShowQueriesRewrite
private final TablePropertyManager tablePropertyManager;
private final ViewPropertyManager viewPropertyManager;
private final MaterializedViewPropertyManager materializedViewPropertyManager;
private final Optional<CatalogSchemaName> functionSchema;

@Inject
public ShowQueriesRewrite(
SqlEnvironmentConfig sqlEnvironmentConfig,
Metadata metadata,
SqlParser parser,
AccessControl accessControl,
Expand All @@ -202,6 +209,7 @@ public ShowQueriesRewrite(
this.tablePropertyManager = requireNonNull(tablePropertyManager, "tablePropertyManager is null");
this.viewPropertyManager = requireNonNull(viewPropertyManager, "viewPropertyManager is null");
this.materializedViewPropertyManager = requireNonNull(materializedViewPropertyManager, "materializedViewPropertyManager is null");
this.functionSchema = defaultFunctionSchema(sqlEnvironmentConfig);
}

@Override
Expand Down Expand Up @@ -553,6 +561,7 @@ protected Node visitShowCreate(ShowCreate node, Void context)
case VIEW -> showCreateView(node);
case TABLE -> showCreateTable(node);
case SCHEMA -> showCreateSchema(node);
case FUNCTION -> showCreateFunction(node);
};
}

Expand Down Expand Up @@ -713,6 +722,26 @@ private Query showCreateSchema(ShowCreate node)
return singleValueQuery("Create Schema", formatSql(createSchema).trim());
}

private Node showCreateFunction(ShowCreate node)
{
QualifiedObjectName functionName = qualifiedFunctionName(functionSchema, node, node.getName());

accessControl.checkCanShowCreateFunction(session.toSecurityContext(), functionName);

Collection<LanguageFunction> functions = metadata.getLanguageFunctions(session, functionName);
if (functions.isEmpty()) {
throw semanticException(NOT_FOUND, node, "Function not found");
}

List<Expression> rows = functions.stream()
.map(function -> row(new StringLiteral("CREATE " + function.sql())))
.collect(toImmutableList());

return simpleQuery(
selectList(new AllColumns()),
aliased(new Values(rows), "t", ImmutableList.of("Create Function")));
}

private static List<Property> buildProperties(
Object objectName,
Optional<String> columnName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@
import io.trino.split.SplitManager;
import io.trino.split.SplitSource;
import io.trino.sql.PlannerContext;
import io.trino.sql.SqlEnvironmentConfig;
import io.trino.sql.analyzer.Analysis;
import io.trino.sql.analyzer.Analyzer;
import io.trino.sql.analyzer.AnalyzerFactory;
Expand Down Expand Up @@ -926,6 +927,7 @@ private AnalyzerFactory createAnalyzerFactory(QueryExplainerFactory queryExplain
new DescribeInputRewrite(sqlParser),
new DescribeOutputRewrite(sqlParser),
new ShowQueriesRewrite(
new SqlEnvironmentConfig(),
plannerContext.getMetadata(),
sqlParser,
accessControl,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,15 @@ public void checkCanDropFunction(SecurityContext context, QualifiedObjectName fu
}
}

@Override
public void checkCanShowCreateFunction(SecurityContext context, QualifiedObjectName functionName)
{
Span span = startSpan("checkCanShowCreateFunction");
try (var ignored = scopedSpan(span)) {
delegate.checkCanShowCreateFunction(context, functionName);
}
}

@Override
public List<ViewExpression> getRowFilters(SecurityContext context, QualifiedObjectName tableName)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1335,6 +1335,15 @@ public FunctionDependencyDeclaration getFunctionDependencies(Session session, Ca
}
}

@Override
public Collection<LanguageFunction> getLanguageFunctions(Session session, QualifiedObjectName name)
{
Span span = startSpan("getLanguageFunctions", name);
try (var ignored = scopedSpan(span)) {
return delegate.getLanguageFunctions(session, name);
}
}

@Override
public boolean languageFunctionExists(Session session, QualifiedObjectName name, String signatureToken)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -880,6 +880,12 @@ public FunctionDependencyDeclaration getFunctionDependencies(Session session, Ca
return NO_DEPENDENCIES;
}

@Override
public Collection<LanguageFunction> getLanguageFunctions(Session session, QualifiedObjectName name)
{
throw new UnsupportedOperationException();
}

@Override
public boolean languageFunctionExists(Session session, QualifiedObjectName name, String signatureToken)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
import io.trino.spi.type.RowType;
import io.trino.spi.type.Type;
import io.trino.sql.PlannerContext;
import io.trino.sql.SqlEnvironmentConfig;
import io.trino.sql.parser.ParsingException;
import io.trino.sql.parser.SqlParser;
import io.trino.sql.planner.OptimizerConfig;
Expand Down Expand Up @@ -7676,6 +7677,7 @@ private void inSetupTransaction(Consumer<Session> consumer)
private Analyzer createAnalyzer(Session session, AccessControl accessControl)
{
StatementRewrite statementRewrite = new StatementRewrite(ImmutableSet.of(new ShowQueriesRewrite(
new SqlEnvironmentConfig(),
plannerContext.getMetadata(),
SQL_PARSER,
accessControl,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1377,6 +1377,7 @@ protected Void visitShowCreate(ShowCreate node, Integer indent)
case TABLE -> "TABLE";
case VIEW -> "VIEW";
case MATERIALIZED_VIEW -> "MATERIALIZED VIEW";
case FUNCTION -> "FUNCTION";
})
.append(" ")
.append(formatName(node.getName()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1492,6 +1492,12 @@ public Node visitShowCreateMaterializedView(SqlBaseParser.ShowCreateMaterialized
return new ShowCreate(getLocation(context), ShowCreate.Type.MATERIALIZED_VIEW, getQualifiedName(context.qualifiedName()));
}

@Override
public Node visitShowCreateFunction(SqlBaseParser.ShowCreateFunctionContext context)
{
return new ShowCreate(getLocation(context), ShowCreate.Type.FUNCTION, getQualifiedName(context.qualifiedName()));
}

@Override
public Node visitShowFunctions(SqlBaseParser.ShowFunctionsContext context)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public enum Type
VIEW,
SCHEMA,
MATERIALIZED_VIEW,
FUNCTION,
/**/;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ public void testStatementBuilder()
printStatement("show create table abc");
printStatement("show create view abc");
printStatement("show create materialized view abc");
printStatement("show create function abc");

printStatement("prepare p from select * from (select * from T) \"A B\"");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
import static io.trino.spi.security.AccessDeniedException.denySetTableProperties;
import static io.trino.spi.security.AccessDeniedException.denySetViewAuthorization;
import static io.trino.spi.security.AccessDeniedException.denyShowColumns;
import static io.trino.spi.security.AccessDeniedException.denyShowCreateFunction;
import static io.trino.spi.security.AccessDeniedException.denyShowCreateSchema;
import static io.trino.spi.security.AccessDeniedException.denyShowCreateTable;
import static io.trino.spi.security.AccessDeniedException.denyShowCurrentRoles;
Expand Down Expand Up @@ -671,6 +672,16 @@ default void checkCanDropFunction(ConnectorSecurityContext context, SchemaRoutin
denyDropFunction(function.toString());
}

/**
* Check if identity is allowed to execute SHOW CREATE FUNCTION.
*
* @throws AccessDeniedException if not allowed
*/
default void checkCanShowCreateFunction(ConnectorSecurityContext context, SchemaRoutineName function)
{
denyShowCreateFunction(function.toString());
}

/**
* Get row filters associated with the given table and identity.
* <p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,16 @@ public static void denyDropFunction(String functionName, String extraInfo)
throw new AccessDeniedException(format("Cannot drop function %s%s", functionName, formatExtraInfo(extraInfo)));
}

public static void denyShowCreateFunction(String functionName)
{
denyShowCreateFunction(functionName, null);
}

public static void denyShowCreateFunction(String functionName, String extraInfo)
{
throw new AccessDeniedException(format("Cannot show create function for %s%s", functionName, formatExtraInfo(extraInfo)));
}

private static Object formatExtraInfo(String extraInfo)
{
if (extraInfo == null || extraInfo.isEmpty()) {
Expand Down
Loading

0 comments on commit aaff6b5

Please sign in to comment.