/**
* Copyright (C) 2009-2013 FoundationDB, LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.foundationdb.sql.optimizer;
import com.foundationdb.server.types.service.TypesRegistryService;
import com.foundationdb.sql.parser.*;
import com.foundationdb.sql.StandardException;
import com.foundationdb.sql.types.DataTypeDescriptor;
import com.foundationdb.ais.model.Routine;
import com.foundationdb.sql.optimizer.plan.AggregateFunctionExpression;
/** Marks aggregate functions as such. */
public class FunctionsTypeComputer extends AISTypeComputer
{
private TypesRegistryService functionsRegistry;
public FunctionsTypeComputer(TypesRegistryService functionsRegistry) {
this.functionsRegistry = functionsRegistry;
}
@Override
protected DataTypeDescriptor computeType(ValueNode node) throws StandardException {
switch (node.getNodeType()) {
case NodeTypes.JAVA_TO_SQL_VALUE_NODE:
return javaValueNode(((JavaToSQLValueNode)node).getJavaValueNode());
default:
return super.computeType(node);
}
}
protected DataTypeDescriptor javaValueNode(JavaValueNode javaValue)
throws StandardException {
if (javaValue instanceof MethodCallNode) {
return methodCallNode((MethodCallNode)javaValue);
}
else {
return null;
}
}
protected DataTypeDescriptor methodCallNode(MethodCallNode methodCall)
throws StandardException {
if (methodCall.getUserData() != null) {
Routine routine = (Routine)methodCall.getUserData();
return routine.getReturnValue().getType().dataTypeDescriptor();
}
if (methodCall.getMethodParameters().length == 1) {
return oneArgMethodCall(methodCall);
}
else {
return null;
}
}
protected DataTypeDescriptor oneArgMethodCall(MethodCallNode methodCall)
throws StandardException {
TypesRegistryService.FunctionKind functionKind =
functionsRegistry.getFunctionKind(methodCall.getMethodName());
if (functionKind == TypesRegistryService.FunctionKind.AGGREGATE) {
// Mark the method call as really an aggregate function.
// Could do the substitution now, but that would require throwing
// a subclass of StandardException up to visit() or something other
// complicated control flow.
methodCall.setJavaClassName(AggregateFunctionExpression.class.getName());
JavaValueNode arg = methodCall.getMethodParameters()[0];
if (arg instanceof SQLToJavaValueNode) {
SQLToJavaValueNode jarg = (SQLToJavaValueNode)arg;
ValueNode sqlArg = jarg.getSQLValueNode();
return sqlArg.getType();
}
}
return null;
}
/** Return the name of a built-in special function. */
public static String specialFunctionName(SpecialFunctionNode node) {
switch (node.getNodeType()) {
case NodeTypes.USER_NODE:
case NodeTypes.CURRENT_USER_NODE:
return "current_user";
case NodeTypes.SESSION_USER_NODE:
return "session_user";
case NodeTypes.SYSTEM_USER_NODE:
return "system_user";
case NodeTypes.CURRENT_SCHEMA_NODE:
return "current_schema";
case NodeTypes.CURRENT_ISOLATION_NODE:
case NodeTypes.IDENTITY_VAL_NODE:
case NodeTypes.CURRENT_ROLE_NODE:
default:
return null;
}
}
/** Return the name of a built-in special function. */
public static String currentDatetimeFunctionName(CurrentDatetimeOperatorNode node) {
switch (node.getField()) {
case DATE:
return "current_date";
case TIME:
return "current_time";
case TIMESTAMP:
return "current_timestamp";
default:
return null;
}
}
}