Skip to content

Commit

Permalink
Add syntax support for CREATE FUNCTION
Browse files Browse the repository at this point in the history
  • Loading branch information
caithagoras0 committed Oct 7, 2019
1 parent 7eae9aa commit ca09ed8
Show file tree
Hide file tree
Showing 10 changed files with 583 additions and 4 deletions.
7 changes: 7 additions & 0 deletions presto-docs/src/main/sphinx/language/reserved.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Keyword SQL:2016 SQL-92
``AS`` reserved reserved
``BETWEEN`` reserved reserved
``BY`` reserved reserved
``CALLED`` reserved
``CASE`` reserved reserved
``CAST`` reserved reserved
``CONSTRAINT`` reserved reserved
Expand All @@ -27,6 +28,7 @@ Keyword SQL:2016 SQL-92
``DEALLOCATE`` reserved reserved
``DELETE`` reserved reserved
``DESCRIBE`` reserved reserved
``DETERMINISTIC`` reserved
``DISTINCT`` reserved reserved
``DROP`` reserved reserved
``ELSE`` reserved reserved
Expand All @@ -40,6 +42,7 @@ Keyword SQL:2016 SQL-92
``FOR`` reserved reserved
``FROM`` reserved reserved
``FULL`` reserved reserved
``FUNCTION`` reserved
``GROUP`` reserved reserved
``GROUPING`` reserved
``HAVING`` reserved reserved
Expand All @@ -50,6 +53,7 @@ Keyword SQL:2016 SQL-92
``INTO`` reserved reserved
``IS`` reserved reserved
``JOIN`` reserved reserved
``LANGUAGE`` reserved reserved
``LEFT`` reserved reserved
``LIKE`` reserved reserved
``LOCALTIME`` reserved
Expand All @@ -64,9 +68,12 @@ Keyword SQL:2016 SQL-92
``OUTER`` reserved reserved
``PREPARE`` reserved reserved
``RECURSIVE`` reserved
``RETURN`` reserved
``RETURNS`` reserved
``RIGHT`` reserved reserved
``ROLLUP`` reserved
``SELECT`` reserved reserved
``SQL`` reserved reserved
``TABLE`` reserved reserved
``THEN`` reserved reserved
``TRUE`` reserved reserved
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ statement
| ANALYZE qualifiedName (WITH properties)? #analyze
| CREATE (OR REPLACE)? VIEW qualifiedName AS query #createView
| DROP VIEW (IF EXISTS)? qualifiedName #dropView
| CREATE (OR REPLACE)? FUNCTION functionName=qualifiedName
'(' (sqlParameterDeclaration (',' sqlParameterDeclaration)*)? ')'
RETURNS returnType=type routineCharacteristics routineBody #createFunction
| CALL qualifiedName '(' (callArgument (',' callArgument)*)? ')' #call
| CREATE ROLE name=identifier
(WITH ADMIN grantor)? #createRole
Expand Down Expand Up @@ -139,6 +142,38 @@ property
: identifier EQ expression
;

sqlParameterDeclaration
: identifier type
;

routineCharacteristics
: routineCharacteristic*
;

routineCharacteristic
: LANGUAGE language
| determinism
| nullCallClause
;

routineBody
: RETURN expression
;

language
: SQL
;

determinism
: DETERMINISTIC
| NOT DETERMINISTIC;

nullCallClause
: RETURNS NULL ON NULL INPUT
| CALLED ON NULL INPUT
;


