/** * Copyright (C) 2009-2014 FoundationDB, LLC * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.foundationdb.server.types.aksql.aktypes; import com.foundationdb.server.error.AkibanInternalException; import com.foundationdb.server.error.UnsupportedSpatialCast; import com.foundationdb.server.spatial.Spatial; import com.foundationdb.server.types.Attribute; import com.foundationdb.server.types.FormatOptions; import com.foundationdb.server.types.TClass; import com.foundationdb.server.types.TClassBase; import com.foundationdb.server.types.TClassFormatter; import com.foundationdb.server.types.TExecutionContext; import com.foundationdb.server.types.TInstance; import com.foundationdb.server.types.TParser; import com.foundationdb.server.types.aksql.AkBundle; import com.foundationdb.server.types.value.ValueSource; import com.foundationdb.server.types.value.ValueTarget; import com.foundationdb.sql.StandardException; import com.foundationdb.sql.types.DataTypeDescriptor; import com.foundationdb.sql.types.TypeId; import com.foundationdb.util.AkibanAppender; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.io.WKTWriter; import java.io.IOException; import java.io.StringWriter; import java.sql.Types; /** An internal, runtime only wrapper around JTS Geometry objects. */ public class AkGeometry extends TClassBase { public static final TClass INSTANCE = new AkGeometry(); private static final String NAME = "GEOMETRY"; private static final TypeId TYPE_ID; private static final DataTypeDescriptor DATA_TYPE_DESCRIPTOR; static { try { TYPE_ID = TypeId.getUserDefinedTypeId(NAME, false); DATA_TYPE_DESCRIPTOR = new DataTypeDescriptor(TYPE_ID, true); } catch(StandardException e) { throw new IllegalStateException(e); } } private static class GeometryParser implements TParser { @Override public void parse(TExecutionContext context, ValueSource in, ValueTarget out) { throw new UnsupportedSpatialCast(); } } private static class GeometryFormatter implements TClassFormatter { @Override public void format(TInstance type, ValueSource source, AkibanAppender out) { out.append(source.getObject().toString()); } @Override public void formatAsLiteral(TInstance type, ValueSource source, AkibanAppender out) { StringWriter sw = new StringWriter(); try { new WKTWriter(Spatial.LAT_LON_DIMENSIONS).write((Geometry)source.getObject(), sw); } catch (IOException ex) { throw new AkibanInternalException("Error formatting to string", ex); } out.append('\''); out.append(sw.toString()); out.append('\''); } @Override public void formatAsJson(TInstance type, ValueSource source, AkibanAppender out, FormatOptions options) { // TODO: GeoJSON? throw new UnsupportedSpatialCast(); } } private AkGeometry() { super(AkBundle.INSTANCE.id(), NAME, null /*category*/, Attribute.NONE.class, new GeometryFormatter(), 1 /*internal version*/, 1 /*version*/, 0 /*size*/, null /*underlying type*/, new GeometryParser(), -1 /*default varchar len*/); } @Override public int jdbcType() { return Types.OTHER; } @Override protected DataTypeDescriptor dataTypeDescriptor(TInstance type) { return DATA_TYPE_DESCRIPTOR; } @Override public TClass widestComparable() { return this; } @Override protected boolean attributeIsPhysical(int attributeIndex) { throw new UnsupportedOperationException(); } @Override protected boolean attributeAlwaysDisplayed(int attributeIndex) { throw new UnsupportedOperationException(); } @Override public TInstance instance(boolean nullable) { return createInstanceNoArgs(nullable); } @Override protected TInstance doPickInstance(TInstance left, TInstance right, boolean suggestedNullability) { return createInstanceNoArgs(suggestedNullability); } @Override protected void validate(TInstance type) { } }