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 }