There are a number of changes. The main ones are:
return oid on insert handle all primitive data types handle single quotes and newlines in Strings handle null variables deal with non public and final variables (not very well, though) Ken K
This commit is contained in:
parent
23287c106d
commit
6f101c806b
@ -41,8 +41,8 @@ public class Serialize
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
conn = c;
|
conn = c;
|
||||||
tableName = type.toLowerCase();
|
tableName = toPostgreSQL(type);
|
||||||
className = toClassName(type);
|
className = type;
|
||||||
ourClass = Class.forName(className);
|
ourClass = Class.forName(className);
|
||||||
} catch(ClassNotFoundException cnfe) {
|
} catch(ClassNotFoundException cnfe) {
|
||||||
throw new PSQLException("postgresql.serial.noclass",type);
|
throw new PSQLException("postgresql.serial.noclass",type);
|
||||||
@ -50,7 +50,7 @@ public class Serialize
|
|||||||
|
|
||||||
// Second check, the type must be a table
|
// Second check, the type must be a table
|
||||||
boolean status = false;
|
boolean status = false;
|
||||||
ResultSet rs = conn.ExecSQL("select typname from pg_type,pg_class where typname=relname and typname='"+type+"'");
|
ResultSet rs = conn.ExecSQL("select typname from pg_type,pg_class where typname=relname and typname='" + tableName + "'");
|
||||||
if(rs!=null) {
|
if(rs!=null) {
|
||||||
if(rs.next())
|
if(rs.next())
|
||||||
status=true;
|
status=true;
|
||||||
@ -63,6 +63,22 @@ public class Serialize
|
|||||||
// Finally cache the fields within the table
|
// Finally cache the fields within the table
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor when Object is passed in
|
||||||
|
*/
|
||||||
|
public Serialize(org.postgresql.Connection c,Object o) throws SQLException
|
||||||
|
{
|
||||||
|
this(c, o.getClass().getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor when Class is passed in
|
||||||
|
*/
|
||||||
|
public Serialize(org.postgresql.Connection c, Class cls) throws SQLException
|
||||||
|
{
|
||||||
|
this(c, cls.getName());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This fetches an object from a table, given it's OID
|
* This fetches an object from a table, given it's OID
|
||||||
* @param oid The oid of the object
|
* @param oid The oid of the object
|
||||||
@ -76,11 +92,17 @@ public class Serialize
|
|||||||
|
|
||||||
// NB: we use java.lang.reflect here to prevent confusion with
|
// NB: we use java.lang.reflect here to prevent confusion with
|
||||||
// the org.postgresql.Field
|
// the org.postgresql.Field
|
||||||
java.lang.reflect.Field f[] = ourClass.getDeclaredFields();
|
|
||||||
|
// used getFields to get only public fields. We have no way to set values
|
||||||
|
// for other declarations. Maybe look for setFieldName() methods?
|
||||||
|
java.lang.reflect.Field f[] = ourClass.getFields();
|
||||||
|
|
||||||
boolean hasOID=false;
|
boolean hasOID=false;
|
||||||
int oidFIELD=-1;
|
int oidFIELD=-1;
|
||||||
StringBuffer sb = new StringBuffer("select");
|
StringBuffer sb = new StringBuffer("select");
|
||||||
char sep=' ';
|
char sep=' ';
|
||||||
|
|
||||||
|
// build a select for the fields. Look for the oid field to use in the where
|
||||||
for(int i=0;i<f.length;i++) {
|
for(int i=0;i<f.length;i++) {
|
||||||
String n = f[i].getName();
|
String n = f[i].getName();
|
||||||
if(n.equals("oid")) {
|
if(n.equals("oid")) {
|
||||||
@ -101,7 +123,31 @@ public class Serialize
|
|||||||
if(rs!=null) {
|
if(rs!=null) {
|
||||||
if(rs.next()) {
|
if(rs.next()) {
|
||||||
for(int i=0;i<f.length;i++) {
|
for(int i=0;i<f.length;i++) {
|
||||||
f[i].set(obj,rs.getObject(i+1));
|
if ( !Modifier.isFinal(f[i].getModifiers()) ) {
|
||||||
|
|
||||||
|
if (f[i].getType().getName().equals("short")){
|
||||||
|
f[i].setShort(obj, rs.getShort(i+1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (f[i].getType().getName().equals("char")){
|
||||||
|
f[i].setChar(obj, rs.getString(i+1).toCharArray()[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (f[i].getType().getName().equals("byte")){
|
||||||
|
f[i].setByte(obj, rs.getByte(i+1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
// booleans come out of pgsql as a t or an f
|
||||||
|
if (f[i].getType().getName().equals("boolean")){
|
||||||
|
if ( rs.getString(i+1).equals("t"))
|
||||||
|
f[i].setBoolean(obj, true);
|
||||||
|
else
|
||||||
|
f[i].setBoolean(obj, false);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
f[i].set(obj,rs.getObject(i+1));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rs.close();
|
rs.close();
|
||||||
@ -138,7 +184,10 @@ public class Serialize
|
|||||||
try {
|
try {
|
||||||
// NB: we use java.lang.reflect here to prevent confusion with
|
// NB: we use java.lang.reflect here to prevent confusion with
|
||||||
// the org.postgresql.Field
|
// the org.postgresql.Field
|
||||||
java.lang.reflect.Field f[] = ourClass.getDeclaredFields();
|
|
||||||
|
// don't save private fields since we would not be able to fetch them
|
||||||
|
java.lang.reflect.Field f[] = ourClass.getFields();
|
||||||
|
|
||||||
boolean hasOID=false;
|
boolean hasOID=false;
|
||||||
int oidFIELD=-1;
|
int oidFIELD=-1;
|
||||||
boolean update=false;
|
boolean update=false;
|
||||||
@ -155,7 +204,7 @@ public class Serialize
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuffer sb = new StringBuffer(update?"update "+tableName+" set":"insert into "+tableName+" values ");
|
StringBuffer sb = new StringBuffer(update?"update "+tableName+" set":"insert into " + tableName);
|
||||||
char sep=update?' ':'(';
|
char sep=update?' ':'(';
|
||||||
for(int i=0;i<f.length;i++) {
|
for(int i=0;i<f.length;i++) {
|
||||||
String n = f[i].getName();
|
String n = f[i].getName();
|
||||||
@ -164,9 +213,15 @@ public class Serialize
|
|||||||
sep=',';
|
sep=',';
|
||||||
if(update) {
|
if(update) {
|
||||||
sb.append('=');
|
sb.append('=');
|
||||||
if(f[i].getType().getName().equals("java.lang.String")) {
|
// handle unset values
|
||||||
|
if (f[i].get(o) == null)
|
||||||
|
sb.append("null");
|
||||||
|
else
|
||||||
|
if(f[i].getType().getName().equals("java.lang.String") ||
|
||||||
|
f[i].getType().getName().equals("char")) {
|
||||||
sb.append('\'');
|
sb.append('\'');
|
||||||
sb.append(f[i].get(o).toString());
|
// don't allow single qoutes or newlines in the string
|
||||||
|
sb.append(fixString(f[i].get(o).toString()));
|
||||||
sb.append('\'');
|
sb.append('\'');
|
||||||
} else
|
} else
|
||||||
sb.append(f[i].get(o).toString());
|
sb.append(f[i].get(o).toString());
|
||||||
@ -177,10 +232,17 @@ public class Serialize
|
|||||||
sb.append(") values ");
|
sb.append(") values ");
|
||||||
sep='(';
|
sep='(';
|
||||||
for(int i=0;i<f.length;i++) {
|
for(int i=0;i<f.length;i++) {
|
||||||
String n = f[i].getName();
|
sb.append(sep);
|
||||||
if(f[i].getType().getName().equals("java.lang.String")) {
|
sep=',';
|
||||||
|
// handle unset values
|
||||||
|
if (f[i].get(o) == null)
|
||||||
|
sb.append("null");
|
||||||
|
else
|
||||||
|
if(f[i].getType().getName().equals("java.lang.String") ||
|
||||||
|
f[i].getType().getName().equals("char")) {
|
||||||
sb.append('\'');
|
sb.append('\'');
|
||||||
sb.append(f[i].get(o).toString());
|
// don't allow single quotes or newlines in the string
|
||||||
|
sb.append(fixString(f[i].get(o).toString()));
|
||||||
sb.append('\'');
|
sb.append('\'');
|
||||||
} else
|
} else
|
||||||
sb.append(f[i].get(o).toString());
|
sb.append(f[i].get(o).toString());
|
||||||
@ -189,17 +251,23 @@ public class Serialize
|
|||||||
}
|
}
|
||||||
|
|
||||||
DriverManager.println("store: "+sb.toString());
|
DriverManager.println("store: "+sb.toString());
|
||||||
ResultSet rs = conn.ExecSQL(sb.toString());
|
org.postgresql.ResultSet rs = (org.postgresql.ResultSet)conn.ExecSQL(sb.toString());
|
||||||
if(rs!=null) {
|
|
||||||
rs.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
// fetch the OID for returning
|
// fetch the OID for returning
|
||||||
int oid=0;
|
int oid=0;
|
||||||
if(hasOID) {
|
if(hasOID) {
|
||||||
// set the oid in the object
|
// If an update use the existing oid in the object
|
||||||
f[oidFIELD].setInt(o,oid);
|
f[oidFIELD].setInt(o,oid);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
String statStr = rs.getStatusString();
|
||||||
|
oid = Integer.parseInt(statStr.substring(statStr.indexOf(" ") + 1, statStr.lastIndexOf(" ")));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(rs!=null) {
|
||||||
|
rs.close();
|
||||||
|
}
|
||||||
|
|
||||||
return oid;
|
return oid;
|
||||||
|
|
||||||
} catch(IllegalAccessException iae) {
|
} catch(IllegalAccessException iae) {
|
||||||
@ -207,6 +275,46 @@ public class Serialize
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private String fixString(String s) {
|
||||||
|
|
||||||
|
int idx = -1;
|
||||||
|
|
||||||
|
// handle null
|
||||||
|
if (s == null)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
// if the string has single quotes in it escape them
|
||||||
|
if ((idx = s.indexOf("'")) > -1) {
|
||||||
|
StringBuffer buf = new StringBuffer();
|
||||||
|
StringTokenizer tok = new StringTokenizer(s, "'");
|
||||||
|
// handle quote as 1St charater
|
||||||
|
if (idx > 0) buf.append(tok.nextToken());
|
||||||
|
|
||||||
|
while(tok.hasMoreTokens())
|
||||||
|
buf.append("\\'").append(tok.nextToken());
|
||||||
|
|
||||||
|
s = buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the string has newlines in it convert them to \n
|
||||||
|
if ((idx = s.indexOf("\n")) > -1) {
|
||||||
|
StringBuffer buf = new StringBuffer();
|
||||||
|
StringTokenizer tok = new StringTokenizer(s, "\n");
|
||||||
|
if (idx > 0) buf.append(tok.nextToken());
|
||||||
|
|
||||||
|
while(tok.hasMoreTokens())
|
||||||
|
buf.append("\\n").append(tok.nextToken());
|
||||||
|
|
||||||
|
s = buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is not used by the driver, but it creates a table, given
|
* This method is not used by the driver, but it creates a table, given
|
||||||
* a Serializable Java Object. It should be used before serializing any
|
* a Serializable Java Object. It should be used before serializing any
|
||||||
@ -238,14 +346,15 @@ public class Serialize
|
|||||||
|
|
||||||
ResultSet rs = con.ExecSQL("select relname from pg_class where relname = '"+tableName+"'");
|
ResultSet rs = con.ExecSQL("select relname from pg_class where relname = '"+tableName+"'");
|
||||||
if(!rs.next()) {
|
if(!rs.next()) {
|
||||||
DriverManager.println("found "+rs.getString(1));
|
// DriverManager.println("found "+rs.getString(1));
|
||||||
// No entries returned, so the table doesn't exist
|
// No entries returned, so the table doesn't exist
|
||||||
|
|
||||||
StringBuffer sb = new StringBuffer("create table ");
|
StringBuffer sb = new StringBuffer("create table ");
|
||||||
sb.append(tableName);
|
sb.append(tableName);
|
||||||
char sep='(';
|
char sep='(';
|
||||||
|
|
||||||
java.lang.reflect.Field[] fields = c.getDeclaredFields();
|
// java.lang.reflect.Field[] fields = c.getDeclaredFields();
|
||||||
|
java.lang.reflect.Field[] fields = c.getFields();
|
||||||
for(int i=0;i<fields.length;i++) {
|
for(int i=0;i<fields.length;i++) {
|
||||||
Class type = fields[i].getType();
|
Class type = fields[i].getType();
|
||||||
|
|
||||||
@ -261,13 +370,13 @@ public class Serialize
|
|||||||
} else {
|
} else {
|
||||||
// convert the java type to org.postgresql, recursing if a class
|
// convert the java type to org.postgresql, recursing if a class
|
||||||
// is found
|
// is found
|
||||||
String n = fields[i].getType().getName();
|
String n = type.getName();
|
||||||
int j=0;
|
int j=0;
|
||||||
for(;j<tp.length && !tp[j][0].equals(n);j++);
|
for(;j<tp.length && !tp[j][0].equals(n);j++);
|
||||||
if(j<tp.length)
|
if(j<tp.length)
|
||||||
sb.append(tp[j][1]);
|
sb.append(tp[j][1]);
|
||||||
else {
|
else {
|
||||||
create(con,fields[i].getType());
|
create(con, type);
|
||||||
sb.append(toPostgreSQL(n));
|
sb.append(toPostgreSQL(n));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -286,17 +395,21 @@ public class Serialize
|
|||||||
|
|
||||||
// This is used to translate between Java primitives and PostgreSQL types.
|
// This is used to translate between Java primitives and PostgreSQL types.
|
||||||
private static final String tp[][] = {
|
private static final String tp[][] = {
|
||||||
{"boolean", "int1"},
|
// {"boolean", "int1"},
|
||||||
|
{"boolean", "bool"},
|
||||||
{"double", "float8"},
|
{"double", "float8"},
|
||||||
{"float", "float4"},
|
{"float", "float4"},
|
||||||
{"int", "int4"},
|
{"int", "int4"},
|
||||||
{"long", "int4"},
|
// {"long", "int4"},
|
||||||
|
{"long", "int8"},
|
||||||
{"short", "int2"},
|
{"short", "int2"},
|
||||||
{"java.lang.String", "text"},
|
{"java.lang.String", "text"},
|
||||||
{"java.lang.Integer", "int4"},
|
{"java.lang.Integer", "int4"},
|
||||||
{"java.lang.Float", "float4"},
|
{"java.lang.Float", "float4"},
|
||||||
{"java.lang.Double", "float8"},
|
{"java.lang.Double", "float8"},
|
||||||
{"java.lang.Short", "int2"}
|
{"java.lang.Short", "int2"},
|
||||||
|
{"char", "char"},
|
||||||
|
{"byte", "int2"}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -318,8 +431,16 @@ public class Serialize
|
|||||||
if(name.indexOf("_")>-1)
|
if(name.indexOf("_")>-1)
|
||||||
throw new PSQLException("postgresql.serial.underscore");
|
throw new PSQLException("postgresql.serial.underscore");
|
||||||
|
|
||||||
if(name.length()>32)
|
// Postgres table names can only be 32 character long
|
||||||
throw new PSQLException("postgresql.serial.namelength",name,new Integer(name.length()));
|
// If the full class name with package is too long
|
||||||
|
// then just use the class name. If the class name is
|
||||||
|
// too long throw an exception.
|
||||||
|
if(name.length() > 32) {
|
||||||
|
name = name.substring(name.lastIndexOf(".") + 1);
|
||||||
|
|
||||||
|
if(name.length()>32)
|
||||||
|
throw new PSQLException("postgresql.serial.namelength",name,new Integer(name.length()));
|
||||||
|
}
|
||||||
|
|
||||||
return name.replace('.','_');
|
return name.replace('.','_');
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user