www.pudn.com > town-1[1].0.4.rar > Record.java


package com.workingdogs.town; 
 
import java.io.*; 
import java.sql.*; 
import java.math.*; 
import java.util.*; 
 
/* 
Town, a Java JDBC abstraction layer 
Copyright (C) 1999  Serge Knystautas, Jon S. Stevens 
 
This library is free software; you can redistribute it and/or 
modify it under the terms of the GNU Library General Public 
License as published by the Free Software Foundation; either 
version 2 of the License, or (at your option) any later version. 
 
This library is distributed in the hope that it will be useful, 
but WITHOUT ANY WARRANTY; without even the implied warranty of 
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
Library General Public License for more details. 
 
You should have received a copy of the GNU Library General Public 
License along with this library; if not, write to the 
Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
Boston, MA  02111-1307, USA. 
*/ 
/** 
A Record represents a row in the database. It contains a collection of 
Values which are the individual contents of each column in the row. 
 
@author Jon S. Stevens jon@working-dogs.com 
@author Serge Knystautas sergek@lokitech.com 
@version 1.0 
*/ 
public class Record 
{ 
    /** an array of Value objects, this is 1 based*/ 
    private Value values[]; 
	/** an array of Value objects, 1 based, storing the original keydef values in case they've been changed*/ 
	private Value keydefValues[]; 
    /** a 1 To 1 relationship between Values and whether they are clean or not */ 
    private boolean isClean[]; 
    /** the parent DataSet for this Record */ 
    private DataSet parentDataSet; 
    /** number of columns in this Record */ 
    private int numberOfColumns; 
    /** this is the state of this record */ 
    private int saveType = 0; 
    /** a saved copy of the schema for this Record */ 
    private Schema schema; 
    /** the status of a record */ 
    //private boolean status; 
    /** 
       Creates a new Record and sets the parent dataset to the passed in value. 
     */ 
    protected Record(DataSet ds) throws DataSetException, 
    ConnectionException 
    { 
        this (ds, true); 
    } 
    /** 
        Creates a new Record and sets the parent dataset to the passed in value. 
      */ 
    protected Record(DataSet ds, 
            boolean readData) throws DataSetException, ConnectionException 
    { 
        parentDataSet = ds; 
        initializeRecord(); 
        if (readData) 
            createValues(parentDataSet.resultSet()); 
        else 
            createValues (null); 
    } 
    /** 
       * 
       * Creates the value objects for this Record. It is 1 based 
       * 
       * @exception   DataSetException 
       * @exception   ConnectionException 
       */ 
    private void createValues(ResultSet rs) throws DataSetException, 
    ConnectionException 
    { 
        for (int i = 1; i <= size(); i++) 
        { 
            Value val = new Value (rs, i, schema.getColumn(i).typeEnum()); 
            this.values[i] = val; 
        } 
				 
		if (parentDataSet instanceof TableDataSet) 
		{ 
	        KeyDef kd = parentDataSet.getKeyDef(); 
			for (int i = 1; i <= kd.size(); i++) 
			{ 
				String attrib = kd.getAttrib(i); 
				int index = schema.index (attrib); 
				this.keydefValues[i] = (Value)this.values[index].clone (); 
			} 
		} 
    } 
    private Hashtable getAffectedColumns() throws DataSetException 
    { 
        Hashtable affectedColumns = new Hashtable (size()); 
        for (int i = 1; i <= size(); i++) 
        { 
            if (isValueClean(i) == false) 
                affectedColumns.put ((Object) new Integer(i), 
                        (Object) schema.getColumns()[i].name()); 
        } 
        return affectedColumns; 
    } 
    /** 
      * Get the value as a BigDecimal 
      * @return java.math.BigDecimal 
      */ 
    public BigDecimal getAsBigDecimal (int index) throws DataSetException 
    { 
        return getValue (index).asBigDecimal (); 
    } 
    /** 
      * Get the value as a BigDecimal 
      * @return java.math.BigDecimal 
      */ 
    public BigDecimal getAsBigDecimal (int index, 
            int scale) throws DataSetException 
    { 
        return getValue (index).asBigDecimal (scale); 
    } 
    /** 
      * Get the value as a BigDecimal 
      * @return java.math.BigDecimal 
      */ 
    public BigDecimal getAsBigDecimal (String column) 
            throws DataSetException 
    { 
        return getValue (column).asBigDecimal (); 
    } 
    /** 
      * Get the value as a BigDecimal 
      * @return java.math.BigDecimal 
      */ 
    public BigDecimal getAsBigDecimal (String column, 
            int scale) throws DataSetException 
    { 
        return getValue (column).asBigDecimal (scale); 
    } 
    /** 
      * Get the value as a boolean 
      * @return boolean 
      */ 
    public boolean getAsBoolean (int index) throws DataSetException 
    { 
        return getValue (index).asBoolean (); 
    } 
    /** 
      * Get the value as a boolean 
      * @return boolean 
      */ 
    public boolean getAsBoolean (String column) throws DataSetException 
    { 
        return getValue (column).asBoolean (); 
    } 
    /** 
      * Get the value as a byte 
      * @return byte 
      */ 
    public byte getAsByte (int index) throws DataSetException 
    { 
        return getValue (index).asByte (); 
    } 
    /** 
      * Get the value as a byte 
      * @return byte 
      */ 
    public byte getAsByte (String column) throws DataSetException 
    { 
        return getValue (column).asByte (); 
    } 
    /** 
      * Get the value as bytes 
      * @return a byte array 
      */ 
    public byte[] getAsBytes (int index) throws DataSetException 
    { 
        return getValue (index).asBytes (); 
    } 
    /** 
      * Get the value as bytes 
      * @return a byte array 
      */ 
    public byte[] getAsBytes (String column) throws DataSetException 
    { 
        return getValue (column).asBytes (); 
    } 
    /** 
      * Get the value as a Date 
      * @return a java.sql.Date 
      */ 
    public java.sql.Date getAsDate (int index) throws DataSetException 
    { 
        return getValue (index).asDate (); 
    } 
    /** 
      * Get the value as a Date 
      * @return a java.sql.Date 
      */ 
    public java.sql.Date getAsDate (String column) throws DataSetException 
    { 
        return getValue (column).asDate (); 
    } 
    /** 
      * Get the value as a Double 
      * @return a double 
      */ 
    public double getAsDouble (int index) throws DataSetException 
    { 
        return getValue (index).asDouble (); 
    } 
    /** 
      * Get the value as a Double 
      * @return a double 
      */ 
    public double getAsDouble (String column) throws DataSetException 
    { 
        return getValue (column).asDouble (); 
    } 
    /** 
      * Get the value as a float 
      * @return a float 
      */ 
    public float getAsFloat (int index) throws DataSetException 
    { 
        return getValue (index).asFloat (); 
    } 
    /** 
      * Get the value as a float 
      * @return a float 
      */ 
    public float getAsFloat (String column) throws DataSetException 
    { 
        return getValue (column).asFloat (); 
    } 
    /** 
      * Get the value as an int 
      * @return an int 
      */ 
    public int getAsInt (int index) throws DataSetException 
    { 
        return getValue (index).asInt (); 
    } 
    /** 
      * Get the value as an int 
      * @return an int 
      */ 
    public int getAsInt (String column) throws DataSetException 
    { 
        return getValue (column).asInt (); 
    } 
    /** 
      * Get the value as a long 
      * @return a long 
      */ 
    public long getAsLong (int index) throws DataSetException 
    { 
        return getValue (index).asLong (); 
    } 
    /** 
      * Get the value as a long 
      * @return a long 
      */ 
    public long getAsLong (String column) throws DataSetException 
    { 
        return getValue (column).asLong (); 
    } 
    /** 
      * Get the value as a short 
      * @return a short 
      */ 
    public short getAsShort (int index) throws DataSetException 
    { 
        return getValue (index).asShort (); 
    } 
    /** 
      * Get the value as a short 
      * @return a short 
      */ 
    public short getAsShort (String column) throws DataSetException 
    { 
        return getValue (column).asShort (); 
    } 
    /** 
      * Get the value as a String 
      * @return a String 
      */ 
    public String getAsString (int index) throws DataSetException 
    { 
        return getValue (index).asString (); 
    } 
    /** 
      * Get the value as a String 
      * @return a String 
      */ 
    public String getAsString (String column) throws DataSetException 
    { 
        return getValue (column).asString (); 
    } 
    /** 
      * Get the value as a Time 
      * @return a Time 
      */ 
    public Time getAsTime (int index) throws DataSetException 
    { 
        return getValue (index).asTime (); 
    } 
    /** 
      * Get the value as a Time 
      * @return a Time 
      */ 
    public Time getAsTime (String column) throws DataSetException 
    { 
        return getValue (column).asTime (); 
    } 
    /** 
      * Get the value as a Timestamp 
      * @return a Timestamp 
      */ 
    public Timestamp getAsTimestamp (int index) throws DataSetException 
    { 
        return getValue (index).asTimestamp (); 
    } 
    /** 
      * Get the value as a Timestamp 
      * @return a Timestamp 
      */ 
    public Timestamp getAsTimestamp (String column) throws DataSetException 
    { 
        return getValue (column).asTimestamp (); 
    } 
    /** 
      * Get the value as a java.util.Date 
      * @return a java.util.Date 
      */ 
    public java.util.Date getAsUtilDate (int index) throws DataSetException 
    { 
        return getValue (index).asUtilDate (); 
    } 
    /** 
      * Get the value as a java.util.Date 
      * @return a java.util.Date 
      */ 
    public java.util.Date getAsUtilDate (String column) 
            throws DataSetException 
    { 
        return getValue (column).asUtilDate (); 
    } 
    /** 
        Gets the DataSet for this Record 
 
        @return the DataSet for this Record 
      */ 
    public DataSet getDataSet() 
    { 
        return parentDataSet; 
    } 
    /** 
        Builds the SQL DELETE statement for this Record 
        @return SQL DELETE statement 
      */ 
    private String getDeleteSaveString() throws DataSetException, 
    ConnectionException 
    { 
        KeyDef kd = parentDataSet.getKeyDef(); 
        if (kd == null || kd.size() == 0) 
        { 
            throw new DataSetException ("You must specify KeyDef attributes for this TableDataSet in order to delete a Record."); 
        } 
 
        StringBuffer iss1 = new StringBuffer (256); 
 
        boolean comma = false; 
        for (int i = 1; i <= kd.size(); i++) 
        { 
            if (! comma) 
            { 
                iss1.append (kd.getAttrib(i)); 
                iss1.append (" = ?"); 
                comma = true; 
            } 
            else 
            { 
                iss1.append (" AND "); 
                iss1.append (kd.getAttrib(i)); 
                iss1.append (" = ? "); 
            } 
        } 
        return "DELETE FROM " + parentDataSet.getTableName () + 
                " WHERE " + iss1.toString(); 
    } 
    /** 
        Builds the SQL INSERT statement for this Record 
        @return SQL INSERT statement 
      */ 
    private String getInsertSaveString() throws DataSetException, 
    ConnectionException 
    { 
        StringBuffer iss1 = new StringBuffer (256); 
        StringBuffer iss2 = new StringBuffer (256); 
 
        boolean comma = false; 
        for (int i = 1; i <= size(); i++) 
        { 
            Value val = getValue (i); 
            if (! isValueClean(i) && 
                    ! schema.getColumn (i).readOnly()) 
            { 
                if (! comma) 
                { 
                    iss1.append (schema.getColumn(i).name()); 
                    iss2.append ("?"); 
                    comma = true; 
                } 
                else 
                { 
                    iss1.append (", " + schema.getColumn(i).name()); 
                    iss2.append (", ?"); 
                } 
            } 
        } 
        return "INSERT INTO " + parentDataSet.getTableName () + " ( " + 
                iss1.toString() + " ) VALUES ( " + iss2.toString() + " )"; 
    } 
 
