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 Show documentation
Show all versions of jaybird 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.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* 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", null);
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, 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] + ")";
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy