diff --git a/flint-spark-integration/src/main/antlr4/FlintSparkSqlExtensions.g4 b/flint-spark-integration/src/main/antlr4/FlintSparkSqlExtensions.g4 index 44fd792ba..ccc9c5e64 100644 --- a/flint-spark-integration/src/main/antlr4/FlintSparkSqlExtensions.g4 +++ b/flint-spark-integration/src/main/antlr4/FlintSparkSqlExtensions.g4 @@ -79,6 +79,7 @@ dropCoveringIndexStatement materializedViewStatement : createMaterializedViewStatement + | showMaterializedViewStatement | dropMaterializedViewStatement ; @@ -88,6 +89,10 @@ createMaterializedViewStatement (WITH LEFT_PAREN propertyList RIGHT_PAREN)? ; +showMaterializedViewStatement + : SHOW MATERIALIZED (VIEW | VIEWS) IN catalogDb=multipartIdentifier + ; + dropMaterializedViewStatement : DROP MATERIALIZED VIEW mvName=multipartIdentifier ; diff --git a/flint-spark-integration/src/main/antlr4/SparkSqlBase.g4 b/flint-spark-integration/src/main/antlr4/SparkSqlBase.g4 index 15652aa79..533d851ba 100644 --- a/flint-spark-integration/src/main/antlr4/SparkSqlBase.g4 +++ b/flint-spark-integration/src/main/antlr4/SparkSqlBase.g4 @@ -162,6 +162,7 @@ DROP: 'DROP'; EXISTS: 'EXISTS'; FALSE: 'FALSE'; IF: 'IF'; +IN: 'IN'; INDEX: 'INDEX'; INDEXES: 'INDEXES'; MATERIALIZED: 'MATERIALIZED'; @@ -172,6 +173,7 @@ REFRESH: 'REFRESH'; SHOW: 'SHOW'; TRUE: 'TRUE'; VIEW: 'VIEW'; +VIEWS: 'VIEWS'; WITH: 'WITH'; diff --git a/flint-spark-integration/src/main/scala/org/opensearch/flint/spark/FlintSpark.scala b/flint-spark-integration/src/main/scala/org/opensearch/flint/spark/FlintSpark.scala index 9c78a07f8..792ef830f 100644 --- a/flint-spark-integration/src/main/scala/org/opensearch/flint/spark/FlintSpark.scala +++ b/flint-spark-integration/src/main/scala/org/opensearch/flint/spark/FlintSpark.scala @@ -166,10 +166,14 @@ class FlintSpark(val spark: SparkSession) { * Flint index list */ def describeIndexes(indexNamePattern: String): Seq[FlintSparkIndex] = { - flintClient - .getAllIndexMetadata(indexNamePattern) - .asScala - .map(FlintSparkIndexFactory.create) + if (flintClient.exists(indexNamePattern)) { + flintClient + .getAllIndexMetadata(indexNamePattern) + .asScala + .map(FlintSparkIndexFactory.create) + } else { + Seq.empty + } } /** diff --git a/flint-spark-integration/src/main/scala/org/opensearch/flint/spark/sql/mv/FlintSparkMaterializedViewAstBuilder.scala b/flint-spark-integration/src/main/scala/org/opensearch/flint/spark/sql/mv/FlintSparkMaterializedViewAstBuilder.scala index 976c6e6bc..4b399cc69 100644 --- a/flint-spark-integration/src/main/scala/org/opensearch/flint/spark/sql/mv/FlintSparkMaterializedViewAstBuilder.scala +++ b/flint-spark-integration/src/main/scala/org/opensearch/flint/spark/sql/mv/FlintSparkMaterializedViewAstBuilder.scala @@ -6,14 +6,17 @@ package org.opensearch.flint.spark.sql.mv import org.antlr.v4.runtime.tree.RuleNode -import org.opensearch.flint.spark.FlintSpark +import org.opensearch.flint.spark.{FlintSpark, FlintSparkIndex} import org.opensearch.flint.spark.FlintSpark.RefreshMode import org.opensearch.flint.spark.mv.FlintSparkMaterializedView import org.opensearch.flint.spark.sql.{FlintSparkSqlCommand, FlintSparkSqlExtensionsVisitor, SparkSqlAstBuilder} import org.opensearch.flint.spark.sql.FlintSparkSqlAstBuilder.getFullTableName -import org.opensearch.flint.spark.sql.FlintSparkSqlExtensionsParser.{CreateMaterializedViewStatementContext, DropMaterializedViewStatementContext, MaterializedViewQueryContext} +import org.opensearch.flint.spark.sql.FlintSparkSqlExtensionsParser.{CreateMaterializedViewStatementContext, DropMaterializedViewStatementContext, MaterializedViewQueryContext, ShowMaterializedViewStatementContext} +import org.apache.spark.sql.Row +import org.apache.spark.sql.catalyst.expressions.AttributeReference import org.apache.spark.sql.catalyst.trees.CurrentOrigin +import org.apache.spark.sql.types.StringType /** * Flint Spark AST builder that builds Spark command for Flint materialized view statement. @@ -47,6 +50,22 @@ trait FlintSparkMaterializedViewAstBuilder extends FlintSparkSqlExtensionsVisito } } + override def visitShowMaterializedViewStatement( + ctx: ShowMaterializedViewStatementContext): AnyRef = { + val outputSchema = Seq( + AttributeReference("materialized_view_name", StringType, nullable = false)()) + + FlintSparkSqlCommand(outputSchema) { flint => + val catalogDbName = ctx.catalogDb.getText + val indexNamePattern = FlintSparkIndex.flintIndexNamePrefix(catalogDbName) + "*" + flint + .describeIndexes(indexNamePattern) + .collect { case mv: FlintSparkMaterializedView => + Row(mv.mvName) + } + } + } + override def visitDropMaterializedViewStatement( ctx: DropMaterializedViewStatementContext): AnyRef = { FlintSparkSqlCommand() { flint => diff --git a/integ-test/src/test/scala/org/opensearch/flint/spark/FlintSparkMaterializedViewSqlITSuite.scala b/integ-test/src/test/scala/org/opensearch/flint/spark/FlintSparkMaterializedViewSqlITSuite.scala index 92b1771f3..eca496c2a 100644 --- a/integ-test/src/test/scala/org/opensearch/flint/spark/FlintSparkMaterializedViewSqlITSuite.scala +++ b/integ-test/src/test/scala/org/opensearch/flint/spark/FlintSparkMaterializedViewSqlITSuite.scala @@ -129,6 +129,20 @@ class FlintSparkMaterializedViewSqlITSuite extends FlintSparkSuite { sql(s"CREATE MATERIALIZED VIEW IF NOT EXISTS $testMvName AS $testQuery") } + test("show all materialized views in catalog") { + flint.materializedView().name("spark_catalog.default.mv1").query(testQuery).create() + checkAnswer( + sql(s"SHOW MATERIALIZED VIEW IN spark_catalog"), + Seq(Row("spark_catalog.default.mv1"))) + + flint.materializedView().name("spark_catalog.default.mv2").query(testQuery).create() + checkAnswer( + sql(s"SHOW MATERIALIZED VIEW IN spark_catalog"), + Seq(Row("spark_catalog.default.mv1"), Row("spark_catalog.default.mv2"))) + + checkAnswer(sql(s"SHOW MATERIALIZED VIEW IN spark_catalog.other"), Seq.empty) + } + test("drop materialized view") { flint .materializedView()