queryNoWith:
queryTerm
(ORDER BY sortItem (',' sortItem)*)?
Expand Down Expand Up @@ -511,6 +546,7 @@ BERNOULLI: 'BERNOULLI';
BETWEEN: 'BETWEEN';
BY: 'BY';
CALL: 'CALL';
CALLED: 'CALLED';
CASCADE: 'CASCADE';
CASE: 'CASE';
CAST: 'CAST';
Expand All @@ -537,6 +573,7 @@ DEALLOCATE: 'DEALLOCATE';
DELETE: 'DELETE';
DESC: 'DESC';
DESCRIBE: 'DESCRIBE';
DETERMINISTIC: 'DETERMINISTIC';
DISTINCT: 'DISTINCT';
DISTRIBUTED: 'DISTRIBUTED';
DROP: 'DROP';
Expand All @@ -557,6 +594,7 @@ FOR: 'FOR';
FORMAT: 'FORMAT';
FROM: 'FROM';
FULL: 'FULL';
FUNCTION: 'FUNCTION';
FUNCTIONS: 'FUNCTIONS';
GRANT: 'GRANT';
GRANTED: 'GRANTED';
Expand All @@ -580,6 +618,7 @@ IS: 'IS';
ISOLATION: 'ISOLATION';
JSON: 'JSON';
JOIN: 'JOIN';
LANGUAGE: 'LANGUAGE';
LAST: 'LAST';
LATERAL: 'LATERAL';
LEFT: 'LEFT';
Expand Down Expand Up @@ -628,6 +667,8 @@ REPEATABLE: 'REPEATABLE';
REPLACE: 'REPLACE';
RESET: 'RESET';
RESTRICT: 'RESTRICT';
RETURN: 'RETURN';
RETURNS: 'RETURNS';
REVOKE: 'REVOKE';
RIGHT: 'RIGHT';
ROLE: 'ROLE';
Expand All @@ -646,6 +687,7 @@ SET: 'SET';
SETS: 'SETS';
SHOW: 'SHOW';
SOME: 'SOME';
SQL: 'SQL';
START: 'START';
STATS: 'STATS';
SUBSTRING: 'SUBSTRING';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.facebook.presto.sql.tree.CallArgument;
import com.facebook.presto.sql.tree.ColumnDefinition;
import com.facebook.presto.sql.tree.Commit;
import com.facebook.presto.sql.tree.CreateFunction;
import com.facebook.presto.sql.tree.CreateRole;
import com.facebook.presto.sql.tree.CreateSchema;
import com.facebook.presto.sql.tree.CreateTable;
Expand Down Expand Up @@ -73,6 +74,7 @@
import com.facebook.presto.sql.tree.Revoke;
import com.facebook.presto.sql.tree.RevokeRoles;
import com.facebook.presto.sql.tree.Rollback;
import com.facebook.presto.sql.tree.RoutineCharacteristics;
import com.facebook.presto.sql.tree.Row;
import com.facebook.presto.sql.tree.SampledRelation;
import com.facebook.presto.sql.tree.Select;
Expand All @@ -91,6 +93,7 @@
import com.facebook.presto.sql.tree.ShowStats;
import com.facebook.presto.sql.tree.ShowTables;
import com.facebook.presto.sql.tree.SingleColumn;
import com.facebook.presto.sql.tree.SqlParameterDeclaration;
import com.facebook.presto.sql.tree.StartTransaction;
import com.facebook.presto.sql.tree.Table;
import com.facebook.presto.sql.tree.TableSubquery;
Expand All @@ -103,6 +106,7 @@
import com.facebook.presto.sql.tree.WithQuery;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;

import java.util.ArrayList;
import java.util.Iterator;
Expand Down Expand Up @@ -548,6 +552,23 @@ protected Void visitCreateView(CreateView node, Integer indent)
return null;
}

@Override
protected Void visitCreateFunction(CreateFunction node, Integer indent)
{
builder.append("CREATE FUNCTION ")
.append(formatName(node.getFunctionName()))
.append(" ")
.append(formatSqlParameterDeclarations(node.getParameters()))
.append("\nRETURNS ")
.append(node.getReturnType())
.append("\n")
.append(formatRoutineCharacteristics(node.getCharacteristics()))
.append("\nRETURN ")
.append(formatExpression(node.getBody(), parameters));

return null;
}

@Override
protected Void visitDropView(DropView node, Integer context)
{
Expand Down Expand Up @@ -852,6 +873,33 @@ private String formatPropertiesSingleLine(List<Property> properties)
return " WITH ( " + propertyList + " )";
}

private String formatSqlParameterDeclarations(List<SqlParameterDeclaration> parameters)
{
if (parameters.isEmpty()) {
return "()";
}
return parameters.stream()
.map(parameter -> format(
"%s%s %s",
INDENT,
formatExpression(parameter.getName(), this.parameters),
parameter.getType()))
.collect(joining(",\n", "(\n", "\n)"));
}

private String formatRoutineCharacteristics(RoutineCharacteristics characteristics)
{
return Joiner.on("\n").join(ImmutableList.of(
"LANGUAGE " + formatRoutineCharacteristicName(characteristics.getLanguage()),
formatRoutineCharacteristicName(characteristics.getDeterminism()),
formatRoutineCharacteristicName(characteristics.getNullCallClause())));
}

private String formatRoutineCharacteristicName(Enum characteristic)
{
return characteristic.name().replace("_", " ");
}

