001/*
002 * Copyright (c) 2004-2016 Tada AB and other contributors, as listed below.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the The BSD 3-Clause License
006 * which accompanies this distribution, and is available at
007 * http://opensource.org/licenses/BSD-3-Clause
008 *
009 * Contributors:
010 *   Tada AB
011 *   Chapman Flack
012 */
013package org.postgresql.pljava.example.annotation;
014
015import java.sql.SQLData;
016import java.sql.SQLException;
017import java.sql.SQLInput;
018import java.sql.SQLOutput;
019import java.util.logging.Logger;
020
021import org.postgresql.pljava.annotation.Function;
022import org.postgresql.pljava.annotation.MappedUDT;
023import org.postgresql.pljava.annotation.SQLAction;
024
025import static org.postgresql.pljava.annotation.Function.Effects.IMMUTABLE;
026import static
027    org.postgresql.pljava.annotation.Function.OnNullInput.RETURNS_NULL;
028
029/**
030 * Example of a "mirrored UDT": a user-defined type that exposes to Java the
031 * internal representation of an existing (but not SQL-standard) PostgreSQL
032 * type. Naturally, the author of this type has to know (from the PostgreSQL
033 * source) that a {@code Point} is stored as two {@code float8}s, {@code x}
034 * first and then {@code y}.
035 */
036@SQLAction(requires={"point mirror type", "point assertHasValues"}, install=
037        "SELECT javatest.assertHasValues(CAST('(1,2)' AS point), 1, 2)"
038)
039@MappedUDT(name="point", provides="point mirror type")
040public class Point implements SQLData {
041    private static Logger s_logger = Logger.getAnonymousLogger();
042
043    /**
044     * Return the same 'point' passed in, logging its contents at level INFO.
045     * @param pt any instance of the type this UDT mirrors
046     * @return the same instance passed in
047     */
048    @Function(schema="javatest", requires="point mirror type",
049        effects=IMMUTABLE, onNullInput=RETURNS_NULL)
050    public static Point logAndReturn(Point pt) {
051        s_logger.info(pt.getSQLTypeName() + pt);
052        return pt;
053    }
054
055    /**
056     * Assert a 'point' has given x and y values, to test that its
057     * representation in Java corresponds to what PostgreSQL sees.
058     * @param pt an instance of this UDT
059     * @param x the x value it should have
060     * @param y the y value it should have
061     * @throws SQLException if the values do not match
062     */
063    @Function(schema="javatest",
064        requires="point mirror type", provides="point assertHasValues",
065        effects=IMMUTABLE, onNullInput=RETURNS_NULL)
066    public static void assertHasValues(Point pt, double x, double y)
067        throws SQLException
068    {
069        if ( pt.m_x != x  ||  pt.m_y != y )
070            throw new SQLException("assertHasValues fails");
071    }
072
073    private double m_x;
074    private double m_y;
075
076    private String m_typeName;
077
078    @Override
079    public String getSQLTypeName() {
080        return m_typeName;
081    }
082
083    @Override
084    public void readSQL(SQLInput stream, String typeName) throws SQLException {
085        s_logger.info(typeName + " from SQLInput");
086        m_x = stream.readDouble();
087        m_y = stream.readDouble();
088        m_typeName = typeName;
089    }
090
091    @Override
092    public void writeSQL(SQLOutput stream) throws SQLException {
093        s_logger.info(m_typeName + " to SQLOutput");
094        stream.writeDouble(m_x);
095        stream.writeDouble(m_y);
096    }
097
098    @Override
099    public String toString()
100    {
101        return String.format("(%g,%g)", m_x, m_y);
102    }
103}