    /** 
       * This builds the SELECT statement in order to refresh the contents of 
       * this Record. It depends on a valid KeyDef to exist and it must have been 
       * created with a TableDataSet. 
       * 
       * @return     the SELECT string 
       * @exception   DataSetException 
       */ 
    public String getRefreshQueryString() throws DataSetException, 
    ConnectionException 
    { 
        if (parentDataSet.getKeyDef() == null || 
                parentDataSet.getKeyDef ().size() == 0) 
            throw new DataSetException ("You can only perform a getRefreshQueryString on a TableDataSet that was created with a KeyDef."); 
        else if (parentDataSet instanceof QueryDataSet) 
            throw new DataSetException ("You can only perform a getRefreshQueryString on Records created with a TableDataSet."); 
 
        StringBuffer iss1 = new StringBuffer (256); 
        StringBuffer iss2 = new StringBuffer (256); 
        boolean comma = false; 
 
        for (int i = 1; i <= size(); i++) 
        { 
            if (! comma) 
            { 
                iss1.append (schema.getColumn(i).name()); 
                comma = true; 
            } 
            else 
            { 
                iss1.append (", "); 
                iss1.append (schema.getColumn(i).name()); 
            } 
        } 
 
        comma = false; 
 
        for (int i = 1; i <= parentDataSet.getKeyDef ().size(); i++) 
        { 
            String attrib = parentDataSet.getKeyDef ().getAttrib(i); 
 
            if (! isValueClean(attrib)) 
                throw new DataSetException ( 
                        "You cannot do a refresh from the database if the value " + 
                        "for a KeyDef column has been changed with a Record.setValue()."); 
 
            if (! comma) 
            { 
                iss2.append (attrib); 
                iss2.append (" = ?"); 
                comma = true; 
            } 
            else 
            { 
                iss2.append (" AND "); 
                iss2.append (attrib); 
                iss2.append (" = ?"); 
            } 
        } 
        return "SELECT " + iss1.toString() + " FROM " + 
                parentDataSet.getTableName () + " WHERE " + iss2.toString(); 
    } 
    /** 
       Gets the appropriate SQL string for this record. 
 
       @return SQL string 
     */ 
    public String getSaveString() throws DataSetException, 
    ConnectionException 
    { 
        if (toBeSavedWithInsert()) 
        { 
            return getInsertSaveString(); 
        } 
        else if (toBeSavedWithUpdate()) 
        { 
            return getUpdateSaveString(); 
        } 
        else if (toBeSavedWithDelete()) 
        { 
            return getDeleteSaveString(); 
        } 
        else 
        { 
            throw new DataSetException ( 
                    "Not able to return save string: " + this.saveType); 
        } 
    } 
    /** 
        Gets the schema for the parent DataSet 
 
        @return the schema for the parent DataSet 
      */ 
    public Schema getSchema() throws DataSetException 
    { 
        if (parentDataSet != null) 
        { 
            return parentDataSet.schema; 
        } 
        throw new DataSetException ("Internal Error: Record DataSet is null"); 
    } 
    /** 
        Builds the SQL UPDATE statement for this Record 
        @return SQL UPDATE statement 
      */ 
    private String getUpdateSaveString() throws DataSetException, 
    ConnectionException 
    { 
        KeyDef kd = parentDataSet.getKeyDef (); 
        if (kd == null || kd.size() == 0) 
            throw new DataSetException ("You must specify KeyDef attributes for this TableDataSet in order to create a Record for update."); 
        else if (isRecordClean()) 
            throw new DataSetException ("You must Record.setValue() on a column before doing an update."); 
 
        StringBuffer iss1 = new StringBuffer (256); 
        StringBuffer iss2 = new StringBuffer (256); 
        boolean comma = false; 
 
        for (int i = 1; i <= size(); i++) 
        { 
            Value val = getValue (i); 
            if (! isValueClean(i) && 
                    ! schema.getColumn(i).readOnly()) 
            { 
                if (! comma) 
                { 
                    iss1.append (schema.getColumn(i).name()); 
                    iss1.append (" = ?"); 
                    comma = true; 
                } 
                else 
                { 
                    iss1.append (", "); 
                    iss1.append (schema.getColumn(i).name()); 
                    iss1.append (" = ?"); 
                } 
            } 
        } 
 
        comma = false; 
 
        for (int i = 1; i <= kd.size(); i++) 
        { 
            String attrib = kd.getAttrib(i); 
 
            //if (! isValueClean (schema.index (attrib))) 
            //    throw new DataSetException ("The value for column '" + 
            //            attrib + "' is a key value and cannot be updated."); 
 
            if (! comma) 
            { 
                iss2.append (attrib); 
                iss2.append (" = ?"); 
                comma = true; 
            } 
            else 
            { 
                iss2.append (" AND "); 
                iss2.append (attrib); 
                iss2.append (" = ?"); 
            } 
        } 
 
        return "UPDATE " + parentDataSet.getTableName () + " SET " + 
                iss1.toString() + " WHERE " + iss2.toString(); 
    } 
    /** 
        gets the value at index i 
        @return the Value object at index i 
      */ 
    public Value getValue (int i) throws DataSetException 
    { 
        if (i == 0) 
            throw new DataSetException ("Values are 1 based!"); 
        else if (i > size()) 
            throw new DataSetException ("Only " + size() + " columns exist!"); 
        else if (values[i] == null) 
            throw new DataSetException ("No values for the requested column!"); 
 
        return values[i]; 
    } 
    /** 
        gets the original keydef value at index i 
        @return the original Value object at index i 
      */ 
    public Value getOrigValue (int i) throws DataSetException 
    { 
		KeyDef kd = parentDataSet.getKeyDef (); 
		if (i == 0) 
            throw new DataSetException ("Values are 1 based!"); 
		else if (kd == null) 
			throw new DataSetException ("Keydef not defined!"); 
        else if (i > kd.size()) 
            throw new DataSetException ("Only " + size() + " keydef columns exist!"); 
        else if (keydefValues[i] == null) 
            throw new DataSetException ("No values for the requested column!"); 
 
        return keydefValues[i]; 
    } 
    public Value getValue (String columnName) throws DataSetException 
    { 
        return getValue(schema.index (columnName)); 
    } 
    public Value getOrigValue (String columnName) throws DataSetException 
    { 
		KeyDef kd = parentDataSet.getKeyDef (); 
		if (kd == null) 
			throw new DataSetException ("Keydef not defined!"); 
		for (int i = 1; i <= kd.size (); i++) 
		{ 
			if (kd.getAttrib (i).equals (columnName)) 
				return getOrigValue (i); 
		} 
        throw new DataSetException ("Key Column name: " + columnName + " does not exist!"); 
    } 
    /** 
        Performs initialization for this Record. 
      */ 
    private void initializeRecord() throws DataSetException 
    { 
        this.schema = getSchema (); 
        this.numberOfColumns = schema.numberOfColumns(); 
        this.values = new Value[size() + 1]; 
        this.isClean = new boolean[size() + 1]; 
        setSaveType(Enums.UNKNOWN); 
		 
        for (int i = 1; i <= size(); i++) 
        { 
            markValueClean(i); 
            this.values[i] = null; 
        } 
		 
		if (parentDataSet instanceof TableDataSet) 
		{ 
	        KeyDef kd = parentDataSet.getKeyDef(); 
			this.keydefValues = new Value[kd.size () + 1]; 
			for (int i = 1; i <= kd.size(); i++) 
				keydefValues[i] = null; 
		} 
    } 
    /** 
        Determines if this record is a Zombie. A Zombie is a record that has been deleted from the 
        database, but not yet removed from the DataSet. 
 
        @return a boolean 
      */ 
    public boolean isAZombie() 
    { 
        return (this.saveType == Enums.ZOMBIE) ? true : false; 
    } 
    /** 
        If the record is not clean, needs to be saved with an Update, Delete or Insert, it returns true. 
 
        @return boolean 
      */ 
    public boolean isDirty () 
    { 
        if (!isAZombie() || !isRecordClean() || toBeSavedWithUpdate() || 
                toBeSavedWithDelete() || toBeSavedWithInsert()) 
            return true; 
        else 
            return false; 
    } 
    /** 
        Goes through all the values in the record to determine if it is clean or not. 
 
        @return true if clean 
      */ 
    public boolean isRecordClean() 
    { 
        for (int i = 1; i <= size(); i++) 
        { 
            if (isValueClean(i) == false) 
                return false; 
        } 
        return true; 
    } 
    /** 
        Determines whether or not a value stored in the record is clean. 
 
        @return true if clean 
      */ 
    public boolean isValueClean(int i) 
    { 
        return isClean[i]; 
    } 
    /** 
        Determines whether or not a value stored in the record is clean. 
 
        @return true if clean 
      */ 
    public boolean isValueClean(String column) throws DataSetException 
    { 
        return isClean[getValue (column).columnNumber()]; 
    } 
    /** 
        Marks this record to be inserted when a save is executed. 
      */ 
    public void markForInsert() throws DataSetException 
    { 
        if (parentDataSet instanceof QueryDataSet) 
            throw new DataSetException ("You cannot mark a record in a QueryDataSet for insert"); 
 
        setSaveType (Enums.INSERT); 
    } 
    /** 
        Marks this record to be updated when a save is executed. 
      */ 
    public void markForUpdate() throws DataSetException 
    { 
        if (parentDataSet instanceof QueryDataSet) 
            throw new DataSetException ("You cannot mark a record in a QueryDataSet for update"); 
 
        setSaveType (Enums.UPDATE); 
    } 
    /** 
       * Marks all the values in this record as clean. 
       * 
       */ 
    public void markRecordClean() throws DataSetException 
    { 
        for (int i = 1; i <= size(); i++) 
        { 
            markValueClean(i); 
        } 
    } 
    /** 
        Marks this record to be deleted when a save is executed. 
      */ 
    public Record markToBeDeleted() throws DataSetException 
    { 
        if (parentDataSet instanceof QueryDataSet) 
            throw new DataSetException ("You cannot mark a record in a QueryDataSet for deletion"); 
 
        setSaveType (Enums.DELETE); 
        return this; 
    } 
    /** 
        marks a value at a given position as clean. 
      */ 
    public void markValueClean (int pos) throws DataSetException 
    { 
        if (pos == 0) 
            throw new DataSetException ("Value position must be greater than 0."); 
        else if (pos > size()) 
            throw new DataSetException ("Value position is greater than number of values."); 
 
        this.isClean[pos] = true; 
    } 
    /** 
        marks a value with a given column name as clean. 
      */ 
    public void markValueClean (String columnName) throws DataSetException 
    { 
        markValueClean (schema.index(columnName)); 
    } 
    /** 
        marks a value at a given position as dirty. 
      */ 
    public void markValueDirty (int pos) throws DataSetException 
    { 
        if (pos == 0) 
            throw new DataSetException ("Value position must be greater than 0."); 
        else if (pos > size()) 
            throw new DataSetException ("Value position is greater than number of values."); 
 
        this.isClean[pos] = false; 
    } 
    /** 
        marks a value with a given column name as dirty. 
      */ 
    public void markValueDirty (String columnName) throws DataSetException 
    { 
        markValueDirty (schema.index(columnName)); 
    } 
    /** 
       * This method refreshes this Record's Value's. It can only be performed on 
       * a Record that has not been modified and has been created with a TableDataSet 
       * and corresponding KeyDef. 
       * 
       * @param   connection 
       * @exception   DataSetException 
       * @exception   ConnectionException 
       */ 
    public void refresh (Connection connection) 
            throws DataSetException, ConnectionException 
    { 
        if (toBeSavedWithDelete()) 
            return; 
        else if (toBeSavedWithInsert()) 
            throw new DataSetException ("There is no way to refresh a record which has been created with addRecord()."); 
        else if (parentDataSet instanceof QueryDataSet) 
            throw new DataSetException ("You can only perform a refresh on Records created with a TableDataSet."); 
 
        PreparedStatement stmt = null; 
        try 
        { 
            stmt = connection.prepareStatement (getRefreshQueryString()); 
            int ps = 1; 
            for (int i = 1; i <= parentDataSet.getKeyDef ().size(); i++) 
            { 
                Value val = getValue ( 
                        parentDataSet.getKeyDef ().getAttrib(i)); 
 
                val.setPreparedStatementValue (stmt, ps++); 
            } 
 
            ResultSet rs = stmt.executeQuery(); 
            rs.next(); 
 
            initializeRecord(); 
 
            createValues(rs); 
        } 
        catch (SQLException e1) 
        { 
            throw new ConnectionException (e1); 
        } 
        finally { try 
            { 
                if (stmt != null) 
                    stmt.close(); 
            } 
            catch (SQLException e2) 
            { 
                throw new ConnectionException (e2); 
            } 
        } } 
    /** 
        Saves the data in this Record to the database. Uses the parent dataset's connection. 
        @return 1 if the save completed. 0 otherwise. 
      */ 
    public int save() throws DataSetException, ConnectionException 
    { 
        return save (parentDataSet.connection()); 
    } 
    /** 
        Saves the data in this Record to the database. Uses the connection passed into it. 
        @return 1 if the save completed. 0 otherwise. 
      */ 
    public int save (Connection connection) throws DataSetException, 
    ConnectionException 
    { 
        int returnValue = 0; 
 
        if (parentDataSet instanceof QueryDataSet) 
            throw new DataSetException ("You cannot save a QueryDataSet. Please use a TableDataSet instead."); 
 
        if (! isDirty ()) 
            return returnValue; 
 
        if (toBeSavedWithInsert()) 
            returnValue = saveWithInsert (connection); 
        else if (toBeSavedWithUpdate()) 
            returnValue = saveWithUpdate (connection); 
        else if (toBeSavedWithDelete()) 
            returnValue = saveWithDelete (connection); 
 
        return returnValue; 
    } 
    /** 
        Saves the data in this Record to the database with an DELETE statement 
        @return SQL DELETE statement 
      */ 
    private int saveWithDelete (Connection connection) 
            throws DataSetException, ConnectionException 
    { 
        PreparedStatement stmt = null; 
        try 
        { 
            stmt = connection.prepareStatement (getSaveString()); 
            int ps = 1; 
            for (int i = 1; i <= parentDataSet.getKeyDef ().size(); i++) 
            { 
                //Value val = getValue (parentDataSet.getKeyDef ().getAttrib(i)); 
				Value val = getOrigValue (parentDataSet.getKeyDef ().getAttrib(i)); 
				 
                val.setPreparedStatementValue (stmt, ps++); 
            } 
 
            int ret = stmt.executeUpdate(); 
 
            setSaveType (Enums.ZOMBIE); 
 
            ((TableDataSet) parentDataSet).removeDeletedRecords(); 
 
            if (ret > 1) 
           		throw new ConnectionException ("There were " + ret + " rows deleted with this records key value."); 
 
            return ret; 
        } 
        catch (SQLException e1) 
        { 
            throw new ConnectionException (e1); 
        } 
        finally { try 
            { 
                if (stmt != null) 
                    stmt.close(); 
            } 
            catch (SQLException e2) 
            { 
                throw new ConnectionException (e2); 
            } 
        } } 
    /** 
        Saves the data in this Record to the database with an INSERT statement 
        @return SQL INSERT statement 
      */ 
    private int saveWithInsert (Connection connection) 
            throws DataSetException, ConnectionException 
    { 
        PreparedStatement stmt = null; 
 
        try 
        { 
            stmt = connection.prepareStatement (getSaveString()); 
            int ps = 1; 
            for (int i = 1; i <= size(); i++) 
            { 
                Value val = getValue (i); 
                if (! isValueClean(i) && 
                        ! schema.getColumn(i).readOnly()) 
                { 
                    val.setPreparedStatementValue (stmt, ps++); 
                } 
            } 
            int ret = stmt.executeUpdate(); 
 
            if (((TableDataSet) parentDataSet).isRefreshOnSave()) 
            { 
                refresh (parentDataSet.connection()); 
            } 
            else 
            { 
                // Marks all of the values clean since they have now been saved 
                markRecordClean(); 
            } 
 
            setSaveType (Enums.AFTERINSERT); 
 
            if (ret > 1) 
                throw new ConnectionException ("There were " + ret + " rows inserted with this records key value."); 
 
            return ret; 
        } 
        catch (SQLException e1) 
        { 
            throw new ConnectionException (e1); 
        } 
        finally { try 
            { 
                if (stmt != null) 
                    stmt.close(); 
            } 
            catch (SQLException e2) 
            { 
                throw new ConnectionException (e2); 
            } 
        } } 
    /** 
        Saves the data in this Record to the database with an UPDATE statement 
        @return SQL UPDATE statement 
      */ 
    private int saveWithUpdate (Connection connection) 
            throws DataSetException, ConnectionException 
    { 
        PreparedStatement stmt = null; 
        try 
        { 
            stmt = connection.prepareStatement (getSaveString()); 
            int ps = 1; 
            for (int i = 1; i <= size(); i++) 
            { 
                Value val = getValue (i); 
                if (! isValueClean(i) && 
                        ! schema.getColumn(i).readOnly()) 
                { 
                    val.setPreparedStatementValue (stmt, ps++); 
                } 
            } 
            for (int i = 1; i <= parentDataSet.getKeyDef ().size(); i++) 
            { 
                //Value val = getValue (parentDataSet.getKeyDef ().getAttrib(i)); 
				Value val = getOrigValue (parentDataSet.getKeyDef ().getAttrib(i)); 
                if (val.isNull()) 
                    throw new DataSetException ("You cannot execute an update with a null value for a KeyDef."); 
 
                val.setPreparedStatementValue (stmt, ps++); 
            } 
 
            int ret = stmt.executeUpdate(); 
 
            if (((TableDataSet) parentDataSet).isRefreshOnSave()) 
            { 
                refresh (parentDataSet.connection()); 
            } 
            else 
            { 
                // Marks all of the values clean since they have now been saved 
                markRecordClean(); 
            } 
 
            setSaveType (Enums.AFTERUPDATE); 
 
            if (ret > 1) 
                throw new SQLException ("There were " + ret + " rows updated with this records key value."); 
 
            return ret; 
        } 
        catch (SQLException e1) 
        { 
            throw new ConnectionException (e1); 
        } 
        finally { try 
            { 
                if (stmt != null) 
                    stmt.close(); 
            } 
            catch (SQLException e2) 
            { 
                throw new ConnectionException (e2); 
            } 
        } } 
    /** 
        sets the internal save type as one of the defined privates (ie: ZOMBIE) 
      */ 
    void setSaveType (int type) 
    { 
        this.saveType = type; 
    } 
    /** 
        gets the internal save type as one of the defined privates (ie: ZOMBIE) 
      */ 
    int getSaveType () 
    { 
        return (this.saveType); 
    } 
    /** 
        sets the value at pos with a byte[] 
      */ 
    public Record setValue (int pos, byte[] value) throws DataSetException 
    { 
        this.values[pos].setValue (value); 
        markValueDirty (pos); 
        return this; 
    } 
    /** 
        sets the value at pos with a double 
      */ 
    public Record setValue (int pos, double value) throws DataSetException 
    { 
        this.values[pos].setValue (new Double (value)); 
        markValueDirty (pos); 
        return this; 
    } 
    /** 
        sets the value at pos with a float 
      */ 
    public Record setValue (int pos, float value) throws DataSetException 
    { 
        this.values[pos].setValue (new Float (value)); 
        markValueDirty (pos); 
        return this; 
    } 
    /** 
        sets the value at pos with a int 
      */ 
    public Record setValue (int pos, int value) throws DataSetException 
    { 
        this.values[pos].setValue (new Integer (value)); 
        markValueDirty (pos); 
        return this; 
    } 
    /** 
        sets the value at pos with a long 
      */ 
    public Record setValue (int pos, long value) throws DataSetException 
    { 
        this.values[pos].setValue (new Long (value)); 
        markValueDirty (pos); 
        return this; 
    } 
    /** 
        sets the value at pos with a Value 
      */ 
    public Record setValue (int pos, Value value) throws DataSetException 
    { 
        this.values[pos].setValue (value.getValue()); 
        markValueDirty (pos); 
        return this; 
    } 
    /** 
        sets the value at pos with a String 
      */ 
    public Record setValue (int pos, String value) throws DataSetException 
    { 
        this.values[pos].setValue (value); 
        markValueDirty (pos); 
        return this; 
    } 
    /** 
        sets the value at pos with a BigDecimal 
      */ 
    public Record setValue (int pos, 
            BigDecimal value) throws DataSetException 
    { 
        this.values[pos].setValue (value); 
        markValueDirty (pos); 
        return this; 
    } 
    /** 
        sets the value at pos with a java.sql.Date 
      */ 
    public Record setValue (int pos, 
            java.sql.Date value) throws DataSetException 
    { 
        this.values[pos].setValue (value); 
        markValueDirty (pos); 
        return this; 
    } 
    /** 
        sets the value at pos with a java.sql.Time 
      */ 
    public Record setValue (int pos, 
            java.sql.Time value) throws DataSetException 
    { 
        this.values[pos].setValue (value); 
        markValueDirty (pos); 
        return this; 
    } 
    /** 
        sets the value at pos with a java.sql.Timestamp 
      */ 
    public Record setValue (int pos, 
            java.sql.Timestamp value) throws DataSetException 
    { 
        this.values[pos].setValue (value); 
        markValueDirty (pos); 
        return this; 
    } 
    /** 
        sets the value at pos with a java.util.Date 
      */ 
    public Record setValue (int pos, 
            java.util.Date value) throws DataSetException 
    { 
        this.values[pos].setValue (value); 
        markValueDirty (pos); 
        return this; 
    } 
    /** 
        sets the value at pos with a boolean 
      */ 
    public Record setValue (int pos, boolean value) throws DataSetException 
    { 
        this.values[pos].setValue (new Boolean (value)); 
        markValueDirty (pos); 
        return this; 
    } 
    /** 
        sets the value at column name with a byte[] 
      */ 
    public Record setValue (String columnName, 
            byte[] value) throws DataSetException 
    { 
        setValue (schema.index(columnName), value); 
        return this; 
    } 
    /** 
        sets the value at column name with a double 
      */ 
    public Record setValue (String columnName, 
            double value) throws DataSetException 
    { 
        setValue (schema.index(columnName), value); 
        return this; 
    } 
    /** 
        sets the value at column name with a float 
      */ 
    public Record setValue (String columnName, 
            float value) throws DataSetException 
    { 
        setValue (schema.index(columnName), value); 
        return this; 
    } 
    /** 
        sets the value at column name with a int 
      */ 
    public Record setValue (String columnName, 
            int value) throws DataSetException 
    { 
        setValue (schema.index(columnName), value); 
        return this; 
    } 
    /** 
        sets the value at column name with a long 
      */ 
    public Record setValue (String columnName, 
            long value) throws DataSetException 
    { 
        setValue (schema.index(columnName), value); 
        return this; 
    } 
    /** 
        sets the value at column name with a Value 
      */ 
    public Record setValue (String columnName, 
            Value value) throws DataSetException 
    { 
        setValue (schema.index(columnName), value); 
        return this; 
    } 
    /** 
        sets the value at column name with a String 
      */ 
    public Record setValue (String columnName, 
            String value) throws DataSetException 
    { 
        setValue (schema.index(columnName), value); 
        return this; 
    } 
    /** 
        sets the value at column name with a BigDecimal 
      */ 
    public Record setValue (String columnName, 
            BigDecimal value) throws DataSetException 
    { 
        setValue (schema.index(columnName), value); 
        return this; 
    } 
    /** 
        sets the value at column name with a java.sql.Date 
      */ 
    public Record setValue (String columnName, 
            java.sql.Date value) throws DataSetException 
    { 
        setValue (schema.index(columnName), value); 
        return this; 
    } 
    /** 
        sets the value at column name with a java.sql.Time 
      */ 
    public Record setValue (String columnName, 
            java.sql.Time value) throws DataSetException 
    { 
        setValue (schema.index(columnName), value); 
        return this; 
    } 
    /** 
        sets the value at column name with a java.sql.Timestamp 
      */ 
    public Record setValue (String columnName, 
            java.sql.Timestamp value) throws DataSetException 
    { 
        setValue (schema.index(columnName), value); 
        return this; 
    } 
    /** 
        sets the value at column name with a java.util.Date 
      */ 
    public Record setValue (String columnName, 
            java.util.Date value) throws DataSetException 
    { 
        setValue (schema.index(columnName), value); 
        return this; 
    } 
    /** 
        sets the value at column name with a boolean 
      */ 
    public Record setValue (String columnName, 
            boolean value) throws DataSetException 
    { 
        setValue (schema.index(columnName), value); 
        return this; 
    } 
    /** 
        sets the value at pos with a NULL 
      */ 
    public Record setValueNull (int pos) throws DataSetException 
    { 
        if (pos == 0) 
            throw new DataSetException ("Value position must be greater than 0."); 
        else if (pos > size()) 
            throw new DataSetException ("Value position is greater than number of values."); 
 
        this.values[pos].setValue (null); 
        markValueDirty (pos); 
        return this; 
    } 
    /** 
        sets the value at column name with a NULL 
      */ 
    public Record setValueNull (String columnName) throws DataSetException 
    { 
        if (columnName == null || columnName.length() == 0) 
            throw new DataSetException ("You must specify a column name!"); 
 
        setValueNull(schema.index(columnName)); 
        return this; 
    } 
    /** 
        the number of columns in this object 
        @return the number of columns in this object 
      */ 
    public int size() 
    { 
        return numberOfColumns; 
    } 
    /** 
        whether or not this Record is to be saved with an SQL delete statement 
        @return true if saved with delete 
      */ 
    public boolean toBeSavedWithDelete() 
    { 
        return (this.saveType == Enums.DELETE) ? true : false; 
    } 
    /** 
        whether or not this Record is to be saved with an SQL insert statement 
        @return true if saved with insert 
      */ 
    public boolean toBeSavedWithInsert() 
    { 
        return (this.saveType == Enums.INSERT) ? true : false; 
    } 
    /** 
        whether or not this Record is to be saved with an SQL update statement 
        @return true if saved with update 
      */ 
    public boolean toBeSavedWithUpdate() 
    { 
        return (this.saveType == Enums.UPDATE) ? true : false; 
    } 
    /** 
      * This returns a representation of this Record 
      * @return java.lang.String 
      */ 
    public String toString () 
    { 
        ByteArrayOutputStream bout = new ByteArrayOutputStream (); 
        PrintWriter out = new PrintWriter (bout); 
        out.print ("{"); 
        try 
        { 
            for (int i = 1; i <= size (); i++) 
            { 
                out.print ("'" + getValue (i) + "'"); 
                if (i < size ()) 
                    out.print (','); 
            } 
        } 
        catch (IOException ioe) 
            {} 
        out.print ("}"); 
        out.flush (); 
        return bout.toString (); 
    } 
    /** 
        Unmarks a record that has been marked for deletion. 
        

WARNING: You must reset the save type before trying to save this record again. @see #markForUpdate() @see #markForInsert() @see #markToBeDeleted() */ public Record unmarkToBeDeleted() throws DataSetException { if (this.saveType == Enums.ZOMBIE) throw new DataSetException ("This record has already been deleted!"); setSaveType (Enums.UNKNOWN); return this; } }