001/* 002 * Copyright (c) 2016-2020 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 * Chapman Flack 011 */ 012package org.postgresql.pljava.example.annotation; 013 014import java.math.BigDecimal; 015import java.sql.Date; 016import java.sql.Time; 017import java.sql.Timestamp; 018import java.net.URL; 019import java.net.MalformedURLException; 020 021import java.io.InputStream; 022import java.io.IOException; 023import java.io.ByteArrayInputStream; 024import java.io.ByteArrayOutputStream; 025import java.io.StringReader; 026import java.nio.ByteBuffer; 027import java.nio.CharBuffer; 028import static java.nio.charset.StandardCharsets.UTF_8; 029import java.nio.charset.CharacterCodingException; 030import java.nio.charset.CharsetDecoder; 031import java.nio.charset.CharsetEncoder; 032import java.util.Arrays; 033import java.util.Scanner; 034 035import java.sql.SQLData; 036import java.sql.SQLDataException; 037import java.sql.SQLException; 038import java.sql.SQLInput; 039import java.sql.SQLOutput; 040 041import org.postgresql.pljava.annotation.Function; 042import org.postgresql.pljava.annotation.BaseUDT; 043import org.postgresql.pljava.annotation.SQLAction; 044 045import static org.postgresql.pljava.annotation.Function.Effects.IMMUTABLE; 046import static 047 org.postgresql.pljava.annotation.Function.OnNullInput.RETURNS_NULL; 048 049/** 050 * A special user-defined type simply to exercise the I/O routines. 051 *<p> 052 * There is only one 'value' of this type. Its text representation is an empty 053 * string. Its binary representation is a sequence of fixed values in all the 054 * supported JDBC data types, which it writes on output, and reads/verifies on 055 * input. 056 */ 057@SQLAction(requires= { "udtscalariotest type" }, 058 install = { 059 "SELECT CAST('' AS javatest.udtscalariotest)" // test send/recv 060 }) 061@BaseUDT(schema="javatest", provides="udtscalariotest type") 062public class UDTScalarIOTest implements SQLData 063{ 064 065 private String m_typeName; 066 067 private static BigDecimal s_bigdec = new BigDecimal( 068 "11111111111111111111111111111111111.22222222222222222222222222222222"); 069 070 private static String s_gedicht = 071"Dû bist mîn, ich bin dîn:\n" + 072"des solt dû gewis sîn;\n" + 073"dû bist beslozzen in mînem herzen,\n" + 074"verlorn ist daz slüzzelîn:\n" + 075"dû muost och immer darinne sîn."; 076 private static byte[] s_utfgedicht; 077 078 private static boolean s_bool = true; 079 private static byte s_byte = 42; 080 private static Date s_date = Date.valueOf("2004-01-07"); 081 private static double s_double = Math.PI; 082 private static float s_float = (float)Math.E; 083 private static int s_int = 42424242; 084 private static long s_long = 4242424242424242L; 085 private static short s_short = 4242; 086 private static Time s_time = Time.valueOf("06:33:24"); 087 private static Timestamp s_timestamp = 088 Timestamp.valueOf("2004-01-07 06:33:24"); 089 private static URL s_url; 090 091 static 092 { 093 try 094 { 095 s_gedicht = s_gedicht + s_gedicht + s_gedicht; // x3 096 s_gedicht = s_gedicht + s_gedicht + s_gedicht; // x9 097 098 ByteBuffer bb = UTF_8.newEncoder().encode( 099 CharBuffer.wrap(s_gedicht)); 100 s_utfgedicht = new byte[bb.limit()]; 101 bb.get(s_utfgedicht); 102 103 s_url = new URL("http://tada.github.io/pljava/"); 104 } 105 catch ( CharacterCodingException | MalformedURLException e ) 106 { 107 throw new RuntimeException(e); 108 } 109 } 110 111 @Function(effects=IMMUTABLE, onNullInput=RETURNS_NULL) 112 public static UDTScalarIOTest parse(String input, String typeName) 113 throws SQLException 114 { 115 if ( ! "".equals(input) ) 116 throw new SQLDataException( 117 "The only valid text value for UDTScalarIOTest is ''", "22P02"); 118 UDTScalarIOTest instance = new UDTScalarIOTest(); 119 instance.m_typeName = typeName; 120 return instance; 121 } 122 123 @Function(effects=IMMUTABLE, onNullInput=RETURNS_NULL) 124 @Override 125 public String toString() 126 { 127 return ""; 128 } 129 130 @Override 131 public String getSQLTypeName() 132 { 133 return m_typeName; 134 } 135 136 public UDTScalarIOTest() 137 { 138 } 139 140 @Function(effects=IMMUTABLE, onNullInput=RETURNS_NULL) 141 @Override 142 public void writeSQL(SQLOutput stream) throws SQLException 143 { 144 stream.writeBigDecimal(s_bigdec); 145 stream.writeBinaryStream(new ByteArrayInputStream(s_utfgedicht)); 146 stream.writeBoolean(s_bool); 147 stream.writeByte(s_byte); 148 stream.writeBytes(s_utfgedicht); 149 stream.writeCharacterStream(new StringReader(s_gedicht)); 150 stream.writeDate(s_date); 151 stream.writeDouble(s_double); 152 stream.writeFloat(s_float); 153 stream.writeInt(s_int); 154 stream.writeLong(s_long); 155 stream.writeShort(s_short); 156 stream.writeString(s_gedicht); 157 stream.writeTime(s_time); 158 stream.writeTimestamp(s_timestamp); 159 stream.writeURL(s_url); 160 } 161 162 @Function(effects=IMMUTABLE, onNullInput=RETURNS_NULL) 163 @Override 164 public void readSQL(SQLInput stream, String typeName) throws SQLException 165 { 166 m_typeName = typeName; 167 168 if ( ! s_bigdec.equals(stream.readBigDecimal()) ) 169 throw new SQLException("BigDecimal mismatch"); 170 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 171 InputStream is = stream.readBinaryStream(); 172 try 173 { 174 for ( int b ; -1 != (b = is.read()) ; ) 175 baos.write(b); 176 } 177 catch ( IOException e ) 178 { 179 throw new SQLException("Reading binary stream", 180 "58030", e); 181 } 182 if ( ! Arrays.equals(s_utfgedicht, baos.toByteArray()) ) 183 throw new SQLException("binaryStream mismatch"); 184 if ( s_bool != stream.readBoolean() ) 185 throw new SQLException("boolean mismatch"); 186 if ( s_byte != stream.readByte() ) 187 throw new SQLException("byte mismatch"); 188 if ( ! Arrays.equals(s_utfgedicht, stream.readBytes()) ) 189 throw new SQLException("bytes mismatch"); 190 String charstream = new Scanner(stream.readCharacterStream()) 191 .useDelimiter("\\A").next(); 192 if ( ! s_gedicht.equals(charstream) ) 193 throw new SQLException("characterStream mismatch"); 194 if ( ! s_date.equals(stream.readDate()) ) 195 throw new SQLException("date mismatch"); 196 if ( s_double != stream.readDouble() ) 197 throw new SQLException("double mismatch"); 198 if ( s_float != stream.readFloat() ) 199 throw new SQLException("float mismatch"); 200 if ( s_int != stream.readInt() ) 201 throw new SQLException("int mismatch"); 202 if ( s_long != stream.readLong() ) 203 throw new SQLException("long mismatch"); 204 if ( s_short != stream.readShort() ) 205 throw new SQLException("short mismatch"); 206 if ( ! s_gedicht.equals(stream.readString()) ) 207 throw new SQLException("string mismatch"); 208 if ( ! s_time.equals(stream.readTime()) ) 209 throw new SQLException("time mismatch"); 210 if ( ! s_timestamp.equals(stream.readTimestamp()) ) 211 throw new SQLException("timestamp mismatch"); 212 if ( ! s_url.equals(stream.readURL()) ) 213 throw new SQLException("url mismatch"); 214 } 215}