001    /*
002    // $Id: //open/mondrian/src/main/mondrian/mdx/ParameterExpr.java#6 $
003    // This software is subject to the terms of the Common Public License
004    // Agreement, available at the following URL:
005    // http://www.opensource.org/licenses/cpl.html.
006    // Copyright (C) 2006-2007 Julian Hyde
007    // All Rights Reserved.
008    // You must accept the terms of that agreement to use this software.
009    */
010    package mondrian.mdx;
011    
012    import mondrian.olap.*;
013    import mondrian.olap.type.Type;
014    import mondrian.olap.type.TypeUtil;
015    import mondrian.calc.Calc;
016    import mondrian.calc.ExpCompiler;
017    import mondrian.calc.ParameterCompilable;
018    
019    import java.io.PrintWriter;
020    
021    /**
022     * MDX expression which is a usage of a {@link mondrian.olap.Parameter}.
023     *
024     * @author jhyde
025     * @version $Id: //open/mondrian/src/main/mondrian/mdx/ParameterExpr.java#6 $
026     */
027    public class ParameterExpr extends ExpBase {
028    
029        private Parameter parameter;
030    
031        public ParameterExpr(Parameter parameter)
032        {
033            this.parameter = parameter;
034        }
035    
036        public Type getType() {
037            return parameter.getType();
038        }
039    
040        public int getCategory() {
041            return TypeUtil.typeToCategory(parameter.getType());
042        }
043    
044        public Exp accept(Validator validator) {
045            // There must be some Parameter with this name registered with the
046            // Query.  After clone(), there will be many copies of the same
047            // parameter, and we rely on this method to bring them down to one.
048            // So if this object is not the registered vesion, that's fine, go with
049            // the other one.  The registered one will be resolved after everything
050            // else in the query has been resolved.
051            String parameterName = parameter.getName();
052            final SchemaReader schemaReader =
053                validator.getQuery().getSchemaReader(false);
054            Parameter p = schemaReader.getParameter(parameterName);
055            if (p == null) {
056                this.parameter =
057                    validator.createOrLookupParam(
058                        true,
059                        parameter.getName(),
060                        parameter.getType(),
061                        parameter.getDefaultExp(),
062                        parameter.getDescription());
063            } else {
064                this.parameter = p;
065            }
066            return this;
067        }
068    
069        public Calc accept(ExpCompiler compiler) {
070            return ((ParameterCompilable) parameter).compile(compiler);
071        }
072    
073        public Object accept(MdxVisitor visitor) {
074            return visitor.visit(this);
075        }
076    
077        public ParameterExpr clone() {
078            return new ParameterExpr(parameter);
079        }
080    
081        /**
082         * Unparses the definition of this Parameter.
083         *
084         * <p>The first usage of a parameter in a query becomes a call to the
085         * <code>Parameter(paramName, description, defaultValue)</code>
086         * function, and subsequent usages become calls to
087         * <code>ParamRef(paramName)</code>
088         *
089         * @param pw PrintWriter
090         */
091        public void unparse(PrintWriter pw) {
092            // Is this the first time we've seen a statement parameter? If so,
093            // we will generate a call to the Parameter() function, to define
094            // the parameter.
095            final boolean def;
096            if (pw instanceof QueryPrintWriter &&
097                parameter.getScope() == Parameter.Scope.Statement) {
098                def = ((QueryPrintWriter) pw).parameters.add(parameter);
099            } else {
100                def = false;
101            }
102            final String name = parameter.getName();
103            final Type type = parameter.getType();
104            final int category = TypeUtil.typeToCategory(type);
105            if (def) {
106                pw.print("Parameter(" + Util.quoteForMdx(name) + ", ");
107                switch (category) {
108                case Category.String:
109                case Category.Numeric:
110                    pw.print(Category.instance.getName(category).toUpperCase());
111                    break;
112                case Category.Member:
113                    String memberName =
114                            type.getLevel() != null ?
115                            type.getLevel().getUniqueName() :
116                            type.getHierarchy() != null ?
117                            type.getHierarchy().getUniqueName() :
118                            type.getDimension().getUniqueName();
119                    pw.print(memberName);
120                    break;
121                default:
122                    throw Category.instance.badValue(category);
123                }
124                pw.print(", ");
125                final Object value = parameter.getValue();
126                if (value == null) {
127                    parameter.getDefaultExp().unparse(pw);
128                } else if (value instanceof String) {
129                    String s = (String) value;
130                    pw.print(Util.quoteForMdx(s));
131                } else {
132                    pw.print(value);
133                }
134                final String description = parameter.getDescription();
135                if (description != null) {
136                    pw.print(", " + Util.quoteForMdx(description));
137                }
138                pw.print(")");
139            } else {
140                pw.print("ParamRef(" + Util.quoteForMdx(name) + ")");
141            }
142        }
143    
144        // For the purposes of type inference and expression substitution, a
145        // parameter is atomic; therefore, we ignore the child member, if any.
146        public Object[] getChildren() {
147            return null;
148        }
149    
150        /**
151         * Returns whether this parameter is equal to another, based upon name,
152         * type and value
153         */
154        public boolean equals(Object other) {
155            if (!(other instanceof ParameterExpr)) {
156                return false;
157            }
158            ParameterExpr that = (ParameterExpr) other;
159            return this.parameter == that.parameter;
160        }
161    
162        public int hashCode() {
163            return parameter.hashCode();
164        }
165    
166        /**
167         * Returns whether the parameter can be modified.
168         *
169         * @return whether parameter can be modified
170         */
171        public boolean isModifiable() {
172            return true;
173        }
174    
175        /**
176         * Returns the parameter used by this expression.
177         *
178         * @return parameter used by this expression
179         */
180        public Parameter getParameter() {
181            return parameter;
182        }
183    }
184    
185    // End ParameterExpr.java