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