NihalJain commented on code in PR #2024: URL: https://github.com/apache/phoenix/pull/2024#discussion_r2047051616
########## phoenix-core-client/src/main/java/org/apache/phoenix/compile/CreateTableCompiler.java: ########## @@ -84,712 +87,689 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SYSTEM_CHILD_LINK_NAMESPACE_BYTES; -import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SYSTEM_CHILD_LINK_NAME_BYTES; -import static org.apache.phoenix.query.QueryServices.DEFAULT_PHOENIX_UPDATABLE_VIEW_RESTRICTION_ENABLED; -import static org.apache.phoenix.query.QueryServices.PHOENIX_UPDATABLE_VIEW_RESTRICTION_ENABLED; - +import org.apache.phoenix.thirdparty.com.google.common.collect.Iterators; public class CreateTableCompiler { - private static final Logger LOGGER = LoggerFactory.getLogger(CreateTableCompiler.class); - private static final PDatum VARBINARY_DATUM = new VarbinaryDatum(); - private final PhoenixStatement statement; - private final Operation operation; - - public CreateTableCompiler(PhoenixStatement statement, Operation operation) { - this.statement = statement; - this.operation = operation; - } - - public MutationPlan compile(CreateTableStatement create) throws SQLException { - final PhoenixConnection connection = statement.getConnection(); - ColumnResolver resolver = FromCompiler.getResolverForCreation(create, connection); - PTableType type = create.getTableType(); - PTable parentToBe = null; - ViewType viewTypeToBe = null; - Scan scan = new Scan(); - final StatementContext context = new StatementContext(statement, resolver, scan, new SequenceManager(statement)); - // TODO: support any statement for a VIEW instead of just a WHERE clause - ParseNode whereNode = create.getWhereClause(); - String viewStatementToBe = null; - byte[][] viewColumnConstantsToBe = null; - BitSet isViewColumnReferencedToBe = null; - Set<PColumn> pkColumnsInWhere = new HashSet<>(); - Set<PColumn> nonPkColumnsInWhere = new HashSet<>(); - byte[] rowKeyMatcher = ByteUtil.EMPTY_BYTE_ARRAY; - - // Check whether column families having local index column family suffix or not if present - // don't allow creating table. - // Also validate the default values expressions. - List<ColumnDef> columnDefs = create.getColumnDefs(); - List<ColumnDef> overideColumnDefs = null; - PrimaryKeyConstraint pkConstraint = create.getPrimaryKeyConstraint(); - for (int i = 0; i < columnDefs.size(); i++) { - ColumnDef columnDef = columnDefs.get(i); - if (columnDef.getColumnDefName().getFamilyName()!=null && columnDef.getColumnDefName().getFamilyName().contains(QueryConstants.LOCAL_INDEX_COLUMN_FAMILY_PREFIX)) { - throw new SQLExceptionInfo.Builder(SQLExceptionCode.UNALLOWED_COLUMN_FAMILY) - .build().buildException(); - } - // False means we do not need the default (because it evaluated to null) - if (!columnDef.validateDefault(context, pkConstraint)) { - if (overideColumnDefs == null) { - overideColumnDefs = new ArrayList<>(columnDefs); - } - overideColumnDefs.set(i, new ColumnDef(columnDef, null)); - } - } - if (overideColumnDefs != null) { - create = new CreateTableStatement(create,overideColumnDefs); - } - final CreateTableStatement finalCreate = create; - - if (type == PTableType.VIEW) { - TableRef tableRef = resolver.getTables().get(0); - int nColumns = tableRef.getTable().getColumns().size(); - isViewColumnReferencedToBe = new BitSet(nColumns); - // Used to track column references in a view - ExpressionCompiler expressionCompiler = new ColumnTrackingExpressionCompiler(context, isViewColumnReferencedToBe); - parentToBe = tableRef.getTable(); - - // Disallow creating views on top of SYSTEM tables. See PHOENIX-5386 - if (parentToBe.getType() == PTableType.SYSTEM) { - throw new SQLExceptionInfo - .Builder(SQLExceptionCode.CANNOT_CREATE_VIEWS_ON_SYSTEM_TABLES) - .build().buildException(); - } - viewTypeToBe = parentToBe.getViewType() == ViewType.MAPPED ? ViewType.MAPPED : ViewType.UPDATABLE; - Expression where = null; - if (whereNode == null) { - if (parentToBe.getViewType() == ViewType.READ_ONLY) { - viewTypeToBe = ViewType.READ_ONLY; - } - viewStatementToBe = parentToBe.getViewStatement(); - if (viewStatementToBe != null) { - SelectStatement select = new SQLParser(viewStatementToBe).parseQuery(); - whereNode = select.getWhere(); - where = whereNode.accept(expressionCompiler); - } - } else { - whereNode = StatementNormalizer.normalize(whereNode, resolver); - if (whereNode.isStateless()) { - throw new SQLExceptionInfo.Builder(SQLExceptionCode.VIEW_WHERE_IS_CONSTANT) - .build().buildException(); - } - // If our parent has a VIEW statement, combine it with this one - if (parentToBe.getViewStatement() != null) { - SelectStatement select = new SQLParser(parentToBe.getViewStatement()).parseQuery().combine(whereNode); - whereNode = select.getWhere(); - } - where = whereNode.accept(expressionCompiler); - if (where != null && !LiteralExpression.isTrue(where)) { - TableName baseTableName = create.getBaseTableName(); - StringBuilder buf = new StringBuilder(); - whereNode.toSQL(resolver, buf); - viewStatementToBe = QueryUtil.getViewStatement(baseTableName.getSchemaName(), baseTableName.getTableName(), buf.toString()); - } - if (viewTypeToBe != ViewType.MAPPED) { - viewColumnConstantsToBe = new byte[nColumns][]; - ViewWhereExpressionVisitor visitor = new ViewWhereExpressionVisitor(parentToBe, viewColumnConstantsToBe); - where.accept(visitor); - - viewTypeToBe = visitor.isUpdatable() ? ViewType.UPDATABLE : ViewType.READ_ONLY; - boolean updatableViewRestrictionEnabled = connection.getQueryServices() - .getProps().getBoolean(PHOENIX_UPDATABLE_VIEW_RESTRICTION_ENABLED, - DEFAULT_PHOENIX_UPDATABLE_VIEW_RESTRICTION_ENABLED); - if (viewTypeToBe == ViewType.UPDATABLE && updatableViewRestrictionEnabled) { - ViewWhereExpressionValidatorVisitor validatorVisitor = - new ViewWhereExpressionValidatorVisitor(parentToBe, - pkColumnsInWhere, nonPkColumnsInWhere); - where.accept(validatorVisitor); - if (!(connection.getQueryServices() - instanceof ConnectionlessQueryServicesImpl)) { - try { - viewTypeToBe = setViewTypeToBe(connection, parentToBe, - pkColumnsInWhere, nonPkColumnsInWhere); - LOGGER.info("VIEW type is set to {}. View Statement: {}, " + - "View Name: {}, " + - "Parent Table/View Name: {}", - viewTypeToBe, viewStatementToBe, - create.getTableName(), parentToBe.getName()); - } catch (IOException e) { - throw new SQLException(e); - } - } - } - - // If view is not updatable, viewColumnConstants should be empty. We will still - // inherit our parent viewConstants, but we have no additional ones. - if (viewTypeToBe != ViewType.UPDATABLE) { - viewColumnConstantsToBe = null; - } - } - } - if (viewTypeToBe == ViewType.MAPPED - && parentToBe.getPKColumns().isEmpty()) { - validateCreateViewCompilation(connection, parentToBe, - columnDefs, pkConstraint); - } else if (where != null && viewTypeToBe == ViewType.UPDATABLE) { - rowKeyMatcher = WhereOptimizer.getRowKeyMatcher(context, create.getTableName(), - parentToBe, where); - } - verifyIfAnyParentHasIndexesAndViewExtendsPk(parentToBe, columnDefs, pkConstraint); - } - final ViewType viewType = viewTypeToBe; - final String viewStatement = viewStatementToBe; - final byte[][] viewColumnConstants = viewColumnConstantsToBe; - final BitSet isViewColumnReferenced = isViewColumnReferencedToBe; - List<ParseNode> splitNodes = create.getSplitNodes(); - final byte[][] splits = new byte[splitNodes.size()][]; - ImmutableBytesWritable ptr = context.getTempPtr(); - ExpressionCompiler expressionCompiler = new ExpressionCompiler(context); - for (int i = 0; i < splits.length; i++) { - ParseNode node = splitNodes.get(i); - if (node instanceof BindParseNode) { - context.getBindManager().addParamMetaData((BindParseNode) node, VARBINARY_DATUM); - } - if (node.isStateless()) { - Expression expression = node.accept(expressionCompiler); - if (expression.evaluate(null, ptr)) {; - splits[i] = ByteUtil.copyKeyBytesIfNecessary(ptr); - continue; - } + private static final Logger LOGGER = LoggerFactory.getLogger(CreateTableCompiler.class); + private static final PDatum VARBINARY_DATUM = new VarbinaryDatum(); + private final PhoenixStatement statement; + private final Operation operation; + + public CreateTableCompiler(PhoenixStatement statement, Operation operation) { + this.statement = statement; + this.operation = operation; + } + + public MutationPlan compile(CreateTableStatement create) throws SQLException { + final PhoenixConnection connection = statement.getConnection(); + ColumnResolver resolver = FromCompiler.getResolverForCreation(create, connection); + PTableType type = create.getTableType(); + PTable parentToBe = null; + ViewType viewTypeToBe = null; + Scan scan = new Scan(); + final StatementContext context = + new StatementContext(statement, resolver, scan, new SequenceManager(statement)); + // TODO: support any statement for a VIEW instead of just a WHERE clause + ParseNode whereNode = create.getWhereClause(); + String viewStatementToBe = null; + byte[][] viewColumnConstantsToBe = null; + BitSet isViewColumnReferencedToBe = null; + Set<PColumn> pkColumnsInWhere = new HashSet<>(); + Set<PColumn> nonPkColumnsInWhere = new HashSet<>(); + byte[] rowKeyMatcher = ByteUtil.EMPTY_BYTE_ARRAY; + + // Check whether column families having local index column family suffix or not if present + // don't allow creating table. + // Also validate the default values expressions. + List<ColumnDef> columnDefs = create.getColumnDefs(); + List<ColumnDef> overideColumnDefs = null; + PrimaryKeyConstraint pkConstraint = create.getPrimaryKeyConstraint(); + for (int i = 0; i < columnDefs.size(); i++) { + ColumnDef columnDef = columnDefs.get(i); + if ( + columnDef.getColumnDefName().getFamilyName() != null && columnDef.getColumnDefName() + .getFamilyName().contains(QueryConstants.LOCAL_INDEX_COLUMN_FAMILY_PREFIX) + ) { + throw new SQLExceptionInfo.Builder(SQLExceptionCode.UNALLOWED_COLUMN_FAMILY).build() + .buildException(); + } + // False means we do not need the default (because it evaluated to null) + if (!columnDef.validateDefault(context, pkConstraint)) { + if (overideColumnDefs == null) { + overideColumnDefs = new ArrayList<>(columnDefs); + } + overideColumnDefs.set(i, new ColumnDef(columnDef, null)); + } + } + if (overideColumnDefs != null) { + create = new CreateTableStatement(create, overideColumnDefs); + } + final CreateTableStatement finalCreate = create; + + if (type == PTableType.VIEW) { + TableRef tableRef = resolver.getTables().get(0); + int nColumns = tableRef.getTable().getColumns().size(); + isViewColumnReferencedToBe = new BitSet(nColumns); + // Used to track column references in a view + ExpressionCompiler expressionCompiler = + new ColumnTrackingExpressionCompiler(context, isViewColumnReferencedToBe); + parentToBe = tableRef.getTable(); + + // Disallow creating views on top of SYSTEM tables. See PHOENIX-5386 + if (parentToBe.getType() == PTableType.SYSTEM) { + throw new SQLExceptionInfo.Builder(SQLExceptionCode.CANNOT_CREATE_VIEWS_ON_SYSTEM_TABLES) + .build().buildException(); + } + viewTypeToBe = + parentToBe.getViewType() == ViewType.MAPPED ? ViewType.MAPPED : ViewType.UPDATABLE; + Expression where = null; + if (whereNode == null) { + if (parentToBe.getViewType() == ViewType.READ_ONLY) { + viewTypeToBe = ViewType.READ_ONLY; + } + viewStatementToBe = parentToBe.getViewStatement(); + if (viewStatementToBe != null) { + SelectStatement select = new SQLParser(viewStatementToBe).parseQuery(); + whereNode = select.getWhere(); + where = whereNode.accept(expressionCompiler); + } + } else { + whereNode = StatementNormalizer.normalize(whereNode, resolver); + if (whereNode.isStateless()) { + throw new SQLExceptionInfo.Builder(SQLExceptionCode.VIEW_WHERE_IS_CONSTANT).build() + .buildException(); + } + // If our parent has a VIEW statement, combine it with this one + if (parentToBe.getViewStatement() != null) { + SelectStatement select = + new SQLParser(parentToBe.getViewStatement()).parseQuery().combine(whereNode); + whereNode = select.getWhere(); + } + where = whereNode.accept(expressionCompiler); + if (where != null && !LiteralExpression.isTrue(where)) { + TableName baseTableName = create.getBaseTableName(); + StringBuilder buf = new StringBuilder(); + whereNode.toSQL(resolver, buf); + viewStatementToBe = QueryUtil.getViewStatement(baseTableName.getSchemaName(), + baseTableName.getTableName(), buf.toString()); + } + if (viewTypeToBe != ViewType.MAPPED) { + viewColumnConstantsToBe = new byte[nColumns][]; + ViewWhereExpressionVisitor visitor = + new ViewWhereExpressionVisitor(parentToBe, viewColumnConstantsToBe); + where.accept(visitor); + + viewTypeToBe = visitor.isUpdatable() ? ViewType.UPDATABLE : ViewType.READ_ONLY; + boolean updatableViewRestrictionEnabled = connection.getQueryServices().getProps() + .getBoolean(PHOENIX_UPDATABLE_VIEW_RESTRICTION_ENABLED, + DEFAULT_PHOENIX_UPDATABLE_VIEW_RESTRICTION_ENABLED); + if (viewTypeToBe == ViewType.UPDATABLE && updatableViewRestrictionEnabled) { + ViewWhereExpressionValidatorVisitor validatorVisitor = + new ViewWhereExpressionValidatorVisitor(parentToBe, pkColumnsInWhere, + nonPkColumnsInWhere); + where.accept(validatorVisitor); + if (!(connection.getQueryServices() instanceof ConnectionlessQueryServicesImpl)) { + try { + viewTypeToBe = + setViewTypeToBe(connection, parentToBe, pkColumnsInWhere, nonPkColumnsInWhere); + LOGGER.info( + "VIEW type is set to {}. View Statement: {}, " + "View Name: {}, " + + "Parent Table/View Name: {}", + viewTypeToBe, viewStatementToBe, create.getTableName(), parentToBe.getName()); + } catch (IOException e) { + throw new SQLException(e); + } } - throw new SQLExceptionInfo.Builder(SQLExceptionCode.SPLIT_POINT_NOT_CONSTANT) - .setMessage("Node: " + node).build().buildException(); - } - final MetaDataClient client = new MetaDataClient(connection); - final PTable parent = parentToBe; - - return new CreateTableMutationPlan(context, client, finalCreate, splits, parent, - viewStatement, viewType, rowKeyMatcher, - viewColumnConstants, isViewColumnReferenced, connection); - } - - /** - * Restrict view to be UPDATABLE if the view specification: - * 1. uses only the PK columns; - * 2. starts from the first PK column (ignore the prefix PK columns, TENANT_ID and/or - * _SALTED, if the parent table is multi-tenant and/or salted); - * 3. PK columns should be in the order they are defined; - * 4. uses the same set of PK columns as its sibling views' specification; - * Otherwise, mark the view as READ_ONLY. - * - * @param connection The client connection - * @param parentToBe To be parent for given view - * @param pkColumnsInWhere Set of primary key in where clause - * @param nonPkColumnsInWhere Set of non-primary key columns in where clause - * @throws IOException thrown if there is an error finding sibling views - * @throws SQLException - */ - private ViewType setViewTypeToBe(final PhoenixConnection connection, final PTable parentToBe, - final Set<PColumn> pkColumnsInWhere, - final Set<PColumn> nonPkColumnsInWhere) - throws IOException, SQLException { - // 1. Check the view specification WHERE clause uses only the PK columns - if (!nonPkColumnsInWhere.isEmpty()) { - LOGGER.info("Setting the view type as READ_ONLY because the view statement contains " + - "non-PK columns: {}", nonPkColumnsInWhere); - return ViewType.READ_ONLY; - } - if (pkColumnsInWhere.isEmpty()) { - return ViewType.UPDATABLE; - } + } + + // If view is not updatable, viewColumnConstants should be empty. We will still + // inherit our parent viewConstants, but we have no additional ones. + if (viewTypeToBe != ViewType.UPDATABLE) { + viewColumnConstantsToBe = null; + } + } + } + if (viewTypeToBe == ViewType.MAPPED && parentToBe.getPKColumns().isEmpty()) { + validateCreateViewCompilation(connection, parentToBe, columnDefs, pkConstraint); + } else if (where != null && viewTypeToBe == ViewType.UPDATABLE) { + rowKeyMatcher = + WhereOptimizer.getRowKeyMatcher(context, create.getTableName(), parentToBe, where); + } + verifyIfAnyParentHasIndexesAndViewExtendsPk(parentToBe, columnDefs, pkConstraint); + } + final ViewType viewType = viewTypeToBe; + final String viewStatement = viewStatementToBe; + final byte[][] viewColumnConstants = viewColumnConstantsToBe; + final BitSet isViewColumnReferenced = isViewColumnReferencedToBe; + List<ParseNode> splitNodes = create.getSplitNodes(); + final byte[][] splits = new byte[splitNodes.size()][]; + ImmutableBytesWritable ptr = context.getTempPtr(); + ExpressionCompiler expressionCompiler = new ExpressionCompiler(context); + for (int i = 0; i < splits.length; i++) { + ParseNode node = splitNodes.get(i); + if (node instanceof BindParseNode) { + context.getBindManager().addParamMetaData((BindParseNode) node, VARBINARY_DATUM); + } + if (node.isStateless()) { + Expression expression = node.accept(expressionCompiler); + if (expression.evaluate(null, ptr)) { + ; + splits[i] = ByteUtil.copyKeyBytesIfNecessary(ptr); + continue; + } + } + throw new SQLExceptionInfo.Builder(SQLExceptionCode.SPLIT_POINT_NOT_CONSTANT) + .setMessage("Node: " + node).build().buildException(); + } + final MetaDataClient client = new MetaDataClient(connection); + final PTable parent = parentToBe; + + return new CreateTableMutationPlan(context, client, finalCreate, splits, parent, viewStatement, + viewType, rowKeyMatcher, viewColumnConstants, isViewColumnReferenced, connection); + } + + /** + * Restrict view to be UPDATABLE if the view specification: 1. uses only the PK columns; 2. starts Review Comment: fix -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: issues-unsubscr...@phoenix.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org