Mapping-an-sql-type-to-a-java-class
Mapping an SQL type to a Java class
Using PL/Java, you can install a mapping between an arbitrary type and a Java class. There are two prerequisites for doing this:
- You must know the storage layout of the SQL type that you are mapping.
- The Java class that you map to must implement the interface
java.sql.SQLData
.
Mapping an existing SQL data type to a java class
Here is an example of how to map the PostgreSQL geometric point type to a Java class. We know that the point is stored as two float8’s, the x and the y coordinate.
You can consult the postgresql source code when the exact layout of a basic
type is unknown. I peeked at the point_recv
function in file
src/backend/utils/adt/geo_ops.c
to determine the exact layout of the
point type.
Once the layout is known, you can create the java.sql.SQLData
implementation
that uses the class java.sql.SQLInput
to read and the class
java.sql.SQLOutput
to write data:
package org.postgresql.pljava.example;
import java.sql.SQLData;
import java.sql.SQLException;
import java.sql.SQLInput;
import java.sql.SQLOutput;
public class Point implements SQLData {
private double m_x;
private double m_y;
private String m_typeName;
public String getSQLTypeName() {
return m_typeName;
}
public void readSQL(SQLInput stream, String typeName) throws SQLException {
m_x = stream.readDouble();
m_y = stream.readDouble();
m_typeName = typeName;
}
public void writeSQL(SQLOutput stream) throws SQLException {
stream.writeDouble(m_x);
stream.writeDouble(m_y);
}
/* Meaningful code that actually does something with this type was
* intentionally left out.
*/
}
Finally, you install the type mapping using the add_type_mapping
command:
SELECT sqlj.add_type_mapping('point', 'org.postgresql.pljava.example.Point');
You should now be able to use your new class. PL/Java will henceforth map any point parameter to the org.postgresql.pljava.example.Point class.
Creating a composite UDT and mapping it to a java class
Here is an example of a complex type created as a composite UDT.
CREATE TYPE javatest.complextuple AS (x float8, y float8);
SELECT sqlj.add_type_mapping('javatest.complextuple',
'org.postgresql.pljava.example.ComplexTuple');
package org.postgresql.pljava.example;
import java.sql.SQLData;
import java.sql.SQLException;
import java.sql.SQLInput;
import java.sql.SQLOutput;
public class ComplexTuple implements SQLData {
private double m_x;
private double m_y;
private String m_typeName;
public String getSQLTypeName()
{
return m_typeName;
}
public void readSQL(SQLInput stream, String typeName) throws SQLException
{
m_typeName = typeName;
m_x = stream.readDouble();
m_y = stream.readDouble();
}
public void writeSQL(SQLOutput stream) throws SQLException
{
stream.writeDouble(m_x);
stream.writeDouble(m_y);
}
/* Meaningful code that actually does something with this type was
* intentionally left out.
*/
}
Generating SQL automatically
The SQL shown above for this example will be written for you by the Java
compiler, if the ComplexTuple
class is simply annotated as a “mapped
user-defined type” with the desired SQL name and structure:
@MappedUDT(schema="javatest", name="complextuple",
structure={"x float8", "y float8"})
public class ComplexTuple implements SQLData {
...
Generating the SQL reduces the burden of keeping the definitions in sync in two places. See the hello world example for more.