1 Complex.java
package com.example.proj;
import java.io.IOException;
import java.io.StreamTokenizer;
import java.io.StringReader;
import java.sql.SQLData;
import java.sql.SQLException;
import java.sql.SQLInput;
import java.sql.SQLOutput;
import java.util.logging.Logger;
import org.postgresql.pljava.annotation.Function;
import org.postgresql.pljava.annotation.SQLType;
import org.postgresql.pljava.annotation.BaseUDT;
import static org.postgresql.pljava.annotation.Function.Effects.IMMUTABLE;
import static
org.postgresql.pljava.annotation.Function.OnNullInput.RETURNS_NULL;
@BaseUDT( name="complex",
internalLength=16, alignment=BaseUDT.Alignment.DOUBLE)
public class Complex implements SQLData
{
private double m_x;
private double m_y;
private String m_typeName;
@Function(effects=IMMUTABLE, onNullInput=RETURNS_NULL)
public static Complex parse(String input, String typeName)
throws SQLException
{
try
{
StreamTokenizer tz = new StreamTokenizer(new StringReader(input));
if(tz.nextToken() == '('
&& tz.nextToken() == StreamTokenizer.TT_NUMBER)
{
double x = tz.nval;
if(tz.nextToken() == ','
&& tz.nextToken() == StreamTokenizer.TT_NUMBER)
{
double y = tz.nval;
if(tz.nextToken() == ')')
{
return new Complex(x, y, typeName);
}
}
}
throw new SQLException("Unable to parse complex from string \""
+ input + '"');
}
catch(IOException e)
{
throw new SQLException(e.getMessage());
}
}
public Complex()
{
}
public Complex(double x, double y, String typeName)
{
m_x = x;
m_y = y;
m_typeName = typeName;
}
@Override
public String getSQLTypeName()
{
return m_typeName;
}
@Function(effects=IMMUTABLE, onNullInput=RETURNS_NULL)
@Override
public void readSQL(SQLInput stream, String typeName) throws SQLException
{
m_x = stream.readDouble();
m_y = stream.readDouble();
m_typeName = typeName;
}
@Function(effects=IMMUTABLE, onNullInput=RETURNS_NULL)
@Override
public void writeSQL(SQLOutput stream) throws SQLException
{
stream.writeDouble(m_x);
stream.writeDouble(m_y);
}
@Function(effects=IMMUTABLE, onNullInput=RETURNS_NULL)
@Override
public String toString()
{
//s_logger.info(m_typeName + " toString");
StringBuffer sb = new StringBuffer();
sb.append('(');
sb.append(m_x);
sb.append(',');
sb.append(m_y);
sb.append(')');
return sb.toString();
}
public static Complex parse1(Complex input, String typeName)
{ return new Complex(1,2,"3"); }
public static Complex add(Complex left, Complex right)
{
return new Complex( left.m_x+right.m_x, left.m_y+right.m_y, left.m_typeName );
}
public static boolean lessThan(Complex a, Complex b) {
return compare(a,b) < 0;
}
public static boolean lessThanOrEquals(Complex a, Complex b) {
return compare(a,b) <= 0;
}
public static boolean equals(Complex a, Complex b) {
return compare(a,b) == 0;
}
public static boolean greaterThan(Complex a, Complex b) {
return compare(a,b) > 0;
}
public static int compare( Complex left, Complex right ){
double amag = left.m_x*left.m_x + left.m_y*left.m_y;
double bmag = right.m_x*right.m_x + right.m_y*right.m_y;
if (amag < bmag)
return -1;
if (amag > bmag)
return 1;
return 0;
}
}
2 Compile
mvn clean package
3 Load the jar
select sqlj.install_jar('file:/home/rudi/hhworkspace/mypljava/target/proj-0.0.1-SNAPSHOT.jar', 'proj', false);
select sqlj.set_classpath('public', 'proj');
4 Create the Complex Type
CREATE TYPE complex;
CREATE OR REPLACE FUNCTION complex_in(cstring, oid, integer)
RETURNS complex
LANGUAGE java IMMUTABLE
RETURNS NULL ON NULL INPUT
AS 'UDT[com.example.proj.Complex] INPUT';
CREATE OR REPLACE FUNCTION complex_out(complex)
RETURNS cstring
LANGUAGE java IMMUTABLE
RETURNS NULL ON NULL INPUT
AS 'UDT[com.example.proj.Complex] OUTPUT';
CREATE OR REPLACE FUNCTION complex_recv(internal, oid, integer)
RETURNS complex
LANGUAGE java IMMUTABLE
RETURNS NULL ON NULL INPUT
AS 'UDT[com.example.proj.Complex] RECEIVE';
CREATE OR REPLACE FUNCTION complex_send(complex)
RETURNS bytea
LANGUAGE java IMMUTABLE
RETURNS NULL ON NULL INPUT
AS 'UDT[com.example.proj.Complex] SEND';
CREATE TYPE complex (
INPUT = complex_in,
OUTPUT = complex_out,
RECEIVE = complex_recv,
SEND = complex_send,
INTERNALLENGTH = 16,
ALIGNMENT = DOUBLE,
STORAGE = PLAIN
);
5 Test Complex
CREATE TABLE test_complex (
a complex,
b complex
);
INSERT INTO test_complex VALUES ('(1.0, 2.5)', '(4.2, 3.55 )');
INSERT INTO test_complex VALUES ('(33.0, 51.4)', '(100.42, 93.55)');
SELECT * FROM test_complex;
6 Support btree index
CREATE FUNCTION complex_cmp(Complex, Complex)
RETURNS int
AS 'com.example.proj.Complex.compare'
LANGUAGE JAVA IMMUTABLE STRICT;
CREATE FUNCTION complex_lt(Complex, Complex)
RETURNS bool
AS 'com.example.proj.Complex.lessThan'
LANGUAGE JAVA IMMUTABLE STRICT;
CREATE FUNCTION complex_le(Complex, Complex)
RETURNS bool
AS 'com.example.proj.Complex.lessThanOrEquals'
LANGUAGE JAVA IMMUTABLE STRICT;
CREATE FUNCTION complex_eq(Complex, Complex)
RETURNS bool
AS 'com.example.proj.Complex.equals'
LANGUAGE JAVA IMMUTABLE STRICT;
CREATE FUNCTION complex_ge(Complex, Complex)
RETURNS bool
AS 'com.example.proj.Complex.greaterThanOrEquals'
LANGUAGE JAVA IMMUTABLE STRICT;
CREATE FUNCTION complex_gt(Complex, Complex)
RETURNS bool
AS 'com.example.proj.Complex.greaterThan'
LANGUAGE JAVA IMMUTABLE STRICT;
CREATE OPERATOR < (
leftarg = Complex, rightarg = Complex, procedure = complex_lt,
commutator = > , negator = >= ,
restrict = scalarltsel, join = scalarltjoinsel, merges
);
CREATE OPERATOR <= (
leftarg = Complex, rightarg = Complex, procedure = complex_le,
commutator = >= , negator = > ,
restrict = scalarltsel, join = scalarltjoinsel, merges
);
CREATE OPERATOR = (
leftarg = Complex, rightarg = Complex, procedure = complex_eq,
commutator = = , negator = <>, hashes, merges
);
CREATE OPERATOR >= (
leftarg = Complex, rightarg = Complex, procedure = complex_lt,
commutator = <= , negator = < ,
restrict = scalarltsel, join = scalarltjoinsel, merges
);
CREATE OPERATOR > (
leftarg = Complex, rightarg = Complex, procedure = complex_le,
commutator = <= , negator = < ,
restrict = scalargtsel, join = scalargtjoinsel, merges
);
-- btree join
CREATE OPERATOR CLASS complex_abs_ops
DEFAULT FOR TYPE Complex USING btree AS
OPERATOR 1 < ,
OPERATOR 2 <= ,
OPERATOR 3 = ,
OPERATOR 4 >= ,
OPERATOR 5 > ,
FUNCTION 1 complex_cmp(Complex, Complex);
7 Test the index
CREATE INDEX test_cplx_ind ON test_complex
USING btree(a complex_abs_ops);
SET enable_seqscan = OFF;
SELECT * from test_complex where a = '(56.0,-22.5)';
SELECT * from test_complex where a < '(56.0,-22.5)';
SELECT * from test_complex where a > '(56.0,-22.5)';