Skip to content

Commit

Permalink
Completed the implementation of the org.olap4j.query API
Browse files Browse the repository at this point in the history
git-svn-id: https://olap4j.svn.sourceforge.net/svnroot/olap4j/trunk@74 c6a108a4-781c-0410-a6c6-c2d559e19af0
  • Loading branch information
Will Gorman committed Feb 13, 2008
1 parent 1b5c317 commit 81a26e5
Show file tree
Hide file tree
Showing 8 changed files with 606 additions and 33 deletions.
9 changes: 9 additions & 0 deletions src/org/olap4j/mdx/SelectNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.olap4j.type.Type;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

Expand Down Expand Up @@ -86,6 +87,14 @@ public Type getType() {
return null;
}

public String toString() {
StringWriter sw = new StringWriter();
ParseTreeWriter pw = new ParseTreeWriter(new PrintWriter(sw));
unparse(pw);
sw.flush();
return sw.toString();
}

public void unparse(ParseTreeWriter writer) {
final PrintWriter pw = writer.getPrintWriter();
if (!withList.isEmpty()) {
Expand Down
235 changes: 224 additions & 11 deletions src/org/olap4j/query/Query.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,14 @@
import org.olap4j.metadata.Dimension;
import org.olap4j.metadata.Member;
import org.olap4j.*;
import org.olap4j.mdx.AxisNode;
import org.olap4j.mdx.CallNode;
import org.olap4j.mdx.CubeNode;
import org.olap4j.mdx.IdentifierNode;
import org.olap4j.mdx.MemberNode;
import org.olap4j.mdx.ParseTreeNode;
import org.olap4j.mdx.SelectNode;
import org.olap4j.mdx.Syntax;

import java.util.*;
import java.sql.SQLException;
Expand Down Expand Up @@ -67,7 +74,7 @@ public Query(String name, Cube cube) throws SQLException {
* Returns the MDX parse tree behind this Query.
*/
public SelectNode getSelect() {
throw new UnsupportedOperationException();
return new Olap4jNodeConverter().toOlap4j(this);
}

public Cube getCube() {
Expand All @@ -86,14 +93,17 @@ public void swapAxes() {
if (axes.size() != 4) {
throw new IllegalArgumentException();
}
List<QueryDimension> tmp = new ArrayList<QueryDimension>();
QueryAxis columnsAxis = axes.get(Axis.COLUMNS);
QueryAxis rowsAxis = axes.get(Axis.ROWS);
tmp.addAll(this.across.getDimensions());
columnsAxis.getDimensions().clear();
columnsAxis.getDimensions().addAll(rowsAxis.getDimensions());
rowsAxis.getDimensions().clear();
rowsAxis.getDimensions().addAll(tmp);
List<QueryDimension> tmpAcross = new ArrayList<QueryDimension>();
tmpAcross.addAll(across.getDimensions());

List<QueryDimension> tmpDown = new ArrayList<QueryDimension>();
tmpDown.addAll(down.getDimensions());

across.getDimensions().clear();
down.getDimensions().clear();

across.getDimensions().addAll(tmpDown);
down.getDimensions().addAll(tmpAcross);
}

public Map<Axis, QueryAxis> getAxes() {
Expand Down Expand Up @@ -128,9 +138,8 @@ public boolean validate() throws OlapException {

public CellSet execute() throws OlapException {
SelectNode mdx = getSelect();
String mdxString = mdx.toString();
OlapStatement olapStatement = connection.createStatement();
return olapStatement.executeOlapQuery(mdxString);
return olapStatement.executeOlapQuery(mdx);
}

public String getName() {
Expand All @@ -144,6 +153,210 @@ public Locale getLocale() {
public SelectionFactory getSelectionFactory() {
return selectionFactory;
}

private static class Olap4jNodeConverter {

public SelectNode toOlap4j(Query query) {
List<IdentifierNode> list = Collections.emptyList();
List<ParseTreeNode> withList = Collections.emptyList();
List<QueryAxis> axisList = new ArrayList<QueryAxis>();
axisList.add(query.getAxes().get(Axis.COLUMNS));
axisList.add(query.getAxes().get(Axis.ROWS));

return new SelectNode(
null,
withList,
toOlap4j(axisList),
new CubeNode(
null,
query.getCube()),
query.getAxes().containsKey(Axis.FILTER)
? null
: toOlap4j(query.getAxes().get(Axis.FILTER)),
list);
}

private CallNode generateSetCall(ParseTreeNode... args) {
final CallNode callNode = new CallNode(
null,
"{}",
Syntax.Braces,
args
);

return callNode;
}

private CallNode generateListSetCall(List<ParseTreeNode> cnodes) {
final CallNode callNode = new CallNode(
null,
"{}",
Syntax.Braces,
cnodes
);
return callNode;
}

private CallNode generateListTupleCall(List<ParseTreeNode> cnodes) {
final CallNode callNode = new CallNode(
null,
"()",
Syntax.Parentheses,
cnodes
);
return callNode;
}

protected CallNode getMemberSet(QueryDimension dimension) {
final CallNode cnode = new CallNode(
null,
"{}",
Syntax.Braces,
toOlap4j(dimension)
);
return cnode;
}

protected CallNode crossJoin(QueryDimension dim1, QueryDimension dim2) {
return new CallNode(
null,
"CrossJoin",
Syntax.Function,
getMemberSet(dim1),
getMemberSet(dim2));
}

//
// This method merges the selections into a single
// MDX axis selection. Right now we do a simple
// crossjoin
//
private AxisNode toOlap4j(QueryAxis axis) {
CallNode callNode = null;
int numDimensions = axis.getDimensions().size();
if( axis.getLocation() == Axis.FILTER ) {
// need a tuple
// need a crossjoin
List<ParseTreeNode> members = new ArrayList<ParseTreeNode>();
for( int dimNo = 0; dimNo < numDimensions; dimNo++ ) {
QueryDimension dimension =
axis.getDimensions().get( dimNo );
if( dimension.getSelections().size() == 1 ) {
members.addAll(toOlap4j(dimension));
}
}
callNode = generateListTupleCall(members);
} else if( numDimensions == 1 ) {
QueryDimension dimension = axis.getDimensions().get( 0 );
List<ParseTreeNode> members = toOlap4j(dimension);
callNode = generateListSetCall(members);
} else if( numDimensions == 2 ) {
callNode =
crossJoin( axis.getDimensions().get(0),
axis.getDimensions().get(1));
} else {
// need a longer crossjoin
// start from the back of the list;
List<QueryDimension> dims = axis.getDimensions();
callNode = getMemberSet(dims.get(dims.size() - 1));
for( int i = dims.size() - 2; i >= 0; i-- ) {
CallNode memberSet = getMemberSet(dims.get(i));
callNode = new CallNode(
null,
"CrossJoin",
Syntax.Function,
memberSet,
callNode);
}
}
return new AxisNode(
null,
false,
axis.getLocation(),
new ArrayList<IdentifierNode>(),
callNode);

}

private List<ParseTreeNode> toOlap4j(QueryDimension dimension) {
List<ParseTreeNode> members = new ArrayList<ParseTreeNode>();
for (Selection selection : dimension.getSelections()) {
members.add(toOlap4j(selection));
}
return members;
}

private ParseTreeNode toOlap4j(Selection selection) {
try {
return toOlap4j(selection.getMember(), selection.getOperator());
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

private ParseTreeNode toOlap4j(Member member, Selection.Operator oper) {
ParseTreeNode node = null;
try {
switch(oper) {
case MEMBER:
node = new MemberNode(null, member);
break;
case SIBLINGS:
node = new CallNode(
null,
"Siblings",
Syntax.Property,
new MemberNode(null, member)
);
break;
case CHILDREN:
node = new CallNode(
null,
"Children",
Syntax.Property,
new MemberNode(null, member)
);
break;
case INCLUDE_CHILDREN:
node = generateSetCall(
new MemberNode(null, member),
toOlap4j(member, Selection.Operator.CHILDREN)
);
break;
case DESCENDANTS:
node = new CallNode(
null,
"Descendants",
Syntax.Function,
new MemberNode(null, member)
);
break;
case ANCESTORS:
node = new CallNode(
null,
"Ascendants",
Syntax.Function,
new MemberNode(null, member)
);
break;
default:
System.out.println("NOT IMPLEMENTED: " + oper);
}
} catch (Exception e) {
e.printStackTrace();
}
return node;
}

private List<AxisNode> toOlap4j(List<QueryAxis> axes) {
final ArrayList<AxisNode> axisList = new ArrayList<AxisNode>();
for (QueryAxis axis : axes) {
axisList.add(toOlap4j(axis));
}
return axisList;
}
}
}

// End Query.java
9 changes: 8 additions & 1 deletion src/org/olap4j/query/QueryAxis.java
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,19 @@ public QueryDimension set(int index, QueryDimension dimension) {
}

public void add(int index, QueryDimension dimension) {
if (this.contains(dimension)) {
throw new IllegalStateException("dimension already on this axis");
}
if (dimension.getAxis() != null) {
// careful! potential for loop
dimension.getAxis().getDimensions().remove(dimension);
}
dimension.setAxis(QueryAxis.this);
list.add(index, dimension);
if (index >= list.size()) {
list.add(dimension);
} else {
list.add(index, dimension);
}
}

public QueryDimension remove(int index) {
Expand Down
Loading

0 comments on commit 81a26e5

Please sign in to comment.