package org.wonderdb.query.parser.jtree;
/*******************************************************************************
* Copyright 2013 Vilas Athavale
*
* Licensed 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.
*******************************************************************************/
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jboss.netty.buffer.ChannelBuffer;
import org.wonderdb.cache.impl.CacheEntryPinner;
import org.wonderdb.cluster.Shard;
import org.wonderdb.collection.StaticTableResultContent;
import org.wonderdb.expression.AndExpression;
import org.wonderdb.expression.BasicExpression;
import org.wonderdb.parser.jtree.QueryEvaluator;
import org.wonderdb.parser.jtree.SimpleNode;
import org.wonderdb.parser.jtree.SimpleNodeHelper;
import org.wonderdb.parser.jtree.Token;
import org.wonderdb.parser.jtree.UQLParserTreeConstants;
import org.wonderdb.query.executor.ScatterGatherQueryExecutor;
import org.wonderdb.query.parse.BaseDBQuery;
import org.wonderdb.query.parse.CollectionAlias;
import org.wonderdb.query.plan.AndQueryExecutor;
import org.wonderdb.query.plan.DataContext;
import org.wonderdb.query.plan.QueryPlan;
import org.wonderdb.query.plan.QueryPlanBuilder;
import org.wonderdb.schema.CollectionMetadata;
import org.wonderdb.schema.SchemaMetadata;
import org.wonderdb.schema.WonderDBFunction;
import org.wonderdb.types.ColumnNameMeta;
import org.wonderdb.types.DBType;
import org.wonderdb.types.RecordId;
import org.wonderdb.types.TableRecordMetadata;
import org.wonderdb.types.record.RecordManager;
import org.wonderdb.types.record.RecordManager.BlockAndRecord;
import org.wonderdb.types.record.TableRecord;
public class DBSelectQueryJTree extends BaseDBQuery {
protected Map<CollectionAlias, List<Integer>> selectColumnNames = new HashMap<CollectionAlias, List<Integer>>();
List<SimpleNode> selectStmt = null;
Map<String, CollectionAlias> fromMap = new HashMap<String, CollectionAlias>();
int type = -1;
protected Set<Object> pinnedBlocks = new HashSet<Object>();
public List<ResultSetColumn> resultsetColumns = new ArrayList<ResultSetColumn>();
AndExpression andExp = null;
public DBSelectQueryJTree(String q, SimpleNode query, SimpleNode selectStmt, int type, ChannelBuffer buffer) {
super(q, query, type, buffer);
QueryEvaluator qe = new QueryEvaluator(null, null);
this.selectStmt = qe.getSelectStmts(selectStmt);
fromMap = SimpleNodeHelper.getInstance().getFromMap(selectStmt);
this.type = type;
buildSelectColumnNames(fromMap);
buildResultSetColumnList();
SimpleNode node = SimpleNodeHelper.getInstance().getFirstNode(selectStmt, UQLParserTreeConstants.JJTFILTEREXPRESSION);
node = SimpleNodeHelper.getInstance().getFirstNode(node, UQLParserTreeConstants.JJTCOMPAREEQUATION);
if (node != null) {
List<BasicExpression> andList = SimpleNodeHelper.getInstance().buildAndExpressionList(node, new ArrayList<CollectionAlias>(fromMap.values()));
andExp = new AndExpression(andList);
}
}
public DBSelectQueryJTree(String q, SimpleNode query, Map<String, CollectionAlias> fromMap, Map<CollectionAlias, List<Integer>> selectColumnNames,
SimpleNode filterNode, int type, ChannelBuffer buffer ) {
super(q, query, type, buffer);
this.fromMap = fromMap;
this.type = type;
this.selectColumnNames = selectColumnNames;
SimpleNode node = filterNode;
node = SimpleNodeHelper.getInstance().getFirstNode(node, UQLParserTreeConstants.JJTCOMPAREEQUATION);
if (node != null) {
List<BasicExpression> andList = SimpleNodeHelper.getInstance().buildAndExpressionList(node, new ArrayList<CollectionAlias>(fromMap.values()));
andExp = new AndExpression(andList);
}
selectStmt = new ArrayList<SimpleNode>();
selectStmt.add(query);
}
public List<CollectionAlias> getFromList() {
return new ArrayList<CollectionAlias>(fromMap.values());
}
// public String getQuery() {
// return query;
// }
//
public AndExpression getAndExpression() {
return andExp;
}
public List<QueryPlan> getPlan(Shard shard) {
List<QueryPlan> planList = QueryPlanBuilder.getInstance().build(new ArrayList<CollectionAlias>(fromMap.values()), shard, andExp, pinnedBlocks);
return planList;
}
public List<List<ResultSetValue>> execute() {
if (selectStmt.size() == 1) {
ScatterGatherQueryExecutor sgqe = new ScatterGatherQueryExecutor(this);
return sgqe.selectQuery();
}
List<List<ResultSetValue>> retVal = new ArrayList<List<ResultSetValue>>();
for (int i = 0; i < selectStmt.size(); i++) {
DBSelectQueryJTree selectQ = new DBSelectQueryJTree(getQueryString(), null, selectStmt.get(i), type, buffer);
ScatterGatherQueryExecutor sgqe = new ScatterGatherQueryExecutor(selectQ);
List<List<ResultSetValue>> l = sgqe.selectQuery();
retVal.addAll(l);
}
return retVal;
}
public List<List<ResultSetValue>> executeLocal(Shard shard) {
List<List<ResultSetValue>> resultListList = new ArrayList<List<ResultSetValue>>();
try {
List<QueryPlan> planList = QueryPlanBuilder.getInstance().build(new ArrayList<CollectionAlias>(fromMap.values()), shard, andExp, pinnedBlocks);
List<Map<CollectionAlias, RecordId>> mapList = new ArrayList<Map<CollectionAlias,RecordId>>();
AndQueryExecutor.getInstance().executeTree(shard, planList, selectStmt.get(0), false, new ArrayList<CollectionAlias>(fromMap.values()), fromMap,
selectColumnNames, mapList, null, true);
DataContext dc = new DataContext();
List<ResultSetValue> resultList = new ArrayList<ResultSetValue>();
boolean isAgegate = false;
for (int i = 0; i < mapList.size(); i++) {
Map<CollectionAlias, RecordId> map = mapList.get(i);
Iterator<CollectionAlias> iter = map.keySet().iterator();
Set<Object> pinnedBlocks = new HashSet<Object>();
dc = new DataContext(dc);
while (iter.hasNext()) {
CollectionAlias ca = iter.next();
RecordId recId = map.get(ca);
TableRecordMetadata meta = (TableRecordMetadata) SchemaMetadata.getInstance().getTypeMetadata(ca.getCollectionName());
List<Integer> selectCols = selectColumnNames.get(ca);
BlockAndRecord bar = null;
try {
bar = RecordManager.getInstance().getTableRecordAndLock(recId, selectCols, meta, pinnedBlocks);
if (bar == null || bar.block == null || bar.record == null) {
continue;
}
dc.add(ca, new StaticTableResultContent((TableRecord) bar.record));
} finally {
if (bar != null && bar.block != null) {
CacheEntryPinner.getInstance().unpin(pinnedBlocks, pinnedBlocks);
}
}
}
if (AndQueryExecutor.filterTree(dc, selectStmt.get(0), fromMap)) {
if (!isAgegate) {
resultList = new ArrayList<ResultSetValue>();
resultListList.add(resultList);
} else {
resultList.clear();
}
for (int x = 0; x < resultsetColumns.size(); x++) {
ResultSetColumn rsc = resultsetColumns.get(x);
ResultSetValue rsv = new ResultSetValue();
if (rsc instanceof VirtualResultSetColumn) {
dc.processFunction(((VirtualResultSetColumn) rsc).function);
if (!isAgegate) {
isAgegate = ((VirtualResultSetColumn) rsc).function.isAggregate();
}
rsv.value = dc.getGlobalValue(((VirtualResultSetColumn) rsc).function.getColumnType());
rsv.columnName = ((VirtualResultSetColumn) rsc).columnAlias;
} else {
rsv.value = dc.getResultMap().get(rsc.ca).getValue(rsc.columnId);
rsv.columnName = rsc.resultColumnName;
}
rsv.ca = rsc.ca;
resultList.add(rsv);
}
}
}
return resultListList;
} finally {
CacheEntryPinner.getInstance().unpin(pinnedBlocks, pinnedBlocks);
}
}
public List<Map<CollectionAlias, TableRecord>> executeAndGetTableRecord(Shard shard) {
List<Map<CollectionAlias, TableRecord>> retList = new ArrayList<Map<CollectionAlias,TableRecord>>();
// List<Map<CollectionAlias, RecordId>> resultList = new ArrayList<Map<CollectionAlias,RecordId>>();
List<QueryPlan> planList = QueryPlanBuilder.getInstance().build(new ArrayList<CollectionAlias>(fromMap.values()), shard, andExp, pinnedBlocks);
List<Map<CollectionAlias, RecordId>> mapList = new ArrayList<Map<CollectionAlias,RecordId>>();
AndQueryExecutor.getInstance().executeTree(shard, planList, selectStmt.get(0), false, new ArrayList<CollectionAlias>(fromMap.values()), fromMap, selectColumnNames, mapList, null, true);
CacheEntryPinner.getInstance().unpin(pinnedBlocks, pinnedBlocks);
for (Map<CollectionAlias, RecordId> map : mapList) {
for (CollectionAlias ca : map.keySet()) {
Map<CollectionAlias, TableRecord> m1 = new HashMap<CollectionAlias, TableRecord>();
retList.add(m1);
TableRecordMetadata meta = (TableRecordMetadata) SchemaMetadata.getInstance().getTypeMetadata(ca.getCollectionName());
RecordId recId = map.get(ca);
List<Integer> selectCols = selectColumnNames.get(ca);
BlockAndRecord bar = null;
try {
bar = RecordManager.getInstance().getTableRecordAndLock(recId, selectCols, meta, pinnedBlocks);
if (bar == null || bar.block == null || bar.record == null) {
continue;
}
m1.put(ca, (TableRecord) bar.record);
} finally {
CacheEntryPinner.getInstance().unpin(pinnedBlocks, pinnedBlocks);
}
}
}
return retList;
}
public List<Map<CollectionAlias, RecordId>> executeGetDC(Shard shard) {
List<Map<CollectionAlias, RecordId>> resultList = new ArrayList<Map<CollectionAlias,RecordId>>();
try {
List<QueryPlan> planList = QueryPlanBuilder.getInstance().build(new ArrayList<CollectionAlias>(fromMap.values()), shard, andExp, pinnedBlocks);
AndQueryExecutor.getInstance().executeTree(shard, planList, selectStmt.get(0), false, new ArrayList<CollectionAlias>(fromMap.values()), fromMap, selectColumnNames, resultList, null, true);
} catch (Exception e) {
e.printStackTrace();
} finally {
CacheEntryPinner.getInstance().unpin(pinnedBlocks, pinnedBlocks);
pinnedBlocks.clear();
}
return resultList;
}
private void buildSelectColumnNames(Map<String, CollectionAlias> map) {
List<SimpleNode> columnAliasList = new ArrayList<SimpleNode>();
SimpleNodeHelper.getInstance().getNodes(queryNode, UQLParserTreeConstants.JJTCOLUMNANDALIAS, columnAliasList);
buildSelectColumnNames(columnAliasList);
}
private void buildResultSetColumnList() {
SimpleNode node = SimpleNodeHelper.getInstance().getFirstNode(queryNode, UQLParserTreeConstants.JJTLITERALLIST);
buildResultSetColumnList(node);
}
private void buildResultSetColumnList(SimpleNode literalListNode) {
List<SimpleNode> list = new ArrayList<SimpleNode>();
SimpleNodeHelper.getInstance().getNodes(literalListNode, UQLParserTreeConstants.JJTCOLUMNANDALIAS, list);
for (int i = 0; i < list.size(); i++) {
SimpleNode node = list.get(i);
Token first = node.jjtGetFirstToken();
Token last = node.jjtGetLastToken();
String columnName = last.image;
String alias = "";
if (first != last) {
alias = first.image;
}
if ("*".equals(columnName)) {
buildAllResultSetColumns();
return;
}
CollectionAlias ca = fromMap.get(alias);
CollectionMetadata colMeta = SchemaMetadata.getInstance().getCollectionMetadata(ca.getCollectionName());
int colId = colMeta.getColumnId(columnName);
ResultSetColumn rsc = new ResultSetColumn();
rsc.ca = ca;
rsc.columnId = colId;
rsc.resultColumnName = colMeta.getColumnName(colId);
resultsetColumns.add(rsc);
}
}
private void buildAllResultSetColumns() {
Iterator<CollectionAlias> iter = fromMap.values().iterator();
while (iter.hasNext()) {
CollectionAlias ca = iter.next();
CollectionMetadata colMeta = SchemaMetadata.getInstance().getCollectionMetadata(ca.getCollectionName());
List<ColumnNameMeta> list = colMeta.getCollectionColumns();
for (int i = 0; i < list.size(); i++) {
ColumnNameMeta cnm = list.get(i);
ResultSetColumn rsc = new ResultSetColumn();
rsc.ca = ca;
rsc.columnId = cnm.getCoulmnId();
rsc.resultColumnName = cnm.getColumnName();
resultsetColumns.add(rsc);
}
}
}
private void buildSelectColumnNames(List<SimpleNode> list) {
for (int i = 0; i < list.size(); i++) {
SimpleNode node = list.get(i);
Token first = node.jjtGetFirstToken();
Token last = node.jjtGetLastToken();
String columnName = last.image;
String alias = "";
if (first != last) {
alias = first.image;
}
if ("*".equals(columnName)) {
buildAllSelectColumns();
return;
}
CollectionAlias ca = fromMap.get(alias);
CollectionMetadata colMeta = SchemaMetadata.getInstance().getCollectionMetadata(ca.getCollectionName());
int colId = colMeta.getColumnId(columnName);
List<Integer> colIdList = selectColumnNames.get(ca);
if (colIdList == null) {
colIdList = new ArrayList<Integer>();
selectColumnNames.put(ca, colIdList);
}
colIdList.add(colId);
}
}
private void buildAllSelectColumns() {
Iterator<CollectionAlias> iter = fromMap.values().iterator();
while (iter.hasNext()) {
CollectionAlias ca = iter.next();
List<Integer> colIdList = selectColumnNames.get(ca);
if (colIdList == null) {
colIdList = new ArrayList<Integer>();
selectColumnNames.put(ca, colIdList);
}
CollectionMetadata colMeta = SchemaMetadata.getInstance().getCollectionMetadata(ca.getCollectionName());
List<ColumnNameMeta> list = colMeta.getCollectionColumns();
for (int i = 0; i < list.size(); i++) {
ColumnNameMeta cnm = list.get(i);
colIdList.add(cnm.getCoulmnId());
}
}
}
public static String extractColumnName(String cName) {
String[] s = cName.split("://");
if (s.length == 1) {
return s[0];
}
if (s.length == 2) {
String x = s[1];
String x1[] = x.split("/");
String x2[] = x1[0].split(":");
return x2[0];
}
return null;
}
public static String extractRootNode(String cName) {
String[] s = cName.split("://");
if (s.length == 1) {
return s[0];
}
if (s.length == 2) {
String x = s[1];
String x1[] = x.split("/");
String x2[] = x1[0].split(":");
if (x2.length == 2) {
return x2[1];
}
}
return null;
}
@Override
public AndExpression getExpression() {
return andExp;
}
public static class ResultSetColumn {
public CollectionAlias ca;
public int columnId;
public String path;
public String resultColumnName;
}
public static class VirtualResultSetColumn extends ResultSetColumn {
public String columnAlias;
public SimpleNode node = null;
public WonderDBFunction function = null;
}
public static class ResultSetValue {
public CollectionAlias ca;
public String columnName;
public DBType value;
}
}