The following example illustrates a Java UDT class with nondefault definitions. JavaType is the new Java UDT, and JavaBuffer is the buffer type for the SQL data being converted, as I/O Function Sets and Related Types shows. For a complete set of required and optional code, see Usage Example.
public class JavaType implements SQLData
{
// Java data Object declarations for this Class....
// non-default Data Input function
public static JavaType JavaTypeInput( JavaBuffer in )
{
JavaType x = new JavaType(); // make a new object
// convert JavaBuffer fields to Java data objects in
// this Class
return( x );// return the new object
}
// non-default Data Output function
public static JavaBuffer JavaTypeOutput( JavaType out )
{
JavaBuffer x = new JavaBuffer();
// Do whatever it takes to translate object to output
// buffer format
return x; // return the initialized buffer
}
// required SQLData implementation
private String type;
public String getSQLTypeName()
{
return type;
}
public void readSQL ( SQLInput instream, String typeName )
throws SQLException
{
type = typeName;
// cast up to Informix specific stream type
IfmxUDTSQLInput in = (IfmxUDTSQLInput) instream;
// read stream fields into Java data objects in this Class
return;
}
public void writeSQL( SQLOutput outstream ) throws SQLException
{
// cast up to Informix specific stream type
IfmxUDTSQLOutput out = (IfmxUDTSQLOutput) outstream;
// write object to output stream
return;
}
}
For an example of the SQL definitions required to use the explicit methods in the preceding code, see SQL Definitions for a Variable-Length UDT Example.
All Java UDT classes must implement the readSQL() and writeSQL() methods for the SQLData interface. The readSQL() method initializes a Java object using data from the database server in a C-language format. The writeSQL() method converts a Java object back to the representation of the database server. The readSQL() and writeSQL() methods receive a Stream argument that encapsulates the conversion methods for each built-in type that the database server uses, for example, int, float, decimal.
In the case of a fixed-length UDT, the readSQL() and writeSQL() methods know the order and number of fields they are to process. In the case of a variable-length UDT, the programmer must rely on the stream.available() method and/or the SQLException to find the end of the data as this example shows.
/* Variable Length UDT example type: Record3
** Example of required and explicit method implementations.
**
** The C language structure equivalent of this JUDT is:
**
** typedef struct
** {
** mi_double_precision d;
** mi_chara[4];
** mi_integerb;
** mi_realc;
** mi_datee;
** mi_smallintf;
** mi_booleang[MAXBOOLS];
** } NewFixUDT;
**
** Where the last boolean array can contain up to MAX values
** but only valid values will be written to disk.
*/
// Put this in our test package,
// could be anywhere but needs to match SQL definitons for UDRs.
package informix.testclasses.jlm.udt;
// get the usual suspect classes
import java.sql.*;
// get informix specific interfaces, etal.
import com.informix.jdbc.*;
// These are only needed for the non-default Input/Output
// functions, remove if you use defaults.
import informix.jvp.dbapplet.impl.IfmxTextInStream;
import informix.jvp.dbapplet.impl.IfmxTextOutStream;
/**************** Now here's our UDT *************/
public class Record3 implements SQLData
{
// to turn debug print lines on and off
private static boolean classDebug = true;
// define storage for Java members of UDT
private double d_double;
private String a_char;
private int b_int;
private float c_float;
private java.sql.Date e_date;
private short f_smint;
// could use a Vector for booleans, but would then need Boolean
// objects ...so I've left it as an exercise for the reader...
private static final int MAXBOOLS = 20;
private boolean g_boolvals[] = new boolean[MAXBOOLS];
private int numbools = 0;
// dummy constructor just so we can log instantiation
public Record3()
{
super();
if( classDebug )
System.out.println( "Record3() " + super.toString() + " created" );
}
// dummy finalizer just so we can log our own destruction
protected void finalize()
{
super.finalize();
if( classDebug )
System.out.println( "Record3() " + super.toString() + " deleted" );
}
/*********** REQUIRED SQLData implementation: ***********/
// needed for SQLData interface
private String type;
public String getSQLTypeName()
{
return type;
}
// Called to convert an SQL buffer TYPE to JAVA class.
// note: we need to use SQLInput as the argument type or this
// method signature won't resolve correctly.
public void readSQL (SQLInput in, String typeName) throws
SQLException
{
if( classDebug )
System.out.println( "Record3.readSQL() entered" );
// save the type name
type = typeName;
// cast the _real_ type of Stream for IFMX extensions.
IfmxUDTSQLInput stream = (IfmxUDTSQLInput) in;
// trap exceptions; don't really know how many bytes
// are in the input.
try
{
d_double = stream.readDouble();
a_char = stream.readString(4);
b_int = stream.readInt();
c_float = stream.readFloat();
e_date = stream.readDate();
f_smint = stream.readShort();
// Read booleans until we get an exception:
// converting a non-existant boolean will throw cookies.
// but we can use available() to make sure there is more
// to read...
for( int count = 0; (stream.available() > 0) && (count
< MAXBOOLS); ++count )
{
g_boolvals[count] = stream.readBoolean();
++numbools;
}
}
catch (SQLException e)
{
// if we got something besides end of input rethrow,
// otherwise just assume we're done.
if( e.getErrorCode() != IfxErrMsg.S_BADSQLDATA )
{
if( classDebug )
System.out.println("Record3.readSQL() exception = " +
e.toString());
throw e;
}
}
}
// Called to convert JAVA class to SQL buffer TYPE.
// note: we need to use SQLOutput as the argument type or this
// method signature won't resolve correctly.
public void writeSQL( SQLOutput out ) throws SQLException
{
if( classDebug )
System.out.println( "Record3.writeSQL() entered" );
// cast up to _real_ type of Stream to use IFMX extensions.
IfmxUDTSQLOutput stream = (IfmxUDTSQLOutput) out;
stream.writeDouble(d_double);
stream.writeString(a_char, 4);
stream.writeInt(b_int);
stream.writeFloat(c_float);
stream.writeDate(e_date);
stream.writeShort(f_smint);
for( int i = 0; i < numbools; i++ )
stream.writeBoolean(g_boolvals[i]);
}
/*********** END SQLData implementation ***********/
/**** NON-DEFAULT implementation of Input and Output functions ****/
/* Remove all this if you only use the Defaults */
The following example illustrates the implementation of user-defined input and output functions that override the default I/O methods. If you use the default methods, you do not need to implement overriding methods like those that follow:
// Called as Input function to convert SQL lvarchar to JAVA class
public static Record3 fromString( String str )
{
if( classDebug )
System.out.println( "Record3.fromString(String) entered" );
// Make a stream of the right kind.
IfmxTextInStream stream = new IfmxTextInStream(str);
// Make a new Java object of the right type.
Record3 record = new Record3();
// Just call readSQL ourselves.
// For a real implementation you would probably copy all the
// readXXX()'s and intersperse delimiting chars as needed...
try
{
readSQL( stream, "Record3" );
}
catch (Exception e)
{
System.err.println(e.getMessage());
}
return record;
}
// Called as Output function; convert JAVA class to SQL lvarchar.
// note: could use toString() directly,
// except that the UDR method must be "static", and
// it needs to take a Record3 as an argument....
public static String makeString(Record3 x)
{
if( classDebug )
System.out.println( "Record3.makeString() entered" );
return x.toString();
}
// Might as well implement the standard toString() as long as
// we're doing non-defaults. If a different method name is
// used here, Object.toString() will be called when the class
// gets printed out in debug lines....
public String toString()
{
// Need to use a StringBuffer because we can't pass a
// reference to a String to be initialized.
// We could optimize by guessing at size of buffer, too.
// StringBuffer str = new StringBuffer();
// IfmxTextOutStream stream = new IfmxTextOutStream(str);
// Just call writeSQL.
// For a real implementation you would probably copy all the
// writeXXX()'s and intersperse delimiting chars as needed...
try
{
writeSQL( stream );
}
catch (Exception e)
{
System.err.println(e.getMessage());
// not sure if we need to clear out result string?
str.setLength(0);
}
return str.toString();
}
The SQL definitions for this example are:
-- VarLen UDT and support functions ----------------------------
create opaque type Record3 (internallength = variable,
alignment = 8, maxlen = 2048, cannothash );
grant usage on type Record3 to public;
-- register JUDT implementation....
-- note package name needs to match class file package
execute procedure setUDTExtName("Record3",
"informix.testclasses.jlm.udt.Record3");
-- Definitions for NON_DEFAULT Input/Output functions.
-- this overrides the defaults setup above
-- LVARCHAR INPUT
drop cast (Record3 as lvarchar);
create implicit cast (Record3 as lvarchar with record3_output);
create function record3_input (l lvarchar) returns Record3
external name
'informix.testclasses.jlm.udt.Record3.fromString(java.lang.String)'
language java not varient;
grant execute on function record3_input to public;
-- CHAR INPUT
drop cast (Record3 as char(100));
create implicit cast (Record3 as char(100) with record3_rout);
create function record3_rin (c char(100)) returns Record3
external name
'informix.testclasses.jlm.udt.Record3.fromString(java.lang.String)'
language java not varient;
grant execute on function record3_rin to public;
-- LVARCHAR OUTPUT
drop cast (lvarchar as Record3);
create explicit cast (lvarchar as Record3 with record3_input);
create function record3_output (c Record3) returns lvarchar
external name
'informix.testclasses.jlm.udt.Record3.makeString(informix.testclasses.jlm.udt.Record3)'
language java not varient;
grant execute on function record3_output to public;
-- CHAR OUTPUT
drop cast (char(100) as Record3);
create explicit cast (char(100) as Record3 with record3_rin);
create function record3_rout (c Record3) returns varchar(100) external name
'informix.testclasses.jlm.udt.Record3.makeString(informix.testclasses.jlm.udt.Record3)'
language java not varient;
grant execute on function record3_rout to public;
-- END definitions for NON_DEFAULT Input/Output functions.
-- end VarLen UDT and support functions --------------------------
-- Example Usage ---
create table rec3tab (record_col Record3);
insert into rec3tab values ('665.999 JAVA 398 197.236 1952-04-10 47 f t t');
insert into rec3tab values ('667.000 Jive 983 791.632 2002-04-11 42 f f f f f');
select * from rec3tab;
Home |
[ Top of Page | Previous Page | Next Page | Contents |
Index ]