/***************************************************************************
* Copyright (C) 2012 by H-Store Project *
* Brown University *
* Massachusetts Institute of Technology *
* Yale University *
* *
* http://hstore.cs.brown.edu/ *
* *
* Permission is hereby granted, free of charge, to any person obtaining *
* a copy of this software and associated documentation files (the *
* "Software"), to deal in the Software without restriction, including *
* without limitation the rights to use, copy, modify, merge, publish, *
* distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to *
* the following conditions: *
* *
* The above copyright notice and this permission notice shall be *
* included in all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, *
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
***************************************************************************/
package edu.brown.utils;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.voltdb.VoltType;
import org.voltdb.catalog.ProcParameter;
import org.voltdb.catalog.Procedure;
import edu.brown.catalog.CatalogUtil;
/**
* Hackishly convert primitive arrays into object arrays
*
* @author pavlo
*/
public class ParameterMangler {
private final Procedure catalog_proc;
private final boolean has_arrays;
private final VoltType param_types[];
private final ProcParameter params[];
private final boolean param_isarray[];
private static final Map<Procedure, ParameterMangler> singletons = new HashMap<Procedure, ParameterMangler>();
public static ParameterMangler singleton(Procedure catalog_proc) {
ParameterMangler mangler = singletons.get(catalog_proc);
if (mangler == null) {
synchronized (ParameterMangler.class) {
mangler = singletons.get(catalog_proc);
if (mangler == null) {
mangler = new ParameterMangler(catalog_proc);
singletons.put(catalog_proc, mangler);
}
} // SYNCH
}
return (mangler);
}
private ParameterMangler(Procedure catalog_proc) {
this.catalog_proc = catalog_proc;
List<ProcParameter> catalog_params = CatalogUtil.getRegularProcParameters(catalog_proc);
int num_params = catalog_params.size();
this.params = new ProcParameter[num_params];
this.param_isarray = new boolean[num_params];
this.param_types = new VoltType[num_params];
boolean found_array = false;
for (int i = 0, cnt = catalog_params.size(); i < cnt; i++) {
ProcParameter catalog_param = catalog_params.get(i);
this.params[i] = catalog_param;
this.param_isarray[i] = catalog_param.getIsarray();
this.param_types[i] = VoltType.get(catalog_param.getType());
found_array = found_array || this.param_isarray[i];
} // FOR
this.has_arrays = found_array;
}
public static String toString(Object mangled[], boolean is_array[]) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < mangled.length; i++) {
sb.append(String.format(" [%02d] ", i));
if (is_array[i]) {
Object inner[] = (Object[]) mangled[i];
sb.append(String.format("%s / length=%d",
Arrays.toString(inner), inner.length));
} else {
sb.append(mangled[i]);
}
sb.append("\n");
} // FOR
return (sb.toString());
}
public String toString(Object mangled[]) {
return ParameterMangler.toString(mangled, this.param_isarray);
}
/**
* Thread-safe
* @param orig
* @return
*/
public Object[] convert(Object orig[]) {
// Nothing!
if (this.has_arrays == false)
return (orig);
Object cast_args[] = new Object[this.params.length];
for (int i = 0; i < this.params.length; i++) {
// Primitive Arrays! This is messed up in Java and why we're even here!
VoltType vtype = this.param_types[i];
if (this.param_isarray[i] && vtype != VoltType.STRING && vtype != VoltType.TIMESTAMP) {
Object inner[] = null;
try {
switch (this.param_types[i]) {
case TINYINT: {
if (orig[i] instanceof byte[]) {
byte arr[] = (byte[]) orig[i];
inner = new Byte[arr.length];
for (int j = 0; j < arr.length; j++) {
inner[j] = (byte)arr[j];
} // FOR
}
else if (orig[i] instanceof short[]) {
short arr[] = (short[]) orig[i];
inner = new Byte[arr.length];
for (int j = 0; j < arr.length; j++) {
inner[j] = (byte)arr[j];
} // FOR
}
else if (orig[i] instanceof int[]) {
int arr[] = (int[]) orig[i];
inner = new Byte[arr.length];
for (int j = 0; j < arr.length; j++) {
inner[j] = (byte)arr[j];
} // FOR
}
else if (orig[i] instanceof long[]) {
long arr[] = (long[]) orig[i];
inner = new Byte[arr.length];
for (int j = 0; j < arr.length; j++) {
inner[j] = (byte)arr[j];
} // FOR
}
else {
inner = new Byte[((Object[])orig[i]).length];
for (int j = 0; j < inner.length; j++) {
inner[j] = ((Number)((Object[])orig[i])[j]).byteValue();
} // FOR
}
break;
}
case SMALLINT: {
if (orig[i] instanceof byte[]) {
byte arr[] = (byte[]) orig[i];
inner = new Short[arr.length];
for (int j = 0; j < arr.length; j++) {
inner[j] = (short)arr[j];
} // FOR
}
else if (orig[i] instanceof short[]) {
short arr[] = (short[]) orig[i];
inner = new Short[arr.length];
for (int j = 0; j < arr.length; j++) {
inner[j] = (short)arr[j];
} // FOR
}
else if (orig[i] instanceof int[]) {
int arr[] = (int[]) orig[i];
inner = new Short[arr.length];
for (int j = 0; j < arr.length; j++) {
inner[j] = (short)arr[j];
} // FOR
}
else if (orig[i] instanceof long[]) {
long arr[] = (long[]) orig[i];
inner = new Short[arr.length];
for (int j = 0; j < arr.length; j++) {
inner[j] = (short)arr[j];
} // FOR
}
else {
inner = new Short[((Object[])orig[i]).length];
for (int j = 0; j < inner.length; j++) {
inner[j] = ((Number)((Object[])orig[i])[j]).shortValue();
} // FOR
}
break;
}
case INTEGER: {
if (orig[i] instanceof byte[]) {
byte arr[] = (byte[]) orig[i];
inner = new Integer[arr.length];
for (int j = 0; j < arr.length; j++) {
inner[j] = (int)arr[j];
} // FOR
}
else if (orig[i] instanceof short[]) {
short arr[] = (short[]) orig[i];
inner = new Integer[arr.length];
for (int j = 0; j < arr.length; j++) {
inner[j] = (int)arr[j];
} // FOR
}
else if (orig[i] instanceof int[]) {
int arr[] = (int[]) orig[i];
inner = new Integer[arr.length];
for (int j = 0; j < arr.length; j++) {
inner[j] = (int)arr[j];
} // FOR
}
else if (orig[i] instanceof long[]) {
long arr[] = (long[]) orig[i];
inner = new Integer[arr.length];
for (int j = 0; j < arr.length; j++) {
inner[j] = (int)arr[j];
} // FOR
}
else {
inner = new Integer[((Object[])orig[i]).length];
for (int j = 0; j < inner.length; j++) {
inner[j] = ((Number)((Object[])orig[i])[j]).intValue();
} // FOR
}
break;
}
case BIGINT: {
if (orig[i] instanceof byte[]) {
byte arr[] = (byte[]) orig[i];
inner = new Long[arr.length];
for (int j = 0; j < arr.length; j++) {
inner[j] = (long)arr[j];
} // FOR
}
else if (orig[i] instanceof short[]) {
short arr[] = (short[]) orig[i];
inner = new Long[arr.length];
for (int j = 0; j < arr.length; j++) {
inner[j] = (long)arr[j];
} // FOR
}
else if (orig[i] instanceof int[]) {
int arr[] = (int[]) orig[i];
inner = new Long[arr.length];
for (int j = 0; j < arr.length; j++) {
inner[j] = (long)arr[j];
} // FOR
}
else if (orig[i] instanceof long[]) {
long arr[] = (long[]) orig[i];
inner = new Long[arr.length];
for (int j = 0; j < arr.length; j++) {
inner[j] = (long)arr[j];
} // FOR
}
else {
inner = new Long[((Object[])orig[i]).length];
for (int j = 0; j < inner.length; j++) {
inner[j] = ((Number)((Object[])orig[i])[j]).longValue();
} // FOR
}
break;
}
case FLOAT: {
if (orig[i] instanceof float[]) {
float arr[] = (float[]) orig[i];
inner = new Double[arr.length];
for (int j = 0; j < arr.length; j++) {
inner[j] = Double.valueOf(arr[j]);
} // FOR
}
else if (orig[i] instanceof double[]) {
double arr[] = (double[]) orig[i];
inner = new Double[arr.length];
for (int j = 0; j < arr.length; j++) {
inner[j] = arr[j];
} // FOR
}
else if (orig[i] instanceof Float[]) {
inner = new Double[((Object[])orig[i]).length];
for (int j = 0; j < inner.length; j++) {
inner[j] = ((Number)((Object[])orig[i])[j]).doubleValue();
} // FOR
}
else {
inner = new Double[((Object[])orig[i]).length];
for (int j = 0; j < inner.length; j++) {
inner[j] = ((Number)((Object[])orig[i])[j]).doubleValue();
} // FOR
}
break;
}
default:
assert (false) : "Unhandled type " + this.param_types[i];
} // SWITCH
} catch (Exception ex) {
throw new RuntimeException("Failed to properly convert " + this.params[i].fullName(), ex);
}
cast_args[i] = inner;
} else {
assert (cast_args.length == orig.length) : String.format("%s #%d :: cast[%d] != orig[%d]\nCAST:%s\nORIG:%s\nPARAMS:%s", catalog_proc, i, cast_args.length, orig.length,
Arrays.toString(cast_args), Arrays.toString(orig), Arrays.toString(this.params));
cast_args[i] = orig[i];
}
} // FOR
return (cast_args);
}
}