/*
* Licensed to Crate under one or more contributor license agreements.
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership. Crate licenses this file
* to you under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may
* obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
* However, if you have executed another commercial license agreement
* with Crate these terms will supersede the license and you may use the
* software solely pursuant to the terms of the relevant commercial
* agreement.
*/
package io.crate.protocols.postgres.types;
import com.carrotsearch.hppc.IntObjectHashMap;
import com.carrotsearch.hppc.IntObjectMap;
import com.google.common.collect.ImmutableMap;
import io.crate.types.*;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
public class PGTypes {
private static final Map<DataType, PGType> CRATE_TO_PG_TYPES = ImmutableMap.<DataType, PGType>builder()
.put(DataTypes.BYTE, CharType.INSTANCE)
.put(DataTypes.STRING, VarCharType.INSTANCE)
.put(DataTypes.BOOLEAN, BooleanType.INSTANCE)
.put(DataTypes.OBJECT, JsonType.INSTANCE)
.put(DataTypes.SHORT, SmallIntType.INSTANCE)
.put(DataTypes.INTEGER, IntegerType.INSTANCE)
.put(DataTypes.LONG, BigIntType.INSTANCE)
.put(DataTypes.FLOAT, RealType.INSTANCE)
.put(DataTypes.DOUBLE, DoubleType.INSTANCE)
.put(DataTypes.TIMESTAMP, TimestampType.INSTANCE)
.put(DataTypes.IP, VarCharType.INSTANCE) // postgres has no IP type, so map it to varchar - it matches the client representation
.put(DataTypes.UNDEFINED, VarCharType.INSTANCE)
.put(DataTypes.GEO_POINT, PGArray.FLOAT8_ARRAY)
.put(DataTypes.GEO_SHAPE, JsonType.INSTANCE)
.put(new ArrayType(DataTypes.BYTE), PGArray.CHAR_ARRAY)
.put(new ArrayType(DataTypes.SHORT), PGArray.INT2_ARRAY)
.put(new ArrayType(DataTypes.INTEGER), PGArray.INT4_ARRAY)
.put(new ArrayType(DataTypes.LONG), PGArray.INT8_ARRAY)
.put(new ArrayType(DataTypes.FLOAT), PGArray.FLOAT4_ARRAY)
.put(new ArrayType(DataTypes.DOUBLE), PGArray.FLOAT8_ARRAY)
.put(new ArrayType(DataTypes.BOOLEAN), PGArray.BOOL_ARRAY)
.put(new ArrayType(DataTypes.TIMESTAMP), PGArray.TIMESTAMPZ_ARRAY)
.put(new ArrayType(DataTypes.STRING), PGArray.VARCHAR_ARRAY)
.put(new ArrayType(DataTypes.GEO_POINT), PGArray.FLOAT8_ARRAY)
.put(new ArrayType(DataTypes.GEO_SHAPE), PGArray.JSON_ARRAY)
.put(new ArrayType(DataTypes.OBJECT), JsonType.INSTANCE)
.put(new SetType(DataTypes.BYTE), PGArray.CHAR_ARRAY) // postgres has no Set type, so map it to array
.put(new SetType(DataTypes.SHORT), PGArray.INT2_ARRAY)
.put(new SetType(DataTypes.INTEGER), PGArray.INT4_ARRAY)
.put(new SetType(DataTypes.LONG), PGArray.INT8_ARRAY)
.put(new SetType(DataTypes.FLOAT), PGArray.FLOAT4_ARRAY)
.put(new SetType(DataTypes.DOUBLE), PGArray.FLOAT8_ARRAY)
.put(new SetType(DataTypes.BOOLEAN), PGArray.BOOL_ARRAY)
.put(new SetType(DataTypes.TIMESTAMP), PGArray.TIMESTAMPZ_ARRAY)
.put(new SetType(DataTypes.STRING), PGArray.VARCHAR_ARRAY)
.put(new SetType(DataTypes.GEO_POINT), PGArray.FLOAT8_ARRAY)
.put(new SetType(DataTypes.GEO_SHAPE), PGArray.JSON_ARRAY)
.put(new SetType(DataTypes.OBJECT), JsonType.INSTANCE)
.build();
private static final IntObjectMap<DataType> PG_TYPES_TO_CRATE_TYPE = new IntObjectHashMap<>();
private static final Set<PGType> TYPES;
static {
for (Map.Entry<DataType, PGType> e : CRATE_TO_PG_TYPES.entrySet()) {
int oid = e.getValue().oid();
// crate string and ip types both map to pg varchar, avoid overwriting the mapping that is first established.
if (!PG_TYPES_TO_CRATE_TYPE.containsKey(oid)) {
PG_TYPES_TO_CRATE_TYPE.put(oid, e.getKey());
}
}
PG_TYPES_TO_CRATE_TYPE.put(0, DataTypes.UNDEFINED);
TYPES = new HashSet<>(CRATE_TO_PG_TYPES.values()); // some pgTypes are used multiple times, de-dup them
}
public static Iterable<PGType> pgTypes() {
return TYPES;
}
public static DataType fromOID(int oid) {
return PG_TYPES_TO_CRATE_TYPE.get(oid);
}
public static PGType get(DataType type) {
if (type instanceof CollectionType) {
DataType<?> innerType = ((CollectionType) type).innerType();
if (innerType instanceof CollectionType) {
// if this is a nested collection stream it as JSON because
// postgres binary format doesn't support multidimensional arrays with sub-arrays of different length
// (something like [ [1, 2], [3] ] is not supported)
return JsonType.INSTANCE;
}
}
PGType pgType = CRATE_TO_PG_TYPES.get(type);
if (pgType == null) {
throw new IllegalArgumentException(String.format(Locale.ENGLISH,
"No type mapping from '%s' to pg_type", type.getName()));
}
return pgType;
}
}