Below are the patches for
org.postgresql.util.Serialize.java

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


*** ./Serialize.java.orig       Sat May 19 20:39:52 2001
--- ./Serialize.java    Sun May 20 21:24:20 2001
***************
*** 23,38 ****
  {
    // This is the connection that the instance refers to
    protected org.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.
--- 23,38 ----
  {
    // This is the connection that the instance refers to
    protected org.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.
***************
*** 41,56 ****
    {
      try {
        conn = c;
!       tableName = type.toLowerCase();
!       className = toClassName(type);
        ourClass = Class.forName(className);
      } catch(ClassNotFoundException cnfe) {
        throw new PSQLException("postgresql.serial.noclass",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;
--- 41,56 ----
    {
      try {
        conn = c;
!       tableName = toPostgreSQL(type);
!       className = type;
        ourClass = Class.forName(className);
      } catch(ClassNotFoundException cnfe) {
        throw new PSQLException("postgresql.serial.noclass",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='" + tableName + "'");
      if(rs!=null) {
        if(rs.next())
        status=true;
***************
*** 59,68 ****
      // This should never occur, as org.postgresql has it's own internal checks
      if(!status)
        throw new PSQLException("postgresql.serial.table",type);
!     
      // 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
--- 59,84 ----
      // This should never occur, as org.postgresql has it's own internal checks
      if(!status)
        throw new PSQLException("postgresql.serial.table",type);
! 
      // 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
     * @param oid The oid of the object
***************
*** 73,86 ****
    {
      try {
        Object obj = ourClass.newInstance();
!       
        // NB: we use java.lang.reflect here to prevent confusion with
        // the org.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")) {
--- 89,108 ----
    {
      try {
        Object obj = ourClass.newInstance();
! 
        // NB: we use java.lang.reflect here to prevent confusion with
        // the org.postgresql.Field
! 
!       // 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;
        int oidFIELD=-1;
        StringBuffer sb = new StringBuffer("select");
        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++) {
        String n = f[i].getName();
        if(n.equals("oid")) {
***************
*** 95,107 ****
        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();
--- 117,153 ----
        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++) {
!             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();
***************
*** 114,120 ****
        throw new SQLException(ie.toString());
      }
    }
!   
    /**
     * This stores an object into a table, returning it's OID.<p>
     *
--- 160,166 ----
        throw new SQLException(ie.toString());
      }
    }
! 
    /**
     * This stores an object into a table, returning it's OID.<p>
     *
***************
*** 138,161 ****
      try {
        // NB: we use java.lang.reflect here to prevent confusion with
        // the org.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();
--- 184,210 ----
      try {
        // NB: we use java.lang.reflect here to prevent confusion with
        // the org.postgresql.Field
! 
!       // don't save private fields since we would not be able to fetch them
!       java.lang.reflect.Field f[] = ourClass.getFields();
! 
        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);
        char sep=update?' ':'(';
        for(int i=0;i<f.length;i++) {
        String n = f[i].getName();
***************
*** 164,212 ****
        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
--- 213,320 ----
        sep=',';
        if(update) {
          sb.append('=');
!           // 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('\'');
!             // don't allow single qoutes or newlines in the string
!           sb.append(fixString(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++) {
!         sb.append(sep);
!         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('\'');
!             // don't allow single quotes or newlines in the string
!           sb.append(fixString(f[i].get(o).toString()));
            sb.append('\'');
          } else
            sb.append(f[i].get(o).toString());
        }
        sb.append(')');
        }
! 
        DriverManager.println("store: "+sb.toString());
!       org.postgresql.ResultSet rs = 
(org.postgresql.ResultSet)conn.ExecSQL(sb.toString());
! 
        // fetch the OID for returning
        int oid=0;
        if(hasOID) {
!       // If an update use the existing oid in the object
        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;
! 
      } catch(IllegalAccessException iae) {
        throw new SQLException(iae.toString());
      }
    }
! 
!   /**
!    *
!    */
!    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
     * a Serializable Java Object. It should be used before serializing any
***************
*** 219,225 ****
    {
      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
--- 327,333 ----
    {
      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
***************
*** 232,280 ****
    {
      if(c.isInterface())
        throw new PSQLException("postgresql.serial.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 org.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());
--- 340,389 ----
    {
      if(c.isInterface())
        throw new PSQLException("postgresql.serial.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();
!       java.lang.reflect.Field[] fields = c.getFields();
        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 org.postgresql, recursing if a class
            // is found
!           String n = type.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, type);
              sb.append(toPostgreSQL(n));
            }
          }
        }
        }
        sb.append(")");
! 
        // Now create the table
        DriverManager.println("Serialize.create:"+sb);
        con.ExecSQL(sb.toString());
***************
*** 283,304 ****
        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 org.postgresql table, by replacing . with
     * _<p>
--- 392,417 ----
        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"},
!     {"boolean",                       "bool"},
      {"double",                        "float8"},
      {"float",                 "float4"},
      {"int",                   "int4"},
! //    {"long",                        "int4"},
!     {"long",                  "int8"},
      {"short",                 "int2"},
      {"java.lang.String",      "text"},
      {"java.lang.Integer",     "int4"},
      {"java.lang.Float",               "float4"},
      {"java.lang.Double",      "float8"},
!     {"java.lang.Short",               "int2"},
!     {"char",                    "char"},
!     {"byte",                    "int2"}
    };
! 
    /**
     * This converts a Java Class name to a org.postgresql table, by replacing . with
     * _<p>
***************
*** 314,330 ****
    public static String toPostgreSQL(String name) throws SQLException
    {
      name = name.toLowerCase();
!     
      if(name.indexOf("_")>-1)
        throw new PSQLException("postgresql.serial.underscore");
!     
!     if(name.length()>32)
!       throw new PSQLException("postgresql.serial.namelength",name,new 
Integer(name.length()));
!     
      return name.replace('.','_');
    }
!   
!   
    /**
     * This converts a org.postgresql table to a Java Class name, by replacing _ with
     * .<p>
--- 427,451 ----
    public static String toPostgreSQL(String name) throws SQLException
    {
      name = name.toLowerCase();
! 
      if(name.indexOf("_")>-1)
        throw new PSQLException("postgresql.serial.underscore");
! 
!     // Postgres table names can only be 32 character long
!     // 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('.','_');
    }
! 
! 
    /**
     * This converts a org.postgresql table to a Java Class name, by replacing _ with
     * .<p>
***************
*** 338,342 ****
      name = name.toLowerCase();
      return name.replace('_','.');
    }
!   
  }
--- 459,463 ----
      name = name.toLowerCase();
      return name.replace('_','.');
    }
! 
  }

---------------------------(end of broadcast)---------------------------
TIP 4: Don't 'kill -9' the postmaster

Reply via email to