From: thomas at tada.se (Thomas Hallgren) Date: Thu, 28 Sep 2006 15:49:40 +0200 Subject: [Pljava-dev] VarLenTuple example code In-Reply-To: <451BD0B1.8000408@logix-tt.com> References: <451BD0B1.8000408@logix-tt.com> Message-ID: <451BD2F4.60202@tada.se> Hmm, perhaps just an oversight, bot you don't have UDT syntax on the send/receive methods, i.e. this line: + AS 'org.postgresql.pljava.example.VarLenTuple.receive' should read + AS 'UDT[org.postgresql.pljava.example.VarLenTuple] receive' Regards, Thomas Hallgren Markus Schaber wrote: > Hi, Thomas, > > Here's a small example I implemented for variable length data types. > > It's not useful for anything but an example. > > I included the source, as well as the diff for the examples.ddr file, so > regard it as contribution. > > It all seems to work fine, apart from one small problem: > > >> [local]:pljavatest=# copy foo to '/tmp/foo' binary; >> COPY >> [local]:pljavatest=# copy foo from '/tmp/foo' binary; >> ERROR: Unable to find static method >> org.postgresql.pljava.example.VarLenTuple.receive >> with signature >> (Ljava/lang/String;)Lorg/postgresql/pljava/example/VarLenTuple; >> CONTEXT: COPY foo, line 1, column t >> > > >From our discussion, I had the impression that the receive method > will get an VarLenTuple instance (as I created a type mapping) > and not a String instance. > > Thanks, > Markus > > ------------------------------------------------------------------------ > > Index: src/java/examples/deployment/examples.ddr > =================================================================== > RCS file: /usr/local/cvsroot/pljava/org.postgresql.pljava/src/java/examples/deployment/examples.ddr,v > retrieving revision 1.35 > diff -u -r1.35 examples.ddr > --- src/java/examples/deployment/examples.ddr 13 May 2006 09:18:38 -0000 1.35 > +++ src/java/examples/deployment/examples.ddr 28 Sep 2006 13:29:26 -0000 > @@ -430,6 +430,57 @@ > AS 'org.postgresql.pljava.example.ComplexTuple.logAndReturn' > LANGUAGE java IMMUTABLE STRICT; > > + /* > + * Shell Type Definition for VarLenTuple: > + */ > + CREATE FUNCTION javatest.varlentuple(cstring) RETURNS javatest.varlentuple AS 'lower' LANGUAGE INTERNAL; > + > + /* The scalar input function */ > + CREATE FUNCTION varlentuple_in(cstring) > + RETURNS javatest.varlentuple > + AS 'UDT[org.postgresql.pljava.example.VarLenTuple] input' > + LANGUAGE java IMMUTABLE STRICT; > + > + /* The scalar output function */ > + CREATE FUNCTION varlentuple_out(javatest.varlentuple) > + RETURNS cstring > + AS 'UDT[org.postgresql.pljava.example.VarLenTuple] output' > + LANGUAGE java IMMUTABLE STRICT; > + > + /* The scalar receive function */ > + CREATE FUNCTION varlentuple_recv(internal) > + RETURNS javatest.varlentuple > + AS 'org.postgresql.pljava.example.VarLenTuple.receive' > + LANGUAGE java IMMUTABLE STRICT; > + > + /* The scalar send function */ > + CREATE FUNCTION varlentuple_send(javatest.varlentuple) > + RETURNS bytea > + AS 'org.postgresql.pljava.example.VarLenTuple.send' > + LANGUAGE java IMMUTABLE STRICT; > + > + /* The scalar type declaration */ > + CREATE TYPE javatest.varlentuple ( > + internallength = -1, > + input = javatest.varlentuple_in, > + output = javatest.varlentuple_out, > + receive = javatest.varlentuple_recv, > + send = javatest.varlentuple_send, > + alignment = int4 > + ); > + > + /* A test function that just logs and returns its argument. > + */ > + CREATE FUNCTION javatest.logvarlentuple(javatest.varlentuple) > + RETURNS javatest.varlentuple > + AS 'org.postgresql.pljava.example.VarLenTuple.logAndReturn' > + LANGUAGE java IMMUTABLE STRICT; > + > + /* Install the actual type mapping. > + */ > + SELECT sqlj.add_type_mapping('javatest.varlentuple', 'org.postgresql.pljava.example.VarLenTuple'); > + > + > /* > * An example using the ANY type > */ > > ------------------------------------------------------------------------ > > /* > * Copyright (c) 2004, 2005, 2006 TADA AB - Taby Sweden > * Copyright (c) 2006 Markus Schaber > * Distributed under the terms shown in the file COPYRIGHT > * found in the root directory of this distribution or at > * http://eng.tada.se/osprojects/COPYRIGHT.html > */ > package org.postgresql.pljava.example; > > import java.io.ByteArrayOutputStream; > import java.io.DataOutputStream; > import java.io.IOException; > import java.nio.ByteOrder; > import java.sql.SQLData; > import java.sql.SQLException; > import java.sql.SQLInput; > import java.sql.SQLOutput; > import java.util.logging.Logger; > > > /** Datatype implementing a variable length Tuple of Doubles. > * > * Not really useful except as an example and test for implementing fully fledged VARLENA datatyes > * including custom binary representation via Java. Code is intentionally kept simple, for the sake > * of efficency, and based on the ComplexTuple example. > * @author schabi > * > */ > public class VarLenTuple implements SQLData > { > private static Logger s_logger = Logger.getAnonymousLogger(); > > private static final String m_typeName = "javatest.varlentuple"; > > private static final double[] EMPTY = {}; > > private double[] arr = EMPTY; > > public static VarLenTuple parse(String input, String typeName) throws SQLException > { > checkType(typeName); > if ((input == null) || (input.length()<2) || (input.charAt(0)!='(') || (input.charAt(input.length()-1) != ')') ) { > throw new SQLException("Illegal value for "+m_typeName+": "+input); > } > > if (input.length()==2) { > return new VarLenTuple(); > } > String[] parts = input.substring(1, input.length()-1).split(","); > > double[] temparr = new double[parts.length]; > > for (int i=0; i < parts.length; i++) { > try { > temparr[i] = Double.parseDouble(parts[i]); > } catch (NumberFormatException e) { > throw new SQLException("Bad double '"+parts[i]+"' while parsing "+m_typeName+": "+e.getMessage()); > } > } > > return new VarLenTuple(temparr); > > } > > private static void checkType(String typeName) throws SQLException { > if (!m_typeName.equalsIgnoreCase(typeName)) { > throw new SQLException("parser for "+m_typeName+" cannot deserialize type "+typeName+"!"); > } > } > > public VarLenTuple() > { > } > > public VarLenTuple(double[] arr) > { > this.arr = arr; > } > > public String getSQLTypeName() > { > return m_typeName; > } > > public void readSQL(SQLInput stream, String typeName) throws SQLException > { > s_logger.info(typeName + " from SQLInput"); > checkType(typeName); > > // fetch PostgreSQL VarLenA Header > int bin_size = stream.readInt() & 0x3fffffff; > int count = (bin_size - 4)/8; > > if (bin_size != (count*8 +4)) > { > throw new SQLException("Bad Size Header!"); > } > > double[] temparr = new double[count]; > > for (int i=0; i < count; i++) > { > temparr[i] = stream.readDouble(); > } > > // all went well, we can assign the value > arr = temparr; > } > > public void writeSQL(SQLOutput stream) throws SQLException > { > s_logger.info(m_typeName + " to SQLOutput"); > int count = arr.length; > > stream.writeInt(count*8 +4); > for (int i=0; i < count; i++) > { > stream.writeDouble(arr[i]); > } > } > > public String toString() > { > s_logger.info(m_typeName + " toString"); > StringBuffer sb = new StringBuffer(); > sb.append('('); > if (arr.length>0) > { > sb.append(arr[0]); > for (int i=1; i < arr.length; i++) > { > sb.append(','); > sb.append(arr[i]); > } > } > sb.append(')'); > return sb.toString(); > } > > public static VarLenTuple logAndReturn(VarLenTuple cpl) > { > s_logger.info(cpl.getSQLTypeName() + cpl); > return cpl; > } > > public static VarLenTuple receive(SQLInput input) throws SQLException { > int count = input.readInt(); > // we have to swap, as we use network byte order for external representation > if (ByteOrder.nativeOrder()==ByteOrder.LITTLE_ENDIAN) { > count = Integer.reverseBytes(count); > } > > if (count==0) { > return new VarLenTuple(); > } > double[] temparr = new double[count]; > > if (ByteOrder.nativeOrder()==ByteOrder.LITTLE_ENDIAN) { > for (int i=0; i < count; i++) { > temparr[i] = Double.longBitsToDouble(Long.reverseBytes(input.readLong())); > } > } else { > for (int i=0; i < count; i++) { > temparr[i] = input.readDouble(); > } > > } > return new VarLenTuple(temparr); > } > > public static byte[] send(VarLenTuple input) throws SQLException { > double[] temparr = input.arr; > int count = temparr.length; > > ByteArrayOutputStream bos = new ByteArrayOutputStream(count*8+4); > > //DataOutputStream always uses Network Byte Order (Big Endian) > DataOutputStream os = new DataOutputStream(bos); > try { > os.writeInt(count); > > for (int i=0; i < count; i++) { > os.writeDouble(temparr[i]); > } > os.flush(); > } catch (IOException e) { > throw new SQLException("Error writing temporary buffer: "+e.getMessage()); > } > return bos.toByteArray(); > > } > } > > ------------------------------------------------------------------------ > > _______________________________________________ > Pljava-dev mailing list > Pljava-dev at gborg.postgresql.org > http://gborg.postgresql.org/mailman/listinfo/pljava-dev >