001/*
002 * Copyright (c) 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 *   Chapman Flack
011 */
012package org.postgresql.pljava.example.annotation;
013
014import java.sql.SQLData;
015import java.sql.SQLException;
016import java.sql.SQLInput;
017import java.sql.SQLOutput;
018
019import org.postgresql.pljava.annotation.SQLAction;
020import org.postgresql.pljava.annotation.BaseUDT;
021import org.postgresql.pljava.annotation.Function;
022import static org.postgresql.pljava.annotation.Function.Effects.IMMUTABLE;
023
024/**
025 * A User Defined Type with varlena storage, testing github issue 52.
026 *
027 * This looks from SQL like an integer type, but is stored in <em>unary</em>:
028 * the integer value <em>n</em> is represented by <em>n</em> {@code a}
029 * characters. That makes it easy to test how big a value gets correctly stored
030 * and retrieved. It should be about a GB, but in issue 52 was failing at 32768
031 * because of a narrowing assignment in the native code.
032 *<p>
033 * This example relies on {@code implementor} tags reflecting the PostgreSQL
034 * version, set up in the {@link ConditionalDDR} example.
035 */
036@SQLAction(requires="varlena UDT", implementor="postgresql_ge_80300", install=
037"  SELECT CASE v::text = v::javatest.VarlenaUDTTest::text " +
038"   WHEN true THEN javatest.logmessage('INFO', 'works for ' || v) " +
039"   ELSE javatest.logmessage('WARNING', 'fails for ' || v) " +
040"   END " +
041"   FROM (VALUES (('32767')), (('32768')), (('65536')), (('1048576'))) " +
042"   AS t ( v )"
043)
044@BaseUDT(schema="javatest", provides="varlena UDT")
045public class VarlenaUDTTest implements SQLData {
046    int apop;
047    String typname;
048
049    public VarlenaUDTTest() { }
050
051    @Function(effects=IMMUTABLE)
052    public static VarlenaUDTTest parse( String s, String typname) {
053        int i = Integer.parseInt( s);
054        VarlenaUDTTest u = new VarlenaUDTTest();
055        u.apop = i;
056        u.typname = typname;
057        return u;
058    }
059
060    @Function(effects=IMMUTABLE)
061    public String toString() {
062        return String.valueOf( apop);
063    }
064
065    public String getSQLTypeName() {
066        return typname;
067    }
068
069    @Function(effects=IMMUTABLE)
070    public void writeSQL( SQLOutput stream) throws SQLException {
071        for ( int i = 0 ; i < apop ; ++ i )
072            stream.writeByte( (byte)'a');
073    }
074
075    @Function(effects=IMMUTABLE)
076    public void readSQL( SQLInput stream, String typname) throws SQLException {
077        this.typname = typname;
078        int i = 0;
079        for ( ;; ++i )
080            try {
081                stream.readByte();
082            }
083            catch ( SQLException sqle ) {
084                if ( "22P03".equals( sqle.getSQLState()) )
085                    break;
086                throw sqle;
087            }
088        apop = i;
089    }
090}