001 /* 002 // $Id: SelectNode.java 233 2009-05-12 06:05:49Z jhyde $ 003 // This software is subject to the terms of the Eclipse Public License v1.0 004 // Agreement, available at the following URL: 005 // http://www.eclipse.org/legal/epl-v10.html. 006 // Copyright (C) 2007-2008 Julian Hyde 007 // All Rights Reserved. 008 // You must accept the terms of that agreement to use this software. 009 */ 010 package org.olap4j.mdx; 011 012 import org.olap4j.type.Type; 013 import org.olap4j.Axis; 014 015 import java.io.PrintWriter; 016 import java.io.StringWriter; 017 import java.util.*; 018 019 /** 020 * Parse tree model for an MDX SELECT statement. 021 * 022 * @author jhyde 023 * @version $Id: SelectNode.java 233 2009-05-12 06:05:49Z jhyde $ 024 * @since Jun 4, 2007 025 */ 026 public class SelectNode implements ParseTreeNode { 027 private final ParseRegion region; 028 private final List<ParseTreeNode> withList; 029 private final List<AxisNode> axisList; 030 private final AxisNode filterAxis; 031 private final List<IdentifierNode> cellPropertyList; 032 private ParseTreeNode from; 033 034 /** 035 * Creates a SelectNode. 036 * 037 * @param region Region of source code from which this node was created 038 * @param withList List of members and sets defined in this query using 039 * a <code>WITH</code> clause 040 * @param axisList List of axes 041 * @param from Name of cube 042 * @param filterAxis Filter axis 043 * @param cellPropertyList List of properties 044 */ 045 public SelectNode( 046 ParseRegion region, 047 List<ParseTreeNode> withList, 048 List<AxisNode> axisList, 049 ParseTreeNode from, 050 AxisNode filterAxis, 051 List<IdentifierNode> cellPropertyList) 052 { 053 this.region = region; 054 this.withList = withList; 055 this.axisList = axisList; 056 this.from = from; 057 if (filterAxis == null) { 058 filterAxis = 059 new AxisNode( 060 null, 061 false, 062 Axis.FILTER, 063 Collections.<IdentifierNode>emptyList(), 064 null); 065 } 066 if (filterAxis.getAxis() != Axis.FILTER) { 067 throw new IllegalArgumentException( 068 "Filter axis must have type FILTER"); 069 } 070 this.filterAxis = filterAxis; 071 this.cellPropertyList = cellPropertyList; 072 } 073 074 /** 075 * Creates an empty SelectNode. 076 * 077 * <p>The contents of the SelectNode, such as the axis list, can be 078 * populated after construction. 079 */ 080 public SelectNode() { 081 this( 082 null, 083 new ArrayList<ParseTreeNode>(), 084 new ArrayList<AxisNode>(), 085 null, 086 null, 087 new ArrayList<IdentifierNode>()); 088 } 089 090 public ParseRegion getRegion() { 091 return region; 092 } 093 094 public <T> T accept(ParseTreeVisitor<T> visitor) { 095 return visitor.visit(this); 096 } 097 098 public Type getType() { 099 // not an expression, so has no type 100 return null; 101 } 102 103 public String toString() { 104 StringWriter sw = new StringWriter(); 105 ParseTreeWriter pw = new ParseTreeWriter(new PrintWriter(sw)); 106 unparse(pw); 107 sw.flush(); 108 return sw.toString(); 109 } 110 111 public void unparse(ParseTreeWriter writer) { 112 final PrintWriter pw = writer.getPrintWriter(); 113 if (!withList.isEmpty()) { 114 pw.println("WITH"); 115 for (ParseTreeNode with : withList) { 116 with.unparse(writer); 117 pw.println(); 118 } 119 } 120 pw.print("SELECT"); 121 int k = 0; 122 for (AxisNode axis : axisList) { 123 if (k++ > 0) { 124 pw.println(","); 125 } else { 126 pw.println(); 127 } 128 axis.unparse(writer); 129 } 130 pw.println(); 131 pw.print("FROM "); 132 from.unparse(writer); 133 if (filterAxis.getExpression() != null) { 134 pw.println(); 135 pw.print("WHERE "); 136 filterAxis.unparse(writer); 137 } 138 if (!cellPropertyList.isEmpty()) { 139 pw.println(); 140 pw.print("CELL PROPERTIES "); 141 k = 0; 142 for (IdentifierNode cellProperty : cellPropertyList) { 143 if (k++ > 0) { 144 pw.print(", "); 145 } 146 cellProperty.unparse(writer); 147 } 148 } 149 } 150 151 /** 152 * Returns a list of calculated members and sets defined as the WITH 153 * clause of this SelectNode. 154 * 155 * <p>For example, the WITH clause of query 156 * 157 * <blockquote> 158 * <code>WITH MEMBER [Measures].[Foo] AS ' [Measures].[Unit Sales] * 2 ' 159 * SET [Customers].[Top] AS ' TopCount([Customers].Members, 10) ' 160 * SELECT FROM [Sales]</code> 161 * </blockquote> 162 * 163 * contains one {@link org.olap4j.mdx.WithMemberNode} and one 164 * {@link org.olap4j.mdx.WithSetNode}. 165 * 166 * <p>The returned list is mutable. 167 * 168 * @return list of calculated members and sets 169 */ 170 public List<ParseTreeNode> getWithList() { 171 return withList; 172 } 173 174 /** 175 * Returns a list of axes in this SelectNode. 176 * 177 * <p>The returned list is mutable. 178 * 179 * @return list of axes 180 */ 181 public List<AxisNode> getAxisList() { 182 return axisList; 183 } 184 185 /** 186 * Returns the filter axis defined by the WHERE clause of this SelectNode. 187 * 188 * <p>Never returns {@code null}. If there is no WHERE clause, returns an 189 * AxisNode for which {@link org.olap4j.mdx.AxisNode#getExpression()} 190 * returns null. 191 * 192 * <p>You can modify the filter expression by calling 193 * {@link org.olap4j.mdx.AxisNode#getExpression()} on the filter AxisNode; 194 * {@code null} means that there is no filter axis. 195 * 196 * @return filter axis 197 */ 198 public AxisNode getFilterAxis() { 199 return filterAxis; 200 } 201 202 /** 203 * Returns the node representing the FROM clause of this SELECT statement. 204 * The node is typically an {@link IdentifierNode} or a {@link CubeNode}. 205 * 206 * @return FROM clause 207 */ 208 public ParseTreeNode getFrom() { 209 return from; 210 } 211 212 /** 213 * Sets the FROM clause of this SELECT statement. 214 * 215 * <p><code>fromNode</code> should typically by an 216 * {@link org.olap4j.mdx.IdentifierNode} containing the cube name, or 217 * a {@link org.olap4j.mdx.CubeNode} referencing an explicit 218 * {@link org.olap4j.metadata.Cube} object. 219 * 220 * @param fromNode FROM clause 221 */ 222 public void setFrom(ParseTreeNode fromNode) { 223 this.from = fromNode; 224 } 225 226 /** 227 * Returns a list of cell properties in this SelectNode. 228 * 229 * <p>The returned list is mutable. 230 * 231 * @return list of cell properties 232 */ 233 public List<IdentifierNode> getCellPropertyList() { 234 return cellPropertyList; 235 } 236 237 public SelectNode deepCopy() { 238 return new SelectNode( 239 this.region, 240 MdxUtil.deepCopyList(withList), 241 MdxUtil.deepCopyList(axisList), 242 this.from != null ? this.from.deepCopy() : null, 243 this.filterAxis.deepCopy(), 244 MdxUtil.deepCopyList(cellPropertyList)); 245 } 246 } 247 248 // End SelectNode.java