This is an automated email from the ASF dual-hosted git repository. stoty pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/phoenix.git
The following commit(s) were added to refs/heads/master by this push: new 68696f3763 PHOENIX-7034 Disallow mapped view creation when the schema does not exists 68696f3763 is described below commit 68696f37630c5836d38953549a7d1867211a48f7 Author: Aron Meszaros <meszaros.aron.att...@gmail.com> AuthorDate: Fri Sep 22 12:23:46 2023 +0200 PHOENIX-7034 Disallow mapped view creation when the schema does not exists --- .../it/java/org/apache/phoenix/end2end/ViewIT.java | 47 +++++++++++++++++++- .../org/apache/phoenix/end2end/ViewMetadataIT.java | 4 ++ .../apache/phoenix/end2end/index/ViewIndexIT.java | 14 +++++- .../org/apache/phoenix/compile/FromCompiler.java | 51 ++++++++++++---------- .../java/org/apache/phoenix/util/SchemaUtil.java | 21 ++++----- 5 files changed, 101 insertions(+), 36 deletions(-) diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/ViewIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/ViewIT.java index 65173c95ef..23eaa1d5ac 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/ViewIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/ViewIT.java @@ -44,8 +44,13 @@ import java.util.List; import java.util.Map; import java.util.Properties; +import org.apache.hadoop.hbase.HBaseTestingUtility; +import org.apache.hadoop.hbase.NamespaceDescriptor; import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.client.Admin; +import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; import org.apache.hadoop.hbase.client.Scan; +import org.apache.hadoop.hbase.client.TableDescriptorBuilder; import org.apache.hadoop.hbase.util.Pair; import org.apache.phoenix.compile.ExplainPlan; import org.apache.phoenix.compile.ExplainPlanAttributes; @@ -60,6 +65,7 @@ import org.apache.phoenix.schema.PTable; import org.apache.phoenix.schema.PTableImpl; import org.apache.phoenix.schema.ReadOnlyTableException; import org.apache.phoenix.schema.ColumnNotFoundException; +import org.apache.phoenix.schema.SchemaNotFoundException; import org.apache.phoenix.schema.TableNotFoundException; import org.apache.phoenix.schema.TableAlreadyExistsException; import org.apache.phoenix.schema.export.DefaultSchemaRegistryRepository; @@ -276,7 +282,46 @@ public class ViewIT extends SplitSystemCatalogIT { assertEquals(4, count); } } - + + @Test + public void testCreateMappedViewWithHbaseNamespace() throws Exception { + Properties props = new Properties(); + props.setProperty(QueryServices.IS_NAMESPACE_MAPPING_ENABLED, + Boolean.TRUE.toString()); + Connection conn1 = DriverManager.getConnection(getUrl(), props); + conn1.setAutoCommit(true); + + HBaseTestingUtility testUtil = getUtility(); + Admin admin = testUtil.getAdmin(); + + String nameSpace = generateUniqueName(); + admin.createNamespace(NamespaceDescriptor.create(nameSpace).build()); + + String tableNameStr = generateUniqueName(); + TableName tableName = TableName.valueOf(nameSpace, tableNameStr); + String familyNameStr = "colFam1"; + TableDescriptorBuilder builder = TableDescriptorBuilder.newBuilder(tableName); + builder.setColumnFamily(ColumnFamilyDescriptorBuilder.of( + familyNameStr)); + admin.createTable(builder.build()); + + + String viewName = SchemaUtil.getTableName(nameSpace, tableNameStr); + try { + conn1.createStatement().execute("CREATE VIEW " + viewName + + " (pk VARCHAR PRIMARY KEY, \"colFam1\".\"lastname\" VARCHAR )"); + } catch (SchemaNotFoundException e) { + assertEquals(nameSpace, e.getSchemaName()); + assertEquals("ERROR 722 (43M05): Schema does not exist schemaName=" + + nameSpace, + e.getMessage()); + } + + conn1.createStatement().execute("CREATE SCHEMA IF NOT EXISTS " + nameSpace); + conn1.createStatement().execute("CREATE VIEW " + viewName + + " (pk VARCHAR PRIMARY KEY, \"colFam1\".\"lastname\" VARCHAR )"); + } + @Test public void testViewWithCurrentDate() throws Exception { try (Connection conn = DriverManager.getConnection(getUrl()); diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/ViewMetadataIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/ViewMetadataIT.java index 7e90118363..f64afae58a 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/ViewMetadataIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/ViewMetadataIT.java @@ -937,6 +937,10 @@ public class ViewMetadataIT extends SplitSystemCatalogIT { if (isNamespaceMapped) { conn.createStatement().execute("CREATE SCHEMA IF NOT EXISTS " + schemaName1); + conn.createStatement().execute("CREATE SCHEMA IF NOT EXISTS " + + viewSchemaName); + conn.createStatement().execute("CREATE SCHEMA IF NOT EXISTS " + + SCHEMA3); } String ddl = "CREATE TABLE " + fullTableName1 + " (k INTEGER NOT NULL PRIMARY KEY, v1 DATE)"; diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/ViewIndexIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/ViewIndexIT.java index 32e74e5ca3..246f80745a 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/ViewIndexIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/ViewIndexIT.java @@ -178,6 +178,9 @@ public class ViewIndexIT extends SplitSystemCatalogIT { try (Connection conn1 = getConnection(); Connection conn2 = getConnection()){ createBaseTable(conn1, schemaName, tableName, false, null, null, true); + if (isNamespaceMapped) { + conn1.createStatement().execute("CREATE SCHEMA IF NOT EXISTS " + viewSchemaName); + } conn1.createStatement().execute("CREATE VIEW " + fullViewName + " AS SELECT * FROM " + fullTableName); conn1.createStatement().execute("CREATE INDEX " + indexName + " ON " + fullViewName + " (v1)"); conn2.createStatement().executeQuery("SELECT * FROM " + fullTableName).next(); @@ -203,6 +206,10 @@ public class ViewIndexIT extends SplitSystemCatalogIT { Connection conn1 = getTenantConnection("10")) { createBaseTable(conn, SCHEMA1, tableName, true, null, null, true); + if (isNamespaceMapped) { + conn.createStatement().execute("CREATE SCHEMA IF NOT EXISTS " + SCHEMA2); + } + PreparedStatement stmt = conn.prepareStatement( "UPSERT INTO " + fullTableName + " VALUES(?,?,?,?,?)"); @@ -482,11 +489,13 @@ public class ViewIndexIT extends SplitSystemCatalogIT { conn.createStatement().execute(viewDdl); conn.createStatement().execute(indexDdl); - String childViewName = String.format("S_%s.\"%s\"", generateUniqueName(), keyPrefix); + String childViewNameSchema = String.format("S_%s", generateUniqueName()); + String childViewName = String.format("%s.\"%s\"", childViewNameSchema, keyPrefix); String viewChildDDl = String.format("CREATE VIEW IF NOT EXISTS %s AS SELECT * FROM %s", childViewName, fullViewName); Connection conn2 = null; if (isNamespaceMapped) { conn2 = getTenantConnection(TENANT1); + conn2.createStatement().execute("CREATE SCHEMA IF NOT EXISTS " + childViewNameSchema); } else { conn2 = conn; } @@ -580,6 +589,8 @@ public class ViewIndexIT extends SplitSystemCatalogIT { Connection tsConn3 = DriverManager.getConnection(getUrl(), tsProps)) { if (isNamespaceMapped) { conn.createStatement().execute("CREATE SCHEMA IF NOT EXISTS " + baseSchemaName); + conn.createStatement().execute("CREATE SCHEMA IF NOT EXISTS " + viewSchemaName); + conn.createStatement().execute("CREATE SCHEMA IF NOT EXISTS " + tsViewSchemaName); } conn.createStatement().execute( "CREATE TABLE " + baseFullName + "(\n" + " ORGANIZATION_ID CHAR(15) NOT NULL,\n" @@ -697,6 +708,7 @@ public class ViewIndexIT extends SplitSystemCatalogIT { c.setAutoCommit(true); if (isNamespaceMapped) { c.createStatement().execute("CREATE SCHEMA IF NOT EXISTS " + SCHEMA1); + c.createStatement().execute("CREATE SCHEMA IF NOT EXISTS " + SCHEMA2); } s.execute("CREATE TABLE " + tableName + " (COL1 VARCHAR PRIMARY KEY, CF.COL2 VARCHAR)"); s.executeUpdate("UPSERT INTO " + tableName + " VALUES ('AAA', 'BBB')"); diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/FromCompiler.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/FromCompiler.java index a4d37b14f3..af7af7c019 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/compile/FromCompiler.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/FromCompiler.java @@ -163,16 +163,19 @@ public class FromCompiler { TableName baseTable = statement.getBaseTableName(); String schemaName; - if (baseTable == null) { - if (SchemaUtil.isSchemaCheckRequired(statement.getTableType(), connection.getQueryServices().getProps())) { - schemaName = statement.getTableName().getSchemaName(); - if (schemaName != null) { - new SchemaResolver(connection, statement.getTableName().getSchemaName(), true); - } else if (connection.getSchema() != null) { - // To ensure schema set through properties or connection string exists before creating table - new SchemaResolver(connection, connection.getSchema(), true); - } + if (SchemaUtil.isSchemaCheckRequired(statement.getTableType(), + connection.getQueryServices().getProps())) { + // To ensure schema set through properties or connection + // string exists before creating table + schemaName = statement.getTableName().getSchemaName() != null + ? statement.getTableName().getSchemaName() : connection.getSchema(); + if (schemaName != null) { + // Only create SchemaResolver object to check if constructor throws exception. + // No exception means schema exists + new SchemaResolver(connection, schemaName, true); } + } + if (baseTable == null) { return EMPTY_TABLE_RESOLVER; } NamedTableNode tableNode = NamedTableNode.create(null, baseTable, Collections.<ColumnDef>emptyList()); @@ -245,7 +248,7 @@ public class FromCompiler { */ public static TableRef refreshDerivedTableNode( ColumnResolver columnResolver, DerivedTableNode derivedTableNode) throws SQLException { - if(!(columnResolver instanceof MultiTableColumnResolver)) { + if (!(columnResolver instanceof MultiTableColumnResolver)) { throw new UnsupportedOperationException(); } return ((MultiTableColumnResolver)columnResolver).refreshDerivedTableNode(derivedTableNode); @@ -595,13 +598,13 @@ public class FromCompiler { List<PFunction> functionsFound = new ArrayList<PFunction>(functionNames.size()); if (updateCacheImmediately || connection.getAutoCommit()) { getFunctionFromCache(functionNames, functionsFound, true); - if(functionNames.isEmpty()) { + if (functionNames.isEmpty()) { return functionsFound; } MetaDataMutationResult result = client.updateCache(functionNames); timeStamp = result.getMutationTime(); functionsFound = result.getFunctions(); - if(functionNames.size() != functionsFound.size()){ + if (functionNames.size() != functionsFound.size()) { throw new FunctionNotFoundException("Some of the functions in " + functionNames.toString()+" are not found"); } @@ -612,11 +615,11 @@ public class FromCompiler { if (!functionNames.isEmpty()) { result = client.updateCache(functionNames); } - if(result!=null) { + if (result != null) { if (!result.getFunctions().isEmpty()) { functionsFound.addAll(result.getFunctions()); } - if(result.wasUpdated()) { + if (result.wasUpdated()) { timeStamp = result.getMutationTime(); } } @@ -640,7 +643,7 @@ public class FromCompiler { List<PFunction> functionsFound, boolean getOnlyTemporyFunctions) { Iterator<String> iterator = functionNames.iterator(); - while(iterator.hasNext()) { + while (iterator.hasNext()) { PFunction function = null; String functionName = iterator.next(); try { @@ -672,7 +675,7 @@ public class FromCompiler { @Override public PFunction resolveFunction(String functionName) throws SQLException { PFunction function = functionMap.get(functionName); - if(function == null) { + if (function == null) { throw new FunctionNotFoundException(functionName); } return function; @@ -1010,14 +1013,14 @@ public class FromCompiler { * @throws SQLException */ public TableRef refreshDerivedTableNode(DerivedTableNode derivedTableNode) throws SQLException { - String tableAlias = derivedTableNode.getAlias(); - List<TableRef> removedTableRefs = this.tableMap.removeAll(tableAlias); - if(removedTableRefs == null || removedTableRefs.isEmpty()) { - return null; - } - tables.removeAll(removedTableRefs); - this.visit(derivedTableNode); - return this.resolveTable(null, tableAlias); + String tableAlias = derivedTableNode.getAlias(); + List<TableRef> removedTableRefs = this.tableMap.removeAll(tableAlias); + if (removedTableRefs == null || removedTableRefs.isEmpty()) { + return null; + } + tables.removeAll(removedTableRefs); + this.visit(derivedTableNode); + return this.resolveTable(null, tableAlias); } private static class ColumnFamilyRef { diff --git a/phoenix-core/src/main/java/org/apache/phoenix/util/SchemaUtil.java b/phoenix-core/src/main/java/org/apache/phoenix/util/SchemaUtil.java index fbca85b3b9..4842e02b90 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/util/SchemaUtil.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/util/SchemaUtil.java @@ -247,7 +247,7 @@ public class SchemaUtil { String schemaName = SchemaUtil.getSchemaNameFromFullName(fullTableName); String tableName = SchemaUtil.getTableNameFromFullName(fullTableName); String normalizedTableName = StringUtil.EMPTY_STRING; - if(!schemaName.isEmpty()) { + if (!schemaName.isEmpty()) { normalizedTableName = normalizeIdentifier(schemaName) + QueryConstants.NAME_SEPARATOR; } return normalizedTableName + normalizeIdentifier(tableName); @@ -692,12 +692,12 @@ public class SchemaUtil { stmt.executeUpdate("ALTER TABLE SYSTEM.\"TABLE\" ADD IF NOT EXISTS " + columnDef); return metaConnection; } finally { - if(stmt != null) { + if (stmt != null) { stmt.close(); } } } finally { - if(metaConnection != null) { + if (metaConnection != null) { metaConnection.close(); } } @@ -845,7 +845,7 @@ public class SchemaUtil { } public static String getEscapedFullColumnName(String fullColumnName) { - if(fullColumnName.startsWith(ESCAPE_CHARACTER)) { + if (fullColumnName.startsWith(ESCAPE_CHARACTER)) { return fullColumnName; } int index = fullColumnName.indexOf(QueryConstants.NAME_SEPARATOR); @@ -1131,7 +1131,8 @@ public class SchemaUtil { } public static boolean isSchemaCheckRequired(PTableType tableType, ReadOnlyProps props) { - return PTableType.TABLE.equals(tableType) && isNamespaceMappingEnabled(tableType, props); + return (PTableType.TABLE.equals(tableType) || PTableType.VIEW.equals(tableType)) + && isNamespaceMappingEnabled(tableType, props); } public static boolean isNamespaceMappingEnabled(PTableType type, Configuration conf) { @@ -1265,7 +1266,7 @@ public class SchemaUtil { fullTableName = tableName; } - if(schemaName != null && schemaName.length() != 0) { + if (schemaName != null && schemaName.length() != 0) { if (schemaNameCaseSensitive) { fullTableName = "\"" + schemaName + "\"" + QueryConstants.NAME_SEPARATOR + fullTableName; } else { @@ -1317,7 +1318,7 @@ public class SchemaUtil { public static String formatIndexColumnName(String name) { String[] splitName = name.split("\\."); - if(splitName.length < 2) { + if (splitName.length < 2) { if (!name.contains("\"")) { if (quotesNeededForColumn(name)) { name = "\"" + name + "\""; @@ -1364,13 +1365,13 @@ public class SchemaUtil { boolean tableNameNeedsQuotes = isQuotesNeeded(pTableName); boolean schemaNameNeedsQuotes = isQuotesNeeded(pSchemaName); - if(schemaNameNeedsQuotes) { + if (schemaNameNeedsQuotes) { pSchemaName= "\""+pSchemaName+"\""; } - if(tableNameNeedsQuotes) { + if (tableNameNeedsQuotes) { pTableName = "\""+pTableName+"\""; } - if(tableNameNeedsQuotes || schemaNameNeedsQuotes) { + if (tableNameNeedsQuotes || schemaNameNeedsQuotes) { if (!Strings.isNullOrEmpty(pSchemaName)) { return String.format("%s.%s", pSchemaName, pTableName); } else {