com.impossibl.postgres.system.procs.Arrays Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of pgjdbc-ng Show documentation
Show all versions of pgjdbc-ng Show documentation
PostgreSQL JDBC - NG - Driver
/**
* Copyright (c) 2013, impossibl.com
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of impossibl.com nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package com.impossibl.postgres.system.procs;
import com.impossibl.postgres.protocol.ResultField.Format;
import com.impossibl.postgres.system.Context;
import com.impossibl.postgres.types.ArrayType;
import com.impossibl.postgres.types.PrimitiveType;
import com.impossibl.postgres.types.Type;
import com.impossibl.postgres.types.Type.Codec;
import java.io.IOException;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static java.lang.reflect.Array.newInstance;
import io.netty.buffer.ByteBuf;
/*
* Array codec
*
*/
public class Arrays extends SimpleProcProvider {
public Arrays() {
super(new TxtEncoder(), new TxtDecoder(), new BinEncoder(), new BinDecoder(), "array_", "anyarray_", "oidvector", "intvector");
}
static class BinDecoder extends BinaryDecoder {
@Override
public PrimitiveType getInputPrimitiveType() {
return PrimitiveType.Array;
}
@Override
public Class> getOutputType() {
return Object[].class;
}
@Override
public Object decode(Type type, Short typeLength, Integer typeModifier, ByteBuf buffer, Context context) throws IOException {
int length = buffer.readInt();
int readStart = buffer.readerIndex();
Object instance = null;
if (length != -1) {
ArrayType atype = ((ArrayType)type);
//
//Header
//
int dimensionCount = buffer.readInt();
/* boolean hasNulls = */ buffer.readInt() /* == 1 ? true : false */;
Type elementType = context.getRegistry().loadType(buffer.readInt());
//Each Dimension
int[] dimensions = new int[dimensionCount];
int[] lowerBounds = new int[dimensionCount];
for (int d = 0; d < dimensionCount; ++d) {
//Dimension
dimensions[d] = buffer.readInt();
//Lower bounds
lowerBounds[d] = buffer.readInt();
}
if (atype.getElementType().getId() != elementType.getId()) {
context.refreshType(atype.getId());
}
//
//Array & Elements
//
instance = readArray(buffer, elementType, dimensions, context);
if (length != buffer.readerIndex() - readStart) {
throw new IOException("invalid length");
}
}
return instance;
}
Object readArray(ByteBuf buffer, Type type, int[] dims, Context context) throws IOException {
if (dims.length == 0) {
return readElements(buffer, type, 0, context);
}
else if (dims.length == 1) {
return readElements(buffer, type, dims[0], context);
}
else {
return readSubArray(buffer, type, dims, context);
}
}
Object readSubArray(ByteBuf buffer, Type type, int[] dims, Context context) throws IOException {
Class> elementClass = type.unwrap().getJavaType(Format.Binary, Collections.> emptyMap());
Object inst = newInstance(elementClass, dims);
int[] subDims = java.util.Arrays.copyOfRange(dims, 1, dims.length);
for (int c = 0; c < dims[0]; ++c) {
Array.set(inst, c, readArray(buffer, type, subDims, context));
}
return inst;
}
Object readElements(ByteBuf buffer, Type type, int len, Context context) throws IOException {
Class> elementClass = type.unwrap().getJavaType(Format.Binary, Collections.> emptyMap());
Object inst = newInstance(elementClass, len);
for (int c = 0; c < len; ++c) {
Array.set(inst, c, type.getBinaryCodec().decoder.decode(type, null, null, buffer, context));
}
return inst;
}
}
static class BinEncoder extends BinaryEncoder {
@Override
public Class> getInputType() {
return Object[].class;
}
@Override
public PrimitiveType getOutputPrimitiveType() {
return PrimitiveType.Array;
}
@Override
public void encode(Type type, ByteBuf buffer, Object val, Context context) throws IOException {
buffer.writeInt(-1);
if (val != null) {
int writeStart = buffer.writerIndex();
ArrayType atype = ((ArrayType)type);
Type elementType = atype.getElementType();
//
//Header
//
int dimensionCount = getDimensions(val.getClass(), atype.unwrapAll());
//Dimension count
buffer.writeInt(dimensionCount);
//Has nulls
buffer.writeInt(hasNulls(val) ? 1 : 0);
//Element type
buffer.writeInt(elementType.getId());
//each dimension
Object dim = val;
for (int d = 0; d < dimensionCount; ++d) {
int dimension = 0;
if (dim != null)
dimension = Array.getLength(dim);
//Dimension
buffer.writeInt(dimension);
//Lower bounds
buffer.writeInt(1);
if (dimension == 0)
dim = null;
else if (dim != null)
dim = Array.get(dim, 0);
}
//
//Array & Elements
writeArray(buffer, elementType, val, context);
//Set length
buffer.setInt(writeStart - 4, buffer.writerIndex() - writeStart);
}
}
void writeArray(ByteBuf buffer, Type type, Object val, Context context) throws IOException {
if (val.getClass().getComponentType().isArray() && !type.getBinaryCodec().encoder.getInputType().isArray()) {
writeSubArray(buffer, type, val, context);
}
else {
writeElements(buffer, type, val, context);
}
}
void writeElements(ByteBuf buffer, Type type, Object val, Context context) throws IOException {
int len = Array.getLength(val);
for (int c = 0; c < len; ++c) {
type.getBinaryCodec().encoder.encode(type, buffer, Array.get(val, c), context);
}
}
void writeSubArray(ByteBuf buffer, Type type, Object val, Context context) throws IOException {
int len = Array.getLength(val);
for (int c = 0; c < len; ++c) {
writeArray(buffer, type, Array.get(val, c), context);
}
}
boolean hasNulls(Object value) {
for (int c = 0, sz = Array.getLength(value); c < sz; ++c) {
if (Array.get(value, c) == null)
return true;
}
return false;
}
@Override
public int length(Type type, Object val, Context context) throws IOException {
int length = 4;
if (val != null) {
ArrayType arrayType = (ArrayType) type;
Type elementType = arrayType.unwrapAll();
int dimensionCount = getDimensions(val.getClass(), arrayType.unwrapAll());
length += 12 + (dimensionCount * 8);
length += subLength(elementType, dimensionCount, val, context);
}
return length;
}
private int subLength(Type type, int dimensionCount, Object val, Context context) throws IOException {
int length = 0;
if (dimensionCount > 1) {
for (int d = 0, len = Array.getLength(val); d < len; ++d) {
length += subLength(type, dimensionCount - 1, Array.get(val, d), context);
}
}
else {
for (int c = 0, len = Array.getLength(val); c < len; ++c) {
length += type.getBinaryCodec().encoder.length(type, Array.get(val, c), context);
}
}
return length;
}
}
static class TxtDecoder extends TextDecoder {
@Override
public PrimitiveType getInputPrimitiveType() {
return PrimitiveType.Array;
}
@Override
public Class> getOutputType() {
return Object[].class;
}
@Override
public Object decode(Type type, Short typeLength, Integer typeModifier, CharSequence buffer, Context context) throws IOException {
int length = buffer.length();
Object instance = null;
if (length != 0) {
ArrayType atype = ((ArrayType)type);
instance = readArray(buffer, atype.getDelimeter(), type.unwrap(), context);
}
return instance;
}
Object readArray(CharSequence data, char delim, Type type, Context context) throws IOException {
if (data.length() < 2 || (data.charAt(0) != '{' && data.charAt(data.length() - 1) != '}')) {
return type.getCodec(Format.Text).decoder.decode(type, null, null, data, context);
}
data = data.subSequence(1, data.length() - 1);
List
© 2015 - 2024 Weber Informatics LLC | Privacy Policy