package org.postgresql.jdbc;
import org.postgresql.core.Oid;
import org.postgresql.core.TypeInfo;
import org.postgresql.util.ByteConverter;
import java.sql.Connection;
import java.sql.SQLFeatureNotSupportedException;
import java.util.HashMap;
import java.util.Map;
abstract class PrimitiveArraySupport<A> {
public abstract int getDefaultArrayTypeOid(TypeInfo tiCache);
public abstract String toArrayString(char delim, A array);
public abstract void appendArray(StringBuilder sb, char delim, A array);
public boolean supportBinaryRepresentation() {
return true;
}
public abstract byte[] toBinaryRepresentation(Connection connection, A array) throws SQLFeatureNotSupportedException;
private static final PrimitiveArraySupport<long[]> LONG_ARRAY = new PrimitiveArraySupport<long[]>() {
@Override
public int getDefaultArrayTypeOid(TypeInfo tiCache) {
return Oid.INT8_ARRAY;
}
@Override
public String toArrayString(char delim, long[] array) {
final StringBuilder sb = new StringBuilder(Math.max(64, array.length * 8));
appendArray(sb, delim, array);
return sb.toString();
}
@Override
public void appendArray(StringBuilder sb, char delim, long[] array) {
sb.append('{');
for (int i = 0; i < array.length; ++i) {
if (i > 0) {
sb.append(delim);
}
sb.append(array[i]);
}
sb.append('}');
}
@Override
public byte[] toBinaryRepresentation(Connection connection, long[] array) {
int length = 20 + (12 * array.length);
final byte[] bytes = new byte[length];
ByteConverter.int4(bytes, 0, 1);
ByteConverter.int4(bytes, 4, 0);
ByteConverter.int4(bytes, 8, Oid.INT8);
ByteConverter.int4(bytes, 12, array.length);
int idx = 20;
for (int i = 0; i < array.length; ++i) {
bytes[idx + 3] = 8;
ByteConverter.int8(bytes, idx + 4, array[i]);
idx += 12;
}
return bytes;
}
};
private static final PrimitiveArraySupport<int[]> INT_ARRAY = new PrimitiveArraySupport<int[]>() {
@Override
public int getDefaultArrayTypeOid(TypeInfo tiCache) {
return Oid.INT4_ARRAY;
}
@Override
public String toArrayString(char delim, int[] array) {
final StringBuilder sb = new StringBuilder(Math.max(32, array.length * 6));
appendArray(sb, delim, array);
return sb.toString();
}
@Override
public void appendArray(StringBuilder sb, char delim, int[] array) {
sb.append('{');
for (int i = 0; i < array.length; ++i) {
if (i > 0) {
sb.append(delim);
}
sb.append(array[i]);
}
sb.append('}');
}
@Override
public byte[] toBinaryRepresentation(Connection connection, int[] array) {
int length = 20 + (8 * array.length);
final byte[] bytes = new byte[length];
ByteConverter.int4(bytes, 0, 1);
ByteConverter.int4(bytes, 4, 0);
ByteConverter.int4(bytes, 8, Oid.INT4);
ByteConverter.int4(bytes, 12, array.length);
int idx = 20;
for (int i = 0; i < array.length; ++i) {
bytes[idx + 3] = 4;
ByteConverter.int4(bytes, idx + 4, array[i]);
idx += 8;
}
return bytes;
}
};
private static final PrimitiveArraySupport<short[]> SHORT_ARRAY = new PrimitiveArraySupport<short[]>() {
@Override
public int getDefaultArrayTypeOid(TypeInfo tiCache) {
return Oid.INT2_ARRAY;
}
@Override
public String toArrayString(char delim, short[] array) {
final StringBuilder sb = new StringBuilder(Math.max(32, array.length * 4));
appendArray(sb, delim, array);
return sb.toString();
}
@Override
public void appendArray(StringBuilder sb, char delim, short[] array) {
sb.append('{');
for (int i = 0; i < array.length; ++i) {
if (i > 0) {
sb.append(delim);
}
sb.append(array[i]);
}
sb.append('}');
}
@Override
public byte[] toBinaryRepresentation(Connection connection, short[] array) {
int length = 20 + (6 * array.length);
final byte[] bytes = new byte[length];
ByteConverter.int4(bytes, 0, 1);
ByteConverter.int4(bytes, 4, 0);
ByteConverter.int4(bytes, 8, Oid.INT2);
ByteConverter.int4(bytes, 12, array.length);
int idx = 20;
for (int i = 0; i < array.length; ++i) {
bytes[idx + 3] = 2;
ByteConverter.int2(bytes, idx + 4, array[i]);
idx += 6;
}
return bytes;
}
};
private static final PrimitiveArraySupport<double[]> DOUBLE_ARRAY = new PrimitiveArraySupport<double[]>() {
@Override
public int getDefaultArrayTypeOid(TypeInfo tiCache) {
return Oid.FLOAT8_ARRAY;
}
@Override
public String toArrayString(char delim, double[] array) {
final StringBuilder sb = new StringBuilder(Math.max(64, array.length * 8));
appendArray(sb, delim, array);
return sb.toString();
}
@Override
public void appendArray(StringBuilder sb, char delim, double[] array) {
sb.append('{');
for (int i = 0; i < array.length; ++i) {
if (i > 0) {
sb.append(delim);
}
sb.append('"');
sb.append(array[i]);
sb.append('"');
}
sb.append('}');
}
@Override
public byte[] toBinaryRepresentation(Connection connection, double[] array) {
int length = 20 + (12 * array.length);
final byte[] bytes = new byte[length];
ByteConverter.int4(bytes, 0, 1);
ByteConverter.int4(bytes, 4, 0);
ByteConverter.int4(bytes, 8, Oid.FLOAT8);
ByteConverter.int4(bytes, 12, array.length);
int idx = 20;
for (int i = 0; i < array.length; ++i) {
bytes[idx + 3] = 8;
ByteConverter.float8(bytes, idx + 4, array[i]);
idx += 12;
}
return bytes;
}
};
private static final PrimitiveArraySupport<float[]> FLOAT_ARRAY = new PrimitiveArraySupport<float[]>() {
@Override
public int getDefaultArrayTypeOid(TypeInfo tiCache) {
return Oid.FLOAT4_ARRAY;
}
@Override
public String toArrayString(char delim, float[] array) {
final StringBuilder sb = new StringBuilder(Math.max(64, array.length * 8));
appendArray(sb, delim, array);
return sb.toString();
}
@Override
public void appendArray(StringBuilder sb, char delim, float[] array) {
sb.append('{');
for (int i = 0; i < array.length; ++i) {
if (i > 0) {
sb.append(delim);
}
sb.append('"');
sb.append(array[i]);
sb.append('"');
}
sb.append('}');
}
@Override
public byte[] toBinaryRepresentation(Connection connection, float[] array) {
int length = 20 + (8 * array.length);
final byte[] bytes = new byte[length];
ByteConverter.int4(bytes, 0, 1);
ByteConverter.int4(bytes, 4, 0);
ByteConverter.int4(bytes, 8, Oid.FLOAT4);
ByteConverter.int4(bytes, 12, array.length);
int idx = 20;
for (int i = 0; i < array.length; ++i) {
bytes[idx + 3] = 4;
ByteConverter.float4(bytes, idx + 4, array[i]);
idx += 8;
}
return bytes;
}
};
private static final PrimitiveArraySupport<boolean[]> BOOLEAN_ARRAY = new PrimitiveArraySupport<boolean[]>() {
@Override
public int getDefaultArrayTypeOid(TypeInfo tiCache) {
return Oid.BOOL_ARRAY;
}
@Override
public String toArrayString(char delim, boolean[] array) {
final StringBuilder sb = new StringBuilder(Math.max(64, array.length * 8));
appendArray(sb, delim, array);
return sb.toString();
}
@Override
public void appendArray(StringBuilder sb, char delim, boolean[] array) {
sb.append('{');
for (int i = 0; i < array.length; ++i) {
if (i > 0) {
sb.append(delim);
}
sb.append(array[i] ? '1' : '0');
}
sb.append('}');
}
@Override
public byte[] toBinaryRepresentation(Connection connection, boolean[] array) throws SQLFeatureNotSupportedException {
int length = 20 + (5 * array.length);
final byte[] bytes = new byte[length];
ByteConverter.int4(bytes, 0, 1);
ByteConverter.int4(bytes, 4, 0);
ByteConverter.int4(bytes, 8, Oid.BOOL);
ByteConverter.int4(bytes, 12, array.length);
int idx = 20;
for (int i = 0; i < array.length; ++i) {
bytes[idx + 3] = 1;
ByteConverter.bool(bytes, idx + 4, array[i]);
idx += 5;
}
return bytes;
}
};
private static final PrimitiveArraySupport<String[]> STRING_ARRAY = new PrimitiveArraySupport<String[]>() {
@Override
public int getDefaultArrayTypeOid(TypeInfo tiCache) {
return Oid.VARCHAR_ARRAY;
}
@Override
public String toArrayString(char delim, String[] array) {
final StringBuilder sb = new StringBuilder(Math.max(64, array.length * 8));
appendArray(sb, delim, array);
return sb.toString();
}
@Override
public void appendArray(StringBuilder sb, char delim, String[] array) {
sb.append('{');
for (int i = 0; i < array.length; ++i) {
if (i > 0) {
sb.append(delim);
}
if (array[i] == null) {
sb.append('N');
sb.append('U');
sb.append('L');
sb.append('L');
} else {
PgArray.escapeArrayElement(sb, array[i]);
}
}
sb.append('}');
}
@Override
public boolean supportBinaryRepresentation() {
return false;
}
@Override
public byte[] toBinaryRepresentation(Connection connection, String[] array) throws SQLFeatureNotSupportedException {
throw new SQLFeatureNotSupportedException();
}
};
private static final Map<Class, PrimitiveArraySupport> ARRAY_CLASS_TO_SUPPORT = new HashMap<Class, PrimitiveArraySupport>((int) (7 / .75) + 1);
static {
ARRAY_CLASS_TO_SUPPORT.put(long[].class, LONG_ARRAY);
ARRAY_CLASS_TO_SUPPORT.put(int[].class, INT_ARRAY);
ARRAY_CLASS_TO_SUPPORT.put(short[].class, SHORT_ARRAY);
ARRAY_CLASS_TO_SUPPORT.put(double[].class, DOUBLE_ARRAY);
ARRAY_CLASS_TO_SUPPORT.put(float[].class, FLOAT_ARRAY);
ARRAY_CLASS_TO_SUPPORT.put(boolean[].class, BOOLEAN_ARRAY);
ARRAY_CLASS_TO_SUPPORT.put(String[].class, STRING_ARRAY);
}
public static boolean isSupportedPrimitiveArray(Object obj) {
return obj != null && ARRAY_CLASS_TO_SUPPORT.containsKey(obj.getClass());
}
public static <A> PrimitiveArraySupport<A> getArraySupport(A array) {
return ARRAY_CLASS_TO_SUPPORT.get(array.getClass());
}
}