View Javadoc

1   package org.apache.torque.util.functions;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.commons.lang.StringUtils;
23  import org.apache.torque.Column;
24  
25  /**
26   * <p>A container for classes that will generate SQL for the SQL99 Standard
27   * Aggregate functions. These can be used via the Criteria.addSelectColumn
28   * method to produce SQL statements that can be called via the
29   * BasePeerImpl.doSelect methods.</p>
30   * <p>
31   * Note database servers that use non-standard function names
32   * can be supported by setting the function name in the constructor accordingly.
33   * </p>
34   * <p>
35   * E.g., older MySQL servers use LEAST instead of MIN. This can be
36   * supported by supplying "LEAST" as function name.</p>
37   *
38   * @author <a href="mailto:greg.monroe@dukece.com">Greg Monroe</a>
39   * @version $Id: AggregateFunction.java 1377464 2012-08-26 17:24:59Z tv $
40   */
41  public class AggregateFunction implements SQLFunction
42  {
43      /** Should the column have DISTINCT added before it */
44      private boolean distinct;
45  
46      /** The function to use */
47      private String function;
48  
49      /** The column to apply the function to, not null. */
50      private Column column;
51  
52      /**
53       * Constructor for aggregate functions.
54       *
55       * @param function the function name, not null or blank.
56       * @param column the column to apply the function to, not null.
57       * @param distinct whether to apply DISTINCT to the column.
58       */
59      protected AggregateFunction(
60              String function,
61              Column column,
62              boolean distinct)
63      {
64          if (StringUtils.isBlank(function))
65          {
66              throw new IllegalArgumentException(
67                      "function must not be null or blank");
68          }
69          this.function = function;
70          setColumn(column);
71          this.distinct = distinct;
72      }
73  
74      /**
75       * Returns the column the function is applied to.
76       *
77       * @return the column, not null.
78       */
79      public Column getColumn()
80      {
81          return column;
82      }
83  
84      /**
85       * Sets the column the function is applied to.
86       *
87       * @param column the column, not null.
88       */
89      public void setColumn(Column column)
90      {
91          if (column == null)
92          {
93              throw new IllegalArgumentException(
94                      "column must not be null");
95          }
96          this.column = column;
97      }
98  
99      /**
100      * Should the column have DISTINCT added in front of it?
101      *
102      * @return True if DISTINCT is needed.
103      */
104     public boolean isDistinct()
105     {
106         return this.distinct;
107     }
108 
109     /**
110      * Get the function name to use, e.g. AVG, MIN, LEAST.
111      *
112      * @return The function name.
113      */
114     protected String getFunction()
115     {
116         return this.function;
117     }
118 
119     /**
120      * Set the function name to use, e.g. AVG, MIN, LEAST.
121      *
122      * @param function The function name to use, not null or blank.
123      *
124      * @throws UnsupportedOperationException if a subclass does not support
125      *         changing the function name; never thrown by this implementation.
126      */
127     public void setFunction(String function)
128     {
129         if (StringUtils.isBlank(function))
130         {
131             throw new IllegalArgumentException(
132                     "function must not be null or blank");
133         }
134         this.function = function;
135     }
136 
137     /**
138      * Generate the SQL for this function.
139      *
140      * @throws IllegalStateException if the arguments are not set
141      */
142     public String getSqlExpression()
143     {
144         StringBuilder sb = new StringBuilder();
145         sb.append(getFunction()).append("(");
146         if (isDistinct())
147         {
148             sb.append("DISTINCT ");
149         }
150         sb.append(column.getSqlExpression())
151               .append(")");
152         return sb.toString();
153     }
154 
155     public Object getArgument(int i)
156     {
157         switch (i)
158         {
159         case 0:
160             return column;
161         case 1:
162             return distinct;
163         default:
164             return null;
165         }
166     }
167 
168 
169     public Object[] getArguments()
170     {
171         return new Object[] {column, distinct};
172     }
173 
174     /**
175      * Assumes that there are one or two arguments being specified.  The
176      * first being a column identifier,
177      * and the second being an optional boolean indicating if DISTINCT
178      * needs to be added.
179      *
180      * @param args The column to apply the function to.
181      * @throws IllegalArgumentException If at least one argument has not
182      *                              been supplied or the second argument
183      *                              object is not Boolean.
184      */
185      public void setArguments(Object[] args)
186      {
187 
188          if (args.length < 1)
189          {
190              throw new IllegalArgumentException(
191                    "There must be at least one argument object specified!");
192          }
193          if (args.length < 2)
194          {
195              this.distinct = false;
196          }
197          else
198          {
199              if (!(args[1] instanceof Boolean))
200              {
201                  throw new IllegalArgumentException(
202                         "Second argument object is not type Boolean!");
203              }
204              this.distinct = ((Boolean) args[1]).booleanValue();
205          }
206          if (!(args[0] instanceof Column))
207          {
208              throw new IllegalArgumentException(
209                     "First argument object is not type Column!");
210          }
211          this.column = (Column) args[0];
212      }
213 
214      /**
215       * Returns the column name.
216       * This implementation always return null because we do not reference
217       * a real column.
218       *
219       * @return the column name, always null.
220       */
221      public String getColumnName()
222      {
223          return null;
224      }
225 
226     public String getTableName()
227     {
228         return column.getTableName();
229     }
230 
231     public String getSchemaName()
232     {
233         return column.getSchemaName();
234     }
235 
236     public String getFullTableName()
237     {
238         return column.getFullTableName();
239     }
240 }