org.firebirdsql.jdbc.FBEscapedFunctionHelper Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jaybird-jdk17 Show documentation
Show all versions of jaybird-jdk17 Show documentation
JDBC Driver for the Firebird RDBMS
/*
* Firebird Open Source J2ee connector - jdbc driver
*
* Distributable under LGPL license.
* You may obtain a copy of the License at http://www.gnu.org/copyleft/lgpl.html
*
* 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
* LGPL License for more details.
*
* This file was created by members of the firebird development team.
* All individual contributions remain the Copyright (C) of those
* individuals. Contributors to this file are either listed here or
* can be obtained from a CVS history command.
*
* All rights reserved.
*/
package org.firebirdsql.jdbc;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.*;
/**
* Helper class for escaped functions.
*
* @author Roman Rokytskyy
*/
public class FBEscapedFunctionHelper {
/*
* This map contains mapping between JDBC function names and Firebird ones.
*/
private static final HashMap FUNCTION_MAP = new HashMap();
static {
/* Numeric Functions */
FUNCTION_MAP.put("ABS", null);
FUNCTION_MAP.put("ACOS", null);
FUNCTION_MAP.put("ASIN", null);
FUNCTION_MAP.put("ATAN", null);
FUNCTION_MAP.put("ATAN2", null);
FUNCTION_MAP.put("CEILING", null);
FUNCTION_MAP.put("COS", null);
FUNCTION_MAP.put("COT", null);
FUNCTION_MAP.put("DEGREES", null);
FUNCTION_MAP.put("EXP", null);
FUNCTION_MAP.put("FLOOR", null);
FUNCTION_MAP.put("LOG", null);
FUNCTION_MAP.put("LOG10", null);
FUNCTION_MAP.put("MOD", null);
FUNCTION_MAP.put("PI", null);
FUNCTION_MAP.put("POWER", null);
FUNCTION_MAP.put("RADIANS", null);
FUNCTION_MAP.put("RAND", null);
FUNCTION_MAP.put("ROUND", null);
FUNCTION_MAP.put("SIGN", null);
FUNCTION_MAP.put("SIN", null);
FUNCTION_MAP.put("SQRT", null);
FUNCTION_MAP.put("TAN", null);
FUNCTION_MAP.put("TRUNCATE", null);
/* String Functions */
FUNCTION_MAP.put("ASCII", null);
FUNCTION_MAP.put("CHAR", null);
FUNCTION_MAP.put("CONCAT", "{0}||{1}");
FUNCTION_MAP.put("DIFFERENCE", null);
FUNCTION_MAP.put("INSERT", null);
FUNCTION_MAP.put("LCASE", null);
FUNCTION_MAP.put("LEFT", "SUBSTRING({0} FROM 1 FOR {1}");
FUNCTION_MAP.put("LENGTH", "CHARACTER_LENGTH({0})");
FUNCTION_MAP.put("LOCATE", null);
FUNCTION_MAP.put("LTRIM", null);
FUNCTION_MAP.put("REPEAT", null);
FUNCTION_MAP.put("REPLACE", null);
FUNCTION_MAP.put("RIGHT", null);
FUNCTION_MAP.put("RTRIM", null);
FUNCTION_MAP.put("SOUNDEX", null);
FUNCTION_MAP.put("SPACE", null);
FUNCTION_MAP.put("SUBSTRING", "SUBSTRING({0} FROM {1} FOR {2})");
FUNCTION_MAP.put("UCASE", "UPPER({0})");
/* Time and Date Functions */
FUNCTION_MAP.put("CURDATE", "CURRENT_DATE");
FUNCTION_MAP.put("CURTIME", "CURRENT_TIME");
FUNCTION_MAP.put("DAYNAME", null);
FUNCTION_MAP.put("DAYOFMONTH", "EXTRACT(DAY FROM {0})");
FUNCTION_MAP.put("DAYOFWEEK", null);
FUNCTION_MAP.put("DAYOFYEAR", null );
FUNCTION_MAP.put("HOUR", "EXTRACT(HOUR FROM {0})");
FUNCTION_MAP.put("MINUTE", "EXTRACT(MINUTE FROM {0})");
FUNCTION_MAP.put("MONTH", "EXTRACT(MONTH FROM {0})");
FUNCTION_MAP.put("MONTHNAME", null);
FUNCTION_MAP.put("NOW", "CURRENT_TIMESTAMP");
FUNCTION_MAP.put("QUARTER", null);
FUNCTION_MAP.put("SECOND", "EXTRACT(SECOND FROM {0})");
FUNCTION_MAP.put("TIMESTAMPADD", null);
FUNCTION_MAP.put("TIMESTAMPDIFF", null);
FUNCTION_MAP.put("WEEK", null);
FUNCTION_MAP.put("YEAR", "EXTRACT(YEAR FROM {0})");
/* System Functions */
FUNCTION_MAP.put("DATABASE", null);
FUNCTION_MAP.put("IFNULL", "COALESCE({0}, {1})");
/* Conversion Functions */
FUNCTION_MAP.put("CONVERT", "CAST({0} AS {1})");
}
/**
* Simple syntax check if function is specified in form "name(...)".
*
* @param functionCall string representing function call.
*
* @throws FBSQLParseException if simple syntax check failed.
*/
private static void checkSyntax(String functionCall) throws FBSQLParseException {
int parenthesisStart = functionCall.indexOf('(');
if (parenthesisStart == -1)
throw new FBSQLParseException("No opening parenthesis found, " +
"not a function call.");
if (functionCall.charAt(functionCall.length() - 1) != ')')
throw new FBSQLParseException("No closing parenthesis found, " +
"not a function call.");
}
/**
* Extract function name from the function call.
*
* @param functionCall escaped function call.
*
* @return name of the function.
*
* @throws FBSQLParseException if parse error occurs.
*/
public static String parseFunction(String functionCall) throws FBSQLParseException {
functionCall = functionCall.trim();
checkSyntax(functionCall);
int parenthesisStart = functionCall.indexOf('(');
return functionCall.substring(0, parenthesisStart);
}
/**
* Extract function arguments from the function call. This method parses
* escaped function call string and extracts function parameters from it.
*
* @param functionCall escaped function call.
*
* @return list of parameters of the function.
*
* @throws FBSQLParseException if parse error occurs.
*/
public static List parseArguments(String functionCall) throws FBSQLParseException {
functionCall = functionCall.trim();
checkSyntax(functionCall);
int parenthesisStart = functionCall.indexOf('(');
String paramsString = functionCall.substring(
parenthesisStart + 1, functionCall.length() - 1);
List params = new ArrayList();
StringBuffer sb = new StringBuffer();
boolean inQuotes = false;
boolean inDoubleQuotes = false;
char[] chars = paramsString.toCharArray();
for(int i = 0; i < chars.length ; i++) {
switch(chars[i]) {
case '\'' :
sb.append(chars[i]);
if (!inDoubleQuotes)
inQuotes = !inQuotes;
break;
case '"' :
sb.append(chars[i]);
if (!inQuotes)
inDoubleQuotes = !inDoubleQuotes;
break;
// we ignore spaces, tabs and new lines if
// we are not in the string literal
case ' ' :
case '\t' :
case '\n' :
case '\r' :
if (inQuotes || inDoubleQuotes)
sb.append(chars[i]);
break;
// comma is considered parameter separator
// if it is not within the string literal
case ',' :
if (inQuotes || inDoubleQuotes)
sb.append(chars[i]);
else {
params.add(sb.toString());
sb = new StringBuffer();
}
break;
// by default we add chars to the buffer
default :
sb.append(chars[i]);
}
}
// add last parameter if present
if (sb.length() > 0)
params.add(sb.toString());
// after processing all parameters all string literals should be closed
if (inQuotes || inDoubleQuotes)
throw new FBSQLParseException(
"String literal is not properly closed.");
return params;
}
/**
* Convert escaped function call using function template.
*
* @param functionCall escaped function call.
*
* @return server-side representation of the function call or null
* if no template found.
*
* @throws FBSQLParseException if escaped function call has incorrect syntax.
*/
public static String convertTemplate(String functionCall, int mode) throws FBSQLParseException {
String name = parseFunction(functionCall);
String[] params = (String[])parseArguments(functionCall).toArray(new String[0]);
String firebirdTemplate = (String)FUNCTION_MAP.get(name.toUpperCase());
if (firebirdTemplate != null)
return MessageFormat.format(firebirdTemplate, (Object[])params);
if (mode == FBEscapedParser.USE_STANDARD_UDF)
return convertUsingStandardUDF(name, params);
return null;
}
/*
* Functions below are conversion routines of the escaped function calls
* into the standard UDF library functions. The conversion function must
* have the name equal to the function name in the escaped syntax in the
* lower case and should take array of strings as parameter and it may throw
* the FBSQLParseException and must be declared as static and have public
* visibility. It should return a string of the converted function call.
*/
private static String convertUsingStandardUDF(String name, String[] params) throws FBSQLParseException {
try {
name = name.toLowerCase();
// workaround for the {fn char()} function, since we cannot use
// "char" as name of the function - it is reserved word.
if ("char".equals(name))
name = "_char";
Method method = FBEscapedFunctionHelper.class.getMethod(
name.toLowerCase(), new Class[] { String[].class});
return (String)method.invoke(null, new Object[]{params});
} catch(NoSuchMethodException ex) {
return null;
} catch (IllegalArgumentException ex) {
throw new FBSQLParseException("Error when converting function "
+ name + ". Error " + ex.getClass().getName() +
" : " + ex.getMessage());
} catch (IllegalAccessException ex) {
throw new FBSQLParseException("Error when converting function "
+ name + ". Error " + ex.getClass().getName() +
" : " + ex.getMessage());
} catch (InvocationTargetException ex) {
throw new FBSQLParseException("Error when converting function "
+ name + ". Error " + ex.getClass().getName() +
" : " + ex.getMessage());
}
}
/*
* Mathematical functions
*/
/**
* Produce a function call for the abs
UDF function.
* The syntax of the abs
function is
* {fn abs(number)}
.
*
* @param params The parameters to be used in the call
* @throws FBSQLParseException if there is an error with the parameters
*/
public static String abs(String[] params) throws FBSQLParseException {
if (params.length != 1)
throw new FBSQLParseException("Incorrect number of " +
"parameters of function abs : " + params.length);
return "abs(" + params[0] + ")";
}
/**
* Produce a function call for the acos
UDF function.
* The syntax of the acos
function is
* {fn acos(float)}
.
*
* @param params The parameters to be used in the call
* @throws FBSQLParseException if there is an error with the parameters
*/
public static String acos(String[] params) throws FBSQLParseException {
if (params.length != 1)
throw new FBSQLParseException("Incorrect number of " +
"parameters of function acos : " + params.length);
return "acos(" + params[0] + ")";
}
/**
* Produce a function call for the asin
UDF function.
* The syntax of the asin
function is
* {fn asin(float)}
.
*
* @param params The parameters to be used in the call
* @throws FBSQLParseException if there is an error with the parameters
*/
public static String asin(String[] params) throws FBSQLParseException {
if (params.length != 1)
throw new FBSQLParseException("Incorrect number of " +
"parameters of function asin : " + params.length);
return "asin(" + params[0] + ")";
}
/**
* Produce a function call for the atan
UDF function.
* The syntax of the atan
function is
* {fn atan(float)}
.
*
* @param params The parameters to be used in the call
* @throws FBSQLParseException if there is an error with the parameters
*/
public static String atan(String[] params) throws FBSQLParseException {
if (params.length != 1)
throw new FBSQLParseException("Incorrect number of " +
"parameters of function atan : " + params.length);
return "atan(" + params[0] + ")";
}
/**
* Produce a function call for the atan2
UDF function.
* The syntax of the atan2
function is
* {fn atan2(float1, float2)}
.
*
* @param params The parameters to be used in the call
* @throws FBSQLParseException if there is an error with the parameters
*/
public static String atan2(String[] params) throws FBSQLParseException {
if (params.length != 2)
throw new FBSQLParseException("Incorrect number of " +
"parameters of function atan2 : " + params.length);
return "atan2(" + params[0] + ", " + params[1] + ")";
}
/**
* Produce a function call for the ceiling
UDF function.
* The syntax of the ceiling
function is
* {fn ceiling(number)}
.
*
* @param params The parameters to be used in the call
* @throws FBSQLParseException if there is an error with the parameters
*/
public static String ceiling(String[] params) throws FBSQLParseException {
if (params.length != 1)
throw new FBSQLParseException("Incorrect number of " +
"parameters of function ceiling : " + params.length);
return "ceiling(" + params[0] + ")";
}
/**
* Produce a function call for the cos
UDF function.
* The syntax of the cos
function is
* {fn cos(float)}
.
*
* @param params The parameters to be used in the call
* @throws FBSQLParseException if there is an error with the parameters
*/
public static String cos(String[] params) throws FBSQLParseException {
if (params.length != 1)
throw new FBSQLParseException("Incorrect number of " +
"parameters of function cos : " + params.length);
return "cos(" + params[0] + ")";
}
/**
* Produce a function call for the cot
UDF function.
* The syntax of the cot
function is
* {fn cot(float)}
.
*
* @param params The parameters to be used in the call
* @throws FBSQLParseException if there is an error with the parameters
*/
public static String cot(String[] params) throws FBSQLParseException {
if (params.length != 1)
throw new FBSQLParseException("Incorrect number of " +
"parameters of function cot : " + params.length);
return "cot(" + params[0] + ")";
}
/**
* Produce a function call for the floor
UDF function.
* The syntax of the floor
function is
* {fn floor(number)}
.
*
* @param params The parameters to be used in the call
* @throws FBSQLParseException if there is an error with the parameters
*/
public static String floor(String[] params) throws FBSQLParseException {
if (params.length != 1)
throw new FBSQLParseException("Incorrect number of " +
"parameters of function floor : " + params.length);
return "floor(" + params[0] + ")";
}
/**
* Produce a function call for the log
UDF function.
* The syntax of the log
function is
* {fn log(number)}
.
*
* @param params The parameters to be used in the call
* @throws FBSQLParseException if there is an error with the parameters
*/
public static String log(String[] params) throws FBSQLParseException {
if (params.length != 1)
throw new FBSQLParseException("Incorrect number of " +
"parameters of function log : " + params.length);
return "ln(" + params[0] + ")";
}
/**
* Produce a function call for the log10
UDF function.
* The syntax of the log10
function is
* {fn log10(number)}
.
*
* @param params The parameters to be used in the call
* @throws FBSQLParseException if there is an error with the parameters
*/
public static String log10(String[] params) throws FBSQLParseException {
if (params.length != 1)
throw new FBSQLParseException("Incorrect number of " +
"parameters of function log10 : " + params.length);
return "log10(" + params[0] + ")";
}
/**
* Produce a function call for the mod
UDF function.
* The syntax of the mod
function is
* {fn mod(integer1, integer2)}
.
*
* @param params The parameters to be used in the call
* @throws FBSQLParseException if there is an error with the parameters
*/
public static String mod(String[] params) throws FBSQLParseException {
if (params.length != 2)
throw new FBSQLParseException("Incorrect number of " +
"parameters of function mod : " + params.length);
return "mod(" + params[0] + ", " + params[1] + ")";
}
/**
* Produce a function call for the pi
UDF function.
* The syntax of the pi
function is {fn pi()}
.
*
* @param params The parameters to be used in the call
* @throws FBSQLParseException if there is an error with the parameters
*/
public static String pi(String[] params) throws FBSQLParseException {
if (params.length != 0)
throw new FBSQLParseException("Incorrect number of " +
"parameters of function pi : " + params.length);
return "pi()";
}
/**
* Produce a function call for the rand
UDF function.
* The syntax for the rand
function is
* {fn rand()}
.
*
* @param params The parameters to be used in the call
* @throws FBSQLParseException if there is an error with the parameters
*/
public static String rand(String[] params) throws FBSQLParseException {
if (params.length != 0)
throw new FBSQLParseException("Incorrect number of " +
"parameters of function rand : " + params.length);
return "rand()";
}
/**
* Produce a function call for the sign
UDF function.
* The syntax for the sign
function is
* {fn sign(number)}
.
*
* @param params The parameters to be used in the call
* @throws FBSQLParseException if there is an error with the parameters
*/
public static String sign(String[] params) throws FBSQLParseException {
if (params.length != 1)
throw new FBSQLParseException("Incorrect number of " +
"parameters of function sign : " + params.length);
return "sign(" + params[0] + ")";
}
/**
* Produce a function call for the sin
UDF function.
* The syntax for the sin
function is
* {fn sin(float)}
.
*
* @param params The parameters to be used in the call
* @throws FBSQLParseException if there is an error with the parameters
*/
public static String sin(String[] params) throws FBSQLParseException {
if (params.length != 1)
throw new FBSQLParseException("Incorrect number of " +
"parameters of function sin : " + params.length);
return "sin(" + params[0] + ")";
}
/**
* Produce a function call for the sqrt
UDF function.
* The syntax for the sqrt
function is
* {fn sqrt(number)}
.
*
* @param params The parameters to be used in the call
* @throws FBSQLParseException if there is an error with the parameters
*/
public static String sqrt(String[] params) throws FBSQLParseException {
if (params.length != 1)
throw new FBSQLParseException("Incorrect number of " +
"parameters of function sqrt : " + params.length);
return "sqrt(" + params[0] + ")";
}
/**
* Produce a function call for the tan UDF function.
* The syntax for the tan
function is
* {fn tan(float)}
.
*
* @param params The parameters to be used in the call
* @throws FBSQLParseException if there is an error with the parameters
*/
public static String tan(String[] params) throws FBSQLParseException {
if (params.length != 1)
throw new FBSQLParseException("Incorrect number of " +
"parameters of function tan : " + params.length);
return "tan(" + params[0] + ")";
}
/*
* String functions.
*/
/**
* Produce a function call for the ascii
UDF function.
* The syntax of the ascii
function is
* {fn ascii(string)}
*
* @param params The parameters to be used in the call
* @throws FBSQLParseException if there is an error with the parameters
*/
public static String ascii(String[] params) throws FBSQLParseException {
if (params.length != 1 )
throw new FBSQLParseException("Incorrect number of " +
"parameters of function ascii : " + params.length);
if (params[0] == null || params[0].length() < 1)
throw new FBSQLParseException("Parameter must not be " +
"empty or null");
return "ascii_val(" + params[0].charAt(0) + ")";
}
/**
* Produce a function call for the char
UDF function.
* The syntax of the char
function is
* {fn char(integer)}
.
*
* @param params The parameters to be used in the call
* @throws FBSQLParseException if there is an error with the parameters
*/
public static String _char(String[] params) throws FBSQLParseException {
if (params.length != 1)
throw new FBSQLParseException("Incorrect number of " +
"parameters of function char : " + params.length);
return "char(" + params[0] + ")";
}
/**
* Produce a function call for the lcase
UDF function.
* The syntax of the lcase
function is
* {fn lcase(string)}
*
* @param params The parameters to be used in the call
* @throws FBSQLParseException if there is an error with the parameters
*/
public static String lcase(String[] params) throws FBSQLParseException {
if (params.length != 1)
throw new FBSQLParseException("Incorrect number of " +
"parameters of function lcase : " + params.length);
return "lower(" + params[0] + ")";
}
/**
* Produce a function call for the length
UDF function.
* The syntax of the length
function is
* {fn length(string)}
.
*
* @param params The parameters to be used in the call
* @throws FBSQLParseException if there is an error with the parameters
*/
public static String length(String[] params) throws FBSQLParseException {
if (params.length != 1)
throw new FBSQLParseException("Incorrect number of " +
"parameters of function length : " + params.length);
return "strlen(" + params[0] + ")";
}
/**
* Produce a function call for the ltrim
UDF function.
* The syntax of the ltrim
function is
* {fn ltrim(string)}
.
*
* @param params The parameters to be used in the call
* @throws FBSQLParseException if there is an error with the parameters
*/
public static String ltrim(String[] params) throws FBSQLParseException {
if (params.length != 1)
throw new FBSQLParseException("Incorrect number of " +
"parameters of function ltrim : " + params.length);
return "ltrim(" + params[0] + ")";
}
/**
* Produce a function call for the rtrim
UDF function.
* The syntax of the rtrim
function is
* {fn rtrim(string)}
.
*
* @param params The parameters to be used in the call
* @throws FBSQLParseException if there is an error with the parameters
*/
public static String rtrim(String[] params) throws FBSQLParseException {
if (params.length != 1)
throw new FBSQLParseException("Incorrect number of " +
"parameters of function rtrim : " + params.length);
return "rtrim(" + params[0] + ")";
}
}