001/* 002 * Copyright (c) 2004-2015 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.Connection; 016import java.sql.DriverManager; 017import java.sql.PreparedStatement; 018import java.sql.ResultSet; 019import java.sql.SQLData; 020import java.sql.SQLException; 021import java.sql.SQLInput; 022import java.sql.SQLOutput; 023import java.util.logging.Logger; 024 025import org.postgresql.pljava.annotation.Function; 026import org.postgresql.pljava.annotation.MappedUDT; 027import org.postgresql.pljava.annotation.SQLAction; 028 029import static org.postgresql.pljava.annotation.Function.Effects.IMMUTABLE; 030import static 031 org.postgresql.pljava.annotation.Function.OnNullInput.RETURNS_NULL; 032 033/** 034 * Complex (re and im parts are doubles) implemented in Java as a mapped UDT. 035 */ 036@SQLAction(requires={ 037 "complextuple assertHasValues","complextuple setParameter"}, install={ 038 "SELECT javatest.assertHasValues(" + 039 " CAST('(1,2)' AS javatest.complextuple), 1, 2)", 040 "SELECT javatest.setParameter()" 041 } 042) 043@MappedUDT(schema="javatest", name="complextuple", 044structure={ 045 "x float8", 046 "y float8" 047}) 048public class ComplexTuple implements SQLData { 049 private static Logger s_logger = Logger.getAnonymousLogger(); 050 051 /** 052 * Return the same 'complextuple' passed in, logging its contents at 053 * level INFO. 054 * @param cpl any instance of this UDT 055 * @return the same instance passed in 056 */ 057 @Function(schema="javatest", name="logcomplex", 058 effects=IMMUTABLE, onNullInput=RETURNS_NULL) 059 public static ComplexTuple logAndReturn(ComplexTuple cpl) { 060 s_logger.info(cpl.getSQLTypeName() + "(" + cpl.m_x + ", " + cpl.m_y 061 + ")"); 062 return cpl; 063 } 064 065 /** 066 * Assert a 'complextuple' has given re and im values, to test that its 067 * representation in Java corresponds to what PostgreSQL sees. 068 * @param cpl an instance of this UDT 069 * @param re the 'real' value it should have 070 * @param im the 'imaginary' value it should have 071 * @throws SQLException if the values do not match 072 */ 073 @Function(schema="javatest", provides="complextuple assertHasValues", 074 effects=IMMUTABLE, onNullInput=RETURNS_NULL) 075 public static void assertHasValues(ComplexTuple cpl, double re, double im) 076 throws SQLException 077 { 078 if ( cpl.m_x != re || cpl.m_y != im ) 079 throw new SQLException("assertHasValues fails"); 080 } 081 082 /** 083 * Pass a 'complextuple' UDT as a parameter to a PreparedStatement 084 * that returns it, and verify that it makes the trip intact. 085 */ 086 @Function(schema="javatest", provides="complextuple setParameter", 087 effects=IMMUTABLE, onNullInput=RETURNS_NULL) 088 public static void setParameter() throws SQLException 089 { 090 Connection c = DriverManager.getConnection("jdbc:default:connection"); 091 PreparedStatement ps = 092 c.prepareStatement("SELECT CAST(? AS javatest.complextuple)"); 093 ComplexTuple ct = new ComplexTuple(); 094 ct.m_x = 1.5; 095 ct.m_y = 2.5; 096 ct.m_typeName = "javatest.complextuple"; 097 ps.setObject(1, ct); 098 ResultSet rs = ps.executeQuery(); 099 rs.next(); 100 ct = (ComplexTuple)rs.getObject(1); 101 ps.close(); 102 assertHasValues(ct, 1.5, 2.5); 103 } 104 105 private double m_x; 106 private double m_y; 107 108 private String m_typeName; 109 110 @Override 111 public String getSQLTypeName() { 112 return m_typeName; 113 } 114 115 @Override 116 public void readSQL(SQLInput stream, String typeName) throws SQLException { 117 m_typeName = typeName; 118 m_x = stream.readDouble(); 119 m_y = stream.readDouble(); 120 s_logger.info(typeName + " from SQLInput"); 121 } 122 123 @Override 124 public void writeSQL(SQLOutput stream) throws SQLException { 125 stream.writeDouble(m_x); 126 stream.writeDouble(m_y); 127 s_logger.info(m_typeName + " to SQLOutput"); 128 } 129}