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