[NO ISSUE][SQLPP] Support dataset synonyms
- user model changes: yes
- storage format changes: no
- interface changes: no
Details:
- Add CREATE / DROP SYNONYM statements to SQL++
- Follow synonyms when resolving dataset references
in SELECT, INSERT, UPSERT, DELETE, LOAD statements
- Add metadata dataset for synonyms: Metadata.Synonym
- Add documentation and tests
Change-Id: Idf806914664205fb186ee3da8b0cebf234266f37
Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/4484
Contrib: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Dmitry Lychagin <dmitry.lychagin@couchbase.com>
Reviewed-by: Ali Alsuliman <ali.al.solaiman@gmail.com>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
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 625b95a..dcea54a 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
@@ -100,6 +100,7 @@
import org.apache.asterix.lang.common.statement.CreateFeedStatement;
import org.apache.asterix.lang.common.statement.CreateFunctionStatement;
import org.apache.asterix.lang.common.statement.CreateIndexStatement;
+import org.apache.asterix.lang.common.statement.CreateSynonymStatement;
import org.apache.asterix.lang.common.statement.DatasetDecl;
import org.apache.asterix.lang.common.statement.DataverseDecl;
import org.apache.asterix.lang.common.statement.DataverseDropStatement;
@@ -122,6 +123,7 @@
import org.apache.asterix.lang.common.statement.SetStatement;
import org.apache.asterix.lang.common.statement.StartFeedStatement;
import org.apache.asterix.lang.common.statement.StopFeedStatement;
+import org.apache.asterix.lang.common.statement.SynonymDropStatement;
import org.apache.asterix.lang.common.statement.TypeDecl;
import org.apache.asterix.lang.common.statement.TypeDropStatement;
import org.apache.asterix.lang.common.statement.WriteStatement;
@@ -148,6 +150,7 @@
import org.apache.asterix.metadata.entities.Index;
import org.apache.asterix.metadata.entities.InternalDatasetDetails;
import org.apache.asterix.metadata.entities.NodeGroup;
+import org.apache.asterix.metadata.entities.Synonym;
import org.apache.asterix.metadata.feeds.FeedMetadataUtil;
import org.apache.asterix.metadata.lock.ExternalDatasetsRegistry;
import org.apache.asterix.metadata.utils.DatasetUtil;
@@ -350,6 +353,12 @@
case FUNCTION_DROP:
handleFunctionDropStatement(metadataProvider, stmt);
break;
+ case CREATE_SYNONYM:
+ handleCreateSynonymStatement(metadataProvider, stmt);
+ break;
+ case SYNONYM_DROP:
+ handleDropSynonymStatement(metadataProvider, stmt);
+ break;
case LOAD:
handleLoadStatement(metadataProvider, stmt, hcc);
break;
@@ -1359,6 +1368,10 @@
}
}
jobsToExecute.add(DataverseUtil.dropDataverseJobSpec(dv, metadataProvider));
+
+ // #. gather all synonyms in this dataverse
+ List<Synonym> synonyms = MetadataManager.INSTANCE.getDataverseSynonyms(mdTxnCtx, dataverseName);
+
// #. mark PendingDropOp on the dataverse record by
// first, deleting the dataverse record from the DATAVERSE_DATASET
// second, inserting the dataverse record with the PendingDropOp value into the
@@ -1379,6 +1392,11 @@
bActiveTxn = true;
metadataProvider.setMetadataTxnContext(mdTxnCtx);
+ // #. delete synonyms in this dataverse
+ for (Synonym synonym : synonyms) {
+ MetadataManager.INSTANCE.dropSynonym(mdTxnCtx, synonym.getDataverseName(), synonym.getSynonymName());
+ }
+
// #. finally, delete the dataverse.
MetadataManager.INSTANCE.dropDataverse(mdTxnCtx, dataverseName);
@@ -1849,19 +1867,90 @@
}
}
+ protected void handleCreateSynonymStatement(MetadataProvider metadataProvider, Statement stmt) throws Exception {
+ CreateSynonymStatement css = (CreateSynonymStatement) stmt;
+ DataverseName dataverseName = getActiveDataverseName(css.getDataverseName());
+ String synonymName = css.getSynonymName();
+ DataverseName objectDataverseName = getActiveDataverseName(css.getObjectDataverseName());
+ String objectName = css.getObjectName();
+ lockUtil.createSynonymBegin(lockManager, metadataProvider.getLocks(), dataverseName, synonymName);
+ try {
+ doCreateSynonym(metadataProvider, css, dataverseName, synonymName, objectDataverseName, objectName);
+ } finally {
+ metadataProvider.getLocks().unlock();
+ }
+ }
+
+ protected void doCreateSynonym(MetadataProvider metadataProvider, CreateSynonymStatement css,
+ DataverseName dataverseName, String synonymName, DataverseName objectDataverseName, String objectName)
+ throws Exception {
+ MetadataTransactionContext mdTxnCtx = MetadataManager.INSTANCE.beginTransaction();
+ metadataProvider.setMetadataTxnContext(mdTxnCtx);
+ try {
+ Synonym synonym = MetadataManager.INSTANCE.getSynonym(metadataProvider.getMetadataTxnContext(),
+ dataverseName, synonymName);
+ if (synonym != null) {
+ if (css.getIfNotExists()) {
+ MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
+ return;
+ }
+ throw new CompilationException(ErrorCode.SYNONYM_EXISTS, css.getSourceLocation(), synonymName);
+ }
+ synonym = new Synonym(dataverseName, synonymName, objectDataverseName, objectName);
+ MetadataManager.INSTANCE.addSynonym(metadataProvider.getMetadataTxnContext(), synonym);
+ MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
+ } catch (Exception e) {
+ abort(e, e, mdTxnCtx);
+ throw e;
+ }
+ }
+
+ protected void handleDropSynonymStatement(MetadataProvider metadataProvider, Statement stmt) throws Exception {
+ SynonymDropStatement stmtSynDrop = (SynonymDropStatement) stmt;
+ DataverseName dataverseName = getActiveDataverseName(stmtSynDrop.getDataverseName());
+ String synonymName = stmtSynDrop.getSynonymName();
+ lockUtil.dropSynonymBegin(lockManager, metadataProvider.getLocks(), dataverseName, synonymName);
+ try {
+ doDropSynonym(metadataProvider, stmtSynDrop, dataverseName, synonymName);
+ } finally {
+ metadataProvider.getLocks().unlock();
+ }
+ }
+
+ protected void doDropSynonym(MetadataProvider metadataProvider, SynonymDropStatement stmtSynDrop,
+ DataverseName dataverseName, String synonymName) throws Exception {
+ MetadataTransactionContext mdTxnCtx = MetadataManager.INSTANCE.beginTransaction();
+ metadataProvider.setMetadataTxnContext(mdTxnCtx);
+ try {
+ Synonym synonym = MetadataManager.INSTANCE.getSynonym(mdTxnCtx, dataverseName, synonymName);
+ if (synonym == null) {
+ if (stmtSynDrop.getIfExists()) {
+ MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
+ return;
+ }
+ throw new CompilationException(ErrorCode.UNKNOWN_SYNONYM, stmtSynDrop.getSourceLocation(), synonymName);
+ }
+ MetadataManager.INSTANCE.dropSynonym(mdTxnCtx, dataverseName, synonymName);
+ MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
+ } catch (Exception e) {
+ abort(e, e, mdTxnCtx);
+ throw e;
+ }
+ }
+
protected void handleLoadStatement(MetadataProvider metadataProvider, Statement stmt, IHyracksClientConnection hcc)
throws Exception {
LoadStatement loadStmt = (LoadStatement) stmt;
DataverseName dataverseName = getActiveDataverseName(loadStmt.getDataverseName());
- String datasetName = loadStmt.getDatasetName().getValue();
+ String datasetName = loadStmt.getDatasetName();
MetadataTransactionContext mdTxnCtx = MetadataManager.INSTANCE.beginTransaction();
boolean bActiveTxn = true;
metadataProvider.setMetadataTxnContext(mdTxnCtx);
lockUtil.modifyDatasetBegin(lockManager, metadataProvider.getLocks(), dataverseName, datasetName);
try {
CompiledLoadFromFileStatement cls =
- new CompiledLoadFromFileStatement(dataverseName, loadStmt.getDatasetName().getValue(),
- loadStmt.getAdapter(), loadStmt.getProperties(), loadStmt.dataIsAlreadySorted());
+ new CompiledLoadFromFileStatement(dataverseName, loadStmt.getDatasetName(), loadStmt.getAdapter(),
+ loadStmt.getProperties(), loadStmt.dataIsAlreadySorted());
cls.setSourceLocation(stmt.getSourceLocation());
JobSpecification spec = apiFramework.compileQuery(hcc, metadataProvider, null, 0, null, sessionOutput, cls,
null, responsePrinter, warningCollector);
@@ -2965,8 +3054,19 @@
}
protected void rewriteStatement(Statement stmt, IStatementRewriter rewriter, MetadataProvider metadataProvider)
- throws CompilationException {
- rewriter.rewrite(stmt, metadataProvider);
+ throws CompilationException, RemoteException {
+ if (!rewriter.isRewritable(stmt.getKind())) {
+ return;
+ }
+ MetadataTransactionContext mdTxnCtx = MetadataManager.INSTANCE.beginTransaction();
+ metadataProvider.setMetadataTxnContext(mdTxnCtx);
+ try {
+ rewriter.rewrite(stmt, metadataProvider);
+ MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
+ } catch (Exception e) {
+ abort(e, e, mdTxnCtx);
+ throw e;
+ }
}
private void ensureNonPrimaryIndexDrop(Index index, SourceLocation sourceLoc) throws AlgebricksException {
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/utils/FeedOperations.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/utils/FeedOperations.java
index 447fdff..21c0f89b 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/utils/FeedOperations.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/utils/FeedOperations.java
@@ -67,7 +67,6 @@
import org.apache.asterix.lang.common.statement.InsertStatement;
import org.apache.asterix.lang.common.statement.Query;
import org.apache.asterix.lang.common.statement.UpsertStatement;
-import org.apache.asterix.lang.common.struct.Identifier;
import org.apache.asterix.lang.common.struct.VarIdentifier;
import org.apache.asterix.lang.common.util.FunctionUtil;
import org.apache.asterix.lang.sqlpp.clause.FromClause;
@@ -245,13 +244,13 @@
Query feedConnQuery = makeConnectionQuery(feedConn);
CompiledStatements.ICompiledDmlStatement clfrqs;
if (insertFeed) {
- InsertStatement stmtUpsert = new InsertStatement(feedConn.getDataverseName(),
- new Identifier(feedConn.getDatasetName()), feedConnQuery, -1, null, null);
+ InsertStatement stmtUpsert = new InsertStatement(feedConn.getDataverseName(), feedConn.getDatasetName(),
+ feedConnQuery, -1, null, null);
clfrqs = new CompiledStatements.CompiledInsertStatement(feedConn.getDataverseName(),
feedConn.getDatasetName(), feedConnQuery, stmtUpsert.getVarCounter(), null, null);
} else {
- UpsertStatement stmtUpsert = new UpsertStatement(feedConn.getDataverseName(),
- new Identifier(feedConn.getDatasetName()), feedConnQuery, -1, null, null);
+ UpsertStatement stmtUpsert = new UpsertStatement(feedConn.getDataverseName(), feedConn.getDatasetName(),
+ feedConnQuery, -1, null, null);
clfrqs = new CompiledStatements.CompiledUpsertStatement(feedConn.getDataverseName(),
feedConn.getDatasetName(), feedConnQuery, stmtUpsert.getVarCounter(), null, null);
}
diff --git a/asterixdb/asterix-app/src/test/resources/metadata/results/basic/metadata_dataset/metadata_dataset.1.adm b/asterixdb/asterix-app/src/test/resources/metadata/results/basic/metadata_dataset/metadata_dataset.1.adm
index d96df28..84ce315 100644
--- a/asterixdb/asterix-app/src/test/resources/metadata/results/basic/metadata_dataset/metadata_dataset.1.adm
+++ b/asterixdb/asterix-app/src/test/resources/metadata/results/basic/metadata_dataset/metadata_dataset.1.adm
@@ -12,3 +12,4 @@
{ "DataverseName": "Metadata", "DatasetName": "Library", "DatatypeDataverseName": "Metadata", "DatatypeName": "LibraryRecordType", "DatasetType": "INTERNAL", "GroupName": "MetadataGroup", "CompactionPolicy": "concurrent", "CompactionPolicyProperties": [ { "Name": "max-component-count", "Value": "30" }, { "Name": "min-merge-component-count", "Value": "3" }, { "Name": "max-merge-component-count", "Value": "10" }, { "Name": "size-ratio", "Value": "1.2" } ], "InternalDetails": { "FileStructure": "BTREE", "PartitioningStrategy": "HASH", "PartitioningKey": [ [ "DataverseName" ], [ "Name" ] ], "PrimaryKey": [ [ "DataverseName" ], [ "Name" ] ], "Autogenerated": false }, "Hints": {{ }}, "Timestamp": "Fri Oct 21 10:29:21 PDT 2016", "DatasetId": 9, "PendingOp": 0 }
{ "DataverseName": "Metadata", "DatasetName": "Node", "DatatypeDataverseName": "Metadata", "DatatypeName": "NodeRecordType", "DatasetType": "INTERNAL", "GroupName": "MetadataGroup", "CompactionPolicy": "concurrent", "CompactionPolicyProperties": [ { "Name": "max-component-count", "Value": "30" }, { "Name": "min-merge-component-count", "Value": "3" }, { "Name": "max-merge-component-count", "Value": "10" }, { "Name": "size-ratio", "Value": "1.2" } ], "InternalDetails": { "FileStructure": "BTREE", "PartitioningStrategy": "HASH", "PartitioningKey": [ [ "NodeName" ] ], "PrimaryKey": [ [ "NodeName" ] ], "Autogenerated": false }, "Hints": {{ }}, "Timestamp": "Fri Oct 21 10:29:21 PDT 2016", "DatasetId": 5, "PendingOp": 0 }
{ "DataverseName": "Metadata", "DatasetName": "Nodegroup", "DatatypeDataverseName": "Metadata", "DatatypeName": "NodeGroupRecordType", "DatasetType": "INTERNAL", "GroupName": "MetadataGroup", "CompactionPolicy": "concurrent", "CompactionPolicyProperties": [ { "Name": "max-component-count", "Value": "30" }, { "Name": "min-merge-component-count", "Value": "3" }, { "Name": "max-merge-component-count", "Value": "10" }, { "Name": "size-ratio", "Value": "1.2" } ], "InternalDetails": { "FileStructure": "BTREE", "PartitioningStrategy": "HASH", "PartitioningKey": [ [ "GroupName" ] ], "PrimaryKey": [ [ "GroupName" ] ], "Autogenerated": false }, "Hints": {{ }}, "Timestamp": "Fri Oct 21 10:29:21 PDT 2016", "DatasetId": 6, "PendingOp": 0 }
+{ "DataverseName": "Metadata", "DatasetName": "Synonym", "DatatypeDataverseName": "Metadata", "DatatypeName": "SynonymRecordType", "DatasetType": "INTERNAL", "GroupName": "MetadataGroup", "CompactionPolicy": "concurrent", "CompactionPolicyProperties": [ { "Name": "max-component-count", "Value": "30" }, { "Name": "min-merge-component-count", "Value": "3" }, { "Name": "max-merge-component-count", "Value": "10" }, { "Name": "size-ratio", "Value": "1.2" } ], "InternalDetails": { "FileStructure": "BTREE", "PartitioningStrategy": "HASH", "PartitioningKey": [ [ "DataverseName" ], [ "SynonymName" ] ], "PrimaryKey": [ [ "DataverseName" ], [ "SynonymName" ] ], "Autogenerated": false }, "Hints": {{ }}, "Timestamp": "Tue Dec 17 10:36:07 PST 2019", "DatasetId": 15, "PendingOp": 0 }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/metadata/results/basic/metadata_datatype/metadata_datatype.1.adm b/asterixdb/asterix-app/src/test/resources/metadata/results/basic/metadata_datatype/metadata_datatype.1.adm
index 5fc2c1e..118225b 100644
--- a/asterixdb/asterix-app/src/test/resources/metadata/results/basic/metadata_datatype/metadata_datatype.1.adm
+++ b/asterixdb/asterix-app/src/test/resources/metadata/results/basic/metadata_datatype/metadata_datatype.1.adm
@@ -41,6 +41,7 @@
{ "DataverseName": "Metadata", "DatatypeName": "NodeGroupRecordType", "Derived": { "Tag": "RECORD", "IsAnonymous": false, "Record": { "IsOpen": true, "Fields": [ { "FieldName": "GroupName", "FieldType": "string", "IsNullable": false }, { "FieldName": "NodeNames", "FieldType": "NodeGroupRecordType_NodeNames", "IsNullable": false }, { "FieldName": "Timestamp", "FieldType": "string", "IsNullable": false } ] } }, "Timestamp": "Mon Jan 08 10:27:04 PST 2018" }
{ "DataverseName": "Metadata", "DatatypeName": "NodeGroupRecordType_NodeNames", "Derived": { "Tag": "UNORDEREDLIST", "IsAnonymous": true, "UnorderedList": "string" }, "Timestamp": "Mon Jan 08 10:27:04 PST 2018" }
{ "DataverseName": "Metadata", "DatatypeName": "NodeRecordType", "Derived": { "Tag": "RECORD", "IsAnonymous": false, "Record": { "IsOpen": true, "Fields": [ { "FieldName": "NodeName", "FieldType": "string", "IsNullable": false }, { "FieldName": "NumberOfCores", "FieldType": "int64", "IsNullable": false }, { "FieldName": "WorkingMemorySize", "FieldType": "int64", "IsNullable": false } ] } }, "Timestamp": "Mon Jan 08 10:27:04 PST 2018" }
+{ "DataverseName": "Metadata", "DatatypeName": "SynonymRecordType", "Derived": { "Tag": "RECORD", "IsAnonymous": false, "Record": { "IsOpen": true, "Fields": [ { "FieldName": "DataverseName", "FieldType": "string", "IsNullable": false }, { "FieldName": "SynonymName", "FieldType": "string", "IsNullable": false }, { "FieldName": "ObjectDataverseName", "FieldType": "string", "IsNullable": false }, { "FieldName": "ObjectName", "FieldType": "string", "IsNullable": false } ] } }, "Timestamp": "Tue Dec 17 10:38:05 PST 2019" }
{ "DataverseName": "Metadata", "DatatypeName": "binary", "Timestamp": "Mon Jan 08 10:27:04 PST 2018" }
{ "DataverseName": "Metadata", "DatatypeName": "boolean", "Timestamp": "Mon Jan 08 10:27:04 PST 2018" }
{ "DataverseName": "Metadata", "DatatypeName": "circle", "Timestamp": "Mon Jan 08 10:27:04 PST 2018" }
diff --git a/asterixdb/asterix-app/src/test/resources/metadata/results/basic/metadata_index/metadata_index.1.adm b/asterixdb/asterix-app/src/test/resources/metadata/results/basic/metadata_index/metadata_index.1.adm
index 0521e37..bdb22c7 100644
--- a/asterixdb/asterix-app/src/test/resources/metadata/results/basic/metadata_index/metadata_index.1.adm
+++ b/asterixdb/asterix-app/src/test/resources/metadata/results/basic/metadata_index/metadata_index.1.adm
@@ -12,3 +12,4 @@
{ "DataverseName": "Metadata", "DatasetName": "Library", "IndexName": "Library", "IndexStructure": "BTREE", "SearchKey": [ [ "DataverseName" ], [ "Name" ] ], "IsPrimary": true, "Timestamp": "Fri Oct 21 10:29:21 PDT 2016", "PendingOp": 0 }
{ "DataverseName": "Metadata", "DatasetName": "Node", "IndexName": "Node", "IndexStructure": "BTREE", "SearchKey": [ [ "NodeName" ] ], "IsPrimary": true, "Timestamp": "Fri Oct 21 10:29:21 PDT 2016", "PendingOp": 0 }
{ "DataverseName": "Metadata", "DatasetName": "Nodegroup", "IndexName": "Nodegroup", "IndexStructure": "BTREE", "SearchKey": [ [ "GroupName" ] ], "IsPrimary": true, "Timestamp": "Fri Oct 21 10:29:21 PDT 2016", "PendingOp": 0 }
+{ "DataverseName": "Metadata", "DatasetName": "Synonym", "IndexName": "Synonym", "IndexStructure": "BTREE", "SearchKey": [ [ "DataverseName" ], [ "SynonymName" ] ], "IsPrimary": true, "Timestamp": "Tue Dec 17 10:39:17 PST 2019", "PendingOp": 0 }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/metadata/results/basic/metadata_selfjoin/metadata_selfjoin.1.adm b/asterixdb/asterix-app/src/test/resources/metadata/results/basic/metadata_selfjoin/metadata_selfjoin.1.adm
index a5ae0e4..7031c72 100644
--- a/asterixdb/asterix-app/src/test/resources/metadata/results/basic/metadata_selfjoin/metadata_selfjoin.1.adm
+++ b/asterixdb/asterix-app/src/test/resources/metadata/results/basic/metadata_selfjoin/metadata_selfjoin.1.adm
@@ -12,3 +12,4 @@
{ "dv1": "Metadata", "dv2": "Metadata" }
{ "dv1": "Metadata", "dv2": "Metadata" }
{ "dv1": "Metadata", "dv2": "Metadata" }
+{ "dv1": "Metadata", "dv2": "Metadata" }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/synonym/synonym-01/synonym-01.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/synonym/synonym-01/synonym-01.1.ddl.sqlpp
new file mode 100644
index 0000000..155f9e8
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/synonym/synonym-01/synonym-01.1.ddl.sqlpp
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+drop dataverse test if exists;
+create dataverse test;
+
+use test;
+
+create type test.TwitterUserType as
+{
+ `screen-name` : string,
+ lang : string,
+ friends_count : integer,
+ statuses_count : integer,
+ name : string,
+ followers_count : integer
+};
+
+create type test.TweetMessageType as
+{
+ tweetid : bigint,
+ user : string,
+ `sender-location` : point,
+ `send-time` : datetime,
+ `forward-from` : bigint,
+ `retweet-from` : bigint,
+ `referred-topics` : {{string}},
+ `message-text` : string
+};
+
+create dataset TwitterUsers(TwitterUserType) primary key `screen-name`;
+
+create dataset TweetMessages(TweetMessageType) primary key tweetid;
+
+create synonym TwitterUsersSynonym for TwitterUsers;
+
+create synonym TwitterUsersSynonym2 for TwitterUsersSynonym;
+
+create synonym TweetMessagesSynonym for TweetMessages;
+
+create synonym TweetMessagesSynonym2 for TweetMessagesSynonym;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/synonym/synonym-01/synonym-01.2.update.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/synonym/synonym-01/synonym-01.2.update.sqlpp
new file mode 100644
index 0000000..2d3b97e
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/synonym/synonym-01/synonym-01.2.update.sqlpp
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+/*
+ * Use synonyms in LOAD
+ */
+
+use test;
+
+load dataset TwitterUsersSynonym using localfs ((`path`=`asterix_nc1://data/index-join/tw_users.adm`),(`format`=`adm`));
+
+load dataset TweetMessagesSynonym2 using localfs ((`path`=`asterix_nc1://data/index-join/tw_messages.adm`),(`format`=`adm`));
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/synonym/synonym-01/synonym-01.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/synonym/synonym-01/synonym-01.3.query.sqlpp
new file mode 100644
index 0000000..6531713
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/synonym/synonym-01/synonym-01.3.query.sqlpp
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+use test;
+
+select count(*) as cnt from TwitterUsers
+union all
+select count(*) as cnt from TwitterUsersSynonym
+union all
+select count(*) as cnt from TwitterUsersSynonym2;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/synonym/synonym-01/synonym-01.4.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/synonym/synonym-01/synonym-01.4.query.sqlpp
new file mode 100644
index 0000000..8b9a9be
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/synonym/synonym-01/synonym-01.4.query.sqlpp
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+use test;
+
+select count(*) as cnt from TweetMessages
+union all
+select count(*) as cnt from TweetMessagesSynonym
+union all
+select count(*) as cnt from TweetMessagesSynonym2;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/synonym/synonym-01/synonym-01.5.update.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/synonym/synonym-01/synonym-01.5.update.sqlpp
new file mode 100644
index 0000000..40a978b
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/synonym/synonym-01/synonym-01.5.update.sqlpp
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+/*
+ * Use synonyms in DELETE
+ */
+
+use test;
+
+delete from TwitterUsersSynonym
+where `screen-name` like "Aaliyah%";
+
+delete from TweetMessagesSynonym2
+where user like "Vernia%";
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/synonym/synonym-01/synonym-01.6.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/synonym/synonym-01/synonym-01.6.query.sqlpp
new file mode 100644
index 0000000..4f67f4d
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/synonym/synonym-01/synonym-01.6.query.sqlpp
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+use test;
+
+{
+ "users": ( select value count(*) from TwitterUsers )[0],
+ "messages": ( select value count(*) from TweetMessages )[0]
+}
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/synonym/synonym-01/synonym-01.7.update.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/synonym/synonym-01/synonym-01.7.update.sqlpp
new file mode 100644
index 0000000..6a3f03b
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/synonym/synonym-01/synonym-01.7.update.sqlpp
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+/*
+ * Use synonyms in INSERT / UPSERT
+ */
+
+use test;
+
+insert into TwitterUsersSynonym
+select value object_put(u, "screen-name", u.`screen-name` || u.`screen-name`)
+from TwitterUsersSynonym2 u;
+
+upsert into TweetMessagesSynonym2
+select value m
+from TweetMessagesSynonym m;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/synonym/synonym-01/synonym-01.8.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/synonym/synonym-01/synonym-01.8.query.sqlpp
new file mode 100644
index 0000000..4f67f4d
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/synonym/synonym-01/synonym-01.8.query.sqlpp
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+use test;
+
+{
+ "users": ( select value count(*) from TwitterUsers )[0],
+ "messages": ( select value count(*) from TweetMessages )[0]
+}
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/synonym/synonym-01/synonym-01.9.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/synonym/synonym-01/synonym-01.9.query.sqlpp
new file mode 100644
index 0000000..1691fd7
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/synonym/synonym-01/synonym-01.9.query.sqlpp
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+/*
+ * Metadata for synonyms
+ */
+
+select value s
+from `Metadata`.`Synonym` s
+order by DataverseName, SynonymName
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/synonym/synonym-01/synonym-01.3.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/synonym/synonym-01/synonym-01.3.adm
new file mode 100644
index 0000000..f8f0035
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/synonym/synonym-01/synonym-01.3.adm
@@ -0,0 +1,3 @@
+{ "cnt": 12 }
+{ "cnt": 12 }
+{ "cnt": 12 }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/synonym/synonym-01/synonym-01.4.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/synonym/synonym-01/synonym-01.4.adm
new file mode 100644
index 0000000..2b007b4
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/synonym/synonym-01/synonym-01.4.adm
@@ -0,0 +1,3 @@
+{ "cnt": 13 }
+{ "cnt": 13 }
+{ "cnt": 13 }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/synonym/synonym-01/synonym-01.6.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/synonym/synonym-01/synonym-01.6.adm
new file mode 100644
index 0000000..d0341a5
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/synonym/synonym-01/synonym-01.6.adm
@@ -0,0 +1 @@
+{ "users": 1, "messages": 1 }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/synonym/synonym-01/synonym-01.8.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/synonym/synonym-01/synonym-01.8.adm
new file mode 100644
index 0000000..5994bee
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/synonym/synonym-01/synonym-01.8.adm
@@ -0,0 +1 @@
+{ "users": 2, "messages": 1 }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/synonym/synonym-01/synonym-01.9.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/synonym/synonym-01/synonym-01.9.adm
new file mode 100644
index 0000000..e4dcb9b
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/synonym/synonym-01/synonym-01.9.adm
@@ -0,0 +1,4 @@
+{ "DataverseName": "test", "SynonymName": "TweetMessagesSynonym", "ObjectDataverseName": "test", "ObjectName": "TweetMessages" }
+{ "DataverseName": "test", "SynonymName": "TweetMessagesSynonym2", "ObjectDataverseName": "test", "ObjectName": "TweetMessagesSynonym" }
+{ "DataverseName": "test", "SynonymName": "TwitterUsersSynonym", "ObjectDataverseName": "test", "ObjectName": "TwitterUsers" }
+{ "DataverseName": "test", "SynonymName": "TwitterUsersSynonym2", "ObjectDataverseName": "test", "ObjectName": "TwitterUsersSynonym" }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
index a239497..b2335c5 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
@@ -9951,6 +9951,13 @@
</compilation-unit>
</test-case>
</test-group>
+ <test-group name="synonym">
+ <test-case FilePath="synonym">
+ <compilation-unit name="synonym-01">
+ <output-dir compare="Text">synonym-01</output-dir>
+ </compilation-unit>
+ </test-case>
+ </test-group>
<test-group name="tokenizers">
<test-case FilePath="tokenizers">
<compilation-unit name="counthashed-gram-tokens_01">
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/api/IMetadataLockManager.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/api/IMetadataLockManager.java
index 1b92394..5764c69 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/api/IMetadataLockManager.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/api/IMetadataLockManager.java
@@ -293,6 +293,36 @@
throws AlgebricksException;
/**
+ * Acquire read lock on the synonym
+ *
+ * @param locks
+ * the lock list to add the new lock to
+ * @param dataverseName
+ * the dataverse name
+ * @param synonymName
+ * the name of the synonym in the given dataverse
+ * @throws AlgebricksException
+ * if lock couldn't be acquired
+ */
+ void acquireSynonymReadLock(LockList locks, DataverseName dataverseName, String synonymName)
+ throws AlgebricksException;
+
+ /**
+ * Acquire write lock on the synonym
+ *
+ * @param locks
+ * the lock list to add the new lock to
+ * @param dataverseName
+ * the dataverse name
+ * @param synonymName
+ * the name of the synonym in the given dataverse
+ * @throws AlgebricksException
+ * if lock couldn't be acquired
+ */
+ void acquireSynonymWriteLock(LockList locks, DataverseName dataverseName, String synonymName)
+ throws AlgebricksException;
+
+ /**
* Acquire read lock on the extension entity
*
* @param locks
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 95cd4a8..009b85c 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
@@ -195,6 +195,8 @@
public static final int OPERATION_NOT_SUPPORTED_ON_PRIMARY_INDEX = 1105;
public static final int EXPECTED_CONSTANT_VALUE = 1106;
public static final int UNEXPECTED_HINT = 1107;
+ public static final int SYNONYM_EXISTS = 1108;
+ public static final int UNKNOWN_SYNONYM = 1109;
// Feed errors
public static final int DATAFLOW_ILLEGAL_STATE = 3001;
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/metadata/IMetadataLockUtil.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/metadata/IMetadataLockUtil.java
index 7f02653..412c73f 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/metadata/IMetadataLockUtil.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/metadata/IMetadataLockUtil.java
@@ -79,6 +79,14 @@
void dropFunctionBegin(IMetadataLockManager lockManager, LockList locks, DataverseName dataverseName,
String functionName) throws AlgebricksException;
+ // Synonym helpers
+
+ void createSynonymBegin(IMetadataLockManager lockManager, LockList locks, DataverseName dataverseName,
+ String synonymName) throws AlgebricksException;
+
+ void dropSynonymBegin(IMetadataLockManager lockManager, LockList locks, DataverseName dataverseName,
+ String synonymName) throws AlgebricksException;
+
// Feed helpers
void createFeedPolicyBegin(IMetadataLockManager lockManager, LockList locks, DataverseName dataverseName,
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/metadata/MetadataIndexImmutableProperties.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/metadata/MetadataIndexImmutableProperties.java
index b131d01..a8cd14f 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/metadata/MetadataIndexImmutableProperties.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/metadata/MetadataIndexImmutableProperties.java
@@ -23,7 +23,7 @@
public static final int FIRST_AVAILABLE_EXTENSION_METADATA_DATASET_ID = 52;
public static final int FIRST_AVAILABLE_USER_DATASET_ID = 100;
public static final int METADATA_DATASETS_PARTITIONS = 1;
- public static final int METADATA_DATASETS_COUNT = 14;
+ public static final int METADATA_DATASETS_COUNT = 15;
private final String indexName;
private final int datasetId;
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 12d7284..3f080c1 100644
--- a/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties
+++ b/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties
@@ -190,6 +190,8 @@
1105 = Operation not supported on primary index %1$s
1106 = Expected constant value
1107 = Unexpected hint: %1$s. %2$s expected at this location
+1108 = A synonym with this name %1$s already exists
+1109 = Cannot find synonym with name %1$s
# Feed Errors
3001 = Illegal state.
diff --git a/asterixdb/asterix-doc/src/main/markdown/sqlpp/0_toc.md b/asterixdb/asterix-doc/src/main/markdown/sqlpp/0_toc.md
index 1a5a3e6..e65ae9f 100644
--- a/asterixdb/asterix-doc/src/main/markdown/sqlpp/0_toc.md
+++ b/asterixdb/asterix-doc/src/main/markdown/sqlpp/0_toc.md
@@ -89,6 +89,7 @@
* [Datasets](#Datasets)
* [Indices](#Indices)
* [Functions](#Functions)
+ * [Synonyms](#Synonyms)
* [Removal](#Removal)
* [Load Statement](#Load_statement)
* [Modification Statements](#Modification_statements)
diff --git a/asterixdb/asterix-doc/src/main/markdown/sqlpp/5_ddl_dataset_index.md b/asterixdb/asterix-doc/src/main/markdown/sqlpp/5_ddl_dataset_index.md
index 79e04ae..9e10aed 100644
--- a/asterixdb/asterix-doc/src/main/markdown/sqlpp/5_ddl_dataset_index.md
+++ b/asterixdb/asterix-doc/src/main/markdown/sqlpp/5_ddl_dataset_index.md
@@ -23,6 +23,7 @@
| TypeSpecification
| DatasetSpecification
| IndexSpecification
+ | SynonymSpecification
| FunctionSpecification )
QualifiedName ::= Identifier ( "." Identifier )?
diff --git a/asterixdb/asterix-doc/src/main/markdown/sqlpp/5_ddl_dml.md b/asterixdb/asterix-doc/src/main/markdown/sqlpp/5_ddl_dml.md
index 1ba5ece2..7a2223e 100644
--- a/asterixdb/asterix-doc/src/main/markdown/sqlpp/5_ddl_dml.md
+++ b/asterixdb/asterix-doc/src/main/markdown/sqlpp/5_ddl_dml.md
@@ -36,6 +36,9 @@
The transactional scope of each insert transaction is the insertion of a single object plus its affiliated secondary index entries (if any).
If the query part of an insert returns a single object, then the INSERT statement will be a single, atomic transaction.
If the query part returns multiple objects, each object being inserted will be treated as a separate tranaction.
+
+The target dataset name may be a synonym introduced by CREATE SYNONYM statement.
+
The following example illustrates a query-based insertion.
##### Example
@@ -53,6 +56,8 @@
for datasets with an auto-generated key as its primary key. This operation will insert the record if no record with that key already exists, but
if a record with the key already exists, then the operation will be converted to a replace/update operation.
+The target dataset name may be a synonym introduced by CREATE SYNONYM statement.
+
The following example illustrates a query-based upsert operation.
##### Example
@@ -73,6 +78,8 @@
If the boolean expression for a delete identifies a single object, then the DELETE statement itself will be a single, atomic transaction.
If the expression identifies multiple objects, then each object deleted will be handled as a separate transaction.
+The target dataset name may be a synonym introduced by CREATE SYNONYM statement.
+
The following examples illustrate single-object deletions.
##### Example
diff --git a/asterixdb/asterix-doc/src/main/markdown/sqlpp/5_ddl_function_removal.md b/asterixdb/asterix-doc/src/main/markdown/sqlpp/5_ddl_function_removal.md
index 9fcaa11..34b611f 100644
--- a/asterixdb/asterix-doc/src/main/markdown/sqlpp/5_ddl_function_removal.md
+++ b/asterixdb/asterix-doc/src/main/markdown/sqlpp/5_ddl_function_removal.md
@@ -19,7 +19,7 @@
### <a id="Functions"> Functions</a>
-The create function statement creates a **named** function that can then be used and reused in queries.
+The CREATE FUNCTION statement creates a **named** function that can then be used and reused in queries.
The body of a function can be any query expression involving the function's parameters.
FunctionSpecification ::= "FUNCTION" FunctionOrTypeName IfNotExists ParameterList "{" Expression "}"
@@ -35,16 +35,35 @@
WHERE u.id = userId)[0]
};
+### <a id="Synonyms"> Synonyms</a>
+
+ SynonymSpecification ::= "SYNONYM" QualifiedName "FOR" QualifiedName IfNotExists
+
+The CREATE SYNONYM statement creates a synonym for a given dataset.
+This synonym may be used used instead of the dataset name in SELECT, INSERT, UPSERT, DELETE, and LOAD statements.
+The target dataset does not need to exist when the synonym is created.
+
+##### Example
+
+ CREATE DATASET GleambookUsers(GleambookUserType) PRIMARY KEY id;
+
+ CREATE SYNONYM GleambookUsersSynonym FOR GleambookUsers;
+
+ SELECT * FROM GleambookUsersSynonym;
+
+More information on how synonyms are resolved can be found in the appendix section on Variable Resolution.
+
### <a id="Removal"> Removal</a>
DropStatement ::= "DROP" ( "DATAVERSE" Identifier IfExists
| "TYPE" FunctionOrTypeName IfExists
| "DATASET" QualifiedName IfExists
| "INDEX" DoubleQualifiedName IfExists
+ | "SYNONYM" QualifiedName IfExists
| "FUNCTION" FunctionSignature IfExists )
IfExists ::= ( "IF" "EXISTS" )?
-The DROP statement is the inverse of the CREATE statement. It can be used to drop dataverses, datatypes, datasets, indexes, and functions.
+The DROP statement is the inverse of the CREATE statement. It can be used to drop dataverses, datatypes, datasets, indexes, functions, and synonyms.
The following examples illustrate some uses of the DROP statement.
@@ -58,6 +77,8 @@
DROP FUNCTION friendInfo@1;
+ DROP SYNONYM GleambookUsersSynonym;
+
DROP DATAVERSE TinySocial;
When an artifact is dropped, it will be droppped from the current dataverse if none is specified
@@ -78,6 +99,8 @@
(See the [guide to external data](externaldata.html) for more information on the available adapters.)
If a dataset has an auto-generated primary key field, the file to be imported should not include that field in it.
+The target dataset name may be a synonym introduced by CREATE SYNONYM statement.
+
The following example shows how to bulk load the GleambookUsers dataset from an external file containing data that has been prepared in ADM (Asterix Data Model) format.
##### Example
diff --git a/asterixdb/asterix-doc/src/main/markdown/sqlpp/appendix_3_resolution.md b/asterixdb/asterix-doc/src/main/markdown/sqlpp/appendix_3_resolution.md
index 1f0c62b..988d89f 100644
--- a/asterixdb/asterix-doc/src/main/markdown/sqlpp/appendix_3_resolution.md
+++ b/asterixdb/asterix-doc/src/main/markdown/sqlpp/appendix_3_resolution.md
@@ -217,9 +217,15 @@
1. If the identifier matches a variable-name that is in scope, it resolves to the binding of that variable.
(Note that in the case of a subquery, an in-scope variable might have been bound in an outer query block; this is called a correlated subquery.)
- 2. Otherwise, if the identifier is the first part of a two-part name like `a.b`, the name is treated as dataverse.dataset.
+ 2. Otherwise, if the identifier is the first part of a two-part name like `a.b`, the name is treated as `dataverse.dataset`.
If the identifier stands alone as a one-part name, it is treated as the name of a dataset in the default dataverse.
- An error will result if the designated dataverse or dataset does not exist.
+ If the designated dataset exists then the identifier is resolved to that dataset,
+ otherwise if a synonym with given name exists then the identifier is resolved to the target dataset of that
+ synonym (potentially recursively if this synonym points to another synonym). An error will result if the designated
+ dataset or a synonym with this name does not exist.
+
+ Datasets take precedence over synonyms, so if both a dataset and a synonym have the same name then the
+ resolution is to the dataset.
2. _Elsewhere in a query block_: In clauses other than FROM, a name typically identifies a field of some object.
For example, if the expression `a.b` is in a SELECT or WHERE clause, it's likely that `a` represents an object and `b` represents a field in that object.
diff --git a/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/rewrites/AqlStatementRewriter.java b/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/rewrites/AqlStatementRewriter.java
index af015b7..6c4b178 100644
--- a/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/rewrites/AqlStatementRewriter.java
+++ b/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/rewrites/AqlStatementRewriter.java
@@ -19,7 +19,7 @@
package org.apache.asterix.lang.aql.rewrites;
import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.lang.aql.visitor.AqlDeleteRewriteVisitor;
+import org.apache.asterix.lang.aql.visitor.AqlStatementRewriteVisitor;
import org.apache.asterix.lang.common.base.IStatementRewriter;
import org.apache.asterix.lang.common.base.Statement;
import org.apache.asterix.metadata.declared.MetadataProvider;
@@ -27,14 +27,14 @@
class AqlStatementRewriter implements IStatementRewriter {
@Override
- public void rewrite(Statement stmt, MetadataProvider metadataProvider) throws CompilationException {
- rewriteDeleteStatement(stmt, metadataProvider);
+ public boolean isRewritable(Statement.Kind kind) {
+ return kind == Statement.Kind.DELETE;
}
- private void rewriteDeleteStatement(Statement stmt, MetadataProvider metadataProvider) throws CompilationException {
+ @Override
+ public void rewrite(Statement stmt, MetadataProvider metadataProvider) throws CompilationException {
if (stmt != null) {
- AqlDeleteRewriteVisitor visitor = new AqlDeleteRewriteVisitor(metadataProvider);
- stmt.accept(visitor, null);
+ stmt.accept(AqlStatementRewriteVisitor.INSTANCE, metadataProvider);
}
}
diff --git a/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AqlDeleteRewriteVisitor.java b/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AqlStatementRewriteVisitor.java
similarity index 90%
rename from asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AqlDeleteRewriteVisitor.java
rename to asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AqlStatementRewriteVisitor.java
index e53caa2..f6a4905 100644
--- a/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AqlDeleteRewriteVisitor.java
+++ b/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AqlStatementRewriteVisitor.java
@@ -38,16 +38,15 @@
import org.apache.asterix.metadata.declared.MetadataProvider;
import org.apache.asterix.om.functions.BuiltinFunctions;
-public class AqlDeleteRewriteVisitor extends AbstractAqlAstVisitor<Void, Void> {
+public class AqlStatementRewriteVisitor extends AbstractAqlAstVisitor<Void, MetadataProvider> {
- private final MetadataProvider metadataProvider;
+ public static final AqlStatementRewriteVisitor INSTANCE = new AqlStatementRewriteVisitor();
- public AqlDeleteRewriteVisitor(MetadataProvider metadataProvider) {
- this.metadataProvider = metadataProvider;
+ private AqlStatementRewriteVisitor() {
}
@Override
- public Void visit(DeleteStatement deleteStmt, Void visitArg) {
+ public Void visit(DeleteStatement deleteStmt, MetadataProvider metadataProvider) {
List<Expression> arguments = new ArrayList<>();
DataverseName dataverseName = deleteStmt.getDataverseName();
if (dataverseName == null) {
diff --git a/asterixdb/asterix-lang-aql/src/main/javacc/AQL.jj b/asterixdb/asterix-lang-aql/src/main/javacc/AQL.jj
index 87d0b93..1e4e3be 100644
--- a/asterixdb/asterix-lang-aql/src/main/javacc/AQL.jj
+++ b/asterixdb/asterix-lang-aql/src/main/javacc/AQL.jj
@@ -1004,7 +1004,7 @@
{
checkBindingVariable(returnExpression, var, query);
query.setTopLevel(true);
- return new InsertStatement(nameComponents.first, nameComponents.second, query, getVarCounter(), var,
+ return new InsertStatement(nameComponents.first, nameComponents.second.getValue(), query, getVarCounter(), var,
returnExpression);
}
}
@@ -1028,7 +1028,7 @@
{
checkBindingVariable(returnExpression, var, query);
query.setTopLevel(true);
- return new UpsertStatement(nameComponents.first, nameComponents.second, query, getVarCounter(), var,
+ return new UpsertStatement(nameComponents.first, nameComponents.second.getValue(), query, getVarCounter(), var,
returnExpression);
}
}
@@ -1048,7 +1048,7 @@
(<WHERE> condition = Expression())?
{
// First we get the dataverses and datasets that we want to lock
- return new DeleteStatement(var, nameComponents.first, nameComponents.second,
+ return new DeleteStatement(var, nameComponents.first, nameComponents.second.getValue(),
condition, getVarCounter());
}
}
@@ -1153,7 +1153,7 @@
}
)?
{
- return new LoadStatement(dataverseName, datasetName, adapterName, properties, alreadySorted);
+ return new LoadStatement(dataverseName, datasetName.getValue(), adapterName, properties, alreadySorted);
}
}
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
index e5fd574..8d5b374 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IStatementRewriter.java
@@ -24,6 +24,11 @@
public interface IStatementRewriter {
/**
+ * Returns {@code true} if given statement kind is handled by this rewriter.
+ */
+ boolean isRewritable(Statement.Kind kind);
+
+ /**
* @param statement,
* a non-query statement.
* @param metadataProvider
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/Statement.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/Statement.java
index cb792d9..5cf1c46 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/Statement.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/Statement.java
@@ -79,6 +79,8 @@
DROP_FEED_POLICY,
CREATE_FUNCTION,
FUNCTION_DROP,
+ CREATE_SYNONYM,
+ SYNONYM_DROP,
COMPACT,
EXTERNAL_DATASET_REFRESH,
SUBSCRIBE_FEED,
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/CreateSynonymStatement.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/CreateSynonymStatement.java
new file mode 100644
index 0000000..4b443b5
--- /dev/null
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/CreateSynonymStatement.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.asterix.lang.common.statement;
+
+import org.apache.asterix.common.exceptions.CompilationException;
+import org.apache.asterix.common.metadata.DataverseName;
+import org.apache.asterix.lang.common.base.AbstractStatement;
+import org.apache.asterix.lang.common.visitor.base.ILangVisitor;
+
+public class CreateSynonymStatement extends AbstractStatement {
+
+ private final DataverseName dataverseName;
+
+ private final String synonymName;
+
+ private final DataverseName objectDataverseName;
+
+ private final String objectName;
+
+ private final boolean ifNotExists;
+
+ public CreateSynonymStatement(DataverseName dataverseName, String synonymName, DataverseName objectDataverseName,
+ String objectName, boolean ifNotExists) {
+ this.dataverseName = dataverseName;
+ this.synonymName = synonymName;
+ this.objectDataverseName = objectDataverseName;
+ this.objectName = objectName;
+ this.ifNotExists = ifNotExists;
+ }
+
+ public DataverseName getDataverseName() {
+ return dataverseName;
+ }
+
+ public String getSynonymName() {
+ return synonymName;
+ }
+
+ public DataverseName getObjectDataverseName() {
+ return objectDataverseName;
+ }
+
+ public String getObjectName() {
+ return objectName;
+ }
+
+ public boolean getIfNotExists() {
+ return ifNotExists;
+ }
+
+ @Override
+ public Kind getKind() {
+ return Kind.CREATE_SYNONYM;
+ }
+
+ @Override
+ public byte getCategory() {
+ return Category.DDL;
+ }
+
+ @Override
+ public <R, T> R accept(ILangVisitor<R, T> visitor, T arg) throws CompilationException {
+ return visitor.visit(this, arg);
+ }
+}
\ No newline at end of file
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/DeleteStatement.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/DeleteStatement.java
index 67180bc..1ce2d55 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/DeleteStatement.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/DeleteStatement.java
@@ -26,19 +26,18 @@
import org.apache.asterix.lang.common.base.Expression;
import org.apache.asterix.lang.common.base.Statement;
import org.apache.asterix.lang.common.expression.VariableExpr;
-import org.apache.asterix.lang.common.struct.Identifier;
import org.apache.asterix.lang.common.visitor.base.ILangVisitor;
public class DeleteStatement extends AbstractStatement {
private VariableExpr vars;
private DataverseName dataverseName;
- private Identifier datasetName;
+ private String datasetName;
private Expression condition;
private int varCounter;
private Query rewrittenQuery;
- public DeleteStatement(VariableExpr vars, DataverseName dataverseName, Identifier datasetName, Expression condition,
+ public DeleteStatement(VariableExpr vars, DataverseName dataverseName, String datasetName, Expression condition,
int varCounter) {
this.vars = vars;
this.dataverseName = dataverseName;
@@ -60,8 +59,16 @@
return dataverseName;
}
+ public void setDataverseName(DataverseName dataverseName) {
+ this.dataverseName = dataverseName;
+ }
+
public String getDatasetName() {
- return datasetName.getValue();
+ return datasetName;
+ }
+
+ public void setDatasetName(String datasetName) {
+ this.datasetName = datasetName;
}
public Expression getCondition() {
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/InsertStatement.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/InsertStatement.java
index 5290bfd..cf720ba 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/InsertStatement.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/InsertStatement.java
@@ -29,19 +29,18 @@
import org.apache.asterix.lang.common.base.IReturningStatement;
import org.apache.asterix.lang.common.base.Statement;
import org.apache.asterix.lang.common.expression.VariableExpr;
-import org.apache.asterix.lang.common.struct.Identifier;
import org.apache.asterix.lang.common.visitor.base.ILangVisitor;
public class InsertStatement extends AbstractStatement implements IReturningStatement {
- private final DataverseName dataverseName;
- private final Identifier datasetName;
+ private DataverseName dataverseName;
+ private String datasetName;
private final Query query;
private final VariableExpr var;
private Expression returnExpression;
private int varCounter;
- public InsertStatement(DataverseName dataverseName, Identifier datasetName, Query query, int varCounter,
+ public InsertStatement(DataverseName dataverseName, String datasetName, Query query, int varCounter,
VariableExpr var, Expression returnExpression) {
this.dataverseName = dataverseName;
this.datasetName = datasetName;
@@ -60,8 +59,16 @@
return dataverseName;
}
+ public void setDataverseName(DataverseName dataverseName) {
+ this.dataverseName = dataverseName;
+ }
+
public String getDatasetName() {
- return datasetName.getValue();
+ return datasetName;
+ }
+
+ public void setDatasetName(String datasetName) {
+ this.datasetName = datasetName;
}
public Query getQuery() {
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/LoadStatement.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/LoadStatement.java
index 42801f0..e649e2a 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/LoadStatement.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/LoadStatement.java
@@ -24,18 +24,17 @@
import org.apache.asterix.common.metadata.DataverseName;
import org.apache.asterix.lang.common.base.AbstractStatement;
import org.apache.asterix.lang.common.base.Statement;
-import org.apache.asterix.lang.common.struct.Identifier;
import org.apache.asterix.lang.common.visitor.base.ILangVisitor;
public class LoadStatement extends AbstractStatement {
- private Identifier datasetName;
private DataverseName dataverseName;
+ private String datasetName;
private String adapter;
private Map<String, String> properties;
private boolean dataIsLocallySorted;
- public LoadStatement(DataverseName dataverseName, Identifier datasetName, String adapter,
+ public LoadStatement(DataverseName dataverseName, String datasetName, String adapter,
Map<String, String> propertiees, boolean dataIsLocallySorted) {
this.dataverseName = dataverseName;
this.datasetName = datasetName;
@@ -73,10 +72,14 @@
return Statement.Kind.LOAD;
}
- public Identifier getDatasetName() {
+ public String getDatasetName() {
return datasetName;
}
+ public void setDatasetName(String datasetName) {
+ this.datasetName = datasetName;
+ }
+
public boolean dataIsAlreadySorted() {
return dataIsLocallySorted;
}
@@ -90,5 +93,4 @@
public byte getCategory() {
return Category.UPDATE;
}
-
}
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/SynonymDropStatement.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/SynonymDropStatement.java
new file mode 100644
index 0000000..3562935
--- /dev/null
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/SynonymDropStatement.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.asterix.lang.common.statement;
+
+import org.apache.asterix.common.exceptions.CompilationException;
+import org.apache.asterix.common.metadata.DataverseName;
+import org.apache.asterix.lang.common.base.AbstractStatement;
+import org.apache.asterix.lang.common.visitor.base.ILangVisitor;
+
+public class SynonymDropStatement extends AbstractStatement {
+
+ private final DataverseName dataverseName;
+
+ private final String synonymName;
+
+ private final boolean ifExists;
+
+ public SynonymDropStatement(DataverseName dataverseName, String synonymName, boolean ifExists) {
+ this.dataverseName = dataverseName;
+ this.synonymName = synonymName;
+ this.ifExists = ifExists;
+ }
+
+ public DataverseName getDataverseName() {
+ return dataverseName;
+ }
+
+ public String getSynonymName() {
+ return synonymName;
+ }
+
+ public boolean getIfExists() {
+ return ifExists;
+ }
+
+ @Override
+ public Kind getKind() {
+ return Kind.SYNONYM_DROP;
+ }
+
+ @Override
+ public byte getCategory() {
+ return Category.DDL;
+ }
+
+ @Override
+ public <R, T> R accept(ILangVisitor<R, T> visitor, T arg) throws CompilationException {
+ return visitor.visit(this, arg);
+ }
+}
\ No newline at end of file
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/UpsertStatement.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/UpsertStatement.java
index f4f48f7..09ef2f2 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/UpsertStatement.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/UpsertStatement.java
@@ -22,11 +22,10 @@
import org.apache.asterix.lang.common.base.Expression;
import org.apache.asterix.lang.common.base.Statement;
import org.apache.asterix.lang.common.expression.VariableExpr;
-import org.apache.asterix.lang.common.struct.Identifier;
public class UpsertStatement extends InsertStatement {
- public UpsertStatement(DataverseName dataverseName, Identifier datasetName, Query query, int varCounter,
+ public UpsertStatement(DataverseName dataverseName, String datasetName, Query query, int varCounter,
VariableExpr var, Expression returnExpression) {
super(dataverseName, datasetName, query, varCounter, var, returnExpression);
}
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/FormatPrintVisitor.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/FormatPrintVisitor.java
index d241a71..a207c01 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/FormatPrintVisitor.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/FormatPrintVisitor.java
@@ -70,6 +70,7 @@
import org.apache.asterix.lang.common.statement.CreateFeedStatement;
import org.apache.asterix.lang.common.statement.CreateFunctionStatement;
import org.apache.asterix.lang.common.statement.CreateIndexStatement;
+import org.apache.asterix.lang.common.statement.CreateSynonymStatement;
import org.apache.asterix.lang.common.statement.DatasetDecl;
import org.apache.asterix.lang.common.statement.DataverseDecl;
import org.apache.asterix.lang.common.statement.DataverseDropStatement;
@@ -91,6 +92,7 @@
import org.apache.asterix.lang.common.statement.SetStatement;
import org.apache.asterix.lang.common.statement.StartFeedStatement;
import org.apache.asterix.lang.common.statement.StopFeedStatement;
+import org.apache.asterix.lang.common.statement.SynonymDropStatement;
import org.apache.asterix.lang.common.statement.TypeDecl;
import org.apache.asterix.lang.common.statement.TypeDropStatement;
import org.apache.asterix.lang.common.statement.UpdateStatement;
@@ -834,6 +836,22 @@
}
@Override
+ public Void visit(CreateSynonymStatement css, Integer step) throws CompilationException {
+ out.println(skip(step) + "create synonym " + generateFullName(css.getDataverseName(), css.getSynonymName())
+ + generateIfNotExists(css.getIfNotExists()) + " for "
+ + generateFullName(css.getObjectDataverseName(), css.getObjectName()));
+ return null;
+ }
+
+ @Override
+ public Void visit(SynonymDropStatement del, Integer step) throws CompilationException {
+ out.print(skip(step) + "drop synonym ");
+ out.print(generateFullName(del.getDataverseName(), del.getSynonymName()));
+ out.println(generateIfExists(del.getIfExists()) + SEMICOLON);
+ return null;
+ }
+
+ @Override
public Void visit(CompactStatement del, Integer step) throws CompilationException {
return null;
}
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/base/AbstractQueryExpressionVisitor.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/base/AbstractQueryExpressionVisitor.java
index 28533e1..78dd45c 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/base/AbstractQueryExpressionVisitor.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/base/AbstractQueryExpressionVisitor.java
@@ -31,6 +31,7 @@
import org.apache.asterix.lang.common.statement.CreateFeedStatement;
import org.apache.asterix.lang.common.statement.CreateFunctionStatement;
import org.apache.asterix.lang.common.statement.CreateIndexStatement;
+import org.apache.asterix.lang.common.statement.CreateSynonymStatement;
import org.apache.asterix.lang.common.statement.DatasetDecl;
import org.apache.asterix.lang.common.statement.DataverseDecl;
import org.apache.asterix.lang.common.statement.DataverseDropStatement;
@@ -50,6 +51,7 @@
import org.apache.asterix.lang.common.statement.SetStatement;
import org.apache.asterix.lang.common.statement.StartFeedStatement;
import org.apache.asterix.lang.common.statement.StopFeedStatement;
+import org.apache.asterix.lang.common.statement.SynonymDropStatement;
import org.apache.asterix.lang.common.statement.TypeDecl;
import org.apache.asterix.lang.common.statement.TypeDropStatement;
import org.apache.asterix.lang.common.statement.UpdateStatement;
@@ -231,4 +233,14 @@
public R visit(FeedPolicyDropStatement dfs, T arg) throws CompilationException {
return null;
}
+
+ @Override
+ public R visit(CreateSynonymStatement css, T arg) throws CompilationException {
+ return null;
+ }
+
+ @Override
+ public R visit(SynonymDropStatement del, T arg) throws CompilationException {
+ return null;
+ }
}
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/base/ILangVisitor.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/base/ILangVisitor.java
index ce6ae6b..5aa9915 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/base/ILangVisitor.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/base/ILangVisitor.java
@@ -48,6 +48,7 @@
import org.apache.asterix.lang.common.statement.CreateFeedStatement;
import org.apache.asterix.lang.common.statement.CreateFunctionStatement;
import org.apache.asterix.lang.common.statement.CreateIndexStatement;
+import org.apache.asterix.lang.common.statement.CreateSynonymStatement;
import org.apache.asterix.lang.common.statement.DatasetDecl;
import org.apache.asterix.lang.common.statement.DataverseDecl;
import org.apache.asterix.lang.common.statement.DataverseDropStatement;
@@ -67,6 +68,7 @@
import org.apache.asterix.lang.common.statement.SetStatement;
import org.apache.asterix.lang.common.statement.StartFeedStatement;
import org.apache.asterix.lang.common.statement.StopFeedStatement;
+import org.apache.asterix.lang.common.statement.SynonymDropStatement;
import org.apache.asterix.lang.common.statement.TypeDecl;
import org.apache.asterix.lang.common.statement.TypeDropStatement;
import org.apache.asterix.lang.common.statement.UpdateStatement;
@@ -174,6 +176,10 @@
R visit(FunctionDropStatement del, T arg) throws CompilationException;
+ R visit(CreateSynonymStatement css, T arg) throws CompilationException;
+
+ R visit(SynonymDropStatement del, T arg) throws CompilationException;
+
R visit(CompactStatement del, T arg) throws CompilationException;
R visit(ListSliceExpression expression, T arg) throws CompilationException;
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppStatementRewriter.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppStatementRewriter.java
index 4a08874..566b313 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppStatementRewriter.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppStatementRewriter.java
@@ -23,19 +23,29 @@
import org.apache.asterix.lang.common.base.Statement;
import org.apache.asterix.lang.sqlpp.util.SqlppVariableUtil;
import org.apache.asterix.lang.sqlpp.visitor.SqlppDeleteRewriteVisitor;
+import org.apache.asterix.lang.sqlpp.visitor.SqlppSynonymRewriteVisitor;
import org.apache.asterix.metadata.declared.MetadataProvider;
class SqlppStatementRewriter implements IStatementRewriter {
@Override
- public void rewrite(Statement stmt, MetadataProvider metadataProvider) throws CompilationException {
- rewriteDeleteStatement(stmt, metadataProvider);
+ public boolean isRewritable(Statement.Kind kind) {
+ switch (kind) {
+ case LOAD:
+ case INSERT:
+ case UPSERT:
+ case DELETE:
+ return true;
+ default:
+ return false;
+ }
}
- private void rewriteDeleteStatement(Statement stmt, MetadataProvider metadataProvider) throws CompilationException {
+ @Override
+ public void rewrite(Statement stmt, MetadataProvider metadataProvider) throws CompilationException {
if (stmt != null) {
- SqlppDeleteRewriteVisitor visitor = new SqlppDeleteRewriteVisitor(metadataProvider);
- stmt.accept(visitor, null);
+ stmt.accept(SqlppSynonymRewriteVisitor.INSTANCE, metadataProvider);
+ stmt.accept(SqlppDeleteRewriteVisitor.INSTANCE, metadataProvider);
}
}
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 70739ed..8190d3b 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
@@ -225,6 +225,12 @@
private Dataset findDataset(DataverseName dataverseName, String datasetName, SourceLocation sourceLoc)
throws CompilationException {
try {
+ Pair<DataverseName, String> dsName =
+ metadataProvider.resolveDatasetNameUsingSynonyms(dataverseName, datasetName);
+ if (dsName != null) {
+ dataverseName = dsName.first;
+ datasetName = dsName.second;
+ }
return metadataProvider.findDataset(dataverseName, datasetName);
} catch (AlgebricksException e) {
throw new CompilationException(ErrorCode.COMPILATION_ERROR, e, sourceLoc, e.getMessage());
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppDeleteRewriteVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppDeleteRewriteVisitor.java
index 966d153..7e7b654 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppDeleteRewriteVisitor.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppDeleteRewriteVisitor.java
@@ -48,16 +48,15 @@
* This class rewrites delete statement to contain a query that specifying
* what to delete.
*/
-public class SqlppDeleteRewriteVisitor extends AbstractSqlppAstVisitor<Void, Void> {
+public class SqlppDeleteRewriteVisitor extends AbstractSqlppAstVisitor<Void, MetadataProvider> {
- private final MetadataProvider metadataProvider;
+ public static final SqlppDeleteRewriteVisitor INSTANCE = new SqlppDeleteRewriteVisitor();
- public SqlppDeleteRewriteVisitor(MetadataProvider metadataProvider) {
- this.metadataProvider = metadataProvider;
+ private SqlppDeleteRewriteVisitor() {
}
@Override
- public Void visit(DeleteStatement deleteStmt, Void visitArg) {
+ public Void visit(DeleteStatement deleteStmt, MetadataProvider metadataProvider) {
List<Expression> arguments = new ArrayList<>();
DataverseName dataverseName = deleteStmt.getDataverseName();
if (dataverseName == null) {
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppSynonymRewriteVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppSynonymRewriteVisitor.java
new file mode 100644
index 0000000..ae999fd
--- /dev/null
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppSynonymRewriteVisitor.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.asterix.lang.sqlpp.visitor;
+
+import org.apache.asterix.common.exceptions.CompilationException;
+import org.apache.asterix.common.exceptions.ErrorCode;
+import org.apache.asterix.common.metadata.DataverseName;
+import org.apache.asterix.lang.common.statement.DeleteStatement;
+import org.apache.asterix.lang.common.statement.InsertStatement;
+import org.apache.asterix.lang.common.statement.LoadStatement;
+import org.apache.asterix.lang.sqlpp.visitor.base.AbstractSqlppAstVisitor;
+import org.apache.asterix.metadata.declared.MetadataProvider;
+import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.hyracks.algebricks.common.utils.Pair;
+import org.apache.hyracks.api.exceptions.SourceLocation;
+
+/**
+ * This class resolves dataset synonyms in load/insert/upsert/delete statements
+ */
+public class SqlppSynonymRewriteVisitor extends AbstractSqlppAstVisitor<Void, MetadataProvider> {
+
+ public static final SqlppSynonymRewriteVisitor INSTANCE = new SqlppSynonymRewriteVisitor();
+
+ private SqlppSynonymRewriteVisitor() {
+ }
+
+ @Override
+ public Void visit(LoadStatement loadStmt, MetadataProvider metadataProvider) throws CompilationException {
+ Pair<DataverseName, String> dsName = resolveDatasetNameUsingSynonyms(metadataProvider,
+ loadStmt.getDataverseName(), loadStmt.getDatasetName(), loadStmt.getSourceLocation());
+ if (dsName != null) {
+ loadStmt.setDataverseName(dsName.first);
+ loadStmt.setDatasetName(dsName.second);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visit(InsertStatement insertStmt, MetadataProvider metadataProvider) throws CompilationException {
+ Pair<DataverseName, String> dsName = resolveDatasetNameUsingSynonyms(metadataProvider,
+ insertStmt.getDataverseName(), insertStmt.getDatasetName(), insertStmt.getSourceLocation());
+ if (dsName != null) {
+ insertStmt.setDataverseName(dsName.first);
+ insertStmt.setDatasetName(dsName.second);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visit(DeleteStatement deleteStmt, MetadataProvider metadataProvider) throws CompilationException {
+ Pair<DataverseName, String> dsName = resolveDatasetNameUsingSynonyms(metadataProvider,
+ deleteStmt.getDataverseName(), deleteStmt.getDatasetName(), deleteStmt.getSourceLocation());
+ if (dsName != null) {
+ deleteStmt.setDataverseName(dsName.first);
+ deleteStmt.setDatasetName(dsName.second);
+ }
+ return null;
+ }
+
+ private Pair<DataverseName, String> resolveDatasetNameUsingSynonyms(MetadataProvider metadataProvider,
+ DataverseName dataverseName, String datasetName, SourceLocation sourceLoc) throws CompilationException {
+ try {
+ return metadataProvider.resolveDatasetNameUsingSynonyms(dataverseName, datasetName);
+ } catch (AlgebricksException e) {
+ throw new CompilationException(ErrorCode.COMPILATION_ERROR, e, sourceLoc, e.getMessage());
+ }
+ }
+}
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
index 7672c56..c33fb68 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
+++ b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
@@ -127,6 +127,7 @@
import org.apache.asterix.lang.common.statement.CreateFeedStatement;
import org.apache.asterix.lang.common.statement.CreateFunctionStatement;
import org.apache.asterix.lang.common.statement.CreateIndexStatement;
+import org.apache.asterix.lang.common.statement.CreateSynonymStatement;
import org.apache.asterix.lang.common.statement.DatasetDecl;
import org.apache.asterix.lang.common.statement.DataverseDecl;
import org.apache.asterix.lang.common.statement.DataverseDropStatement;
@@ -147,6 +148,7 @@
import org.apache.asterix.lang.common.statement.Query;
import org.apache.asterix.lang.common.statement.RefreshExternalDatasetStatement;
import org.apache.asterix.lang.common.statement.SetStatement;
+import org.apache.asterix.lang.common.statement.SynonymDropStatement;
import org.apache.asterix.lang.common.statement.TypeDecl;
import org.apache.asterix.lang.common.statement.TypeDropStatement;
import org.apache.asterix.lang.common.statement.UpdateStatement;
@@ -584,6 +586,7 @@
| stmt = CreateIndexStatement(startToken)
| stmt = CreateDataverseStatement(startToken)
| stmt = CreateFunctionStatement(startToken)
+ | stmt = CreateSynonymStatement(startToken)
| stmt = CreateFeedStatement(startToken)
| stmt = CreateFeedPolicyStatement(startToken)
)
@@ -1102,6 +1105,33 @@
}
}
+CreateSynonymStatement CreateSynonymStatement(Token startStmtToken) throws ParseException:
+{
+ CreateSynonymStatement stmt = null;
+}
+{
+ <SYNONYM> stmt = SynonymSpecification(startStmtToken)
+ {
+ return stmt;
+ }
+}
+
+CreateSynonymStatement SynonymSpecification(Token startStmtToken) throws ParseException:
+{
+ Pair<DataverseName,Identifier> nameComponents = null;
+ Pair<DataverseName,Identifier> objectNameComponents = null;
+ boolean ifNotExists = false;
+}
+{
+ nameComponents = QualifiedName() ifNotExists = IfNotExists()
+ <FOR> objectNameComponents = QualifiedName()
+ {
+ CreateSynonymStatement stmt = new CreateSynonymStatement(nameComponents.first, nameComponents.second.getValue(),
+ objectNameComponents.first, objectNameComponents.second.getValue(), ifNotExists);
+ return addSourceLocation(stmt, startStmtToken);
+ }
+}
+
boolean IfNotExists() throws ParseException:
{
}
@@ -1206,6 +1236,7 @@
| stmt = DropFunctionStatement(startToken)
| stmt = DropFeedStatement(startToken)
| stmt = DropFeedPolicyStatement(startToken)
+ | stmt = DropSynonymStatement(startToken)
)
{
return stmt;
@@ -1404,6 +1435,30 @@
}
}
+SynonymDropStatement DropSynonymStatement(Token startStmtToken) throws ParseException:
+{
+ SynonymDropStatement stmt = null;
+}
+{
+ <SYNONYM> stmt = DropSynonymSpecification(startStmtToken)
+ {
+ return stmt;
+ }
+}
+
+SynonymDropStatement DropSynonymSpecification(Token startStmtToken) throws ParseException:
+{
+ Pair<DataverseName,Identifier> pairId = null;
+ boolean ifExists = false;
+}
+{
+ pairId = QualifiedName() ifExists = IfExists()
+ {
+ SynonymDropStatement stmt = new SynonymDropStatement(pairId.first, pairId.second.getValue(), ifExists);
+ return addSourceLocation(stmt, startStmtToken);
+ }
+}
+
boolean IfExists() throws ParseException :
{
}
@@ -1436,8 +1491,8 @@
addSourceLocation(var, startToken);
}
query.setTopLevel(true);
- InsertStatement stmt = new InsertStatement(nameComponents.first, nameComponents.second, query, getVarCounter(),
- var, returnExpression);
+ InsertStatement stmt = new InsertStatement(nameComponents.first, nameComponents.second.getValue(), query,
+ getVarCounter(), var, returnExpression);
return addSourceLocation(stmt, startToken);
}
}
@@ -1460,8 +1515,8 @@
addSourceLocation(var, startToken);
}
query.setTopLevel(true);
- UpsertStatement stmt = new UpsertStatement(nameComponents.first, nameComponents.second, query, getVarCounter(),
- var, returnExpression);
+ UpsertStatement stmt = new UpsertStatement(nameComponents.first, nameComponents.second.getValue(), query,
+ getVarCounter(), var, returnExpression);
return addSourceLocation(stmt, startToken);
}
}
@@ -1482,7 +1537,7 @@
var = new VariableExpr(SqlppVariableUtil.toInternalVariableIdentifier(nameComponents.second.getValue()));
addSourceLocation(var, startToken);
}
- DeleteStatement stmt = new DeleteStatement(var, nameComponents.first, nameComponents.second,
+ DeleteStatement stmt = new DeleteStatement(var, nameComponents.first, nameComponents.second.getValue(),
condition, getVarCounter());
return addSourceLocation(stmt, startToken);
}
@@ -1595,7 +1650,8 @@
}
)?
{
- LoadStatement stmt = new LoadStatement(dataverseName, datasetName, adapterName, properties, alreadySorted);
+ LoadStatement stmt = new LoadStatement(dataverseName, datasetName.getValue(), adapterName, properties,
+ alreadySorted);
return addSourceLocation(stmt, startToken);
}
}
@@ -4100,6 +4156,7 @@
| <SOME : "some">
| <START : "start">
| <STOP : "stop">
+ | <SYNONYM : "synonym">
| <TEMPORARY : "temporary"> // intentionally not used but reserved for future usage
| <THEN : "then">
| <TYPE : "type">
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/MetadataCache.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/MetadataCache.java
index 9d738ed..116e55b 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/MetadataCache.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/MetadataCache.java
@@ -41,6 +41,7 @@
import org.apache.asterix.metadata.entities.Index;
import org.apache.asterix.metadata.entities.Library;
import org.apache.asterix.metadata.entities.NodeGroup;
+import org.apache.asterix.metadata.entities.Synonym;
import org.apache.asterix.metadata.utils.IndexUtil;
/**
@@ -76,6 +77,8 @@
protected final Map<DataverseName, Map<String, CompactionPolicy>> compactionPolicies = new HashMap<>();
// Key is DataverseName, Key of value map is feedConnectionId
protected final Map<DataverseName, Map<String, FeedConnection>> feedConnections = new HashMap<>();
+ // Key is synonym dataverse. Key of value map is the synonym name
+ protected final Map<DataverseName, Map<String, Synonym>> synonyms = new HashMap<>();
// Atomically executes all metadata operations in ctx's log.
public void commit(MetadataTransactionContext ctx) {
@@ -113,15 +116,18 @@
synchronized (adapters) {
synchronized (libraries) {
synchronized (compactionPolicies) {
- dataverses.clear();
- nodeGroups.clear();
- datasets.clear();
- indexes.clear();
- datatypes.clear();
- functions.clear();
- adapters.clear();
- libraries.clear();
- compactionPolicies.clear();
+ synchronized (synonyms) {
+ dataverses.clear();
+ nodeGroups.clear();
+ datasets.clear();
+ indexes.clear();
+ datatypes.clear();
+ functions.clear();
+ adapters.clear();
+ libraries.clear();
+ compactionPolicies.clear();
+ synonyms.clear();
+ }
}
}
}
@@ -235,23 +241,27 @@
synchronized (libraries) {
synchronized (feeds) {
synchronized (compactionPolicies) {
- datasets.remove(dataverse.getDataverseName());
- indexes.remove(dataverse.getDataverseName());
- datatypes.remove(dataverse.getDataverseName());
- adapters.remove(dataverse.getDataverseName());
- compactionPolicies.remove(dataverse.getDataverseName());
- List<FunctionSignature> markedFunctionsForRemoval = new ArrayList<>();
- for (FunctionSignature signature : functions.keySet()) {
- if (signature.getDataverseName().equals(dataverse.getDataverseName())) {
- markedFunctionsForRemoval.add(signature);
+ synchronized (synonyms) {
+ datasets.remove(dataverse.getDataverseName());
+ indexes.remove(dataverse.getDataverseName());
+ datatypes.remove(dataverse.getDataverseName());
+ adapters.remove(dataverse.getDataverseName());
+ compactionPolicies.remove(dataverse.getDataverseName());
+ List<FunctionSignature> markedFunctionsForRemoval = new ArrayList<>();
+ for (FunctionSignature signature : functions.keySet()) {
+ if (signature.getDataverseName()
+ .equals(dataverse.getDataverseName())) {
+ markedFunctionsForRemoval.add(signature);
+ }
}
+ for (FunctionSignature signature : markedFunctionsForRemoval) {
+ functions.remove(signature);
+ }
+ libraries.remove(dataverse.getDataverseName());
+ feeds.remove(dataverse.getDataverseName());
+ synonyms.remove(dataverse.getDataverseName());
+ return dataverses.remove(dataverse.getDataverseName());
}
- for (FunctionSignature signature : markedFunctionsForRemoval) {
- functions.remove(signature);
- }
- libraries.remove(dataverse.getDataverseName());
- feeds.remove(dataverse.getDataverseName());
- return dataverses.remove(dataverse.getDataverseName());
}
}
}
@@ -547,6 +557,27 @@
}
}
+ public Synonym addSynonymIfNotExists(Synonym synonym) {
+ synchronized (synonyms) {
+ Map<String, Synonym> synonymsInDataverse = synonyms.get(synonym.getDataverseName());
+ if (synonymsInDataverse == null) {
+ synonymsInDataverse = new HashMap<>();
+ synonyms.put(synonym.getDataverseName(), synonymsInDataverse);
+ }
+ return synonymsInDataverse.put(synonym.getSynonymName(), synonym);
+ }
+ }
+
+ public Synonym dropSynonym(Synonym synonym) {
+ synchronized (synonyms) {
+ Map<String, Synonym> synonymsInDataverse = synonyms.get(synonym.getDataverseName());
+ if (synonymsInDataverse != null) {
+ return synonymsInDataverse.remove(synonym.getSynonymName());
+ }
+ return null;
+ }
+ }
+
private Index addIndexIfNotExistsInternal(Index index) {
Map<String, Map<String, Index>> datasetMap = indexes.get(index.getDataverseName());
if (datasetMap == null) {
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/MetadataManager.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/MetadataManager.java
index eb5f59a..f134ee5 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/MetadataManager.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/MetadataManager.java
@@ -54,6 +54,7 @@
import org.apache.asterix.metadata.entities.Library;
import org.apache.asterix.metadata.entities.Node;
import org.apache.asterix.metadata.entities.NodeGroup;
+import org.apache.asterix.metadata.entities.Synonym;
import org.apache.asterix.om.types.ARecordType;
import org.apache.asterix.transaction.management.opcallbacks.AbstractIndexModificationOperationCallback.Operation;
import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
@@ -906,6 +907,45 @@
return file;
}
+ @Override
+ public void addSynonym(MetadataTransactionContext ctx, Synonym synonym) throws AlgebricksException {
+ try {
+ metadataNode.addSynonym(ctx.getTxnId(), synonym);
+ } catch (RemoteException e) {
+ throw new MetadataException(ErrorCode.REMOTE_EXCEPTION_WHEN_CALLING_METADATA_NODE, e);
+ }
+ }
+
+ @Override
+ public void dropSynonym(MetadataTransactionContext ctx, DataverseName dataverseName, String synonymName)
+ throws AlgebricksException {
+ try {
+ metadataNode.dropSynonym(ctx.getTxnId(), dataverseName, synonymName);
+ } catch (RemoteException e) {
+ throw new MetadataException(ErrorCode.REMOTE_EXCEPTION_WHEN_CALLING_METADATA_NODE, e);
+ }
+ }
+
+ @Override
+ public Synonym getSynonym(MetadataTransactionContext ctx, DataverseName dataverseName, String synonymName)
+ throws AlgebricksException {
+ try {
+ return metadataNode.getSynonym(ctx.getTxnId(), dataverseName, synonymName);
+ } catch (RemoteException e) {
+ throw new MetadataException(ErrorCode.REMOTE_EXCEPTION_WHEN_CALLING_METADATA_NODE, e);
+ }
+ }
+
+ @Override
+ public List<Synonym> getDataverseSynonyms(MetadataTransactionContext ctx, DataverseName dataverseName)
+ throws AlgebricksException {
+ try {
+ return metadataNode.getDataverseSynonyms(ctx.getTxnId(), dataverseName);
+ } catch (RemoteException e) {
+ throw new MetadataException(ErrorCode.REMOTE_EXCEPTION_WHEN_CALLING_METADATA_NODE, e);
+ }
+ }
+
// TODO: Optimize <-- use keys instead of object -->
@Override
public void dropDatasetExternalFiles(MetadataTransactionContext mdTxnCtx, Dataset dataset)
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 45534c7..4177c64 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
@@ -68,6 +68,7 @@
import org.apache.asterix.metadata.entities.Library;
import org.apache.asterix.metadata.entities.Node;
import org.apache.asterix.metadata.entities.NodeGroup;
+import org.apache.asterix.metadata.entities.Synonym;
import org.apache.asterix.metadata.entitytupletranslators.CompactionPolicyTupleTranslator;
import org.apache.asterix.metadata.entitytupletranslators.DatasetTupleTranslator;
import org.apache.asterix.metadata.entitytupletranslators.DatasourceAdapterTupleTranslator;
@@ -83,6 +84,7 @@
import org.apache.asterix.metadata.entitytupletranslators.MetadataTupleTranslatorProvider;
import org.apache.asterix.metadata.entitytupletranslators.NodeGroupTupleTranslator;
import org.apache.asterix.metadata.entitytupletranslators.NodeTupleTranslator;
+import org.apache.asterix.metadata.entitytupletranslators.SynonymTupleTranslator;
import org.apache.asterix.metadata.utils.DatasetUtil;
import org.apache.asterix.metadata.valueextractors.MetadataEntityValueExtractor;
import org.apache.asterix.metadata.valueextractors.TupleCopyValueExtractor;
@@ -1894,6 +1896,78 @@
}
@Override
+ public void addSynonym(TxnId txnId, Synonym synonym) throws AlgebricksException {
+ try {
+ // Insert into the 'Synonym' dataset.
+ SynonymTupleTranslator tupleReaderWriter = tupleTranslatorProvider.getSynonymTupleTranslator(true);
+ ITupleReference synonymTuple = tupleReaderWriter.getTupleFromMetadataEntity(synonym);
+ insertTupleIntoIndex(txnId, MetadataPrimaryIndexes.SYNONYM_DATASET, synonymTuple);
+ } catch (HyracksDataException e) {
+ if (e.getComponent().equals(ErrorCode.HYRACKS) && e.getErrorCode() == ErrorCode.DUPLICATE_KEY) {
+ throw new AlgebricksException("A synonym with name '" + synonym.getSynonymName() + "' already exists.",
+ e);
+ } else {
+ throw new AlgebricksException(e);
+ }
+ }
+ }
+
+ @Override
+ public void dropSynonym(TxnId txnId, DataverseName dataverseName, String synonymName) throws AlgebricksException {
+ Synonym synonym = getSynonym(txnId, dataverseName, synonymName);
+ if (synonym == null) {
+ throw new AlgebricksException("Cannot drop synonym '" + synonym + "' because it doesn't exist.");
+ }
+ try {
+ // Delete entry from the 'Synonym' dataset.
+ ITupleReference searchKey = createTuple(dataverseName, synonymName);
+ // Searches the index for the tuple to be deleted. Acquires an S
+ // lock on the 'Synonym' dataset.
+ ITupleReference synonymTuple =
+ getTupleToBeDeleted(txnId, MetadataPrimaryIndexes.SYNONYM_DATASET, searchKey);
+ deleteTupleFromIndex(txnId, MetadataPrimaryIndexes.SYNONYM_DATASET, synonymTuple);
+ } catch (HyracksDataException e) {
+ if (e.getComponent().equals(ErrorCode.HYRACKS)
+ && e.getErrorCode() == ErrorCode.UPDATE_OR_DELETE_NON_EXISTENT_KEY) {
+ throw new AlgebricksException("Cannot drop synonym '" + synonymName, e);
+ } else {
+ throw new AlgebricksException(e);
+ }
+ }
+ }
+
+ @Override
+ public Synonym getSynonym(TxnId txnId, DataverseName dataverseName, String synonymName) throws AlgebricksException {
+ try {
+ ITupleReference searchKey = createTuple(dataverseName, synonymName);
+ SynonymTupleTranslator tupleReaderWriter = tupleTranslatorProvider.getSynonymTupleTranslator(false);
+ List<Synonym> results = new ArrayList<>();
+ IValueExtractor<Synonym> valueExtractor = new MetadataEntityValueExtractor<>(tupleReaderWriter);
+ searchIndex(txnId, MetadataPrimaryIndexes.SYNONYM_DATASET, searchKey, valueExtractor, results);
+ if (results.isEmpty()) {
+ return null;
+ }
+ return results.get(0);
+ } catch (HyracksDataException e) {
+ throw new AlgebricksException(e);
+ }
+ }
+
+ @Override
+ public List<Synonym> getDataverseSynonyms(TxnId txnId, DataverseName dataverseName) throws AlgebricksException {
+ try {
+ ITupleReference searchKey = createTuple(dataverseName);
+ SynonymTupleTranslator tupleReaderWriter = tupleTranslatorProvider.getSynonymTupleTranslator(false);
+ IValueExtractor<Synonym> valueExtractor = new MetadataEntityValueExtractor<>(tupleReaderWriter);
+ List<Synonym> results = new ArrayList<>();
+ searchIndex(txnId, MetadataPrimaryIndexes.SYNONYM_DATASET, searchKey, valueExtractor, results);
+ return results;
+ } catch (HyracksDataException e) {
+ throw new AlgebricksException(e);
+ }
+ }
+
+ @Override
public void updateDataset(TxnId txnId, Dataset dataset) throws AlgebricksException {
try {
// This method will delete previous entry of the dataset and insert the new one
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/api/IMetadataManager.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/api/IMetadataManager.java
index e6992e3..fbacac1 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/api/IMetadataManager.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/api/IMetadataManager.java
@@ -41,6 +41,7 @@
import org.apache.asterix.metadata.entities.Library;
import org.apache.asterix.metadata.entities.Node;
import org.apache.asterix.metadata.entities.NodeGroup;
+import org.apache.asterix.metadata.entities.Synonym;
import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
/**
@@ -637,6 +638,59 @@
Integer fileNumber) throws AlgebricksException;
/**
+ * Adds a synonym, acquiring local locks on behalf of the given transaction id.
+ *
+ * @param ctx
+ * MetadataTransactionContext of an active metadata transaction.
+ * @param synonym
+ * Library to be added
+ * @throws AlgebricksException
+ * for example, if the synonym is already added.
+ */
+ void addSynonym(MetadataTransactionContext ctx, Synonym synonym) throws AlgebricksException;
+
+ /**
+ * Removes a synonym, acquiring local locks on behalf of the given transaction id.
+ *
+ * @param ctx
+ * MetadataTransactionContext of an active metadata transaction.
+ * @param dataverseName
+ * dataverse asociated with the synonym that is to be deleted.
+ * @param synonymName
+ * Name of synonym to be deleted. AlgebricksException for example, if
+ * the synonym does not exists.
+ * @throws AlgebricksException
+ */
+ void dropSynonym(MetadataTransactionContext ctx, DataverseName dataverseName, String synonymName)
+ throws AlgebricksException;
+
+ /**
+ * @param ctx
+ * MetadataTransactionContext of an active metadata transaction.
+ * @param dataverseName
+ * dataverse asociated with the synonym that is to be retrieved.
+ * @param synonymName
+ * name of the library that is to be retrieved
+ * @return Library
+ * @throws AlgebricksException
+ */
+ Synonym getSynonym(MetadataTransactionContext ctx, DataverseName dataverseName, String synonymName)
+ throws AlgebricksException;
+
+ /**
+ * Retireve synonyms installed in a given dataverse.
+ *
+ * @param ctx
+ * MetadataTransactionContext of an active metadata transaction.
+ * @param dataverseName
+ * dataverse associated with synonyms that are to be retrieved.
+ * @return list of synonyms
+ * @throws AlgebricksException
+ */
+ List<Synonym> getDataverseSynonyms(MetadataTransactionContext ctx, DataverseName dataverseName)
+ throws AlgebricksException;
+
+ /**
* update an existing dataset in metadata.
*
* @param ctx
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/api/IMetadataNode.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/api/IMetadataNode.java
index e299f43..8a052b7 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/api/IMetadataNode.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/api/IMetadataNode.java
@@ -41,6 +41,7 @@
import org.apache.asterix.metadata.entities.Library;
import org.apache.asterix.metadata.entities.Node;
import org.apache.asterix.metadata.entities.NodeGroup;
+import org.apache.asterix.metadata.entities.Synonym;
import org.apache.asterix.transaction.management.opcallbacks.AbstractIndexModificationOperationCallback;
import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
@@ -731,6 +732,63 @@
throws AlgebricksException, RemoteException;
/**
+ * Adds a synonym, acquiring local locks on behalf of the given transaction id.
+ *
+ * @param txnId
+ * A globally unique id for an active metadata transaction.
+ * @param synonym
+ * Synonym to be added
+ * @throws AlgebricksException
+ * for example, if the synonym is already added.
+ * @throws RemoteException
+ */
+ void addSynonym(TxnId txnId, Synonym synonym) throws AlgebricksException, RemoteException;
+
+ /**
+ * Removes a synonym, acquiring local locks on behalf of the given transaction id.
+ *
+ * @param txnId
+ * A globally unique id for an active metadata transaction.
+ * @param dataverseName
+ * dataverse asociated with the synonym that is to be deleted.
+ * @param synonymName
+ * Name of synonym to be deleted. AlgebricksException for example, if
+ * the synonym does not exists.
+ * @throws AlgebricksException
+ * @throws RemoteException
+ */
+ void dropSynonym(TxnId txnId, DataverseName dataverseName, String synonymName)
+ throws AlgebricksException, RemoteException;
+
+ /**
+ * @param txnId
+ * A globally unique id for an active metadata transaction.
+ * @param dataverseName
+ * dataverse asociated with the synonym that is to be retrieved.
+ * @param synonymName
+ * name of the synonym that is to be retrieved
+ * @return Synonym
+ * @throws AlgebricksException
+ * @throws RemoteException
+ */
+ Synonym getSynonym(TxnId txnId, DataverseName dataverseName, String synonymName)
+ throws AlgebricksException, RemoteException;
+
+ /**
+ * Retrieve synonyms installed in a given dataverse.
+ *
+ * @param txnId
+ * A globally unique id for an active metadata transaction.
+ * @param dataverseName
+ * dataverse associated with synonyms that are to be retrieved.
+ * @return list of synonyms
+ * @throws AlgebricksException
+ * @throws RemoteException
+ */
+ List<Synonym> getDataverseSynonyms(TxnId txnId, DataverseName dataverseName)
+ throws AlgebricksException, RemoteException;
+
+ /**
* update an existing dataset in the metadata, acquiring local locks on behalf
* of the given transaction id.
*
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataBootstrap.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataBootstrap.java
index 49fffe6..c3926a4 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataBootstrap.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataBootstrap.java
@@ -120,7 +120,8 @@
MetadataPrimaryIndexes.FUNCTION_DATASET, MetadataPrimaryIndexes.DATASOURCE_ADAPTER_DATASET,
MetadataPrimaryIndexes.FEED_DATASET, MetadataPrimaryIndexes.FEED_POLICY_DATASET,
MetadataPrimaryIndexes.LIBRARY_DATASET, MetadataPrimaryIndexes.COMPACTION_POLICY_DATASET,
- MetadataPrimaryIndexes.EXTERNAL_FILE_DATASET, MetadataPrimaryIndexes.FEED_CONNECTION_DATASET };
+ MetadataPrimaryIndexes.EXTERNAL_FILE_DATASET, MetadataPrimaryIndexes.FEED_CONNECTION_DATASET,
+ MetadataPrimaryIndexes.SYNONYM_DATASET };
private MetadataBootstrap() {
}
@@ -352,7 +353,16 @@
ILSMPageWriteCallbackFactory pageWriteCallbackFactory = new LSMIndexPageWriteCallbackFactory();
IStorageComponentProvider storageComponentProvider = appContext.getStorageComponentProvider();
+ boolean createMetadataDataset;
+ LocalResource resource;
if (isNewUniverse()) {
+ resource = null;
+ createMetadataDataset = true;
+ } else {
+ resource = localResourceRepository.get(file.getRelativePath());
+ createMetadataDataset = resource == null;
+ }
+ if (createMetadataDataset) {
final double bloomFilterFalsePositiveRate =
appContext.getStorageProperties().getBloomFilterFalsePositiveRate();
LSMBTreeLocalResourceFactory lsmBtreeFactory =
@@ -373,13 +383,6 @@
index::getResourceId, file, dsLocalResourceFactory, true);
indexBuilder.build();
} else {
- final LocalResource resource = localResourceRepository.get(file.getRelativePath());
- if (resource == null) {
- throw new HyracksDataException("Could not find required metadata indexes. Please delete "
- + appContext.getMetadataProperties().getTransactionLogDirs()
- .get(appContext.getTransactionSubsystem().getId())
- + " to intialize as a new instance. (WARNING: all data will be lost.)");
- }
// Why do we care about metadata dataset's resource ids? why not assign them ids
// similar to other resources?
if (index.getResourceId() != resource.getId()) {
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataPrimaryIndexes.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataPrimaryIndexes.java
index f612c44..556090a 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataPrimaryIndexes.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataPrimaryIndexes.java
@@ -59,6 +59,8 @@
new MetadataIndexImmutableProperties(MetadataConstants.COMPACTION_POLICY_DATASET_NAME, 13, 13);
public static final MetadataIndexImmutableProperties PROPERTIES_EXTERNAL_FILE =
new MetadataIndexImmutableProperties(MetadataConstants.EXTERNAL_FILE_DATASET_NAME, 14, 14);
+ public static final MetadataIndexImmutableProperties PROPERTIES_SYNONYM =
+ new MetadataIndexImmutableProperties(MetadataConstants.SYNONYM_DATASET_NAME, 15, 15);
public static final IMetadataIndex DATAVERSE_DATASET =
new MetadataIndex(PROPERTIES_DATAVERSE, 2, new IAType[] { BuiltinType.ASTRING },
@@ -134,6 +136,12 @@
Arrays.asList(MetadataRecordTypes.FIELD_NAME_DATASET_NAME)),
0, MetadataRecordTypes.FEED_CONNECTION_RECORDTYPE, true, new int[] { 0, 1, 2 });
+ public static final IMetadataIndex SYNONYM_DATASET =
+ new MetadataIndex(PROPERTIES_SYNONYM, 3, new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING },
+ Arrays.asList(Arrays.asList(MetadataRecordTypes.FIELD_NAME_DATAVERSE_NAME),
+ Arrays.asList(MetadataRecordTypes.FIELD_NAME_SYNONYM_NAME)),
+ 0, MetadataRecordTypes.SYNONYM_RECORDTYPE, true, new int[] { 0, 1 });
+
private MetadataPrimaryIndexes() {
}
}
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataRecordTypes.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataRecordTypes.java
index ac36680..59a6cde 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataRecordTypes.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataRecordTypes.java
@@ -80,6 +80,8 @@
public static final String FIELD_NAME_NODE_NAME = "NodeName";
public static final String FIELD_NAME_NODE_NAMES = "NodeNames";
public static final String FIELD_NAME_NUMBER_OF_CORES = "NumberOfCores";
+ public static final String FIELD_NAME_OBJECT_DATAVERSE_NAME = "ObjectDataverseName";
+ public static final String FIELD_NAME_OBJECT_NAME = "ObjectName";
public static final String FIELD_NAME_ORDERED_LIST = "OrderedList";
public static final String FIELD_NAME_PARAMS = "Params";
public static final String FIELD_NAME_PARTITIONING_KEY = "PartitioningKey";
@@ -92,6 +94,7 @@
public static final String FIELD_NAME_RETURN_TYPE = "ReturnType";
public static final String FIELD_NAME_SEARCH_KEY = "SearchKey";
public static final String FIELD_NAME_STATUS = "Status";
+ public static final String FIELD_NAME_SYNONYM_NAME = "SynonymName";
public static final String FIELD_NAME_TAG = "Tag";
public static final String FIELD_NAME_TIMESTAMP = "Timestamp";
public static final String FIELD_NAME_TRANSACTION_STATE = "TransactionState";
@@ -468,6 +471,23 @@
//IsOpen?
true);
+ //-------------------------------------- Synonym ---------------------------------------//
+ public static final String RECORD_NAME_SYNONYM = "SynonymRecordType";
+ public static final int SYNONYM_ARECORD_DATAVERSENAME_FIELD_INDEX = 0;
+ public static final int SYNONYM_ARECORD_SYNONYMNAME_FIELD_INDEX = 1;
+ public static final int SYNONYM_ARECORD_OBJECTDATAVERSENAME_FIELD_INDEX = 2;
+ public static final int SYNONYM_ARECORD_OBJECTNAME_FIELD_INDEX = 3;
+ public static final ARecordType SYNONYM_RECORDTYPE = createRecordType(
+ // RecordTypeName
+ RECORD_NAME_SYNONYM,
+ // FieldNames
+ new String[] { FIELD_NAME_DATAVERSE_NAME, FIELD_NAME_SYNONYM_NAME, FIELD_NAME_OBJECT_DATAVERSE_NAME,
+ FIELD_NAME_OBJECT_NAME },
+ // FieldTypes
+ new IAType[] { BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING, BuiltinType.ASTRING },
+ //IsOpen?
+ true);
+
// private members
private MetadataRecordTypes() {
}
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/MetadataManagerUtil.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/MetadataManagerUtil.java
index cc96ce6..72d989a 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/MetadataManagerUtil.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/MetadataManagerUtil.java
@@ -34,6 +34,7 @@
import org.apache.asterix.metadata.entities.FeedPolicyEntity;
import org.apache.asterix.metadata.entities.Index;
import org.apache.asterix.metadata.entities.NodeGroup;
+import org.apache.asterix.metadata.entities.Synonym;
import org.apache.asterix.metadata.utils.MetadataConstants;
import org.apache.asterix.om.types.ARecordType;
import org.apache.asterix.om.types.IAType;
@@ -134,6 +135,11 @@
return MetadataManager.INSTANCE.getFeedPolicy(mdTxnCtx, dataverseName, policyName);
}
+ public static Synonym findSynonym(MetadataTransactionContext mdTxnCtx, DataverseName dataverseName,
+ String synonymName) throws AlgebricksException {
+ return MetadataManager.INSTANCE.getSynonym(mdTxnCtx, dataverseName, synonymName);
+ }
+
public static List<Index> getDatasetIndexes(MetadataTransactionContext mdTxnCtx, DataverseName dataverseName,
String datasetName) throws AlgebricksException {
return MetadataManager.INSTANCE.getDatasetIndexes(mdTxnCtx, dataverseName, datasetName);
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/MetadataProvider.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/MetadataProvider.java
index 5eff20b..55df495 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/MetadataProvider.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/MetadataProvider.java
@@ -81,6 +81,7 @@
import org.apache.asterix.metadata.entities.FeedConnection;
import org.apache.asterix.metadata.entities.FeedPolicyEntity;
import org.apache.asterix.metadata.entities.Index;
+import org.apache.asterix.metadata.entities.Synonym;
import org.apache.asterix.metadata.feeds.FeedMetadataUtil;
import org.apache.asterix.metadata.lock.ExternalDatasetsRegistry;
import org.apache.asterix.metadata.utils.DatasetUtil;
@@ -327,6 +328,11 @@
this.externalDataLocks = locks;
}
+ private DataverseName getActiveDataverseName(DataverseName dataverseName) {
+ return dataverseName != null ? dataverseName
+ : defaultDataverse != null ? defaultDataverse.getDataverseName() : null;
+ }
+
/**
* Retrieve the Output RecordType, as defined by "set output-record-type".
*/
@@ -336,8 +342,7 @@
}
public Dataset findDataset(DataverseName dataverseName, String datasetName) throws AlgebricksException {
- DataverseName dvName = dataverseName == null
- ? (defaultDataverse == null ? null : defaultDataverse.getDataverseName()) : dataverseName;
+ DataverseName dvName = getActiveDataverseName(dataverseName);
if (dvName == null) {
return null;
}
@@ -408,6 +413,23 @@
return MetadataManagerUtil.getDatasetIndexes(mdTxnCtx, dataverseName, datasetName);
}
+ public Pair<DataverseName, String> resolveDatasetNameUsingSynonyms(DataverseName dataverseName, String datasetName)
+ throws AlgebricksException {
+ DataverseName dvName = getActiveDataverseName(dataverseName);
+ if (dvName == null) {
+ return null;
+ }
+ while (MetadataManagerUtil.findDataset(mdTxnCtx, dvName, datasetName) == null) {
+ Synonym synonym = MetadataManagerUtil.findSynonym(mdTxnCtx, dvName, datasetName);
+ if (synonym == null) {
+ return null;
+ }
+ dvName = synonym.getObjectDataverseName();
+ datasetName = synonym.getObjectName();
+ }
+ return new Pair<>(dvName, datasetName);
+ }
+
@Override
public IFunctionInfo lookupFunction(FunctionIdentifier fid) {
return BuiltinFunctions.lookupFunction(fid);
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/Synonym.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/Synonym.java
new file mode 100644
index 0000000..34ecaed
--- /dev/null
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/Synonym.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.asterix.metadata.entities;
+
+import java.util.Objects;
+
+import org.apache.asterix.common.metadata.DataverseName;
+import org.apache.asterix.metadata.MetadataCache;
+import org.apache.asterix.metadata.api.IMetadataEntity;
+
+public class Synonym implements IMetadataEntity<Synonym> {
+
+ private static final long serialVersionUID = 1L;
+
+ private final DataverseName dataverseName;
+
+ private final String synonymName;
+
+ private final DataverseName objectDataverseName;
+
+ private final String objectName;
+
+ public Synonym(DataverseName dataverseName, String synonymName, DataverseName objectDataverseName,
+ String objectName) {
+ this.dataverseName = Objects.requireNonNull(dataverseName);
+ this.synonymName = Objects.requireNonNull(synonymName);
+ this.objectDataverseName = Objects.requireNonNull(objectDataverseName);
+ this.objectName = Objects.requireNonNull(objectName);
+ }
+
+ public DataverseName getDataverseName() {
+ return dataverseName;
+ }
+
+ public String getSynonymName() {
+ return synonymName;
+ }
+
+ public DataverseName getObjectDataverseName() {
+ return objectDataverseName;
+ }
+
+ public String getObjectName() {
+ return objectName;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (o == null || getClass() != o.getClass())
+ return false;
+ Synonym synonym = (Synonym) o;
+ return dataverseName.equals(synonym.dataverseName) && synonymName.equals(synonym.synonymName)
+ && objectDataverseName.equals(synonym.objectDataverseName) && objectName.equals(synonym.objectName);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(dataverseName, synonymName, objectDataverseName, objectName);
+ }
+
+ @Override
+ public Synonym addToCache(MetadataCache cache) {
+ return cache.addSynonymIfNotExists(this);
+ }
+
+ @Override
+ public Synonym dropFromCache(MetadataCache cache) {
+ return cache.dropSynonym(this);
+ }
+}
\ No newline at end of file
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/MetadataTupleTranslatorProvider.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/MetadataTupleTranslatorProvider.java
index ef5256b..4a661c8 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/MetadataTupleTranslatorProvider.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/MetadataTupleTranslatorProvider.java
@@ -79,4 +79,8 @@
public NodeGroupTupleTranslator getNodeGroupTupleTranslator(boolean getTuple) {
return new NodeGroupTupleTranslator(getTuple);
}
+
+ public SynonymTupleTranslator getSynonymTupleTranslator(boolean getTuple) {
+ return new SynonymTupleTranslator(getTuple);
+ }
}
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/SynonymTupleTranslator.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/SynonymTupleTranslator.java
new file mode 100644
index 0000000..2d8ec9b
--- /dev/null
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/SynonymTupleTranslator.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.asterix.metadata.entitytupletranslators;
+
+import org.apache.asterix.common.metadata.DataverseName;
+import org.apache.asterix.metadata.bootstrap.MetadataPrimaryIndexes;
+import org.apache.asterix.metadata.bootstrap.MetadataRecordTypes;
+import org.apache.asterix.metadata.entities.Synonym;
+import org.apache.asterix.om.base.ARecord;
+import org.apache.asterix.om.base.AString;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.apache.hyracks.dataflow.common.data.accessors.ITupleReference;
+
+/**
+ * Translates a Synonym metadata entity to an ITupleReference and vice versa.
+ */
+public final class SynonymTupleTranslator extends AbstractTupleTranslator<Synonym> {
+
+ // Payload field containing serialized Synonym.
+
+ private static final int SYNONYM_PAYLOAD_TUPLE_FIELD_INDEX = 2;
+
+ protected SynonymTupleTranslator(boolean getTuple) {
+ super(getTuple, MetadataPrimaryIndexes.SYNONYM_DATASET, SYNONYM_PAYLOAD_TUPLE_FIELD_INDEX);
+ }
+
+ @Override
+ protected Synonym createMetadataEntityFromARecord(ARecord synonymRecord) {
+ String dataverseCanonicalName =
+ ((AString) synonymRecord.getValueByPos(MetadataRecordTypes.SYNONYM_ARECORD_DATAVERSENAME_FIELD_INDEX))
+ .getStringValue();
+ DataverseName dataverseName = DataverseName.createFromCanonicalForm(dataverseCanonicalName);
+
+ String synonymName =
+ ((AString) synonymRecord.getValueByPos(MetadataRecordTypes.SYNONYM_ARECORD_SYNONYMNAME_FIELD_INDEX))
+ .getStringValue();
+
+ String objectDataverseCanonicalName = ((AString) synonymRecord
+ .getValueByPos(MetadataRecordTypes.SYNONYM_ARECORD_OBJECTDATAVERSENAME_FIELD_INDEX)).getStringValue();
+ DataverseName objectDataverseName = DataverseName.createFromCanonicalForm(objectDataverseCanonicalName);
+
+ String objectName =
+ ((AString) synonymRecord.getValueByPos(MetadataRecordTypes.SYNONYM_ARECORD_OBJECTNAME_FIELD_INDEX))
+ .getStringValue();
+
+ return new Synonym(dataverseName, synonymName, objectDataverseName, objectName);
+ }
+
+ @Override
+ public ITupleReference getTupleFromMetadataEntity(Synonym synonym) throws HyracksDataException {
+ String dataverseCanonicalName = synonym.getDataverseName().getCanonicalForm();
+
+ // write the key in the first 2 fields of the tuple
+ tupleBuilder.reset();
+
+ aString.setValue(dataverseCanonicalName);
+ stringSerde.serialize(aString, tupleBuilder.getDataOutput());
+ tupleBuilder.addFieldEndOffset();
+ aString.setValue(synonym.getSynonymName());
+ stringSerde.serialize(aString, tupleBuilder.getDataOutput());
+ tupleBuilder.addFieldEndOffset();
+
+ // write the pay-load in the third field of the tuple
+
+ recordBuilder.reset(MetadataRecordTypes.SYNONYM_RECORDTYPE);
+
+ // write field 0
+ fieldValue.reset();
+ aString.setValue(dataverseCanonicalName);
+ stringSerde.serialize(aString, fieldValue.getDataOutput());
+ recordBuilder.addField(MetadataRecordTypes.SYNONYM_ARECORD_DATAVERSENAME_FIELD_INDEX, fieldValue);
+
+ // write field 1
+ fieldValue.reset();
+ aString.setValue(synonym.getSynonymName());
+ stringSerde.serialize(aString, fieldValue.getDataOutput());
+ recordBuilder.addField(MetadataRecordTypes.SYNONYM_ARECORD_SYNONYMNAME_FIELD_INDEX, fieldValue);
+
+ // write field 2
+ fieldValue.reset();
+ aString.setValue(synonym.getObjectDataverseName().getCanonicalForm());
+ stringSerde.serialize(aString, fieldValue.getDataOutput());
+ recordBuilder.addField(MetadataRecordTypes.SYNONYM_ARECORD_OBJECTDATAVERSENAME_FIELD_INDEX, fieldValue);
+
+ // write field 3
+ fieldValue.reset();
+ aString.setValue(synonym.getObjectName());
+ stringSerde.serialize(aString, fieldValue.getDataOutput());
+ recordBuilder.addField(MetadataRecordTypes.SYNONYM_ARECORD_OBJECTNAME_FIELD_INDEX, fieldValue);
+
+ // write record
+ recordBuilder.write(tupleBuilder.getDataOutput(), true);
+ tupleBuilder.addFieldEndOffset();
+
+ tuple.reset(tupleBuilder.getFieldEndOffsets(), tupleBuilder.getByteArray());
+ return tuple;
+ }
+}
\ No newline at end of file
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/lock/MetadataLockKey.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/lock/MetadataLockKey.java
index 0df1c2c..46070de 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/lock/MetadataLockKey.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/lock/MetadataLockKey.java
@@ -35,7 +35,8 @@
FEED_POLICY,
FUNCTION,
MERGE_POLICY,
- NODE_GROUP
+ NODE_GROUP,
+ SYNONYM
}
private final EntityKind entityKind;
@@ -113,6 +114,10 @@
return new MetadataLockKey(EntityKind.FEED_POLICY, null, dataverseName, feedPolicyName);
}
+ static MetadataLockKey createSynonymLockKey(DataverseName dataverseName, String synonymName) {
+ return new MetadataLockKey(EntityKind.SYNONYM, null, dataverseName, synonymName);
+ }
+
static MetadataLockKey createExtensionEntityLockKey(String extension, DataverseName dataverseName,
String entityName) {
return new MetadataLockKey(EntityKind.EXTENSION, extension, dataverseName, entityName);
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/lock/MetadataLockManager.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/lock/MetadataLockManager.java
index dd2517a..9c4f97f 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/lock/MetadataLockManager.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/lock/MetadataLockManager.java
@@ -94,17 +94,17 @@
}
@Override
- public void acquireFunctionReadLock(LockList locks, DataverseName dataverseName, String functionName)
+ public void acquireFunctionReadLock(LockList locks, DataverseName dataverseName, String synonymName)
throws AlgebricksException {
- MetadataLockKey key = MetadataLockKey.createFunctionLockKey(dataverseName, functionName);
+ MetadataLockKey key = MetadataLockKey.createFunctionLockKey(dataverseName, synonymName);
IMetadataLock lock = mdlocks.computeIfAbsent(key, LOCK_FUNCTION);
locks.add(IMetadataLock.Mode.READ, lock);
}
@Override
- public void acquireFunctionWriteLock(LockList locks, DataverseName dataverseName, String functionName)
+ public void acquireFunctionWriteLock(LockList locks, DataverseName dataverseName, String synonymName)
throws AlgebricksException {
- MetadataLockKey key = MetadataLockKey.createFunctionLockKey(dataverseName, functionName);
+ MetadataLockKey key = MetadataLockKey.createFunctionLockKey(dataverseName, synonymName);
IMetadataLock lock = mdlocks.computeIfAbsent(key, LOCK_FUNCTION);
locks.add(IMetadataLock.Mode.WRITE, lock);
}
@@ -186,6 +186,22 @@
}
@Override
+ public void acquireSynonymReadLock(LockList locks, DataverseName dataverseName, String synonymName)
+ throws AlgebricksException {
+ MetadataLockKey key = MetadataLockKey.createSynonymLockKey(dataverseName, synonymName);
+ IMetadataLock lock = mdlocks.computeIfAbsent(key, LOCK_FUNCTION);
+ locks.add(IMetadataLock.Mode.READ, lock);
+ }
+
+ @Override
+ public void acquireSynonymWriteLock(LockList locks, DataverseName dataverseName, String synonymName)
+ throws AlgebricksException {
+ MetadataLockKey key = MetadataLockKey.createSynonymLockKey(dataverseName, synonymName);
+ IMetadataLock lock = mdlocks.computeIfAbsent(key, LOCK_FUNCTION);
+ locks.add(IMetadataLock.Mode.WRITE, lock);
+ }
+
+ @Override
public void acquireExtensionEntityReadLock(LockList locks, String extension, DataverseName dataverseName,
String entityName) throws AlgebricksException {
MetadataLockKey key = MetadataLockKey.createExtensionEntityLockKey(extension, dataverseName, entityName);
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/MetadataConstants.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/MetadataConstants.java
index c263ee6..4489050 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/MetadataConstants.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/MetadataConstants.java
@@ -45,6 +45,7 @@
public static final String FEED_POLICY_DATASET_NAME = "FeedPolicy";
public static final String COMPACTION_POLICY_DATASET_NAME = "CompactionPolicy";
public static final String EXTERNAL_FILE_DATASET_NAME = "ExternalFile";
+ public static final String SYNONYM_DATASET_NAME = "Synonym";
private MetadataConstants() {
}
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/MetadataLockUtil.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/MetadataLockUtil.java
index 3e5ccd1..79215e7 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/MetadataLockUtil.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/MetadataLockUtil.java
@@ -125,6 +125,20 @@
}
@Override
+ public void createSynonymBegin(IMetadataLockManager lockMgr, LockList locks, DataverseName dataverseName,
+ String synonymName) throws AlgebricksException {
+ lockMgr.acquireDataverseReadLock(locks, dataverseName);
+ lockMgr.acquireSynonymWriteLock(locks, dataverseName, synonymName);
+ }
+
+ @Override
+ public void dropSynonymBegin(IMetadataLockManager lockMgr, LockList locks, DataverseName dataverseName,
+ String synonymName) throws AlgebricksException {
+ lockMgr.acquireDataverseReadLock(locks, dataverseName);
+ lockMgr.acquireSynonymWriteLock(locks, dataverseName, synonymName);
+ }
+
+ @Override
public void modifyDatasetBegin(IMetadataLockManager lockMgr, LockList locks, DataverseName dataverseName,
String datasetName) throws AlgebricksException {
lockMgr.acquireDataverseReadLock(locks, dataverseName);