in asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java [2908:3099]
protected CreateResult doCreateView(MetadataProvider metadataProvider, CreateViewStatement cvs, String databaseName,
DataverseName dataverseName, String viewName, String itemTypeDatabaseName,
DataverseName itemTypeDataverseName, String itemTypeName, IStatementRewriter stmtRewriter,
IRequestParameters requestParameters, Creator creator) throws Exception {
SourceLocation sourceLoc = cvs.getSourceLocation();
MetadataTransactionContext mdTxnCtx = MetadataManager.INSTANCE.beginTransaction();
metadataProvider.setMetadataTxnContext(mdTxnCtx);
try {
Dataverse dv = MetadataManager.INSTANCE.getDataverse(mdTxnCtx, databaseName, dataverseName);
if (dv == null) {
throw new CompilationException(ErrorCode.UNKNOWN_DATAVERSE, sourceLoc,
MetadataUtil.dataverseName(databaseName, dataverseName, metadataProvider.isUsingDatabase()));
}
Namespace ns = new Namespace(dv.getDatabaseName(), dv.getDataverseName());
Dataset existingDataset =
MetadataManager.INSTANCE.getDataset(mdTxnCtx, databaseName, dataverseName, viewName);
if (existingDataset != null) {
if (DatasetUtil.isNotView(existingDataset)) {
throw new CompilationException(ErrorCode.DATASET_EXISTS, sourceLoc,
existingDataset.getDatasetName(), existingDataset.getDataverseName());
}
if (cvs.getIfNotExists()) {
MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
return CreateResult.NOOP;
} else if (!cvs.getReplaceIfExists()) {
throw new CompilationException(ErrorCode.VIEW_EXISTS, sourceLoc,
existingDataset.getDatasetFullyQualifiedName());
}
}
DatasetFullyQualifiedName viewQualifiedName =
new DatasetFullyQualifiedName(databaseName, dataverseName, viewName);
Datatype itemTypeEntity = null;
boolean itemTypeIsInline = false;
CreateViewStatement.KeyDecl primaryKeyDecl = cvs.getPrimaryKeyDecl();
List<String> primaryKeyFields = null;
List<CreateViewStatement.ForeignKeyDecl> foreignKeyDecls = cvs.getForeignKeyDecls();
List<ViewDetails.ForeignKey> foreignKeys = null;
String datetimeFormat = null, dateFormat = null, timeFormat = null;
if (cvs.hasItemType()) {
Pair<Datatype, Boolean> itemTypePair = fetchDatasetItemType(mdTxnCtx, DatasetType.VIEW,
DatasetConfig.DatasetFormat.ROW, null, itemTypeDatabaseName, itemTypeDataverseName,
itemTypeName, cvs.getItemType(), false, metadataProvider, sourceLoc);
itemTypeEntity = itemTypePair.first;
itemTypeIsInline = itemTypePair.second;
ARecordType itemType = (ARecordType) itemTypeEntity.getDatatype();
if (primaryKeyDecl != null) {
primaryKeyFields = ValidateUtil.validateViewKeyFields(primaryKeyDecl, itemType, false, sourceLoc);
}
if (foreignKeyDecls != null) {
foreignKeys = new ArrayList<>(foreignKeyDecls.size());
for (CreateViewStatement.ForeignKeyDecl foreignKeyDecl : foreignKeyDecls) {
List<String> foreignKeyFields =
ValidateUtil.validateViewKeyFields(foreignKeyDecl, itemType, true, sourceLoc);
DataverseName refDataverseName = foreignKeyDecl.getReferencedDataverseName();
String refDatabaseName = foreignKeyDecl.getReferencedDatabaseName();
if (refDataverseName == null) {
refDataverseName = dataverseName;
refDatabaseName = databaseName;
} else {
Dataverse refDataverse =
MetadataManager.INSTANCE.getDataverse(mdTxnCtx, refDatabaseName, refDataverseName);
if (refDataverse == null) {
throw new CompilationException(ErrorCode.UNKNOWN_DATAVERSE, sourceLoc,
MetadataUtil.dataverseName(refDatabaseName, refDataverseName,
metadataProvider.isUsingDatabase()));
}
}
String refDatasetName = foreignKeyDecl.getReferencedDatasetName().getValue();
boolean isSelfRef = refDatabaseName.equals(databaseName)
&& refDataverseName.equals(dataverseName) && refDatasetName.equals(viewName);
DatasetType refDatasetType;
DatasetFullyQualifiedName refQualifiedName;
List<String> refPrimaryKeyFields;
if (isSelfRef) {
refDatasetType = DatasetType.VIEW;
refQualifiedName = viewQualifiedName;
refPrimaryKeyFields = primaryKeyFields;
} else {
// findDataset() will acquire lock on referenced dataset (view)
Dataset refDataset = metadataProvider.findDataset(refDatabaseName, refDataverseName,
refDatasetName, true);
if (refDataset == null || DatasetUtil.isNotView(refDataset)) {
throw new CompilationException(ErrorCode.UNKNOWN_VIEW, sourceLoc,
DatasetUtil.getFullyQualifiedDisplayName(refDataverseName, refDatasetName));
}
ViewDetails refViewDetails = (ViewDetails) refDataset.getDatasetDetails();
refDatasetType = refDataset.getDatasetType();
refQualifiedName =
new DatasetFullyQualifiedName(refDatabaseName, refDataverseName, refDatasetName);
refPrimaryKeyFields = refViewDetails.getPrimaryKeyFields();
}
if (refPrimaryKeyFields == null) {
throw new CompilationException(ErrorCode.INVALID_FOREIGN_KEY_DEFINITION_REF_PK_NOT_FOUND,
sourceLoc, DatasetUtil.getDatasetTypeDisplayName(refDatasetType),
DatasetUtil.getFullyQualifiedDisplayName(refDataverseName, refDatasetName));
} else if (refPrimaryKeyFields.size() != foreignKeyFields.size()) {
throw new CompilationException(ErrorCode.INVALID_FOREIGN_KEY_DEFINITION_REF_PK_MISMATCH,
sourceLoc, DatasetUtil.getDatasetTypeDisplayName(refDatasetType),
DatasetUtil.getFullyQualifiedDisplayName(refDataverseName, refDatasetName));
} else if (isSelfRef
&& !OperatorPropertiesUtil.disjoint(refPrimaryKeyFields, foreignKeyFields)) {
throw new CompilationException(ErrorCode.INVALID_FOREIGN_KEY_DEFINITION, sourceLoc);
}
foreignKeys.add(new ViewDetails.ForeignKey(foreignKeyFields, refQualifiedName));
}
}
Map<String, String> viewConfig =
TypeUtil.validateConfiguration(cvs.getViewConfiguration(), cvs.getSourceLocation());
datetimeFormat = TypeUtil.getDatetimeFormat(viewConfig);
dateFormat = TypeUtil.getDateFormat(viewConfig);
timeFormat = TypeUtil.getTimeFormat(viewConfig);
} else {
if (primaryKeyDecl != null) {
throw new CompilationException(ErrorCode.INVALID_PRIMARY_KEY_DEFINITION, cvs.getSourceLocation());
}
if (foreignKeyDecls != null) {
throw new CompilationException(ErrorCode.INVALID_FOREIGN_KEY_DEFINITION, cvs.getSourceLocation());
}
if (cvs.getViewConfiguration() != null) {
throw new CompilationException(ErrorCode.ILLEGAL_SET_PARAMETER, cvs.getSourceLocation(),
cvs.getViewConfiguration().keySet().iterator().next());
}
}
if (existingDataset != null) {
ViewDetails existingViewDetails = (ViewDetails) existingDataset.getDatasetDetails();
List<String> existingPrimaryKeyFields = existingViewDetails.getPrimaryKeyFields();
// For now don't allow view replacement if existing view has primary keys and they are different
// from the new view's primary keys, because there could be another view that references
// these primary keys via its foreign keys declaration.
// In the future we should relax this check: scan datasets metadata and allow replacement in this case
// if there's no view that references this view
boolean allowToReplace =
existingPrimaryKeyFields == null || existingPrimaryKeyFields.equals(primaryKeyFields);
if (!allowToReplace) {
throw new CompilationException(ErrorCode.CANNOT_CHANGE_PRIMARY_KEY, cvs.getSourceLocation(),
DatasetUtil.getDatasetTypeDisplayName(existingDataset.getDatasetType()),
DatasetUtil.getFullyQualifiedDisplayName(existingDataset));
}
}
// Check whether the view is usable:
// create a view declaration for this function,
// and a query body that queries this view:
ViewDecl viewDecl = new ViewDecl(viewQualifiedName, cvs.getViewBodyExpression());
viewDecl.setSourceLocation(sourceLoc);
IQueryRewriter queryRewriter = rewriterFactory.createQueryRewriter();
Query wrappedQuery =
queryRewriter.createViewAccessorQuery(viewDecl, metadataProvider.getNamespaceResolver());
metadataProvider.setDefaultNamespace(ns);
LangRewritingContext langRewritingContext = createLangRewritingContext(metadataProvider, declaredFunctions,
Collections.singletonList(viewDecl), null, warningCollector, wrappedQuery.getVarCounter());
apiFramework.reWriteQuery(langRewritingContext, wrappedQuery, sessionOutput, false, false,
Collections.emptyList());
List<List<DependencyFullyQualifiedName>> dependencies =
ViewUtil.getViewDependencies(metadataProvider, viewDecl, foreignKeys, queryRewriter);
appCtx.getReceptionist().ensureAuthorized(requestParameters, metadataProvider);
ViewDetails viewDetails = new ViewDetails(cvs.getViewBody(), dependencies, cvs.getDefaultNull(),
primaryKeyFields, foreignKeys, datetimeFormat, dateFormat, timeFormat);
Dataset view = new Dataset(databaseName, dataverseName, viewName, itemTypeDatabaseName,
itemTypeDataverseName, itemTypeName, MetadataConstants.METADATA_NODEGROUP_NAME, "",
Collections.emptyMap(), viewDetails, Collections.emptyMap(), DatasetType.VIEW, 0,
MetadataUtil.PENDING_NO_OP, creator);
if (existingDataset == null) {
if (itemTypeIsInline) {
MetadataManager.INSTANCE.addDatatype(mdTxnCtx, itemTypeEntity);
}
MetadataManager.INSTANCE.addDataset(mdTxnCtx, view);
} else {
if (itemTypeIsInline) {
MetadataManager.INSTANCE.updateDatatype(mdTxnCtx, itemTypeEntity);
}
MetadataManager.INSTANCE.updateDataset(mdTxnCtx, view);
}
beforeTxnCommit(metadataProvider, creator, EntityDetails.newView(databaseName, dataverseName, viewName));
MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
return existingDataset != null ? CreateResult.REPLACED : CreateResult.CREATED;
} catch (Exception e) {
abort(e, e, mdTxnCtx);
throw e;
}
}