/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.huawei.streaming.cql.semanticanalyzer;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.Lists;
import com.huawei.streaming.api.streams.Column;
import com.huawei.streaming.api.streams.Schema;
import com.huawei.streaming.cql.exception.SemanticAnalyzerException;
import com.huawei.streaming.cql.semanticanalyzer.analyzecontext.AnalyzeContext;
import com.huawei.streaming.cql.semanticanalyzer.analyzecontext.SelectClauseAnalyzeContext;
import com.huawei.streaming.cql.semanticanalyzer.parsecontextwalker.PropertyExpressionWalker;
import com.huawei.streaming.cql.semanticanalyzer.parsecontextwalker.PropertyValueExpressionWalker;
import com.huawei.streaming.cql.semanticanalyzer.parser.context.AtomExpressionContext;
import com.huawei.streaming.cql.semanticanalyzer.parser.context.BaseExpressionParseContext;
import com.huawei.streaming.cql.semanticanalyzer.parser.context.ExpressionContext;
import com.huawei.streaming.cql.semanticanalyzer.parser.context.FieldExpressionContext;
import com.huawei.streaming.cql.semanticanalyzer.parser.context.ParseContext;
import com.huawei.streaming.cql.semanticanalyzer.parser.context.SelectClauseContext;
import com.huawei.streaming.cql.semanticanalyzer.parser.context.SelectItemContext;
import com.huawei.streaming.cql.semanticanalyzer.parser.context.StreamAllColumnsContext;
import com.huawei.streaming.exception.ErrorCode;
/**
* select子句语法分析
*
*/
public class SelectClauseAnalyzer extends BaseAnalyzer
{
private static final Logger LOG = LoggerFactory.getLogger(SelectClauseAnalyzer.class);
private static final String DEFAULT_SCHEMA_NAME = "tmpschema";
private SelectClauseAnalyzeContext selectAnalyzeContext;
private SelectClauseContext selectClauseParseConext;
private List<BaseExpressionParseContext> selectExpressions = null;
private Schema selectOutputSchema;
/**
* <默认构造函数>
*
*/
public SelectClauseAnalyzer(ParseContext parseContext)
throws SemanticAnalyzerException
{
super(parseContext);
selectClauseParseConext = (SelectClauseContext)parseContext;
selectExpressions = Lists.newArrayList();
selectOutputSchema = new Schema(DEFAULT_SCHEMA_NAME);
}
/**
* {@inheritDoc}
*/
@Override
public AnalyzeContext analyze()
throws SemanticAnalyzerException
{
parseSelectItems();
createSelectExpressionDescs();
selectAnalyzeContext.setOutputSchema(selectOutputSchema);
return selectAnalyzeContext;
}
/**
* {@inheritDoc}
*/
@Override
protected void createAnalyzeContext()
{
selectAnalyzeContext = new SelectClauseAnalyzeContext();
}
/**
* {@inheritDoc}
*/
@Override
protected AnalyzeContext getAnalyzeContext()
{
return selectAnalyzeContext;
}
private void parseSelectItems()
throws SemanticAnalyzerException
{
selectAnalyzeContext.setDistinct(selectClauseParseConext.isDistinct());
for (SelectItemContext selectItem : selectClauseParseConext.getSelectItems())
{
parseSelectItem(selectItem);
}
}
private void parseSelectItem(SelectItemContext selectItem)
throws SemanticAnalyzerException
{
boolean selectStar = selectItem.getExpression().getAllColumns() != null;
if (selectStar)
{
parseStarExpression(selectItem);
}
else
{
parseExpression(selectItem);
}
}
private void parseExpression(SelectItemContext selectItem)
throws SemanticAnalyzerException
{
selectExpressions.add(selectItem.getExpression().getExpression());
addColumnForSelectItem(selectItem);
}
private void createSelectExpressionDescs()
throws SemanticAnalyzerException
{
for (BaseExpressionParseContext exps : selectExpressions)
{
selectAnalyzeContext.addExpressionDesc(exps.createExpressionDesc(getAllSchemas()));
}
}
private void addColumnForSelectItem(SelectItemContext selectItem)
throws SemanticAnalyzerException
{
if (selectItem.getExpression().getAlias() != null)
{
addColumnsForAlias(selectItem);
}
else
{
addColumnForExpression(selectItem);
}
}
private void addColumnForExpression(SelectItemContext selectItem)
{
ExpressionContext expression = selectItem.getExpression().getExpression();
String newColName = createColumnNameForPropertyValueExpression(expression);
if (newColName == null)
{
newColName = createNewName(selectOutputSchema);
}
selectOutputSchema.addCol(new Column(newColName, null));
}
private void addColumnsForAlias(SelectItemContext selectItem)
throws SemanticAnalyzerException
{
for (String alia : selectItem.getExpression().getAlias().getAlias())
{
if (selectOutputSchema.isAttributeExist(alia))
{
alia = renameNewName(selectOutputSchema, alia);
}
//输出schema的类型,后面完成了表达式解析之后再计算
selectOutputSchema.addCol(new Column(alia, null));
//设置原始列对应schema的列别名
resetColumnAlias(selectItem, alia);
}
}
/*
* 如果是propertyValueExpression,则将原始的列名称赋给现在的列名称
*/
private String createColumnNameForPropertyValueExpression(ExpressionContext exp)
{
PropertyValueExpressionWalker walker = new PropertyValueExpressionWalker();
exp.walk(walker);
String newColName = walker.getColumnName();
if (newColName != null)
{
if (selectOutputSchema.isAttributeExist(newColName))
{
newColName = renameNewName(selectOutputSchema, newColName);
}
}
return newColName;
}
private void resetColumnAlias(SelectItemContext selectItem, String alia)
throws SemanticAnalyzerException
{
PropertyExpressionWalker walker = new PropertyExpressionWalker();
selectItem.getExpression().getExpression().walk(walker);
String columnName = walker.getColumnName();
String streamName = walker.getStreamName();
if (columnName == null)
{
return;
}
if (streamName != null)
{
Schema schema = getSchemaByName(streamName);
List<Column> columns = BaseAnalyzer.getAttributeByName(columnName, schema, getAllSchemas());
validateMoreColumnError(columns);
validateNonColumns(columnName, schema, columns);
columns.get(0).setAlias(alia);
}
else
{
List<Column> columns = BaseAnalyzer.getAttributeByName(columnName, getAllSchemas());
validateMoreColumnError(columns);
validateNonColumns(columnName, columns);
columns.get(0).setAlias(alia);
}
}
private void validateNonColumns(String columnName, List<Column> columns)
throws SemanticAnalyzerException
{
if (columns.size() == 0)
{
SemanticAnalyzerException exception =
new SemanticAnalyzerException(ErrorCode.SEMANTICANALYZE_NO_COLUMN_ALLSTREAM, columnName);
LOG.error("Can't find column in streams.", exception);
throw exception;
}
}
private void validateNonColumns(String columnName, Schema schema, List<Column> columns)
throws SemanticAnalyzerException
{
if (columns.size() == 0)
{
SemanticAnalyzerException exception =
new SemanticAnalyzerException(ErrorCode.SEMANTICANALYZE_NO_COLUMN, columnName, schema.getId());
LOG.error("Can't find column in stream.", exception);
throw exception;
}
}
private void validateMoreColumnError(List<Column> columns)
throws SemanticAnalyzerException
{
if (columns.size() > 1)
{
SemanticAnalyzerException exception =
new SemanticAnalyzerException(ErrorCode.SEMANTICANALYZE_DUPLICATE_COLUMN_ALLSTREAM, columns.get(0)
.getName());
LOG.error("One column in multi stream.", exception);
throw exception;
}
}
private void parseStarExpression(SelectItemContext selectItem)
throws SemanticAnalyzerException
{
if (isStarWithStreamNameExpression(selectItem.getExpression().getAllColumns()))
{
parseStarWithStreamNameExpression(selectItem);
}
else
{
parseStarWithOutStreamNameExpression();
}
}
private void parseStarWithOutStreamNameExpression()
{
for (Schema schema : getAllSchemas())
{
for (Column column : schema.getCols())
{
String colName = column.getName();
if (selectOutputSchema.isAttributeExist(colName))
{
colName = renameNewName(selectOutputSchema, colName);
}
selectOutputSchema.addCol(new Column(colName, null));
selectExpressions.add(createFieldExpression(schema.getId(), column.getName()));
}
}
}
private void parseStarWithStreamNameExpression(SelectItemContext selectItem)
throws SemanticAnalyzerException
{
String schemaName = selectItem.getExpression().getAllColumns().getStreamName();
List<Column> attrsInSchema = getAttributes(getSchemaByName(schemaName));
for (int i = 0; i < attrsInSchema.size(); i++)
{
String colName = attrsInSchema.get(i).getName();
addColumnForOutputSchema(colName);
selectExpressions.add(createFieldExpression(schemaName, colName));
}
}
private void addColumnForOutputSchema(final String colName)
{
String newColName = colName;
if (selectOutputSchema.isAttributeExist(newColName))
{
newColName = renameNewName(selectOutputSchema, newColName);
}
selectOutputSchema.addCol(new Column(newColName, null));
}
private FieldExpressionContext createFieldExpression(String schemaName, String columnName)
{
AtomExpressionContext atomExp = craeteAtomExpression(columnName);
FieldExpressionContext fexp = new FieldExpressionContext();
fexp.setStreamNameOrAlias(schemaName);
fexp.setAtomExpression(atomExp);
return fexp;
}
private AtomExpressionContext craeteAtomExpression(String columnName)
{
AtomExpressionContext atomExp = new AtomExpressionContext();
atomExp.setColumnName(columnName);
return atomExp;
}
/**
* 是否包含了Schema名称
*
*/
private boolean isStarWithStreamNameExpression(StreamAllColumnsContext allColumns)
{
return allColumns.getStreamName() != null;
}
}