Skip to content

Commit

Permalink
Add CREATE FOLDER $ RECUSRIVE SQL Support
Browse files Browse the repository at this point in the history
  • Loading branch information
Peter Wicks committed Feb 6, 2020
1 parent ee4cfb7 commit e3b0da2
Show file tree
Hide file tree
Showing 6 changed files with 211 additions and 3 deletions.
9 changes: 6 additions & 3 deletions sabot/kernel/src/main/codegen/data/Parser.tdd
Expand Up @@ -73,7 +73,8 @@
"FORCE",
"LAZY",
"MAINTAIN",
"MISSING"
"MISSING",
"FOLDER"
]

nonReservedKeywords: [
Expand Down Expand Up @@ -111,7 +112,8 @@
"FORCE",
"LAZY",
"MAINTAIN",
"MISSING"
"MISSING",
"FOLDER"
]

# List of methods for parsing custom SQL statements.
Expand All @@ -128,7 +130,8 @@
"SqlAccel()",
"SqlRefreshReflection()",
"SqlLoadMaterialization()",
"SqlCompactMaterialization()"
"SqlCompactMaterialization()",
"SqlCreateFolderRecursive()"
]

# List of methods for parsing custom literals.
Expand Down
18 changes: 18 additions & 0 deletions sabot/kernel/src/main/codegen/includes/parserImpls.ftl
Expand Up @@ -376,3 +376,21 @@ SqlNode SqlCompactMaterialization() :
return new SqlCompactMaterialization(pos, materializationPath, newMaterializationId);
}
}

/**
* Parses a CREATE FOLDER statement
*/
SqlNode SqlCreateFolderRecursive() :
{
SqlParserPos pos;
SqlIdentifier folderPath;
}
{
<CREATE> { pos = getPos(); }
<FOLDER>
{ folderPath = CompoundIdentifier(); }
<RECURSIVE>
{
return new SqlCreateFolderRecursive(pos, folderPath);
}
}
Expand Up @@ -21,6 +21,8 @@
import java.util.Locale;
import java.util.Optional;

import com.dremio.exec.planner.sql.handlers.direct.CreateFolderRecursiveHandler;
import com.dremio.exec.planner.sql.parser.SqlCreateFolderRecursive;
import org.apache.calcite.sql.SqlNode;

import com.dremio.common.exceptions.UserException;
Expand Down Expand Up @@ -313,6 +315,8 @@ private CommandRunner<?> getSqlCommand(String sql, boolean isPrepare) {
return direct.create(new RefreshSourceStatusHandler(catalog));
} else if (sqlNode instanceof SqlSetApprox) {
return direct.create(new SetApproxHandler(catalog, context.getNamespaceService()));
} else if (sqlNode instanceof SqlCreateFolderRecursive) {
return direct.create(new CreateFolderRecursiveHandler(catalog, context.getNamespaceService()));
}

