/*
* JBoss, Home of Professional Open Source.
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership. Some portions may be licensed
* to Red Hat, Inc. under one or more contributor license agreements.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*/
package org.teiid.translator.hbase;
import static org.teiid.language.SQLConstants.Reserved.AS;
import static org.teiid.language.SQLConstants.Reserved.DISTINCT;
import static org.teiid.language.SQLConstants.Reserved.FROM;
import static org.teiid.language.SQLConstants.Reserved.HAVING;
import static org.teiid.language.SQLConstants.Reserved.INTO;
import static org.teiid.language.SQLConstants.Reserved.SELECT;
import static org.teiid.language.SQLConstants.Reserved.WHERE;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.phoenix.schema.PColumn;
import org.apache.phoenix.schema.PDataType;
import org.apache.phoenix.schema.PName;
import org.apache.phoenix.schema.PTable;
import org.teiid.core.types.BinaryType;
import org.teiid.core.types.BlobType;
import org.teiid.core.types.ClobType;
import org.teiid.core.types.XMLType;
import org.teiid.language.Argument;
import org.teiid.language.ColumnReference;
import org.teiid.language.DerivedColumn;
import org.teiid.language.ExpressionValueSource;
import org.teiid.language.Insert;
import org.teiid.language.Literal;
import org.teiid.language.NamedTable;
import org.teiid.language.Select;
import org.teiid.language.TableReference;
import org.teiid.language.SQLConstants.Tokens;
import org.teiid.language.visitor.SQLStringVisitor;
import org.teiid.metadata.AbstractMetadataRecord;
import org.teiid.metadata.Column;
import org.teiid.metadata.Table;
import org.teiid.translator.ExecutionContext;
import org.teiid.translator.hbase.phoenix.PColumnTeiidImpl;
import org.teiid.translator.hbase.phoenix.PNameTeiidImpl;
import org.teiid.translator.hbase.phoenix.PTableTeiidImpl;
import org.teiid.translator.hbase.phoenix.PhoenixUtils;
public class SQLConversionVisitor extends SQLStringVisitor implements SQLStringVisitor.Substitutor {
public static final String INSERT = "UPSERT";
private HBaseExecutionFactory executionFactory ;
private ExecutionContext context ;
private boolean replaceWithBinding = false;
// used to map hbase table to phoenix
// private PTable ptable;
private boolean prepared;
private List preparedValues = new ArrayList();
private Map<Column, PColumn> columnsMap = new HashMap<Column, PColumn> ();
private Map<Table, PTable> tablesMap = new HashMap<Table, PTable> ();
private List<String> mappingDDLlist = new ArrayList<String>();
// private String mappingDDL;
public SQLConversionVisitor(HBaseExecutionFactory ef) {
this.executionFactory = ef;
this.prepared = executionFactory.usePreparedStatements();
}
public void setExecutionContext(ExecutionContext context) {
this.context = context;
}
List getPreparedValues() {
return this.preparedValues;
}
public boolean isPrepared() {
return prepared;
}
public void setPrepared(boolean prepared) {
this.prepared = prepared;
}
public List<String> getMappingDDLList() {
return mappingDDLlist;
}
@Override
public void visit(Select obj) {
if (obj.getFrom() != null && !obj.getFrom().isEmpty()) {
phoenixTableMapping(obj.getFrom());
}
if (obj.getWith() != null) {
append(obj.getWith());
}
buffer.append(SELECT).append(Tokens.SPACE);
if (obj.isDistinct()) {
buffer.append(DISTINCT).append(Tokens.SPACE);
}
if (useSelectLimit() && obj.getLimit() != null) {
append(obj.getLimit());
buffer.append(Tokens.SPACE);
}
append(obj.getDerivedColumns());
if (obj.getFrom() != null && !obj.getFrom().isEmpty()) {
buffer.append(Tokens.SPACE).append(FROM).append(Tokens.SPACE);
append(obj.getFrom());
// buffer.append(Tokens.SPACE).append(FROM).append(Tokens.SPACE);
// buffer.append(ptable.getTableName().getString()).append(Tokens.SPACE).append(AS).append(Tokens.SPACE).append(ptable.getName().getString());
}
if (obj.getWhere() != null) {
buffer.append(Tokens.SPACE)
.append(WHERE)
.append(Tokens.SPACE);
append(obj.getWhere());
}
if (obj.getGroupBy() != null) {
buffer.append(Tokens.SPACE);
append(obj.getGroupBy());
}
if (obj.getHaving() != null) {
buffer.append(Tokens.SPACE)
.append(HAVING)
.append(Tokens.SPACE);
append(obj.getHaving());
}
if (obj.getOrderBy() != null) {
buffer.append(Tokens.SPACE);
append(obj.getOrderBy());
}
if (!useSelectLimit() && obj.getLimit() != null) {
buffer.append(Tokens.SPACE);
append(obj.getLimit());
}
}
@Override
public void visit(Insert obj) {
phoenixTableMapping(obj.getTable());
buffer.append(INSERT).append(Tokens.SPACE);
buffer.append(INTO).append(Tokens.SPACE);
PTable ptable = tablesMap.get(obj.getTable().getMetadataObject());
buffer.append(ptable.getTableName().getString());
buffer.append(Tokens.SPACE).append(Tokens.LPAREN);
this.shortNameOnly = true;
append(obj.getColumns());
this.shortNameOnly = false;
buffer.append(Tokens.RPAREN);
buffer.append(Tokens.SPACE);
append(obj.getValueSource());
}
private void phoenixTableMapping(NamedTable namedtable) {
Table table = namedtable.getMetadataObject();
String tname = table.getProperty(HBaseMetadataProcessor.TABLE, false);
PName tableName = PNameTeiidImpl.makePName(tname);
List<PColumn> columns = new ArrayList<PColumn>();
for(Column column : table.getColumns()) {
PColumn pcolumn;
String cell = column.getProperty(HBaseMetadataProcessor.CELL, false);
String[] qua = cell.split(":");
if(qua.length != 2) {
pcolumn = new PColumnTeiidImpl(PNameTeiidImpl.makePName(cell), null, convertType(column));
} else {
pcolumn = new PColumnTeiidImpl(PNameTeiidImpl.makePName(qua[1]), PNameTeiidImpl.makePName(qua[0]), convertType(column));
}
columns.add(pcolumn);
columnsMap.put(column, pcolumn);
}
PTable ptable = PTableTeiidImpl.makeTable(tableName, columns);
tablesMap.put(table, ptable);
mappingDDLlist.add(PhoenixUtils.hbaseTableMappingDDL(ptable));
}
private void phoenixTableMapping(List<TableReference> list) {
for(TableReference reference : list) {
if(reference instanceof NamedTable) {
NamedTable namedtable = (NamedTable) reference;
phoenixTableMapping(namedtable);
}
}
}
/*
* Convert teiid type to phoenix type, the following types not support by phoenix
* object -> Any
* blob -> java.sql.Blob
* clob -> java.sql.Clob
* xml -> java.sql.SQLXML
*/
private PDataType convertType(Column column) {
Class<?> clas = column.getJavaType();
if(clas.equals(String.class)){
return PDataType.VARCHAR;
} else if (clas.equals(BinaryType.class)){
return PDataType.VARBINARY;
} else if (clas.equals(Character.class)){
return PDataType.VARCHAR;
} else if (clas.equals(Boolean.class)){
return PDataType.BOOLEAN;
} else if (clas.equals(Byte.class)){
return PDataType.TINYINT;
} else if (clas.equals(Short.class)){
return PDataType.SMALLINT;
} else if (clas.equals(Integer.class)){
return PDataType.INTEGER;
} else if (clas.equals(Long.class)){
return PDataType.LONG;
} else if (clas.equals(BigInteger.class)){
return PDataType.LONG;
} else if (clas.equals(Float.class)){
return PDataType.FLOAT;
} else if (clas.equals(Double.class)){
return PDataType.DOUBLE;
} else if (clas.equals(BigDecimal.class)){
return PDataType.DECIMAL;
} else if (clas.equals(Date.class)){
return PDataType.DATE;
} else if (clas.equals(Time.class)){
return PDataType.TIME;
} else if (clas.equals(Timestamp.class)){
return PDataType.TIMESTAMP;
} else if (clas.equals(BlobType.class)){
return PDataType.UNSIGNED_LONG_ARRAY;
} else if (clas.equals(ClobType.class)){
return PDataType.UNSIGNED_LONG_ARRAY;
} else if (clas.equals(XMLType.class)){
return PDataType.UNSIGNED_LONG_ARRAY;
} else if (clas.equals(Object.class)){
return PDataType.UNSIGNED_LONG_ARRAY;
}
return null;
}
@Override
public void visit(Literal obj) {
if(isPrepared() && ((replaceWithBinding && obj.isBindEligible()) || executionFactory.isBindEligible(obj))){
buffer.append(UNDEFINED_PARAM);
preparedValues.add(obj);
} else {
super.visit(obj);
}
}
@Override
public void visit(ExpressionValueSource obj) {
replaceWithBinding = true;
super.visit(obj);
}
@Override
public void visit(DerivedColumn obj) {
replaceWithBinding = false;
append(obj.getExpression());
}
@Override
public void visit(ColumnReference obj) {
String groupName = getGroupName(obj, !shortNameOnly);
Column column = obj.getMetadataObject();
PColumn pcolumn = columnsMap.get(column);
if(null != groupName){
buffer.append(groupName + Tokens.DOT + pcolumn.getName().getString());
} else {
buffer.append(pcolumn.getName().getString());
}
}
@Override
public void visit(NamedTable obj) {
PTable ptable = tablesMap.get(obj.getMetadataObject());
buffer.append(ptable.getTableName().getString());
String groupName = getGroupName(obj, !shortNameOnly);
if (groupName != null) {
buffer.append(Tokens.SPACE);
if (useAsInGroupAlias()){
buffer.append(AS).append(Tokens.SPACE);
}
buffer.append(groupName);
}
}
private String getGroupName(NamedTable group, boolean qualify) {
String groupName = null;
if (group != null && qualify) {
if(group.getCorrelationName() != null) {
groupName = group.getCorrelationName();
} else {
AbstractMetadataRecord groupID = group.getMetadataObject();
if(groupID != null) {
groupName = getName(groupID);
} else {
groupName = group.getName();
}
}
}
return groupName;
}
private String getGroupName(ColumnReference obj, boolean qualify){
return getGroupName(obj.getTable(), qualify);
}
public String getSQL(){
return buffer.toString();
}
@Override
public void substitute(Argument arg, StringBuilder builder, int index) {
// TODO Auto-generated method stub
}
}