OmniSciDB  2e3a973ef4
OmniSciEscapeFunctions.java
Go to the documentation of this file.
1 package com.omnisci.jdbc;
2 
3 import java.lang.reflect.Method;
4 import java.sql.SQLException;
5 import java.util.List;
6 import java.util.Locale;
7 import java.util.concurrent.ConcurrentHashMap;
8 import java.util.concurrent.ConcurrentMap;
9 
10 public final class OmniSciEscapeFunctions {
14  private static final ConcurrentMap<String, Method> FUNCTION_MAP =
15  createFunctionMap("sql");
16 
17  private static ConcurrentMap<String, Method> createFunctionMap(String prefix) {
18  Method[] methods = OmniSciEscapeFunctions.class.getMethods();
19  ConcurrentMap<String, Method> functionMap =
20  new ConcurrentHashMap<String, Method>(methods.length * 2);
21  for (Method method : methods) {
22  if (method.getName().startsWith(prefix)) {
23  functionMap.put(
24  method.getName().substring(prefix.length()).toLowerCase(Locale.US),
25  method);
26  }
27  }
28  return functionMap;
29  }
30 
37  public static Method getFunction(String functionName) {
38  Method method = FUNCTION_MAP.get(functionName);
39  if (method != null) {
40  return method;
41  }
42  // FIXME: this probably should not use the US locale
43  String nameLower = functionName.toLowerCase(Locale.US);
44  if (nameLower.equals(functionName)) {
45  // Input name was in lower case, the function is not there
46  return null;
47  }
48  method = FUNCTION_MAP.get(nameLower);
49  if (method != null && FUNCTION_MAP.size() < 1000) {
50  // Avoid OutOfMemoryError in case input function names are randomized
51  // The number of methods is finite, however the number of upper-lower case
52  // combinations is quite a few (e.g. substr, Substr, sUbstr, SUbstr, etc).
53  FUNCTION_MAP.putIfAbsent(functionName, method);
54  }
55  return method;
56  }
57 
58  // ** numeric functions translations **
59 
67  public static void sqlceiling(StringBuilder buf,
68  List<? extends CharSequence> parsedArgs) throws SQLException {
69  singleArgumentFunctionCall(buf, "ceil(", "ceiling", parsedArgs);
70  }
71 
79  public static void sqldayofmonth(StringBuilder buf,
80  List<? extends CharSequence> parsedArgs) throws SQLException {
81  singleArgumentFunctionCall(buf, "extract(day from ", "dayofmonth", parsedArgs);
82  }
83 
92  public static void sqldayofweek(StringBuilder buf,
93  List<? extends CharSequence> parsedArgs) throws SQLException {
94  if (parsedArgs.size() != 1) {
95  throw new RuntimeException(
96  "Syntax error function 'dayofweek' takes one and only one argument.");
97  }
98  appendCall(buf, "extract(dow from ", ",", ")+1", parsedArgs);
99  }
100 
108  public static void sqldayofyear(StringBuilder buf,
109  List<? extends CharSequence> parsedArgs) throws SQLException {
110  singleArgumentFunctionCall(buf, "extract(doy from ", "dayofyear", parsedArgs);
111  }
112 
120  public static void sqlhour(StringBuilder buf, List<? extends CharSequence> parsedArgs)
121  throws SQLException {
122  singleArgumentFunctionCall(buf, "extract(hour from ", "hour", parsedArgs);
123  }
124 
132  public static void sqlminute(StringBuilder buf, List<? extends CharSequence> parsedArgs)
133  throws SQLException {
134  singleArgumentFunctionCall(buf, "extract(minute from ", "minute", parsedArgs);
135  }
136 
144  public static void sqlmonth(StringBuilder buf, List<? extends CharSequence> parsedArgs)
145  throws SQLException {
146  singleArgumentFunctionCall(buf, "extract(month from ", "month", parsedArgs);
147  }
148 
156  public static void sqlquarter(StringBuilder buf,
157  List<? extends CharSequence> parsedArgs) throws SQLException {
158  singleArgumentFunctionCall(buf, "extract(quarter from ", "quarter", parsedArgs);
159  }
160 
168  public static void sqlsecond(StringBuilder buf, List<? extends CharSequence> parsedArgs)
169  throws SQLException {
170  singleArgumentFunctionCall(buf, "extract(second from ", "second", parsedArgs);
171  }
172 
180  public static void sqlweek(StringBuilder buf, List<? extends CharSequence> parsedArgs)
181  throws SQLException {
182  singleArgumentFunctionCall(buf, "extract(week from ", "week", parsedArgs);
183  }
184 
192  public static void sqlyear(StringBuilder buf, List<? extends CharSequence> parsedArgs)
193  throws SQLException {
194  singleArgumentFunctionCall(buf, "extract(year from ", "year", parsedArgs);
195  }
196 
197  private static void singleArgumentFunctionCall(StringBuilder buf,
198  String call,
199  String functionName,
200  List<? extends CharSequence> parsedArgs) {
201  if (parsedArgs.size() != 1) {
202  throw new RuntimeException(
203  "Syntax error " + functionName + " takes one and only one argument.");
204  }
205  CharSequence arg0 = parsedArgs.get(0);
206  buf.ensureCapacity(buf.length() + call.length() + arg0.length() + 1);
207  buf.append(call).append(arg0).append(')');
208  }
209 
220  public static void appendCall(StringBuilder sb,
221  String begin,
222  String separator,
223  String end,
224  List<? extends CharSequence> args) {
225  int size = begin.length();
226  // Typically just-in-time compiler would eliminate Iterator in case foreach is used,
227  // however the code below uses indexed iteration to keep the conde independent from
228  // various JIT implementations (== avoid Iterator allocations even for not-so-smart
229  // JITs) see https://bugs.openjdk.java.net/browse/JDK-8166840 see
230  // http://2016.jpoint.ru/talks/cheremin/ (video and slides)
231  int numberOfArguments = args.size();
232  for (int i = 0; i < numberOfArguments; i++) {
233  size += args.get(i).length();
234  }
235  size += separator.length() * (numberOfArguments - 1);
236  sb.ensureCapacity(sb.length() + size + 1);
237  sb.append(begin);
238  for (int i = 0; i < numberOfArguments; i++) {
239  if (i > 0) {
240  sb.append(separator);
241  }
242  sb.append(args.get(i));
243  }
244  sb.append(end);
245  }
246 }
static void sqldayofyear(StringBuilder buf, List<? extends CharSequence > parsedArgs)
static void sqlminute(StringBuilder buf, List<? extends CharSequence > parsedArgs)
static void sqldayofmonth(StringBuilder buf, List<? extends CharSequence > parsedArgs)
static void sqlyear(StringBuilder buf, List<? extends CharSequence > parsedArgs)
static void singleArgumentFunctionCall(StringBuilder buf, String call, String functionName, List<? extends CharSequence > parsedArgs)
static void sqlmonth(StringBuilder buf, List<? extends CharSequence > parsedArgs)
static void sqlceiling(StringBuilder buf, List<? extends CharSequence > parsedArgs)
static final ConcurrentMap< String, Method > FUNCTION_MAP
static Method getFunction(String functionName)
static void sqlsecond(StringBuilder buf, List<? extends CharSequence > parsedArgs)
static void sqlweek(StringBuilder buf, List<? extends CharSequence > parsedArgs)
static void sqlhour(StringBuilder buf, List<? extends CharSequence > parsedArgs)
static ConcurrentMap< String, Method > createFunctionMap(String prefix)
static void sqldayofweek(StringBuilder buf, List<? extends CharSequence > parsedArgs)
static void appendCall(StringBuilder sb, String begin, String separator, String end, List<? extends CharSequence > args)
static void sqlquarter(StringBuilder buf, List<? extends CharSequence > parsedArgs)