diff --git a/common/utils/src/main/resources/error/error-conditions.json b/common/utils/src/main/resources/error/error-conditions.json index c0046b7c7ab7f..2caebfffae6da 100644 --- a/common/utils/src/main/resources/error/error-conditions.json +++ b/common/utils/src/main/resources/error/error-conditions.json @@ -557,6 +557,44 @@ ], "sqlState" : "0A000" }, + "CANNOT_LOAD_CATALOG" : { + "message" : [ + "Cannot load catalog '' with the plugin class '':" + ], + "subClass" : { + "ABSTRACT_CLASS" : { + "message" : [ + "the class is abstract and cannot be instantiated." + ] + }, + "CONSTRUCTOR_FAILURE" : { + "message" : [ + "the constructor threw an exception during instantiation." + ] + }, + "CONSTRUCTOR_NOT_ACCESSIBLE" : { + "message" : [ + "failed to call the public no-arg constructor." + ] + }, + "CONSTRUCTOR_NOT_FOUND" : { + "message" : [ + "failed to find the public no-arg constructor." + ] + }, + "NOT_A_CATALOG_PLUGIN" : { + "message" : [ + "the class does not implement CatalogPlugin." + ] + }, + "PLUGIN_CLASS_NOT_FOUND" : { + "message" : [ + "cannot find the plugin class." + ] + } + }, + "sqlState" : "46103" + }, "CANNOT_LOAD_CHECKPOINT_FILE_MANAGER" : { "message" : [ "Error loading streaming checkpoint file manager for path=." @@ -10950,36 +10988,6 @@ "Invalid catalog name: ." ] }, - "_LEGACY_ERROR_TEMP_2214" : { - "message" : [ - "Plugin class for catalog '' does not implement CatalogPlugin: ." - ] - }, - "_LEGACY_ERROR_TEMP_2215" : { - "message" : [ - "Cannot find catalog plugin class for catalog '': ." - ] - }, - "_LEGACY_ERROR_TEMP_2216" : { - "message" : [ - "Failed to find public no-arg constructor for catalog '': )." - ] - }, - "_LEGACY_ERROR_TEMP_2217" : { - "message" : [ - "Failed to call public no-arg constructor for catalog '': )." - ] - }, - "_LEGACY_ERROR_TEMP_2218" : { - "message" : [ - "Cannot instantiate abstract catalog plugin class for catalog '': ." - ] - }, - "_LEGACY_ERROR_TEMP_2219" : { - "message" : [ - "Failed during instantiating constructor for catalog '': ." - ] - }, "_LEGACY_ERROR_TEMP_2220" : { "message" : [ "" diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/errors/QueryExecutionErrors.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/errors/QueryExecutionErrors.scala index a5d64ddd314ed..a9ea3f9f1c26c 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/errors/QueryExecutionErrors.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/errors/QueryExecutionErrors.scala @@ -1920,7 +1920,7 @@ private[sql] object QueryExecutionErrors extends QueryErrorsBase with ExecutionE def catalogPluginClassNotImplementedError(name: String, pluginClassName: String): Throwable = { new SparkException( - errorClass = "_LEGACY_ERROR_TEMP_2214", + errorClass = "CANNOT_LOAD_CATALOG.NOT_A_CATALOG_PLUGIN", messageParameters = Map( "name" -> name, "pluginClassName" -> pluginClassName), @@ -1932,7 +1932,7 @@ private[sql] object QueryExecutionErrors extends QueryErrorsBase with ExecutionE pluginClassName: String, e: Exception): Throwable = { new SparkException( - errorClass = "_LEGACY_ERROR_TEMP_2215", + errorClass = "CANNOT_LOAD_CATALOG.PLUGIN_CLASS_NOT_FOUND", messageParameters = Map( "name" -> name, "pluginClassName" -> pluginClassName), @@ -1944,7 +1944,7 @@ private[sql] object QueryExecutionErrors extends QueryErrorsBase with ExecutionE pluginClassName: String, e: Exception): Throwable = { new SparkException( - errorClass = "_LEGACY_ERROR_TEMP_2216", + errorClass = "CANNOT_LOAD_CATALOG.CONSTRUCTOR_NOT_FOUND", messageParameters = Map( "name" -> name, "pluginClassName" -> pluginClassName), @@ -1956,7 +1956,7 @@ private[sql] object QueryExecutionErrors extends QueryErrorsBase with ExecutionE pluginClassName: String, e: Exception): Throwable = { new SparkException( - errorClass = "_LEGACY_ERROR_TEMP_2217", + errorClass = "CANNOT_LOAD_CATALOG.CONSTRUCTOR_NOT_ACCESSIBLE", messageParameters = Map( "name" -> name, "pluginClassName" -> pluginClassName), @@ -1968,7 +1968,7 @@ private[sql] object QueryExecutionErrors extends QueryErrorsBase with ExecutionE pluginClassName: String, e: Exception): Throwable = { new SparkException( - errorClass = "_LEGACY_ERROR_TEMP_2218", + errorClass = "CANNOT_LOAD_CATALOG.ABSTRACT_CLASS", messageParameters = Map( "name" -> name, "pluginClassName" -> pluginClassName), @@ -1980,7 +1980,7 @@ private[sql] object QueryExecutionErrors extends QueryErrorsBase with ExecutionE pluginClassName: String, e: Exception): Throwable = { new SparkException( - errorClass = "_LEGACY_ERROR_TEMP_2219", + errorClass = "CANNOT_LOAD_CATALOG.CONSTRUCTOR_FAILURE", messageParameters = Map( "name" -> name, "pluginClassName" -> pluginClassName), diff --git a/sql/catalyst/src/test/java/org/apache/spark/sql/connector/catalog/CatalogLoadingSuite.java b/sql/catalyst/src/test/java/org/apache/spark/sql/connector/catalog/CatalogLoadingSuite.java index c7e8d7b0f7f30..655cb55852a7a 100644 --- a/sql/catalyst/src/test/java/org/apache/spark/sql/connector/catalog/CatalogLoadingSuite.java +++ b/sql/catalyst/src/test/java/org/apache/spark/sql/connector/catalog/CatalogLoadingSuite.java @@ -97,7 +97,7 @@ public void testLoadMissingClass() { SparkException exc = Assertions.assertThrows(SparkException.class, () -> Catalogs.load("missing", conf)); - Assertions.assertTrue(exc.getMessage().contains("Cannot find catalog plugin class"), + Assertions.assertEquals("CANNOT_LOAD_CATALOG.PLUGIN_CLASS_NOT_FOUND", exc.getCondition(), "Should complain that the class is not found"); Assertions.assertTrue(exc.getMessage().contains("missing"), "Should identify the catalog by name"); @@ -127,7 +127,7 @@ public void testLoadNonCatalogPlugin() { SparkException exc = Assertions.assertThrows(SparkException.class, () -> Catalogs.load("invalid", conf)); - Assertions.assertTrue(exc.getMessage().contains("does not implement CatalogPlugin"), + Assertions.assertEquals("CANNOT_LOAD_CATALOG.NOT_A_CATALOG_PLUGIN", exc.getCondition(), "Should complain that class does not implement CatalogPlugin"); Assertions.assertTrue(exc.getMessage().contains("invalid"), "Should identify the catalog by name"); @@ -144,8 +144,7 @@ public void testLoadConstructorFailureCatalogPlugin() { SparkException exc = Assertions.assertThrows(SparkException.class, () -> Catalogs.load("invalid", conf)); - Assertions.assertTrue( - exc.getMessage().contains("Failed during instantiating constructor for catalog"), + Assertions.assertEquals("CANNOT_LOAD_CATALOG.CONSTRUCTOR_FAILURE", exc.getCondition(), "Should identify the constructor error"); Assertions.assertTrue(exc.getCause().getMessage().contains("Expected failure"), "Should have expected error message"); @@ -160,14 +159,47 @@ public void testLoadAccessErrorCatalogPlugin() { SparkException exc = Assertions.assertThrows(SparkException.class, () -> Catalogs.load("invalid", conf)); - Assertions.assertTrue( - exc.getMessage().contains("Failed to call public no-arg constructor for catalog"), + Assertions.assertEquals("CANNOT_LOAD_CATALOG.CONSTRUCTOR_NOT_ACCESSIBLE", exc.getCondition(), "Should complain that no public constructor is provided"); Assertions.assertTrue(exc.getMessage().contains("invalid"), "Should identify the catalog by name"); Assertions.assertTrue(exc.getMessage().contains(invalidClassName), "Should identify the class"); } + + @Test + public void testLoadNoNoArgConstructorCatalogPlugin() { + SQLConf conf = new SQLConf(); + String invalidClassName = NoNoArgConstructorCatalogPlugin.class.getCanonicalName(); + conf.setConfString("spark.sql.catalog.invalid", invalidClassName); + + SparkException exc = Assertions.assertThrows(SparkException.class, + () -> Catalogs.load("invalid", conf)); + + Assertions.assertEquals("CANNOT_LOAD_CATALOG.CONSTRUCTOR_NOT_FOUND", exc.getCondition(), + "Should complain that no public no-arg constructor is found"); + Assertions.assertTrue(exc.getMessage().contains("invalid"), + "Should identify the catalog by name"); + Assertions.assertTrue(exc.getMessage().contains(invalidClassName), + "Should identify the class"); + } + + @Test + public void testLoadAbstractCatalogPlugin() { + SQLConf conf = new SQLConf(); + String invalidClassName = AbstractCatalogPlugin.class.getCanonicalName(); + conf.setConfString("spark.sql.catalog.invalid", invalidClassName); + + SparkException exc = Assertions.assertThrows(SparkException.class, + () -> Catalogs.load("invalid", conf)); + + Assertions.assertEquals("CANNOT_LOAD_CATALOG.ABSTRACT_CLASS", exc.getCondition(), + "Should complain that the class is abstract"); + Assertions.assertTrue(exc.getMessage().contains("invalid"), + "Should identify the catalog by name"); + Assertions.assertTrue(exc.getMessage().contains(invalidClassName), + "Should identify the class"); + } } class TestCatalogPlugin implements CatalogPlugin { @@ -218,6 +250,25 @@ public String name() { } } +class NoNoArgConstructorCatalogPlugin implements CatalogPlugin { // no public no-arg constructor + NoNoArgConstructorCatalogPlugin(String arg) { + } + + @Override + public void initialize(String name, CaseInsensitiveStringMap options) { + } + + @Override + public String name() { + return null; + } +} + +abstract class AbstractCatalogPlugin implements CatalogPlugin { // abstract, cannot be instantiated + AbstractCatalogPlugin() { + } +} + class InvalidCatalogPlugin { // doesn't implement CatalogPlugin public void initialize(CaseInsensitiveStringMap options) { } diff --git a/sql/core/src/test/scala/org/apache/spark/sql/connector/SupportsCatalogOptionsSuite.scala b/sql/core/src/test/scala/org/apache/spark/sql/connector/SupportsCatalogOptionsSuite.scala index 98904e6976074..bcd8ba185d1dd 100644 --- a/sql/core/src/test/scala/org/apache/spark/sql/connector/SupportsCatalogOptionsSuite.scala +++ b/sql/core/src/test/scala/org/apache/spark/sql/connector/SupportsCatalogOptionsSuite.scala @@ -285,7 +285,7 @@ class SupportsCatalogOptionsSuite extends SharedSparkSession with BeforeAndAfter sql(s"create table t1 (id bigint) using $format") } - assert(e.getMessage.contains("Cannot find catalog plugin class")) + assert(e.getMessage.contains("cannot find the plugin class")) assert(e.getMessage.contains("InvalidCatalogClass")) } finally { spark.sessionState.catalogManager.reset()