]> granicus.if.org Git - postgresql/commitdiff
Added missing file.
authorBruce Momjian <bruce@momjian.us>
Tue, 16 Jun 1998 06:57:27 +0000 (06:57 +0000)
committerBruce Momjian <bruce@momjian.us>
Tue, 16 Jun 1998 06:57:27 +0000 (06:57 +0000)
src/interfaces/jdbc/postgresql/util/Serialize.java [new file with mode: 0644]
src/interfaces/libpq/fe-print.c

diff --git a/src/interfaces/jdbc/postgresql/util/Serialize.java b/src/interfaces/jdbc/postgresql/util/Serialize.java
new file mode 100644 (file)
index 0000000..5601849
--- /dev/null
@@ -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('_','.');
+  }
+  
+}
index 493b37d0a3e3a851455f388a357fa9b909549756..140658b9422ad3f512529e3afa127595dd92faaf 100644 (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>