// fallthrough
Expand Down
@@ -0,0 +1,99 @@
/*
* Copyright (C) 2017-2019 Dremio Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.dremio.exec.planner.sql.handlers.direct;

import static java.util.Collections.singletonList;

import java.util.ArrayList;
import java.util.List;

import com.dremio.common.exceptions.UserException;
import com.dremio.exec.catalog.Catalog;
import com.dremio.exec.planner.sql.parser.SqlCreateFolderRecursive;
import com.dremio.service.namespace.NamespaceException;
import com.dremio.service.namespace.NamespaceKey;
import com.dremio.service.namespace.NamespaceService;
import com.dremio.service.namespace.space.proto.FolderConfig;
import com.dremio.service.namespace.space.proto.SpaceConfig;

import static com.dremio.exec.planner.sql.handlers.direct.SimpleCommandResult.successful;

import org.apache.calcite.sql.SqlNode;


/**
* Handler for <code>CREATE FOLDER RECURSIVE</code> command.
*/
public class CreateFolderRecursiveHandler extends SimpleDirectHandler {
private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(CreateFolderRecursiveHandler.class);

private final Catalog catalog;
private final NamespaceService namespaceService;

public CreateFolderRecursiveHandler(Catalog catalog, NamespaceService namespaceService) {
this.catalog = catalog;
this.namespaceService = namespaceService;
}

@Override
public List<SimpleCommandResult> toResult(String sql, SqlNode sqlNode) throws Exception {
final SqlCreateFolderRecursive sqlRefreshSourceStatus = SqlNodeUtil.unwrap(sqlNode, SqlCreateFolderRecursive.class);
final NamespaceKey path = sqlRefreshSourceStatus.getPath();

String root = path.getRoot();
if(root.startsWith("@") || root.equalsIgnoreCase("sys") || root.equalsIgnoreCase("INFORMATION_SCHEMA")) {
throw UserException.parseError().message("Unable to create spaces or folders in Home, sys, or INFORMATION_SCHEMA.", path).build(logger);
}

String message;
try {
// Check if space exists
final NamespaceKey rootKey = new NamespaceKey(path.getRoot());
try {
namespaceService.getSpace(rootKey);
} catch (NamespaceException nse) {
// Space does not exist, create it
SpaceConfig spaceConfig = new SpaceConfig()
.setName(path.getRoot());
namespaceService.addOrUpdateSpace(rootKey, spaceConfig);
}

// For each sub folder, create folder
final List<String> folderPath = new ArrayList<>();
folderPath.add(path.getRoot());
for(int p=1;p<path.getPathComponents().size();p++){
final String folderName = path.getPathComponents().get(p);
folderPath.add(folderName);
final NamespaceKey folderKey = new NamespaceKey(folderPath);
try {
namespaceService.getFolder(folderKey);
} catch (NamespaceException nse) {
// Space does not exist, create it
final FolderConfig folderConfig = new FolderConfig();
folderConfig.setFullPathList(folderPath);
folderConfig.setName(folderName);
namespaceService.addOrUpdateFolder(folderKey, folderConfig);
}
}

message = "Created Successfully";
} catch (Exception ex) {
message = ex.getMessage();
}

return singletonList(successful(String.format(message, path.toString())));
}
}
Expand Up @@ -160,6 +160,7 @@ RewriteType[] should be R(D, E, D, D).
rules.put(SqlSelect.class, R(D, E, D, E, E, E, E, E, D, D));
rules.put(SqlCreateTable.class, R(D, D, D, D, D, D, E, D, D));
rules.put(SqlCreateView.class, R(D, E, E, D));
rules.put(SqlCreateFolderRecursive.class, R(D));
rules.put(SqlDescribeTable.class, R(D, D, E));
rules.put(SqlDropView.class, R(D, D));
rules.put(SqlShowFiles.class, R(D));
Expand Down
@@ -0,0 +1,83 @@
/*
* Copyright (C) 2017-2019 Dremio Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.dremio.exec.planner.sql.parser;

import java.util.List;

import org.apache.calcite.sql.SqlCall;
import org.apache.calcite.sql.SqlIdentifier;
import org.apache.calcite.sql.SqlKind;
import org.apache.calcite.sql.SqlLiteral;
import org.apache.calcite.sql.SqlNode;
import org.apache.calcite.sql.SqlOperator;
import org.apache.calcite.sql.SqlSpecialOperator;
import org.apache.calcite.sql.SqlWriter;
import org.apache.calcite.sql.parser.SqlParserPos;
import org.apache.calcite.util.ImmutableNullableList;

import com.dremio.service.namespace.NamespaceKey;

/**
* SQL node tree for <code>CREATE FOLDER folder_path RECURSIVE </code>
*/
public class SqlCreateFolderRecursive extends SqlSystemCall {

public static final SqlSpecialOperator OPERATOR =
new SqlSpecialOperator("CREATE_FOLDER", SqlKind.OTHER) {
@Override public SqlCall createCall(SqlLiteral functionQualifier,
SqlParserPos pos, SqlNode... operands) {
return new SqlCreateFolderRecursive(pos, (SqlIdentifier) operands[0]);
}
};

private SqlIdentifier folderPath;

/** Creates a SqlCreateFolderRecursive. */
public SqlCreateFolderRecursive(SqlParserPos pos, SqlIdentifier source) {
super(pos);
this.folderPath = source;
}

@Override public void unparse(SqlWriter writer, int leftPrec, int rightPrec) {
writer.keyword("CREATE");
writer.keyword("FOLDER");
folderPath.unparse(writer, leftPrec, rightPrec);
writer.keyword("RECURSIVE");
}

@Override public void setOperand(int i, SqlNode operand) {
switch (i) {
case 0:
folderPath = (SqlIdentifier) operand;
break;
default:
throw new AssertionError(i);
}
}

@Override public SqlOperator getOperator() {
return OPERATOR;
}

@Override public List<SqlNode> getOperandList() {
return ImmutableNullableList.<SqlNode>of(folderPath);
}

public NamespaceKey getPath() {
return new NamespaceKey(folderPath.names);
}
}

0 comments on commit e3b0da2

Please sign in to comment.