Added missing file.

This commit is contained in:
Bruce Momjian 1998-06-16 06:57:27 +00:00
parent 0f356be054
commit d6e0ee6bcb
2 changed files with 344 additions and 1 deletions

View File

@ -0,0 +1,342 @@
package postgresql.util;
import java.io.*;
import java.lang.*;
import java.lang.reflect.*;
import java.net.*;
import java.util.*;
import java.sql.*;
/**
* This class uses PostgreSQL's object oriented features to store Java Objects.
*
* It does this by mapping a Java Class name to a table in the database. Each
* entry in this new table then represents a Serialized instance of this
* class. As each entry has an OID (Object IDentifier), this OID can be
* included in another table.
*
* This is too complex to show here, and will be documented in the main
* documents in more detail.
*
*/
public class Serialize
{
// This is the connection that the instance refers to
protected postgresql.Connection conn;
// This is the table name
protected String tableName;
// This is the class name
protected String className;
// This is the Class for this serialzed object
protected Class ourClass;
/**
* This creates an instance that can be used to serialize or deserialize
* a Java object from a PostgreSQL table.
*/
public Serialize(postgresql.Connection c,String type) throws SQLException
{
try {
conn = c;
tableName = type.toLowerCase();
className = toClassName(type);
ourClass = Class.forName(className);
} catch(ClassNotFoundException cnfe) {
throw new SQLException("No class found for '"+type+"`");
}
// Second check, the type must be a table
boolean status = false;
ResultSet rs = conn.ExecSQL("select typname from pg_type,pg_class where typname=relname and typname='"+type+"'");
if(rs!=null) {
if(rs.next())
status=true;
rs.close();
}
// This should never occur, as postgresql has it's own internal checks
if(!status)
throw new SQLException("The table for "+type+" is not in the database. Contact the DBA, as the database is in an inconsistent state.");
// Finally cache the fields within the table
}
/**
* This fetches an object from a table, given it's OID
* @param oid The oid of the object
* @return Object relating to oid
* @exception SQLException on error
*/
public Object fetch(int oid) throws SQLException
{
try {
Object obj = ourClass.newInstance();
// NB: we use java.lang.reflect here to prevent confusion with
// the postgresql.Field
java.lang.reflect.Field f[] = ourClass.getDeclaredFields();
boolean hasOID=false;
int oidFIELD=-1;
StringBuffer sb = new StringBuffer("select");
char sep=' ';
for(int i=0;i<f.length;i++) {
String n = f[i].getName();
if(n.equals("oid")) {
hasOID=true;
oidFIELD=i;
}
sb.append(sep);
sb.append(n);
sep=',';
}
sb.append(" from ");
sb.append(tableName);
sb.append(" where oid=");
sb.append(oid);
DriverManager.println("store: "+sb.toString());
ResultSet rs = conn.ExecSQL(sb.toString());
if(rs!=null) {
if(rs.next()) {
for(int i=0;i<f.length;i++) {
f[i].set(obj,rs.getObject(i+1));
}
}
rs.close();
} else
throw new SQLException("Unexpected result from query");
return obj;
} catch(IllegalAccessException iae) {
throw new SQLException(iae.toString());
} catch(InstantiationException ie) {
throw new SQLException(ie.toString());
}
}
/**
* This stores an object into a table, returning it's OID.<p>
*
* If the object has an int called OID, and it is > 0, then
* that value is used for the OID, and the table will be updated.
* If the value of OID is 0, then a new row will be created, and the
* value of OID will be set in the object. This enables an object's
* value in the database to be updateable.
*
* If the object has no int called OID, then the object is stored. However
* if the object is later retrieved, amended and stored again, it's new
* state will be appended to the table, and will not overwrite the old
* entries.
*
* @param o Object to store (must implement Serializable)
* @return oid of stored object
* @exception SQLException on error
*/
public int store(Object o) throws SQLException
{
try {
// NB: we use java.lang.reflect here to prevent confusion with
// the postgresql.Field
java.lang.reflect.Field f[] = ourClass.getDeclaredFields();
boolean hasOID=false;
int oidFIELD=-1;
boolean update=false;
// Find out if we have an oid value
for(int i=0;i<f.length;i++) {
String n = f[i].getName();
if(n.equals("oid")) {
hasOID=true;
oidFIELD=i;
// We are an update if oid != 0
update = f[i].getInt(o)>0;
}
}
StringBuffer sb = new StringBuffer(update?"update "+tableName+" set":"insert into "+tableName+" values ");
char sep=update?' ':'(';
for(int i=0;i<f.length;i++) {
String n = f[i].getName();
sb.append(sep);
sb.append(n);
sep=',';
if(update) {
sb.append('=');
if(f[i].getType().getName().equals("java.lang.String")) {
sb.append('\'');
sb.append(f[i].get(o).toString());
sb.append('\'');
} else
sb.append(f[i].get(o).toString());
}
}
if(!update) {
sb.append(") values ");
sep='(';
for(int i=0;i<f.length;i++) {
String n = f[i].getName();
if(f[i].getType().getName().equals("java.lang.String")) {
sb.append('\'');
sb.append(f[i].get(o).toString());
sb.append('\'');
} else
sb.append(f[i].get(o).toString());
}
sb.append(')');
}
DriverManager.println("store: "+sb.toString());
ResultSet rs = conn.ExecSQL(sb.toString());
if(rs!=null) {
rs.close();
}
// fetch the OID for returning
int oid=0;
if(hasOID) {
// set the oid in the object
f[oidFIELD].setInt(o,oid);
}
return oid;
} catch(IllegalAccessException iae) {
throw new SQLException(iae.toString());
}
}
/**
* 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
* objects.
* @param c Connection to database
* @param o Object to base table on
* @exception SQLException on error
*/
public static void create(postgresql.Connection con,Object o) throws SQLException
{
create(con,o.getClass());
}
/**
* 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
* objects.
* @param c Connection to database
* @param o Class to base table on
* @exception SQLException on error
*/
public static void create(postgresql.Connection con,Class c) throws SQLException
{
if(c.isInterface())
throw new SQLException("Cannot serialize an Interface");
// See if the table exists
String tableName = toPostgreSQL(c.getName());
ResultSet rs = con.ExecSQL("select relname from pg_class where relname = '"+tableName+"'");
if(!rs.next()) {
DriverManager.println("found "+rs.getString(1));
// No entries returned, so the table doesn't exist
StringBuffer sb = new StringBuffer("create table ");
sb.append(tableName);
char sep='(';
java.lang.reflect.Field[] fields = c.getDeclaredFields();
for(int i=0;i<fields.length;i++) {
Class type = fields[i].getType();
// oid is a special field
if(!fields[i].getName().equals("oid")) {
sb.append(sep);
sb.append(fields[i].getName());
sb.append(' ');
sep=',';
if(type.isArray()) {
// array handling
} else {
// convert the java type to postgresql, recursing if a class
// is found
String n = fields[i].getType().getName();
int j=0;
for(;j<tp.length && !tp[j][0].equals(n);j++);
if(j<tp.length)
sb.append(tp[j][1]);
else {
create(con,fields[i].getType());
sb.append(toPostgreSQL(n));
}
}
}
}
sb.append(")");
// Now create the table
DriverManager.println("Serialize.create:"+sb);
con.ExecSQL(sb.toString());
rs.close();
} else {
DriverManager.println("Serialize.create: table "+tableName+" exists, skipping");
}
}
// This is used to translate between Java primitives and PostgreSQL types.
private static final String tp[][] = {
{"boolean", "int1"},
{"double", "float8"},
{"float", "float4"},
{"int", "int4"},
{"long", "int4"},
{"short", "int2"},
{"java.lang.String", "text"},
{"java.lang.Integer", "int4"},
{"java.lang.Float", "float4"},
{"java.lang.Double", "float8"},
{"java.lang.Short", "int2"}
};
/**
* This converts a Java Class name to a postgresql table, by replacing . with
* _<p>
*
* Because of this, a Class name may not have _ in the name.<p>
* Another limitation, is that the entire class name (including packages)
* cannot be longer than 32 characters (a limit forced by PostgreSQL).
*
* @param name Class name
* @return PostgreSQL table name
* @exception SQLException on error
*/
public static String toPostgreSQL(String name) throws SQLException
{
name = name.toLowerCase();
if(name.indexOf("_")>-1)
throw new SQLException("Class names may not have _ in them: "+name);
if(name.length()>32)
throw new SQLException("Class & Package name length cannot be longer than 32 characters. "+name+" is "+name.length()+" characters.");
return name.replace('.','_');
}
/**
* This converts a postgresql table to a Java Class name, by replacing _ with
* .<p>
*
* @param name PostgreSQL table name
* @return Class name
* @exception SQLException on error
*/
public static String toClassName(String name) throws SQLException
{
name = name.toLowerCase();
return name.replace('_','.');
}
}

View File

@ -9,10 +9,11 @@
* didn't really belong there.
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-print.c,v 1.3 1998/06/15 19:30:26 momjian Exp $
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-print.c,v 1.4 1998/06/16 06:57:27 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include <postgres.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>