[ASTERIXDB-3259][MTD] Implement database name resolution
- user model changes: no
- storage format changes: no
- interface changes: yes
Details:
Currently, qualification to database objects are resolved
as DataverseName only. That is a multipart identifier is
resolved as pure DataverseName only and the
database name is defaulted to 'System'/'Default'.
This patch is to resolve qualification to database objects
as database_name + dataverse_name + database_object.
This resolution is only applicable when database is used.
That is when cloud deployment is used.
Change-Id: Ic3f1d7b2019fcf62e5dcbce8c05a78d18cc0a710
Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/17861
Reviewed-by: Murtadha Hubail <mhubail@apache.org>
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Tested-by: Ali Alsuliman <ali.al.solaiman@gmail.com>
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/cc/CcApplicationContext.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/cc/CcApplicationContext.java
index 24b4856..6ea7aeb 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/cc/CcApplicationContext.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/cc/CcApplicationContext.java
@@ -57,7 +57,6 @@
import org.apache.asterix.common.external.IAdapterFactoryService;
import org.apache.asterix.common.metadata.IMetadataBootstrap;
import org.apache.asterix.common.metadata.IMetadataLockUtil;
-import org.apache.asterix.common.metadata.NamespacePathResolver;
import org.apache.asterix.common.replication.INcLifecycleCoordinator;
import org.apache.asterix.common.storage.ICompressionManager;
import org.apache.asterix.common.transactions.IResourceIdManager;
@@ -126,7 +125,7 @@
private final IDataPartitioningProvider dataPartitioningProvider;
private final IGlobalTxManager globalTxManager;
private final IOManager ioManager;
- private final NamespacePathResolver namespacePathResolver;
+ private final INamespacePathResolver namespacePathResolver;
private final INamespaceResolver namespaceResolver;
public CcApplicationContext(ICCServiceContext ccServiceCtx, HyracksConnection hcc,
@@ -136,8 +135,8 @@
IMetadataLockUtil mdLockUtil, IReceptionistFactory receptionistFactory,
IConfigValidatorFactory configValidatorFactory, Object extensionManager,
IAdapterFactoryService adapterFactoryService, IGlobalTxManager globalTxManager, IOManager ioManager,
- CloudProperties cloudProperties, INamespaceResolver namespaceResolver)
- throws AlgebricksException, IOException {
+ CloudProperties cloudProperties, INamespaceResolver namespaceResolver,
+ INamespacePathResolver namespacePathResolver) throws AlgebricksException, IOException {
this.ccServiceCtx = ccServiceCtx;
this.hcc = hcc;
this.activeLifeCycleListener = activeLifeCycleListener;
@@ -173,7 +172,7 @@
requestTracker = new RequestTracker(this);
configValidator = configValidatorFactory.create();
this.adapterFactoryService = adapterFactoryService;
- this.namespacePathResolver = new NamespacePathResolver(isCloudDeployment());
+ this.namespacePathResolver = namespacePathResolver;
this.namespaceResolver = namespaceResolver;
this.globalTxManager = globalTxManager;
this.ioManager = ioManager;
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/nc/NCAppRuntimeContext.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/nc/NCAppRuntimeContext.java
index ab6a62a..a439fe5 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/nc/NCAppRuntimeContext.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/nc/NCAppRuntimeContext.java
@@ -61,7 +61,6 @@
import org.apache.asterix.common.context.GlobalVirtualBufferCache;
import org.apache.asterix.common.context.IStorageComponentProvider;
import org.apache.asterix.common.library.ILibraryManager;
-import org.apache.asterix.common.metadata.NamespacePathResolver;
import org.apache.asterix.common.replication.IReplicationChannel;
import org.apache.asterix.common.replication.IReplicationManager;
import org.apache.asterix.common.replication.IReplicationStrategyFactory;
@@ -172,11 +171,12 @@
private IDiskWriteRateLimiterProvider diskWriteRateLimiterProvider;
private final CloudProperties cloudProperties;
private IPartitionBootstrapper partitionBootstrapper;
- private final NamespacePathResolver namespacePathResolver;
+ private final INamespacePathResolver namespacePathResolver;
private final INamespaceResolver namespaceResolver;
public NCAppRuntimeContext(INCServiceContext ncServiceContext, NCExtensionManager extensionManager,
- IPropertiesFactory propertiesFactory, INamespaceResolver namespaceResolver) {
+ IPropertiesFactory propertiesFactory, INamespaceResolver namespaceResolver,
+ INamespacePathResolver namespacePathResolver) {
this.ncServiceContext = ncServiceContext;
compilerProperties = propertiesFactory.newCompilerProperties();
externalProperties = propertiesFactory.newExternalProperties();
@@ -195,7 +195,7 @@
.createResourceIdFactory();
persistedResourceRegistry = ncServiceContext.getPersistedResourceRegistry();
cacheManager = new CacheManager();
- namespacePathResolver = new NamespacePathResolver(isCloudDeployment());
+ this.namespacePathResolver = namespacePathResolver;
this.namespaceResolver = namespaceResolver;
}
@@ -205,7 +205,8 @@
boolean initialRun) throws IOException {
ioManager = getServiceContext().getIoManager();
if (isCloudDeployment()) {
- persistenceIOManager = CloudManagerProvider.createIOManager(cloudProperties, ioManager);
+ persistenceIOManager =
+ CloudManagerProvider.createIOManager(cloudProperties, ioManager, namespacePathResolver);
partitionBootstrapper = CloudManagerProvider.getCloudPartitionBootstrapper(persistenceIOManager);
} else {
persistenceIOManager = ioManager;
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java
index 4b19200..f404ca5 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java
@@ -663,8 +663,7 @@
MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
return false;
} else {
- //TODO(DB): change
- throw new CompilationException(ErrorCode.DATAVERSE_EXISTS, stmtCreateDatabase.getSourceLocation(),
+ throw new CompilationException(ErrorCode.DATABASE_EXISTS, stmtCreateDatabase.getSourceLocation(),
databaseName);
}
}
@@ -703,6 +702,12 @@
try {
DataverseName dvName = stmtCreateDataverse.getDataverseName();
String dbName = stmtCreateDataverse.getDatabaseName();
+ Database db = MetadataManager.INSTANCE.getDatabase(mdTxnCtx, dbName);
+ if (db == null) {
+ throw new CompilationException(ErrorCode.UNKNOWN_DATABASE, stmtCreateDataverse.getSourceLocation(),
+ dbName);
+ }
+
Dataverse dv =
MetadataManager.INSTANCE.getDataverse(metadataProvider.getMetadataTxnContext(), dbName, dvName);
if (dv != null) {
@@ -872,6 +877,8 @@
DatasetFormatInfo datasetFormatInfo = dd.getDatasetFormatInfo(storageProperties.getStorageFormat(),
storageProperties.getColumnMaxTupleCount(), storageProperties.getColumnFreeSpaceTolerance());
try {
+ //TODO(DB): also check for database existence?
+
// Check if the dataverse exists
Dataverse dv = MetadataManager.INSTANCE.getDataverse(mdTxnCtx, databaseName, dataverseName);
if (dv == null) {
@@ -2137,6 +2144,18 @@
List<FeedEventsListener> feedsToStop = new ArrayList<>();
List<JobSpecification> jobsToExecute = new ArrayList<>();
try {
+ Database db = MetadataManager.INSTANCE.getDatabase(mdTxnCtx, databaseName);
+ if (db == null) {
+ if (stmtDropDataverse.getIfExists()) {
+ if (warningCollector.shouldWarn()) {
+ warningCollector.warn(Warning.of(sourceLoc, ErrorCode.UNKNOWN_DATABASE, databaseName));
+ }
+ MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
+ return false;
+ } else {
+ throw new CompilationException(ErrorCode.UNKNOWN_DATABASE, sourceLoc, databaseName);
+ }
+ }
Dataverse dv = MetadataManager.INSTANCE.getDataverse(mdTxnCtx, databaseName, dataverseName);
if (dv == null) {
if (stmtDropDataverse.getIfExists()) {
@@ -2338,6 +2357,8 @@
List<JobSpecification> jobsToExecute = new ArrayList<>();
Dataset ds = null;
try {
+ //TODO(DB): also check for database existence?
+
// Check if the dataverse exists
Dataverse dv = MetadataManager.INSTANCE.getDataverse(mdTxnCtx.getValue(), databaseName, dataverseName);
if (dv == null) {
@@ -2896,7 +2917,8 @@
ViewDecl viewDecl = new ViewDecl(viewQualifiedName, cvs.getViewBodyExpression());
viewDecl.setSourceLocation(sourceLoc);
IQueryRewriter queryRewriter = rewriterFactory.createQueryRewriter();
- Query wrappedQuery = queryRewriter.createViewAccessorQuery(viewDecl);
+ Query wrappedQuery =
+ queryRewriter.createViewAccessorQuery(viewDecl, metadataProvider.getNamespaceResolver());
metadataProvider.setDefaultNamespace(ns);
LangRewritingContext langRewritingContext = createLangRewritingContext(metadataProvider, declaredFunctions,
Collections.singletonList(viewDecl), warningCollector, wrappedQuery.getVarCounter());
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/CCApplication.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/CCApplication.java
index de3cb82..c93a23b 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/CCApplication.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/CCApplication.java
@@ -64,6 +64,7 @@
import org.apache.asterix.cloud.CloudManagerProvider;
import org.apache.asterix.common.api.AsterixThreadFactory;
import org.apache.asterix.common.api.IConfigValidatorFactory;
+import org.apache.asterix.common.api.INamespacePathResolver;
import org.apache.asterix.common.api.INamespaceResolver;
import org.apache.asterix.common.api.INodeJobTracker;
import org.apache.asterix.common.api.IReceptionistFactory;
@@ -71,6 +72,7 @@
import org.apache.asterix.common.cluster.IGlobalTxManager;
import org.apache.asterix.common.config.AsterixExtension;
import org.apache.asterix.common.config.CloudProperties;
+import org.apache.asterix.common.config.CompilerProperties;
import org.apache.asterix.common.config.ExtensionProperties;
import org.apache.asterix.common.config.ExternalProperties;
import org.apache.asterix.common.config.GlobalConfig;
@@ -82,6 +84,7 @@
import org.apache.asterix.common.external.IAdapterFactoryService;
import org.apache.asterix.common.library.ILibraryManager;
import org.apache.asterix.common.metadata.IMetadataLockUtil;
+import org.apache.asterix.common.metadata.NamespacePathResolver;
import org.apache.asterix.common.metadata.NamespaceResolver;
import org.apache.asterix.common.replication.INcLifecycleCoordinator;
import org.apache.asterix.common.utils.Servlets;
@@ -167,8 +170,12 @@
new ReplicationProperties(PropertiesAccessor.getInstance(ccServiceCtx.getAppConfig()));
INcLifecycleCoordinator lifecycleCoordinator = createNcLifeCycleCoordinator(repProp.isReplicationEnabled());
componentProvider = new StorageComponentProvider();
+ boolean isDbResolutionEnabled =
+ ccServiceCtx.getAppConfig().getBoolean(CompilerProperties.Option.COMPILER_ENABLE_DB_RESOLUTION);
boolean cloudDeployment = ccServiceCtx.getAppConfig().getBoolean(CLOUD_DEPLOYMENT);
- INamespaceResolver namespaceResolver = new NamespaceResolver(cloudDeployment);
+ boolean useDatabaseResolution = cloudDeployment && isDbResolutionEnabled;
+ INamespaceResolver namespaceResolver = new NamespaceResolver(useDatabaseResolution);
+ INamespacePathResolver namespacePathResolver = new NamespacePathResolver(useDatabaseResolution);
ccExtensionManager = new CCExtensionManager(new ArrayList<>(getExtensions()), namespaceResolver);
IGlobalRecoveryManager globalRecoveryManager = createGlobalRecoveryManager();
final CCConfig ccConfig = controllerService.getCCConfig();
@@ -179,12 +186,13 @@
CloudProperties cloudProperties = null;
if (cloudDeployment) {
cloudProperties = new CloudProperties(PropertiesAccessor.getInstance(ccServiceCtx.getAppConfig()));
- ioManager = (IOManager) CloudManagerProvider.createIOManager(cloudProperties, ioManager);
+ ioManager =
+ (IOManager) CloudManagerProvider.createIOManager(cloudProperties, ioManager, namespacePathResolver);
}
IGlobalTxManager globalTxManager = createGlobalTxManager(ioManager);
appCtx = createApplicationContext(null, globalRecoveryManager, lifecycleCoordinator, Receptionist::new,
ConfigValidator::new, ccExtensionManager, new AdapterFactoryService(), globalTxManager, ioManager,
- cloudProperties, namespaceResolver);
+ cloudProperties, namespaceResolver, namespacePathResolver);
if (System.getProperty("java.rmi.server.hostname") == null) {
System.setProperty("java.rmi.server.hostname", ccConfig.getClusterPublicAddress());
}
@@ -233,11 +241,13 @@
IReceptionistFactory receptionistFactory, IConfigValidatorFactory configValidatorFactory,
CCExtensionManager ccExtensionManager, IAdapterFactoryService adapterFactoryService,
IGlobalTxManager globalTxManager, IOManager ioManager, CloudProperties cloudProperties,
- INamespaceResolver namespaceResolver) throws AlgebricksException, IOException {
+ INamespaceResolver namespaceResolver, INamespacePathResolver namespacePathResolver)
+ throws AlgebricksException, IOException {
return new CcApplicationContext(ccServiceCtx, hcc, () -> MetadataManager.INSTANCE, globalRecoveryManager,
lifecycleCoordinator, new ActiveNotificationHandler(), componentProvider, new MetadataLockManager(),
createMetadataLockUtil(), receptionistFactory, configValidatorFactory, ccExtensionManager,
- adapterFactoryService, globalTxManager, ioManager, cloudProperties, namespaceResolver);
+ adapterFactoryService, globalTxManager, ioManager, cloudProperties, namespaceResolver,
+ namespacePathResolver);
}
protected IGlobalRecoveryManager createGlobalRecoveryManager() throws Exception {
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/NCApplication.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/NCApplication.java
index eea87d8..4acc039 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/NCApplication.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/NCApplication.java
@@ -55,11 +55,13 @@
import org.apache.asterix.app.replication.message.RegistrationTasksRequestMessage;
import org.apache.asterix.common.api.AsterixThreadFactory;
import org.apache.asterix.common.api.IConfigValidatorFactory;
+import org.apache.asterix.common.api.INamespacePathResolver;
import org.apache.asterix.common.api.INamespaceResolver;
import org.apache.asterix.common.api.INcApplicationContext;
import org.apache.asterix.common.api.IPropertiesFactory;
import org.apache.asterix.common.api.IReceptionistFactory;
import org.apache.asterix.common.config.AsterixExtension;
+import org.apache.asterix.common.config.CompilerProperties;
import org.apache.asterix.common.config.ExtensionProperties;
import org.apache.asterix.common.config.ExternalProperties;
import org.apache.asterix.common.config.GlobalConfig;
@@ -70,6 +72,7 @@
import org.apache.asterix.common.config.PropertiesFactory;
import org.apache.asterix.common.config.StorageProperties;
import org.apache.asterix.common.exceptions.AsterixException;
+import org.apache.asterix.common.metadata.NamespacePathResolver;
import org.apache.asterix.common.metadata.NamespaceResolver;
import org.apache.asterix.common.replication.IReplicationStrategyFactory;
import org.apache.asterix.common.replication.ReplicationStrategyFactory;
@@ -157,12 +160,16 @@
}
MetadataBuiltinFunctions.init();
+ boolean isDbResolutionEnabled =
+ ncServiceCtx.getAppConfig().getBoolean(CompilerProperties.Option.COMPILER_ENABLE_DB_RESOLUTION);
boolean cloudDeployment = ncServiceCtx.getAppConfig().getBoolean(CLOUD_DEPLOYMENT);
- NamespaceResolver namespaceResolver = new NamespaceResolver(cloudDeployment);
+ boolean useDatabaseResolution = cloudDeployment && isDbResolutionEnabled;
+ NamespaceResolver namespaceResolver = new NamespaceResolver(useDatabaseResolution);
+ NamespacePathResolver namespacePathResolver = new NamespacePathResolver(useDatabaseResolution);
ncExtensionManager =
new NCExtensionManager(new ArrayList<>(getExtensions()), cloudDeployment, namespaceResolver);
- runtimeContext =
- createNCApplicationContext(ncServiceCtx, ncExtensionManager, getPropertiesFactory(), namespaceResolver);
+ runtimeContext = createNCApplicationContext(ncServiceCtx, ncExtensionManager, getPropertiesFactory(),
+ namespaceResolver, namespacePathResolver);
MetadataProperties metadataProperties = runtimeContext.getMetadataProperties();
if (!metadataProperties.getNodeNames().contains(this.ncServiceCtx.getNodeId())) {
if (LOGGER.isInfoEnabled()) {
@@ -196,8 +203,10 @@
protected INcApplicationContext createNCApplicationContext(INCServiceContext ncServiceCtx,
NCExtensionManager ncExtensionManager, IPropertiesFactory propertiesFactory,
- INamespaceResolver namespaceResolver) throws IOException, AsterixException {
- return new NCAppRuntimeContext(ncServiceCtx, ncExtensionManager, propertiesFactory, namespaceResolver);
+ INamespaceResolver namespaceResolver, INamespacePathResolver namespacePathResolver)
+ throws IOException, AsterixException {
+ return new NCAppRuntimeContext(ncServiceCtx, ncExtensionManager, propertiesFactory, namespaceResolver,
+ namespacePathResolver);
}
protected IRecoveryManagerFactory getRecoveryManagerFactory() {
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/cloud_storage/CloudStorageTest.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/cloud_storage/CloudStorageTest.java
index a45a1bf..a23da8c 100644
--- a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/cloud_storage/CloudStorageTest.java
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/cloud_storage/CloudStorageTest.java
@@ -19,13 +19,19 @@
package org.apache.asterix.test.cloud_storage;
import java.util.Collection;
+import java.util.List;
import org.apache.asterix.api.common.LocalCloudUtil;
import org.apache.asterix.common.config.GlobalConfig;
import org.apache.asterix.test.common.TestExecutor;
import org.apache.asterix.test.runtime.LangExecutionUtil;
import org.apache.asterix.testframework.context.TestCaseContext;
+import org.apache.asterix.testframework.xml.Description;
+import org.apache.asterix.testframework.xml.TestCase;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import org.junit.AfterClass;
+import org.junit.Assume;
import org.junit.BeforeClass;
import org.junit.FixMethodOrder;
import org.junit.Test;
@@ -41,11 +47,14 @@
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class CloudStorageTest {
- protected TestCaseContext tcCtx;
+ private static final Logger LOGGER = LogManager.getLogger();
+
+ private final TestCaseContext tcCtx;
private static final String SUITE_TESTS = "testsuite_cloud_storage.xml";
private static final String ONLY_TESTS = "testsuite_cloud_storage_only.xml";
private static final String CONFIG_FILE_NAME = "src/test/resources/cc-cloud-storage.conf";
private static final String DELTA_RESULT_PATH = "results_cloud";
+ private static final String EXCLUDED_TESTS = "MP";
public CloudStorageTest(TestCaseContext tcCtx) {
this.tcCtx = tcCtx;
@@ -55,6 +64,7 @@
public static void setUp() throws Exception {
LocalCloudUtil.startS3CloudEnvironment(true);
TestExecutor testExecutor = new TestExecutor(DELTA_RESULT_PATH);
+ testExecutor.stripSubstring = "//DB:";
LangExecutionUtil.setUp(CONFIG_FILE_NAME, testExecutor);
System.setProperty(GlobalConfig.CONFIG_FILE_PROPERTY, CONFIG_FILE_NAME);
}
@@ -71,6 +81,12 @@
@Test
public void test() throws Exception {
+ List<TestCase.CompilationUnit> cu = tcCtx.getTestCase().getCompilationUnit();
+ Assume.assumeTrue(cu.size() > 1 || !EXCLUDED_TESTS.equals(getText(cu.get(0).getDescription())));
LangExecutionUtil.test(tcCtx);
}
+
+ private static String getText(Description description) {
+ return description == null ? "" : description.getValue();
+ }
}
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java
index 2860813..9498979 100644
--- a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java
@@ -276,6 +276,7 @@
protected int loopIteration;
protected String deltaPath = null;
+ public String stripSubstring = null;
public TestExecutor() {
this(Collections.singletonList(
@@ -861,6 +862,9 @@
}
str = applyExternalDatasetSubstitution(str, placeholders);
+ if (stripSubstring != null && !stripSubstring.isBlank()) {
+ str = strip(str, stripSubstring);
+ }
HttpUriRequest method = jsonEncoded ? constructPostMethodJson(str, uri, "statement", params)
: constructPostMethodUrl(str, uri, "statement", params);
@@ -2325,6 +2329,10 @@
return substitute;
}
+ protected static String strip(String str, String target) {
+ return str.replace(target, "");
+ }
+
protected String applyExternalDatasetSubstitution(String str, List<Placeholder> placeholders) {
// This replaces the full template of parameters depending on the adapter type
for (Placeholder placeholder : placeholders) {
@@ -2589,12 +2597,12 @@
public void cleanup(String testCase, List<String> badtestcases) throws Exception {
try {
- List<DataverseName> toBeDropped = new ArrayList<>();
+ List<Pair<String, DataverseName>> toBeDropped = new ArrayList<>();
listUserDefinedDataverses(toBeDropped);
if (!toBeDropped.isEmpty()) {
badtestcases.add(testCase);
LOGGER.info("Last test left some garbage. Dropping dataverses: " + StringUtils.join(toBeDropped, ','));
- for (DataverseName dv : toBeDropped) {
+ for (Pair<String, DataverseName> dv : toBeDropped) {
dropDataverse(dv);
}
}
@@ -2604,8 +2612,9 @@
}
}
- protected void listUserDefinedDataverses(List<DataverseName> outDataverses) throws Exception {
- String query = "select dv.DataverseName from Metadata.`Dataverse` as dv order by dv.DataverseName";
+ protected void listUserDefinedDataverses(List<Pair<String, DataverseName>> outDataverses) throws Exception {
+ String query =
+ "select dv.DatabaseName, dv.DataverseName from Metadata.`Dataverse` as dv order by dv.DataverseName";
InputStream resultStream =
executeQueryService(query, getEndpoint(Servlets.QUERY_SERVICE), OutputFormat.CLEAN_JSON);
JsonNode result = extractResult(IOUtils.toString(resultStream, UTF_8));
@@ -2615,16 +2624,26 @@
DataverseName dvName = DataverseName.createFromCanonicalForm(json.get("DataverseName").asText());
if (!dvName.equals(MetadataConstants.METADATA_DATAVERSE_NAME)
&& !dvName.equals(MetadataConstants.DEFAULT_DATAVERSE_NAME)) {
- outDataverses.add(dvName);
+ JsonNode databaseName = json.get("DatabaseName");
+ String dbName = null;
+ if (databaseName != null && !databaseName.isNull() && !databaseName.isMissingNode()) {
+ dbName = databaseName.asText();
+ }
+ outDataverses.add(new Pair<>(dbName, dvName));
}
}
}
}
- protected void dropDataverse(DataverseName dv) throws Exception {
+ protected void dropDataverse(Pair<String, DataverseName> dv) throws Exception {
StringBuilder dropStatement = new StringBuilder();
dropStatement.append("drop dataverse ");
- SqlppStatementUtil.encloseDataverseName(dropStatement, dv);
+ if (dv.first == null) {
+ SqlppStatementUtil.encloseDataverseName(dropStatement, dv.second);
+ } else {
+ SqlppStatementUtil.enclose(dropStatement, dv.first).append(SqlppStatementUtil.DOT);
+ SqlppStatementUtil.encloseDataverseName(dropStatement, dv.second);
+ }
dropStatement.append(";\n");
InputStream resultStream = executeQueryService(dropStatement.toString(), getEndpoint(Servlets.QUERY_SERVICE),
OutputFormat.CLEAN_JSON, UTF_8);
@@ -2652,6 +2671,18 @@
}
}
+ protected boolean metadataHasDatabase() throws Exception {
+ String query = "select d.DatabaseName from Metadata.`Dataverse` d limit 1;";
+ InputStream resultStream = executeQueryService(query, getEndpoint(Servlets.QUERY_SERVICE),
+ TestCaseContext.OutputFormat.CLEAN_JSON);
+ JsonNode result = extractResult(IOUtils.toString(resultStream, UTF_8));
+ if (result.size() > 1) {
+ JsonNode json = result.get(0);
+ return json != null && !json.get("DatabaseName").isNull() && !json.get("DatabaseName").isMissingNode();
+ }
+ return false;
+ }
+
private JsonNode extractResult(String jsonString) throws IOException {
try {
final JsonNode result = RESULT_NODE_READER.<ObjectNode> readValue(jsonString).get("results");
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/api/request-dataverse/request-dataverse.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/api/request-dataverse/request-dataverse.1.ddl.sqlpp
index cb28d2f..33130f2 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/api/request-dataverse/request-dataverse.1.ddl.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/api/request-dataverse/request-dataverse.1.ddl.sqlpp
@@ -20,6 +20,8 @@
drop dataverse test1 if exists;
create dataverse test1;
+//DB: drop database test2 if exists;
+//DB: create database test2;
drop dataverse test2.test3 if exists;
create dataverse test2.test3;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/cloud_storage/special-chars/test.000.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/cloud_storage/special-chars/test.000.ddl.sqlpp
index 18a98e3..e7c2769 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/cloud_storage/special-chars/test.000.ddl.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/cloud_storage/special-chars/test.000.ddl.sqlpp
@@ -17,6 +17,8 @@
* under the License.
*/
+DROP DATABASE `part1` IF EXISTS;
+CREATE DATABASE `part1`;
DROP DATAVERSE `part1`.`p%r t2` IF EXISTS;
CREATE DATAVERSE `part1`.`p%r t2`;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/cloud_storage/special-chars/test.999.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/cloud_storage/special-chars/test.999.ddl.sqlpp
index 3580ae9..923c81b 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/cloud_storage/special-chars/test.999.ddl.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/cloud_storage/special-chars/test.999.ddl.sqlpp
@@ -18,3 +18,4 @@
*/
DROP DATAVERSE `part1`.`p%r t2` IF EXISTS;
+DROP DATABASE `part1`;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/multipart-dataverse/index_1/index_1.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/multipart-dataverse/index_1/index_1.1.ddl.sqlpp
index 910b6df..e657e61 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/multipart-dataverse/index_1/index_1.1.ddl.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/multipart-dataverse/index_1/index_1.1.ddl.sqlpp
@@ -20,6 +20,8 @@
* Description: index in a dataverse with a multipart name
*/
+//DB: drop database x if exists;
+//DB: create database x;
drop dataverse x.y if exists;
create dataverse x.y;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/multipart-dataverse/resolution_1/resolution_1.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/multipart-dataverse/resolution_1/resolution_1.1.ddl.sqlpp
index 1089bc3..e6c06f9 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/multipart-dataverse/resolution_1/resolution_1.1.ddl.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/multipart-dataverse/resolution_1/resolution_1.1.ddl.sqlpp
@@ -20,6 +20,8 @@
* Description: name resolution for a dataverse with a multipart name
*/
+//DB: drop database sales if exists;
+//DB: create database sales;
drop dataverse sales.east if exists;
create dataverse sales.east;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/multipart-dataverse/udf_1/udf_1.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/multipart-dataverse/udf_1/udf_1.1.ddl.sqlpp
index 6b01a11..fea7c0a 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/multipart-dataverse/udf_1/udf_1.1.ddl.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/multipart-dataverse/udf_1/udf_1.1.ddl.sqlpp
@@ -20,6 +20,8 @@
* Description: user-defined function in a dataverse with a multipart name
*/
+//DB: drop database x if exists;
+//DB: create database x;
drop dataverse x.y if exists;
create dataverse x.y;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/sqlpp_queries.xml b/asterixdb/asterix-app/src/test/resources/runtimets/sqlpp_queries.xml
index ffe81d6..0f537d7 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/sqlpp_queries.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/sqlpp_queries.xml
@@ -7352,11 +7352,13 @@
</test-case>
<test-case FilePath="multipart-dataverse">
<compilation-unit name="special_chars_1">
+ <description>MP</description>
<output-dir compare="Text">special_chars_1</output-dir>
</compilation-unit>
</test-case>
<test-case FilePath="multipart-dataverse">
<compilation-unit name="special_chars_2">
+ <description>MP</description>
<output-dir compare="Text">special_chars_2</output-dir>
</compilation-unit>
</test-case>
diff --git a/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/AbstractCloudIOManager.java b/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/AbstractCloudIOManager.java
index 3179280..8c7cd8a 100644
--- a/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/AbstractCloudIOManager.java
+++ b/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/AbstractCloudIOManager.java
@@ -35,8 +35,10 @@
import org.apache.asterix.cloud.clients.CloudClientProvider;
import org.apache.asterix.cloud.clients.ICloudClient;
import org.apache.asterix.cloud.util.CloudFileUtil;
+import org.apache.asterix.common.api.INamespacePathResolver;
import org.apache.asterix.common.cloud.IPartitionBootstrapper;
import org.apache.asterix.common.config.CloudProperties;
+import org.apache.asterix.common.metadata.MetadataConstants;
import org.apache.asterix.common.transactions.IRecoveryManager;
import org.apache.asterix.common.utils.StoragePathUtil;
import org.apache.hyracks.api.exceptions.HyracksDataException;
@@ -54,8 +56,8 @@
public abstract class AbstractCloudIOManager extends IOManager implements IPartitionBootstrapper {
private static final Logger LOGGER = LogManager.getLogger();
- private static final String DATAVERSE_PATH =
- FileUtil.joinPath(STORAGE_ROOT_DIR_NAME, PARTITION_DIR_PREFIX + METADATA_PARTITION, "Metadata");
+ //TODO(DB): change
+ private final String metadataNamespacePath;
protected final ICloudClient cloudClient;
protected final WriteBufferProvider writeBufferProvider;
protected final String bucket;
@@ -63,9 +65,12 @@
protected final List<FileReference> partitionPaths;
protected final IOManager localIoManager;
- public AbstractCloudIOManager(IOManager ioManager, CloudProperties cloudProperties) throws HyracksDataException {
+ public AbstractCloudIOManager(IOManager ioManager, CloudProperties cloudProperties,
+ INamespacePathResolver nsPathResolver) throws HyracksDataException {
super(ioManager.getIODevices(), ioManager.getDeviceComputer(), ioManager.getIOParallelism(),
ioManager.getQueueSize());
+ this.metadataNamespacePath = FileUtil.joinPath(STORAGE_ROOT_DIR_NAME, PARTITION_DIR_PREFIX + METADATA_PARTITION,
+ nsPathResolver.resolve(MetadataConstants.METADATA_NAMESPACE));
this.bucket = cloudProperties.getStorageBucket();
cloudClient = CloudClientProvider.getClient(cloudProperties);
int numOfThreads = getIODevices().size() * getIOParallelism();
@@ -83,7 +88,7 @@
@Override
public IRecoveryManager.SystemState getSystemStateOnMissingCheckpoint() {
- if (cloudClient.listObjects(bucket, DATAVERSE_PATH, IoUtil.NO_OP_FILTER).isEmpty()) {
+ if (cloudClient.listObjects(bucket, metadataNamespacePath, IoUtil.NO_OP_FILTER).isEmpty()) {
LOGGER.info("First time to initialize this cluster: systemState = PERMANENT_DATA_LOSS");
return IRecoveryManager.SystemState.PERMANENT_DATA_LOSS;
} else {
diff --git a/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/CloudManagerProvider.java b/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/CloudManagerProvider.java
index 6ba31db..f325f41 100644
--- a/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/CloudManagerProvider.java
+++ b/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/CloudManagerProvider.java
@@ -18,6 +18,7 @@
*/
package org.apache.asterix.cloud;
+import org.apache.asterix.common.api.INamespacePathResolver;
import org.apache.asterix.common.cloud.CloudCachePolicy;
import org.apache.asterix.common.cloud.IPartitionBootstrapper;
import org.apache.asterix.common.config.CloudProperties;
@@ -29,14 +30,14 @@
private CloudManagerProvider() {
}
- public static IIOManager createIOManager(CloudProperties cloudProperties, IIOManager ioManager)
- throws HyracksDataException {
+ public static IIOManager createIOManager(CloudProperties cloudProperties, IIOManager ioManager,
+ INamespacePathResolver nsPathResolver) throws HyracksDataException {
IOManager localIoManager = (IOManager) ioManager;
if (cloudProperties.getCloudCachePolicy() == CloudCachePolicy.LAZY) {
- return new LazyCloudIOManager(localIoManager, cloudProperties);
+ return new LazyCloudIOManager(localIoManager, cloudProperties, nsPathResolver);
}
- return new EagerCloudIOManager(localIoManager, cloudProperties);
+ return new EagerCloudIOManager(localIoManager, cloudProperties, nsPathResolver);
}
public static IPartitionBootstrapper getCloudPartitionBootstrapper(IIOManager ioManager) {
diff --git a/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/EagerCloudIOManager.java b/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/EagerCloudIOManager.java
index b1f88cb..d0b982c 100644
--- a/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/EagerCloudIOManager.java
+++ b/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/EagerCloudIOManager.java
@@ -26,6 +26,7 @@
import java.util.stream.Collectors;
import org.apache.asterix.cloud.clients.IParallelDownloader;
+import org.apache.asterix.common.api.INamespacePathResolver;
import org.apache.asterix.common.config.CloudProperties;
import org.apache.hyracks.api.exceptions.HyracksDataException;
import org.apache.hyracks.api.io.FileReference;
@@ -44,8 +45,9 @@
final class EagerCloudIOManager extends AbstractCloudIOManager {
private static final Logger LOGGER = LogManager.getLogger();
- public EagerCloudIOManager(IOManager ioManager, CloudProperties cloudProperties) throws HyracksDataException {
- super(ioManager, cloudProperties);
+ public EagerCloudIOManager(IOManager ioManager, CloudProperties cloudProperties,
+ INamespacePathResolver nsPathResolver) throws HyracksDataException {
+ super(ioManager, cloudProperties, nsPathResolver);
}
/*
diff --git a/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/LazyCloudIOManager.java b/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/LazyCloudIOManager.java
index 97a6173..6ecd201 100644
--- a/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/LazyCloudIOManager.java
+++ b/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/LazyCloudIOManager.java
@@ -39,6 +39,7 @@
import org.apache.asterix.cloud.lazy.accessor.InitialCloudAccessor;
import org.apache.asterix.cloud.lazy.accessor.LocalAccessor;
import org.apache.asterix.cloud.lazy.accessor.ReplaceableCloudAccessor;
+import org.apache.asterix.common.api.INamespacePathResolver;
import org.apache.asterix.common.config.CloudProperties;
import org.apache.asterix.common.utils.StoragePathUtil;
import org.apache.hyracks.api.exceptions.HyracksDataException;
@@ -60,8 +61,9 @@
private final ILazyAccessorReplacer replacer;
private ILazyAccessor accessor;
- public LazyCloudIOManager(IOManager ioManager, CloudProperties cloudProperties) throws HyracksDataException {
- super(ioManager, cloudProperties);
+ public LazyCloudIOManager(IOManager ioManager, CloudProperties cloudProperties,
+ INamespacePathResolver nsPathResolver) throws HyracksDataException {
+ super(ioManager, cloudProperties, nsPathResolver);
accessor = new InitialCloudAccessor(cloudClient, bucket, localIoManager);
replacer = () -> {
synchronized (this) {
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/api/INamespaceResolver.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/api/INamespaceResolver.java
index 7f9bde6..fb30509 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/api/INamespaceResolver.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/api/INamespaceResolver.java
@@ -31,4 +31,5 @@
Namespace resolve(String namespace) throws AsterixException;
+ boolean isUsingDatabase();
}
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/CompilerProperties.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/CompilerProperties.java
index 01f9509..85b80a6 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/CompilerProperties.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/CompilerProperties.java
@@ -122,7 +122,9 @@
COMPILER_COLUMN_FILTER(
BOOLEAN,
AlgebricksConfig.COLUMN_FILTER_DEFAULT,
- "Enable/disable the use of column min/max filters");
+ "Enable/disable the use of column min/max filters"),
+ //TODO(DB): remove after
+ COMPILER_ENABLE_DB_RESOLUTION(BOOLEAN, true, "Enable/disable the resolution of namespaces to database");
private final IOptionType type;
private final Object defaultValue;
@@ -156,7 +158,8 @@
@Override
public boolean hidden() {
- return this == COMPILER_EXTERNALSCANMEMORY || this == COMPILER_CBOTEST;
+ return this == COMPILER_EXTERNALSCANMEMORY || this == COMPILER_CBOTEST
+ || this == COMPILER_ENABLE_DB_RESOLUTION;
}
}
@@ -204,6 +207,8 @@
public static final String COMPILER_COLUMN_FILTER_KEY = Option.COMPILER_COLUMN_FILTER.ini();
+ public static final String COMPILER_ENABLE_DB_RESOLUTION_KEY = Option.COMPILER_ENABLE_DB_RESOLUTION.ini();
+
public static final int COMPILER_PARALLELISM_AS_STORAGE = 0;
public CompilerProperties(PropertiesAccessor accessor) {
@@ -306,4 +311,8 @@
public boolean isColumnFilter() {
return accessor.getBoolean(Option.COMPILER_COLUMN_FILTER);
}
+
+ public boolean isDbResolutionEnabled() {
+ return accessor.getBoolean(Option.COMPILER_ENABLE_DB_RESOLUTION);
+ }
}
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java
index ff00aef..83418a4 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java
@@ -279,6 +279,8 @@
FAILED_TO_CALCULATE_COMPUTED_FIELDS(1182),
FAILED_TO_EVALUATE_COMPUTED_FIELD(1183),
ILLEGAL_DML_OPERATION(1184),
+ UNKNOWN_DATABASE(1185),
+ DATABASE_EXISTS(1186),
// Feed errors
DATAFLOW_ILLEGAL_STATE(3001),
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/metadata/DatasetFullyQualifiedName.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/metadata/DatasetFullyQualifiedName.java
index f53a3a3..261cddc 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/metadata/DatasetFullyQualifiedName.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/metadata/DatasetFullyQualifiedName.java
@@ -48,7 +48,8 @@
@Override
public String toString() {
- return dataverseName + "." + datasetName;
+ return (MetadataConstants.DEFAULT_DATABASE.equals(databaseName) ? "" : datasetName + ".") + dataverseName + "."
+ + datasetName;
}
@Override
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/metadata/MetadataConstants.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/metadata/MetadataConstants.java
index 02cf6d6..044d920 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/metadata/MetadataConstants.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/metadata/MetadataConstants.java
@@ -43,6 +43,7 @@
// Name of the pre-defined default dataverse
public static final DataverseName DEFAULT_DATAVERSE_NAME = DataverseName.createBuiltinDataverseName("Default");
+ public static final Namespace METADATA_NAMESPACE = new Namespace(SYSTEM_DATABASE, METADATA_DATAVERSE_NAME);
public static final Namespace DEFAULT_NAMESPACE = new Namespace(DEFAULT_DATABASE, DEFAULT_DATAVERSE_NAME);
// Name of the node group where metadata is stored on.
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/metadata/MetadataUtil.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/metadata/MetadataUtil.java
index 06d12fa..539b8c4 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/metadata/MetadataUtil.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/metadata/MetadataUtil.java
@@ -46,6 +46,11 @@
return dataverseName + "." + objectName;
}
+ public static String getFullyQualifiedDisplayName(String databaseName, DataverseName dataverseName,
+ String objectName) {
+ return databaseName + "." + dataverseName + "." + objectName;
+ }
+
public static String databaseFor(DataverseName dataverse) {
if (dataverse == null) {
return null;
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/metadata/NamespacePathResolver.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/metadata/NamespacePathResolver.java
index 26d1ce0..910c3ef 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/metadata/NamespacePathResolver.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/metadata/NamespacePathResolver.java
@@ -19,6 +19,8 @@
package org.apache.asterix.common.metadata;
+import java.io.File;
+
import org.apache.asterix.common.api.INamespacePathResolver;
import org.apache.asterix.common.utils.StoragePathUtil;
@@ -27,16 +29,32 @@
private final boolean usingDatabase;
public NamespacePathResolver(boolean usingDatabase) {
- this.usingDatabase = false;
+ this.usingDatabase = usingDatabase;
}
@Override
public String resolve(Namespace namespace) {
- return StoragePathUtil.prepareDataverseName(namespace.getDataverseName());
+ DataverseName dataverseName = namespace.getDataverseName();
+ if (usingDatabase) {
+ if (MetadataConstants.METADATA_DATAVERSE_NAME.equals(dataverseName)) {
+ return StoragePathUtil.prepareDataverseName(dataverseName);
+ }
+ return namespace.getDatabaseName() + File.separatorChar
+ + StoragePathUtil.prepareDataverseName(dataverseName);
+ } else {
+ return StoragePathUtil.prepareDataverseName(dataverseName);
+ }
}
@Override
public String resolve(String databaseName, DataverseName dataverseName) {
- return StoragePathUtil.prepareDataverseName(dataverseName);
+ if (usingDatabase) {
+ if (MetadataConstants.METADATA_DATAVERSE_NAME.equals(dataverseName)) {
+ return StoragePathUtil.prepareDataverseName(dataverseName);
+ }
+ return databaseName + File.separatorChar + StoragePathUtil.prepareDataverseName(dataverseName);
+ } else {
+ return StoragePathUtil.prepareDataverseName(dataverseName);
+ }
}
}
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/metadata/NamespaceResolver.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/metadata/NamespaceResolver.java
index b18562e..d1d813e 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/metadata/NamespaceResolver.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/metadata/NamespaceResolver.java
@@ -29,7 +29,7 @@
private final boolean usingDatabase;
public NamespaceResolver(boolean usingDatabase) {
- this.usingDatabase = false;
+ this.usingDatabase = usingDatabase;
}
@Override
@@ -42,13 +42,49 @@
if (multiIdentifier == null) {
return null;
}
- DataverseName dataverseName = DataverseName.create(multiIdentifier, fromIndex, toIndex);
- return new Namespace(MetadataUtil.databaseFor(dataverseName), dataverseName);
+ if (usingDatabase) {
+ int partsNum = toIndex - fromIndex;
+ if (partsNum > 1) {
+ String databaseName = multiIdentifier.get(fromIndex);
+ return ofDatabase(databaseName, multiIdentifier, fromIndex + 1, toIndex);
+ } else {
+ return ofDataverse(multiIdentifier, fromIndex, toIndex);
+ }
+ } else {
+ return ofDataverse(multiIdentifier, fromIndex, toIndex);
+ }
}
@Override
public Namespace resolve(String namespace) throws AsterixException {
DataverseName dataverseName = DataverseName.createFromCanonicalForm(namespace);
+ if (usingDatabase) {
+ List<String> parts = dataverseName.getParts();
+ if (parts.size() > 1) {
+ String databaseName = parts.get(0);
+ return ofDatabase(databaseName, parts, 1, parts.size());
+ } else {
+ return new Namespace(MetadataUtil.databaseFor(dataverseName), dataverseName);
+ }
+ } else {
+ return new Namespace(MetadataUtil.databaseFor(dataverseName), dataverseName);
+ }
+ }
+
+ @Override
+ public boolean isUsingDatabase() {
+ return usingDatabase;
+ }
+
+ private static Namespace ofDatabase(String databaseName, List<String> multiIdentifier, int fromIndex, int toIndex)
+ throws AsterixException {
+ DataverseName dataverseName = DataverseName.create(multiIdentifier, fromIndex, toIndex);
+ return new Namespace(databaseName, dataverseName);
+ }
+
+ private static Namespace ofDataverse(List<String> multiIdentifier, int fromIndex, int toIndex)
+ throws AsterixException {
+ DataverseName dataverseName = DataverseName.create(multiIdentifier, fromIndex, toIndex);
return new Namespace(MetadataUtil.databaseFor(dataverseName), dataverseName);
}
}
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/storage/DatasetCopyIdentifier.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/storage/DatasetCopyIdentifier.java
index 6fea755..4533361 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/storage/DatasetCopyIdentifier.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/storage/DatasetCopyIdentifier.java
@@ -25,19 +25,22 @@
public class DatasetCopyIdentifier implements Serializable {
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = 2L;
+ private final String database;
private final DataverseName dataverse;
private final String dataset;
private final String rebalance;
- private DatasetCopyIdentifier(DataverseName dataverse, String datasetName, String rebalance) {
+ private DatasetCopyIdentifier(String database, DataverseName dataverse, String datasetName, String rebalance) {
+ this.database = database;
this.dataverse = dataverse;
this.dataset = datasetName;
this.rebalance = rebalance;
}
- public static DatasetCopyIdentifier of(DataverseName dataverse, String datasetName, String rebalance) {
- return new DatasetCopyIdentifier(dataverse, datasetName, rebalance);
+ public static DatasetCopyIdentifier of(String database, DataverseName dataverse, String datasetName,
+ String rebalance) {
+ return new DatasetCopyIdentifier(database, dataverse, datasetName, rebalance);
}
public String getDataset() {
@@ -57,13 +60,13 @@
return false;
}
DatasetCopyIdentifier that = (DatasetCopyIdentifier) o;
- return Objects.equals(dataverse, that.dataverse) && Objects.equals(dataset, that.dataset)
- && Objects.equals(rebalance, that.rebalance);
+ return Objects.equals(database, that.database) && Objects.equals(dataverse, that.dataverse)
+ && Objects.equals(dataset, that.dataset) && Objects.equals(rebalance, that.rebalance);
}
@Override
public int hashCode() {
- return Objects.hash(dataverse, dataset, rebalance);
+ return Objects.hash(database, dataverse, dataset, rebalance);
}
public DataverseName getDataverse() {
@@ -71,8 +74,8 @@
}
public boolean isMatch(ResourceReference resourceReference) {
- return resourceReference.getDataverse().equals(dataverse) && resourceReference.getDataset().equals(dataset)
- && resourceReference.getRebalance().equals(rebalance);
+ return resourceReference.getDatabase().equals(database) && resourceReference.getDataverse().equals(dataverse)
+ && resourceReference.getDataset().equals(dataset) && resourceReference.getRebalance().equals(rebalance);
}
@Override
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/storage/ResourceReference.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/storage/ResourceReference.java
index 7065767..a163ece 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/storage/ResourceReference.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/storage/ResourceReference.java
@@ -27,6 +27,7 @@
import org.apache.asterix.common.exceptions.AsterixException;
import org.apache.asterix.common.metadata.DataverseName;
+import org.apache.asterix.common.metadata.MetadataUtil;
import org.apache.asterix.common.utils.StorageConstants;
import org.apache.asterix.common.utils.StoragePathUtil;
import org.apache.commons.lang3.ArrayUtils;
@@ -40,6 +41,7 @@
private static final Logger LOGGER = LogManager.getLogger();
protected final String root;
protected final String partition;
+ protected final String database;
protected final DataverseName dataverse;
protected final String dataset;
protected final String rebalance;
@@ -68,12 +70,19 @@
String probablyPartition = tokens[--offset];
if (dvParts.isEmpty()) {
// root/partition/dataverse/dataset/rebalanceCount/index/fileName
+ // root/partition/database?/dataverse/dataset/rebalanceCount/index/fileName
try {
dataverse = DataverseName.createSinglePartName(dvPart);
} catch (AsterixException e) {
throw new IllegalArgumentException("unable to parse path: '" + path + "'!", e);
}
- partition = probablyPartition;
+ if (!probablyPartition.startsWith(StorageConstants.PARTITION_DIR_PREFIX)) {
+ database = probablyPartition;
+ partition = tokens[--offset];
+ } else {
+ database = MetadataUtil.databaseFor(dataverse);
+ partition = probablyPartition;
+ }
root = tokens[--offset];
} else if (probablyPartition.startsWith(StorageConstants.PARTITION_DIR_PREFIX)) {
// root/partition/dataverse_p1/^dataverse_p2/.../^dataverse_pn/dataset/rebalanceCount/index/fileName
@@ -84,6 +93,7 @@
} catch (AsterixException e) {
throw new IllegalArgumentException("unable to parse path: '" + path + "'!", e);
}
+ database = MetadataUtil.databaseFor(dataverse);
partition = probablyPartition;
root = tokens[--offset];
} else if (dvPart.startsWith(StorageConstants.PARTITION_DIR_PREFIX)) {
@@ -99,6 +109,7 @@
}
LOGGER.info("legacy dataverse starting with ^ found: '{}'; this is not supported for new dataverses",
dataverse);
+ database = MetadataUtil.databaseFor(dataverse);
partition = dvPart;
root = probablyPartition;
} else {
@@ -119,6 +130,10 @@
return partition;
}
+ public String getDatabase() {
+ return database;
+ }
+
public DataverseName getDataverse() {
return dataverse;
}
diff --git a/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties b/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties
index 3f61b85..ab77067 100644
--- a/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties
+++ b/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties
@@ -281,6 +281,8 @@
1182 = Failed to calculate computed fields: %1$s
1183 = Failed to evaluate computed field. File: '%1$s'. Computed Field Name: '%2$s'. Computed Field Type: '%3$s'. Computed Field Value: '%4$s'. Reason: '%5$s'
1184 = Compilation error: %1$s: %2$s dataset is not supported on datasets with meta records
+1185 = Cannot find database with name %1$s
+1186 = A database with this name %1$s already exists
# Feed Errors
3001 = Illegal state.
diff --git a/asterixdb/asterix-common/src/test/java/org/apache/asterix/test/ioopcallbacks/LSMIOOperationCallbackTest.java b/asterixdb/asterix-common/src/test/java/org/apache/asterix/test/ioopcallbacks/LSMIOOperationCallbackTest.java
index 33d513f..befdd1a 100644
--- a/asterixdb/asterix-common/src/test/java/org/apache/asterix/test/ioopcallbacks/LSMIOOperationCallbackTest.java
+++ b/asterixdb/asterix-common/src/test/java/org/apache/asterix/test/ioopcallbacks/LSMIOOperationCallbackTest.java
@@ -21,6 +21,7 @@
import static org.apache.hyracks.storage.am.lsm.common.impls.LSMComponentId.MIN_VALID_COMPONENT_ID;
+import java.io.File;
import java.util.HashMap;
import java.util.Map;
@@ -91,7 +92,9 @@
flushMap.put(LSMIOOperationCallback.KEY_NEXT_COMPONENT_ID, nextComponentId);
ILSMIndexAccessor firstAccessor = new TestLSMIndexAccessor(new TestLSMIndexOperationContext(mockIndex));
firstAccessor.getOpContext().setParameters(flushMap);
- FileReference firstTarget = new FileReference(Mockito.mock(IODeviceHandle.class), getComponentFileName());
+ IODeviceHandle mockIoDevice = Mockito.mock(IODeviceHandle.class);
+ Mockito.when(mockIoDevice.getMount()).thenReturn(new File(getIndexPath()));
+ FileReference firstTarget = new FileReference(mockIoDevice, getComponentFileName());
LSMComponentFileReferences firstFiles = new LSMComponentFileReferences(firstTarget, firstTarget, firstTarget);
FlushOperation firstFlush = new TestFlushOperation(firstAccessor, firstTarget, callback, indexId, firstFiles,
new LSMComponentId(0, 0));
@@ -107,7 +110,7 @@
flushMap.put(LSMIOOperationCallback.KEY_NEXT_COMPONENT_ID, nextComponentId);
ILSMIndexAccessor secondAccessor = new TestLSMIndexAccessor(new TestLSMIndexOperationContext(mockIndex));
secondAccessor.getOpContext().setParameters(flushMap);
- FileReference secondTarget = new FileReference(Mockito.mock(IODeviceHandle.class), getComponentFileName());
+ FileReference secondTarget = new FileReference(mockIoDevice, getComponentFileName());
LSMComponentFileReferences secondFiles =
new LSMComponentFileReferences(secondTarget, secondTarget, secondTarget);
FlushOperation secondFlush = new TestFlushOperation(secondAccessor, secondTarget, callback, indexId,
@@ -173,6 +176,8 @@
callback.recycled(mockComponent);
checkMemoryComponent(id, mockComponent);
+ IODeviceHandle mockIoDevice = Mockito.mock(IODeviceHandle.class);
+ Mockito.when(mockIoDevice.getMount()).thenReturn(new File(getIndexPath()));
Mockito.when(mockIndex.isMemoryComponentsAllocated()).thenReturn(true);
for (int i = 0; i < 100; i++) {
// schedule a flush
@@ -184,7 +189,7 @@
flushMap.put(LSMIOOperationCallback.KEY_NEXT_COMPONENT_ID, expectedId);
ILSMIndexAccessor accessor = new TestLSMIndexAccessor(new TestLSMIndexOperationContext(mockIndex));
accessor.getOpContext().setParameters(flushMap);
- FileReference target = new FileReference(Mockito.mock(IODeviceHandle.class), getComponentFileName());
+ FileReference target = new FileReference(mockIoDevice, getComponentFileName());
LSMComponentFileReferences files = new LSMComponentFileReferences(target, target, target);
FlushOperation flush =
new TestFlushOperation(accessor, target, callback, indexId, files, new LSMComponentId(0, 0));
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IQueryRewriter.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IQueryRewriter.java
index 6099cb6..12c3b93 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IQueryRewriter.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IQueryRewriter.java
@@ -21,6 +21,7 @@
import java.util.Collection;
import java.util.Set;
+import org.apache.asterix.common.api.INamespaceResolver;
import org.apache.asterix.common.exceptions.CompilationException;
import org.apache.asterix.lang.common.expression.AbstractCallExpression;
import org.apache.asterix.lang.common.expression.VariableExpr;
@@ -64,5 +65,5 @@
Query createFunctionAccessorQuery(FunctionDecl functionDecl);
- Query createViewAccessorQuery(ViewDecl viewDecl);
+ Query createViewAccessorQuery(ViewDecl viewDecl, INamespaceResolver namespaceResolver);
}
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppQueryRewriter.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppQueryRewriter.java
index 0ce09e5..bad48c2 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppQueryRewriter.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppQueryRewriter.java
@@ -28,6 +28,7 @@
import java.util.Map;
import java.util.Set;
+import org.apache.asterix.common.api.INamespaceResolver;
import org.apache.asterix.common.exceptions.CompilationException;
import org.apache.asterix.common.exceptions.ErrorCode;
import org.apache.asterix.common.functions.FunctionSignature;
@@ -603,22 +604,34 @@
}
@Override
- public Query createViewAccessorQuery(ViewDecl viewDecl) {
+ public Query createViewAccessorQuery(ViewDecl viewDecl, INamespaceResolver namespaceResolver) {
+ boolean usingDatabase = namespaceResolver.isUsingDatabase();
// dataverse_name.view_name
+ String databaseName = viewDecl.getViewName().getDatabaseName();
DataverseName dataverseName = viewDecl.getViewName().getDataverseName();
String viewName = viewDecl.getViewName().getDatasetName();
- Expression vAccessExpr = createDatasetAccessExpression(dataverseName, viewName, viewDecl.getSourceLocation());
+ Expression vAccessExpr = createDatasetAccessExpression(databaseName, dataverseName, viewName,
+ viewDecl.getSourceLocation(), usingDatabase);
return ExpressionUtils.createWrappedQuery(vAccessExpr, viewDecl.getSourceLocation());
}
- private static Expression createDatasetAccessExpression(DataverseName dataverseName, String datasetName,
- SourceLocation sourceLoc) {
- AbstractExpression resultExpr = null;
+ private static Expression createDatasetAccessExpression(String databaseName, DataverseName dataverseName,
+ String datasetName, SourceLocation sourceLoc, boolean usingDatabase) {
+ AbstractExpression resultExpr;
List<String> dataverseNameParts = dataverseName.getParts();
- for (int i = 0, n = dataverseNameParts.size(); i < n; i++) {
+ int startIdx;
+ if (usingDatabase) {
+ resultExpr = new VariableExpr(new VarIdentifier(SqlppVariableUtil.toInternalVariableName(databaseName)));
+ startIdx = 0;
+ } else {
+ resultExpr = new VariableExpr(
+ new VarIdentifier(SqlppVariableUtil.toInternalVariableName(dataverseNameParts.get(0))));
+ startIdx = 1;
+ }
+ resultExpr.setSourceLocation(sourceLoc);
+ for (int i = startIdx, n = dataverseNameParts.size(); i < n; i++) {
String part = dataverseNameParts.get(i);
- resultExpr = i == 0 ? new VariableExpr(new VarIdentifier(SqlppVariableUtil.toInternalVariableName(part)))
- : new FieldAccessor(resultExpr, new Identifier(part));
+ resultExpr = new FieldAccessor(resultExpr, new Identifier(part));
resultExpr.setSourceLocation(sourceLoc);
}
resultExpr = new FieldAccessor(resultExpr, new Identifier(datasetName));
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/VariableCheckAndRewriteVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/VariableCheckAndRewriteVisitor.java
index 27a63d2..97a4171 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/VariableCheckAndRewriteVisitor.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/VariableCheckAndRewriteVisitor.java
@@ -126,15 +126,16 @@
if (resolveAsVariableReference(topVarExpr)) {
return fa;
} else {
- DataverseName dataverseName;
+ Namespace namespace;
try {
- dataverseName = DataverseName.create(dataverseNameParts);
+ namespace = metadataProvider.resolve(dataverseNameParts);
} catch (AsterixException e) {
throw new CompilationException(ErrorCode.INVALID_DATABASE_OBJECT_NAME, fa.getSourceLocation(),
dataverseNameParts.toString());
}
//TODO(DB): decide
- String databaseName = MetadataUtil.resolveDatabase(null, dataverseName);
+ String databaseName = namespace.getDatabaseName();
+ DataverseName dataverseName = namespace.getDataverseName();
String datasetName = fa.getIdent().getValue();
CallExpr datasetExpr =
resolveAsDataset(databaseName, dataverseName, datasetName, parent, topVarExpr);
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/MetadataNode.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/MetadataNode.java
index cc1251b..5383ac9 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/MetadataNode.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/MetadataNode.java
@@ -40,6 +40,7 @@
import org.apache.asterix.common.functions.FunctionSignature;
import org.apache.asterix.common.metadata.DataverseName;
import org.apache.asterix.common.metadata.DependencyFullyQualifiedName;
+import org.apache.asterix.common.metadata.MetadataConstants;
import org.apache.asterix.common.metadata.MetadataIndexImmutableProperties;
import org.apache.asterix.common.metadata.MetadataUtil;
import org.apache.asterix.common.transactions.IRecoveryManager.ResourceType;
@@ -63,6 +64,7 @@
import org.apache.asterix.metadata.api.IMetadataIndex;
import org.apache.asterix.metadata.api.IMetadataNode;
import org.apache.asterix.metadata.api.IValueExtractor;
+import org.apache.asterix.metadata.bootstrap.MetadataBuiltinEntities;
import org.apache.asterix.metadata.bootstrap.MetadataIndexesProvider;
import org.apache.asterix.metadata.entities.CompactionPolicy;
import org.apache.asterix.metadata.entities.Database;
@@ -354,13 +356,15 @@
@Override
public void addDatabase(TxnId txnId, Database database) throws AlgebricksException, RemoteException {
try {
+ if (!mdIndexesProvider.isUsingDatabase()) {
+ return;
+ }
DatabaseTupleTranslator tupleReaderWriter = tupleTranslatorProvider.getDatabaseTupleTranslator(true);
ITupleReference tuple = tupleReaderWriter.getTupleFromMetadataEntity(database);
insertTupleIntoIndex(txnId, mdIndexesProvider.getDatabaseEntity().getIndex(), tuple);
} catch (HyracksDataException e) {
if (e.matches(ErrorCode.DUPLICATE_KEY)) {
- //TODO(DB): change to database
- throw new AsterixException(org.apache.asterix.common.exceptions.ErrorCode.DATAVERSE_EXISTS, e,
+ throw new AsterixException(org.apache.asterix.common.exceptions.ErrorCode.DATABASE_EXISTS, e,
database.getDatabaseName());
} else {
throw new AlgebricksException(e);
@@ -699,6 +703,9 @@
@Override
public void dropDatabase(TxnId txnId, String databaseName) throws AlgebricksException, RemoteException {
try {
+ if (!mdIndexesProvider.isUsingDatabase()) {
+ return;
+ }
//TODO(DB): review
confirmDatabaseCanBeDeleted(txnId, databaseName);
@@ -1123,6 +1130,9 @@
@Override
public Database getDatabase(TxnId txnId, String databaseName) throws AlgebricksException {
try {
+ if (!mdIndexesProvider.isUsingDatabase()) {
+ return defaultDatabase(databaseName);
+ }
ITupleReference searchKey = createTuple(databaseName);
DatabaseTupleTranslator tupleReaderWriter = tupleTranslatorProvider.getDatabaseTupleTranslator(false);
IValueExtractor<Database> valueExtractor = new MetadataEntityValueExtractor<>(tupleReaderWriter);
@@ -2995,4 +3005,13 @@
public ITxnIdFactory getTxnIdFactory() {
return txnIdFactory;
}
+
+ private Database defaultDatabase(String databaseName) {
+ //TODO(DB): review
+ if (MetadataConstants.SYSTEM_DATABASE.equals(databaseName)) {
+ return MetadataBuiltinEntities.SYSTEM_DATABASE;
+ } else {
+ return MetadataBuiltinEntities.DEFAULT_DATABASE;
+ }
+ }
}
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/DatasetUtil.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/DatasetUtil.java
index 73797d8..4d1c4a6 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/DatasetUtil.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/DatasetUtil.java
@@ -628,6 +628,11 @@
return MetadataUtil.getFullyQualifiedDisplayName(dataverseName, datasetName);
}
+ public static String getFullyQualifiedDisplayName(String databaseName, DataverseName dataverseName,
+ String datasetName) {
+ return MetadataUtil.getFullyQualifiedDisplayName(databaseName, dataverseName, datasetName);
+ }
+
/***
* Creates a node group that is associated with a new dataset.
*