private static String formatName(String name)
{
if (NAME_PATTERN.matcher(name).matches()) {
Expand Down Expand Up @@ -1284,6 +1332,7 @@ protected Void visitShowRoleGrants(ShowRoleGrants node, Integer context)

return null;
}

private void processRelation(Relation relation, Integer indent)
{
// TODO: handle this properly
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import com.facebook.presto.sql.tree.ColumnDefinition;
import com.facebook.presto.sql.tree.Commit;
import com.facebook.presto.sql.tree.ComparisonExpression;
import com.facebook.presto.sql.tree.CreateFunction;
import com.facebook.presto.sql.tree.CreateRole;
import com.facebook.presto.sql.tree.CreateSchema;
import com.facebook.presto.sql.tree.CreateTable;
Expand Down Expand Up @@ -118,6 +119,8 @@
import com.facebook.presto.sql.tree.RevokeRoles;
import com.facebook.presto.sql.tree.Rollback;
import com.facebook.presto.sql.tree.Rollup;
import com.facebook.presto.sql.tree.RoutineCharacteristics;
import com.facebook.presto.sql.tree.RoutineCharacteristics.Language;
import com.facebook.presto.sql.tree.Row;
import com.facebook.presto.sql.tree.SampledRelation;
import com.facebook.presto.sql.tree.SearchedCaseExpression;
Expand All @@ -140,6 +143,7 @@
import com.facebook.presto.sql.tree.SimpleGroupBy;
import com.facebook.presto.sql.tree.SingleColumn;
import com.facebook.presto.sql.tree.SortItem;
import com.facebook.presto.sql.tree.SqlParameterDeclaration;
import com.facebook.presto.sql.tree.StartTransaction;
import com.facebook.presto.sql.tree.Statement;
import com.facebook.presto.sql.tree.StringLiteral;
Expand Down Expand Up @@ -175,6 +179,13 @@
import java.util.Optional;
import java.util.stream.Collectors;

import static com.facebook.presto.sql.tree.RoutineCharacteristics.Determinism;
import static com.facebook.presto.sql.tree.RoutineCharacteristics.Determinism.DETERMINISTIC;
import static com.facebook.presto.sql.tree.RoutineCharacteristics.Determinism.NOT_DETERMINISTIC;
import static com.facebook.presto.sql.tree.RoutineCharacteristics.NullCallClause;
import static com.facebook.presto.sql.tree.RoutineCharacteristics.NullCallClause.CALLED_ON_NULL_INPUT;
import static com.facebook.presto.sql.tree.RoutineCharacteristics.NullCallClause.RETURNS_NULL_ON_NULL_INPUT;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.Iterables.getOnlyElement;
import static java.lang.String.format;
Expand Down Expand Up @@ -390,6 +401,26 @@ public Node visitCreateView(SqlBaseParser.CreateViewContext context)
context.REPLACE() != null);
}

@Override
public Node visitCreateFunction(SqlBaseParser.CreateFunctionContext context)
{
return new CreateFunction(
getQualifiedName(context.functionName),
context.REPLACE() != null,
context.sqlParameterDeclaration().stream()
.map(this::getParameterDeclarations)
.collect(toImmutableList()),
getType(context.returnType),
getRoutineCharacteristics(context.routineCharacteristics()),
(Expression) visit(context.routineBody()));
}

@Override
public Node visitRoutineBody(SqlBaseParser.RoutineBodyContext context)
{
return visit(context.expression());
}

@Override
public Node visitStartTransaction(SqlBaseParser.StartTransactionContext context)
{
Expand Down Expand Up @@ -2161,6 +2192,48 @@ private String getType(SqlBaseParser.TypeContext type)
throw new IllegalArgumentException("Unsupported type specification: " + type.getText());
}

private SqlParameterDeclaration getParameterDeclarations(SqlBaseParser.SqlParameterDeclarationContext context)
{
return new SqlParameterDeclaration((Identifier) visit(context.identifier()), getType(context.type()));
}

private RoutineCharacteristics getRoutineCharacteristics(SqlBaseParser.RoutineCharacteristicsContext context)
{
Language language = null;
Determinism determinism = null;
NullCallClause nullCallClause = null;

for (SqlBaseParser.RoutineCharacteristicContext characteristic : context.routineCharacteristic()) {
if (characteristic.language() != null) {
checkArgument(characteristic.language().SQL() != null, "Unsupported language: %s", characteristic.language().getText());
if (language != null) {
throw new ParsingException(format("Duplicate language clause: %s", characteristic.language().getText()), getLocation(characteristic.language()));
}
language = Language.SQL;
}
else if (characteristic.determinism() != null) {
if (determinism != null) {
throw new ParsingException(format("Duplicate determinism characteristics: %s", characteristic.determinism().getText()), getLocation(characteristic.determinism()));
}
determinism = characteristic.determinism().NOT() == null ? DETERMINISTIC : NOT_DETERMINISTIC;
}
else if (characteristic.nullCallClause() != null) {
if (nullCallClause != null) {
throw new ParsingException(format("Duplicate null-call clause: %s", characteristic.nullCallClause().getText()), getLocation(characteristic.nullCallClause()));
}
nullCallClause = characteristic.nullCallClause().CALLED() != null ? CALLED_ON_NULL_INPUT : RETURNS_NULL_ON_NULL_INPUT;
}
else {
throw new IllegalArgumentException(format("Unsupported RoutineCharacteristic: %s", characteristic.getText()));
}
}

return new RoutineCharacteristics(
Optional.ofNullable(language),
Optional.ofNullable(determinism),
Optional.ofNullable(nullCallClause));
}

private String typeParameterToString(SqlBaseParser.TypeParameterContext typeParameter)
{
if (typeParameter.INTEGER_VALUE() != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,11 @@ protected R visitDropView(DropView node, C context)
return visitStatement(node, context);
}

protected R visitCreateFunction(CreateFunction node, C context)
{
return visitStatement(node, context);
}

protected R visitInsert(Insert node, C context)
{
return visitStatement(node, context);
Expand Down
Loading

0 comments on commit ca09ed8

Please sign in to comment.